diff -Nru openra-20200503/appveyor.yml openra-20210321/appveyor.yml --- openra-20200503/appveyor.yml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/appveyor.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -version: 1.0.{build} -image: Visual Studio 2017 - -environment: - CoverityProjectToken: - secure: BYP5qnptMazSCwTwgiFHlfqZd7BM3bwTRq2Cbs++ofg= - CoverityNotificationEmail: - secure: 0kyu0t8QwQYUQzqguVJP3N+VpEDfET2ArP+JNnOsUELJQvH8qbeQzPTM0ga0ek5G - -install: - -cache: - - thirdparty\download -> thirdparty\fetch-thirdparty-deps.ps1 - -before_build: -- make dependencies - -build: - project: OpenRA.sln - verbosity: minimal - -after_build: -- ps: | - if ($env:APPVEYOR_SCHEDULED_BUILD -eq "True") - { - cov-build.exe --dir cov-int make all - nuget.exe install PublishCoverity -ExcludeVersion - PublishCoverity\tools\PublishCoverity.exe compress -o coverity.zip -i cov-int - $version = Get-Date -format s - PublishCoverity\tools\PublishCoverity.exe publish ` - -t "$env:CoverityProjectToken" ` - -e "$env:CoverityNotificationEmail" ` - -r "$env:APPVEYOR_REPO_NAME" ` - -z coverity.zip ` - -d "AppVeyor scheduled build ($env:APPVEYOR_BUILD_VERSION)." ` - --codeVersion "$version" - } - -before_test: -- ps: | - if ($env:APPVEYOR_SCHEDULED_BUILD -eq "True") - { - choco install resharper-clt -y - dupFinder /output=dupReport.xml /show-text OpenRA.sln - choco install xmlstarlet -y - xml transform dupFinder.xslt dupReport.xml > dupReport.html - choco install pandoc -y - } - -test_script: - - nunit3-console OpenRA.Test.dll --result=myresults.xml;format=AppVeyor - -after_test: - - appveyor DownloadFile "https://download.ip2location.com/lite/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP" -FileName IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP - - appveyor DownloadFile "https://raw.githubusercontent.com/wiki/OpenRA/OpenRA/Changelog.md" -FileName Changelog.md - - make docs - - ps: dir *.md | % {gc $_ -Raw | .\ConvertFrom-Markdown.ps1 | Out-File -FilePath "$($_.Name.TrimEnd(".md")).html"} - - ps: (Get-Content "${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\WindowsLauncher.cs.in").replace('DISPLAY_NAME', 'Red Alert').replace('MOD_ID', 'ra').replace('FAQ_URL', 'http://wiki.openra.net/FAQ') | Set-Content "${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\WindowsLauncher.cs" - - ps: C:\"Program Files (x86)"\"Microsoft Visual Studio"\2017\Community\MSBuild\15.0\Bin\Roslyn\csc.exe /noconfig /platform:x64 /reference:System.dll /reference:System.Core.dll /reference:System.Drawing.dll /reference:System.Windows.Forms.dll /reference:"${env:APPVEYOR_BUILD_FOLDER}\OpenRA.Game.exe" /out:"${env:APPVEYOR_BUILD_FOLDER}\RedAlert.exe" /win32icon:"${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\RedAlert.ico" /target:winexe ${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\WindowsLauncher.cs - - ps: (Get-Content "${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\WindowsLauncher.cs.in").replace('DISPLAY_NAME', 'Tiberian Dawn').replace('MOD_ID', 'cnc').replace('FAQ_URL', 'http://wiki.openra.net/FAQ') | Set-Content "${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\WindowsLauncher.cs" - - ps: C:\"Program Files (x86)"\"Microsoft Visual Studio"\2017\Community\MSBuild\15.0\Bin\Roslyn\csc.exe /noconfig /platform:x64 /reference:System.dll /reference:System.Core.dll /reference:System.Drawing.dll /reference:System.Windows.Forms.dll /reference:"${env:APPVEYOR_BUILD_FOLDER}\OpenRA.Game.exe" /out:"${env:APPVEYOR_BUILD_FOLDER}\TiberianDawn.exe" /win32icon:"${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\TiberianDawn.ico" /target:winexe ${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\WindowsLauncher.cs - - ps: (Get-Content "${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\WindowsLauncher.cs.in").replace('DISPLAY_NAME', 'Dune 2000').replace('MOD_ID', 'd2k').replace('FAQ_URL', 'http://wiki.openra.net/FAQ') | Set-Content "${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\WindowsLauncher.cs" - - ps: C:\"Program Files (x86)"\"Microsoft Visual Studio"\2017\Community\MSBuild\15.0\Bin\Roslyn\csc.exe /noconfig /platform:x64 /reference:System.dll /reference:System.Core.dll /reference:System.Drawing.dll /reference:System.Windows.Forms.dll /reference:"${env:APPVEYOR_BUILD_FOLDER}\OpenRA.Game.exe" /out:"${env:APPVEYOR_BUILD_FOLDER}\Dune2000.exe" /win32icon:"${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\Dune2000.ico" /target:winexe ${env:APPVEYOR_BUILD_FOLDER}\packaging\windows\WindowsLauncher.cs - - ps: cp packaging\windows\OpenRA.ico . - - ps: cp packaging\windows\RedAlert.ico . - - ps: cp packaging\windows\TiberianDawn.ico . - - ps: cp packaging\windows\Dune2000.ico . - - if defined APPVEYOR_REPO_TAG_NAME set VERSION=%APPVEYOR_REPO_TAG_NAME% - - if not defined APPVEYOR_REPO_TAG_NAME set VERSION=%APPVEYOR_REPO_COMMIT:~0,7% - - '"C:\Program Files (x86)\NSIS\makensis.exe" /DSRCDIR="%APPVEYOR_BUILD_FOLDER%" /DDEPSDIR="%APPVEYOR_BUILD_FOLDER%\thirdparty\download\windows" /DTAG="git-%VERSION%" /DSUFFIX=" (dev)" /V3 packaging/windows/OpenRA.nsi' - - move /Y %APPVEYOR_BUILD_FOLDER%\packaging\windows\OpenRA.Setup.exe %APPVEYOR_BUILD_FOLDER%\OpenRA-%VERSION%.exe - -artifacts: - - path: OpenRA-$(VERSION).exe - name: Installer - - path: coverity.zip - name: Coverity Build - - path: dupReport.html - name: dupFinder Report diff -Nru openra-20200503/AUTHORS openra-20210321/AUTHORS --- openra-20200503/AUTHORS 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/AUTHORS 2021-03-21 11:10:05.000000000 +0000 @@ -40,6 +40,7 @@ * Biofreak * Braxton Williams (Buddytex) * Brendan Gluth (Mechanical_Man) + * Brent Gardner (bggardner) * Bryan Wilbur * Bugra Cuhadaroglu (BugraC) * Chris Cameron (Vesuvian) @@ -137,16 +138,19 @@ * Sebastien Kerguen (xanax) * Shawn Collins (UberWaffe) * Simon Verbeke (Saticmotion) + * Stuart McHattie (SDJMcHattie) * Taryn Hill (Phrohdoh) * Teemu Nieminen (Temeez) * Tim Mylemans (gecko) * Tirili * Tomas Einarsson (Mesacer) * Tom van Leth (tovl) + * Trevor Nichols (ocdi) * Tristan Keating (Kilkakon) * Tristan Mühlbacher (MicroBit) * UnknownProgrammer * Vladimir Komarov (VrKomarov) + * Wojciech Walaszek (Voidwalker) * Wuschel Using GNU FreeFont distributed under the GNU GPL @@ -179,6 +183,14 @@ Using rix0rrr.BeaconLib developed by Rico Huijbers distributed under MIT License. +Using DiscordRichPresence developed by Lachee +distributed under MIT License. + +Using Json.NET developed by James Newton-King +distributed under MIT License. + +Using ANGLE distributed under the BS3 3-Clause license. + This site or product includes IP2Location LITE data available from http://www.ip2location.com. diff -Nru openra-20200503/configure-system-libraries.sh openra-20210321/configure-system-libraries.sh --- openra-20200503/configure-system-libraries.sh 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/configure-system-libraries.sh 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,51 @@ +#!/bin/sh +# Patch *.dll.config files to use system libraries, working around issues with directories and naming schemes + +#### +# This file must stay /bin/sh and POSIX compliant for macOS and BSD portability. +# Copy-paste the entire script into http://shellcheck.net to check. +#### + +patch_config() +{ + LABEL=$1 + SEARCHDIRS=$2 + CONFIG=$3 + REPLACE=$4 + SEARCH=$5 + + # Exit early if the file has already been patched + grep -q "target=\"${REPLACE}\"" "${CONFIG}" || return 0 + + printf "Searching for %s... " "${LABEL}" + for DIR in ${SEARCHDIRS} ; do + for LIB in ${SEARCH}; do + if [ -f "${DIR}/${LIB}" ]; then + echo "${LIB}" + sed "s|target=\"${REPLACE}\"|target=\"${DIR}/${LIB}\"|" "${CONFIG}" > "${CONFIG}.temp" + mv "${CONFIG}.temp" "${CONFIG}" + return 0 + fi + done + done + + echo "FAILED" + + echo "OpenRA expects to find a file matching \"${SEARCH}\" in one of the following locations:" + echo "${SEARCHDIRS}" + exit 1 +} + +if [ "$(uname -s)" = "Darwin" ]; then + SEARCHDIRS="/usr/local/lib /usr/local/opt/openal-soft/lib" + patch_config "Lua 5.1" "${SEARCHDIRS}" bin/Eluant.dll.config lua51.dylib liblua5.1.dylib + patch_config SDL2 "${SEARCHDIRS}" bin/SDL2-CS.dll.config SDL2.dylib libSDL2-2.0.0.dylib + patch_config OpenAL "${SEARCHDIRS}" bin/OpenAL-CS.Core.dll.config soft_oal.dylib libopenal.1.dylib + patch_config FreeType "${SEARCHDIRS}" bin/OpenRA.Platforms.Default.dll.config freetype6.dylib libfreetype.6.dylib +else + SEARCHDIRS="/lib /lib64 /usr/lib /usr/lib64 /usr/lib/i386-linux-gnu /usr/lib/x86_64-linux-gnu /usr/lib/arm-linux-gnueabihf /usr/lib/aarch64-linux-gnu /usr/lib/powerpc64le-linux-gnu /usr/lib/mipsel-linux-gnu /usr/local/lib /opt/lib /opt/local/lib /app/lib" + patch_config "Lua 5.1" "${SEARCHDIRS}" bin/Eluant.dll.config lua51.so "liblua.so.5.1.5 liblua5.1.so.5.1 liblua5.1.so.0 liblua.so.5.1 liblua-5.1.so liblua5.1.so" + patch_config SDL2 "${SEARCHDIRS}" bin/SDL2-CS.dll.config SDL2.so "libSDL2-2.0.so.0 libSDL2-2.0.so libSDL2.so" + patch_config OpenAL "${SEARCHDIRS}" bin/OpenAL-CS.Core.dll.config soft_oal.so "libopenal.so.1 libopenal.so" + patch_config FreeType "${SEARCHDIRS}" bin/OpenRA.Platforms.Default.dll.config freetype6.so "libfreetype.so.6 libfreetype.so" +fi diff -Nru openra-20200503/ConvertFrom-Markdown.ps1 openra-20210321/ConvertFrom-Markdown.ps1 --- openra-20200503/ConvertFrom-Markdown.ps1 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/ConvertFrom-Markdown.ps1 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -<# -.SYNOPSIS - Converts Markdown formatted text to HTML. -.DESCRIPTION - Converts Markdown formatted text to HTML using the Github API. Output is "flavored" depending on - the chosen mode. The default output flavor is 'Markdown' and includes Syntax highlighting and - Github stylesheets. - - Based on the Ruby version by Brett Terpstra: - http://brettterpstra.com/easy-command-line-github-flavored-markdown/ - - About Markdown: http://daringfireball.net/projects/markdown/ -#> -function ConvertFrom-Markdown { - [CmdletBinding()] - Param - ( - [Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)] - [PSObject[]]$InputObject - ) - - Begin - { - $URL = "https://api.github.com/markdown" - } - - Process - { - Foreach ($item in $InputObject) - { - $object = New-Object -TypeName psobject - $object | Add-Member -MemberType NoteProperty -Name 'text' -Value ($item | Out-String) - $object | Add-Member -MemberType NoteProperty -Name 'mode' -Value 'markdown' - - $response = Invoke-WebRequest -Method Post -Uri $url -Body ($object | ConvertTo-Json) - - if ($response.StatusCode -eq "200") - { - $HtmlOutput = - @" - - - - - - - -
- $($response.Content) -
- - -"@ - - Write-Output $HtmlOutput - } - else - { - "Error: $($response.StatusCode)" - } - } - } -} diff -Nru openra-20200503/debian/backuprestore.sh openra-20210321/debian/backuprestore.sh --- openra-20200503/debian/backuprestore.sh 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/debian/backuprestore.sh 2021-03-24 10:53:50.000000000 +0000 @@ -0,0 +1,13 @@ +#/bin/sh +action=${1:-restore} + +for i in VERSION mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml; +do + + if [ "$action" = "restore" ]; then + test -f ${i}.ORIG && mv ${i}.ORIG ${i} || true; + + else + test -f ${i}.ORIG || cp ${i} ${i}.ORIG; + fi +done diff -Nru openra-20200503/debian/changelog openra-20210321/debian/changelog --- openra-20200503/debian/changelog 2021-01-14 06:24:20.000000000 +0000 +++ openra-20210321/debian/changelog 2021-03-26 06:29:41.000000000 +0000 @@ -1,3 +1,576 @@ +openra (20210321-1~xtradeb6) focal; urgency=medium + + * MSBUILD nuget restore is working. Remove debug. + + -- Jhonny Oliveira Fri, 26 Mar 2021 06:29:41 +0000 + +openra (20210321-1~xtradeb5) focal; urgency=medium + + * Another attempt + + -- Jhonny Oliveira Thu, 25 Mar 2021 20:29:15 +0000 + +openra (20210321-1~xtradeb4) focal; urgency=medium + + * Another attempt to build offline in Launchpad: use non relative path + + -- Jhonny Oliveira Thu, 25 Mar 2021 16:41:12 +0000 + +openra (20210321-1~xtradeb3) focal; urgency=medium + + * Fix broken nuget cache path + + -- Jhonny Oliveira Thu, 25 Mar 2021 12:58:05 +0000 + +openra (20210321-1~xtradeb2) focal; urgency=medium + + * Ensure offline packaging + + -- Jhonny Oliveira Thu, 25 Mar 2021 12:57:37 +0000 + +openra (20210321-1~xtradeb1) focal; urgency=medium + + * Fix upstream download URL in debian watch file + * New upstream release. + - General Improvements + - Added a per-player handicap option to the lobby in all mods. + [#18971, #19083] + - Added a setting to pause the shellmap. [#18973] + - Added map and server name to Discord details. [#19010] + - Added support for Discord Rich Presence. [#17847, #18469, #18547] + - Added the ability to right click on spawn points in the server lobby to + disable them. [#18425, #18823] + - Added support for server-side replay recording. [#17578, #18672, #18696, + #18715] + - Added DisplayFaction details to the replay metadata. [#18874] + - Added an option for overriding duplicate hotkeys in the settings dialog. + [#17666] + - Added support for the macOS Dark appearance. [#18837] + - Added IPv6 support for server and direct connect. [#18026, #18902] + - Added player status label to the spectator visibility selector. [#18143] + - Added support for DirectX 11 rendering via ANGLE and disabled legacy + OpenGL 2.1 support. [#18666] + - Fixed lobby options clickable area overlapping with scrollbars. [#19202] + - Fixed production rally points not drawing from the building's exit point. + [#18987] + - Fixed production structures using the wrong exits under some situations. + [#18988] + - Fixed a crash when a production structure is captured at the same time it + builds a unit. [#19009] + - Fixed a crash when a non-admin player tried to switch maps in the lobby. + [#18984] + - Fixed lobby options not being reported to the first player who joins a + dedicated server. [#19000] + - Fixed support power targetting cursor not resetting when the power cannot + be activated. [#19032] + - Fixed Discord join button not allowing spectators to join after player + slots were filled. [#19007] + - Fixed an issue that could cause sounds to stop working after loading a + saved game. [#18593] + - Fixed several graphical issues when playing campaign videos. [#18623, + #18369, #18661] + - Fixed non-functional AI bots in multiplayer games if the Game Admin role + is tranferred between players. [#18184] + - Fixed an issue that could cause aircraft to be lost outside the map. + [#18108] + - Fixed infantry sometimes cancelling attack animation prematurely. [#18893, + #18913] + - Fixed an issue that could give players permanent vision at map edge when + using air-based support powers. [#18294] + - Fixed clearing mission objectives sometimes not properly ending the game. + [#18892] + - Fixed viewport moving to incorrect position when jumping to control group + that contains units inside a transport. [#18076] + - Fixed authentication key being copied to clipboard at game start for + accounts that have already been linked to the OpenRA forum. [#18257] + - Fixed non-turreted units delaying unnecessarily when Attack-moving or + attacking moving targets. [#18549, #18605, #18885] + - Fixed issues with capturing actors not correctly updating power usage. + [#18303, #18457] + - Fixed incorrect target line display for units after repairing/reloading on + a repair depot [#18141, #18159] + - Fixed target lines appearing not long enough on screen. [#18401] + - Fixed ill-fitting selection decorations when spectators zoom too far out + by hiding them. [#17992] + - Fixed an issue that could allow orders to be issues to the wrong units + when using control groups. [#18003, #18699] + - Fixed an issue with custom maps that may cause a dedicated server to + crash. [#18630] + - Fixed tooltips remaining after leaving/switching the menu. [#18775] + - Fixed several issues with vibility for players that have become spectators + after losing (or winning) a game. [#18772] + - Fixed infantry moving to the top-left instead of the center of a cell + after being produced. [#18879] + - Fixed vehicle turrets not rotating with their body as they turn. [#18418, + #18679, #18738, #18903] + - Fixed a crash with attempted out-of-bounds movement. [#18083, #18343] + - Fixed a crash when targeting an airstrike at the map edge. [#18366] + - Fixed a crash with certain Linux GPU drivers. [#18575] + - Fixed a crash when an aircraft leaves a reserved airfield or helipad. + [#18810] + - Changed the default UPnP device discovery timeout from 1 to 5 seconds. + [#18216] + - Changed infantry to always turn in place instead of moving in a curve. + [#18293] + - Changed replay filenames to be prefixed by the mod id for easier + identification. [#18390] + - Changed the battlefield zoom to be centered on the mouse cursor. [#18406] + - Changed the Cmd+Q hotkey to no longer quit the game on macOS. [#18438] + - Changed unit behaviour to attack-move to service depot and airfield rally + points. [#18161] + - Changed game lobby behaviour to remove player "Ready" status when the host + changes a map option. [#18494, #18590] + - Changed production buildings to prefer the closest available exit to a + requested rally point. [#18461, #18863, #18880, #18894] + - Improved AI unit and support power targeting behaviour. [#17855, #17986, + #18055, #18692, #18697, #18710, #18900] + - Improved the player asset value shown to spectators by ignoring walls and + support aircraft. [#18592] + - Improved performance. [#17472, #17763, #18126, #18167, #18180, #18202, + #18205, #18207, #18346, #18349, #18357, #18371, #18512, #18530, #18531, + #18544, #18559, #18587, #18613, #18640, #18667, #18671, #18698, #18707, + #18708, #18709, #18743, #18770, #18774, #18762, #18869] + - Improved presentation of non-default map options in the lobby chat when + join a server. [#18704] + - Various minor fixes and code cleanups. [#18519, #18604, #18606, #18607, + #18614, #18621] + - Removed ingame music downloads to comply with new C&C modding policy. + [#18647] + - Red Alert + - Added missing civilian clothing colors. [#18099] + - Added the ability for Hijackers to steal landed aircraft. [#18432] + - Added new artwork for the disguised spy indicator. [#17810] + - Added minigame Oil Spill. [#18934] + - Fixed infantry stopping next to buildings when attack-moving. [#19030] + - Fixed bot-controlled aircraft sometimes stopping mid-air above submerged + submarines. [#19036] + - Fixed missing/incorrect Shock Trooper and Mechanic voices. [#18967, #18964] + - Fixed infantry death animations playing too fast. [#19096] + - Fixed rendering artifacts with RA's video background on HiDPI displays. + [#19177] + - Fixed Minelayers getting stuck at the edge of the map when a minefield is + created out of bounds. [#18101] + - Fixed unit artwork facing the wrong direction at some angles. [#18020, + #18200] + - Fixed MiG missile splash damaging airborne actors. [#18470] + - Fixed units chasing newly disguised enemies. [#18703] + - Fixed missing "Select Target" audio when selecting the Chronoshift + superweapon. [#18787] + - Changed tech buildings to spawn 'cheaper' scientists, and as result more + engineers. [#18875] + - Changed fake building tags to be always visible (to self and allies). + [#17812] + - Changed the Chronosphere, Iron Curtain, Nuke Silo and Allied Tech Center + to be infiltratable to reset the support power timer. [#17783] + - Changed submarines to no longer be produced in the "Hold Fire" stance. + [#18237] + - Changed DepthCharge sound and explosion effects. [#18068] + - Changed Oil Derricks to only show money indicators when captured by a + player. [#18682] + - Changed the RA Phase Tank to uncloak during repair. [#18107] + - Reduced Tanya fire rate and polished fire animation. [#19064, #19118] + - Removed civilians spawning from civilian buildings to avoid mission bugs. + [#19069] + - Improved weapon visual effects for several units/weapons. [#17284, #18068, + #18126, #18307, #18440, #18629, #18712, #18738] + - Improved death animations for ships. [#18068] + - Mission fixes and additions: + - Added campaign mission Allies-09a. [#18695] + - Added campaign mission Soviet-08b. [#17973] + - Added campaign mission Soviet-09. [#17963] + - Added mission Production Disruption from Aftermath. [#18230] + - Added mission Fall of Greece 1: Personal War from Counterstrike. [#18098, + #18429] + - Added mission Situation Critical from Aftermath. [#18156, #18429, #19233] + - Added Aftermath mission Shock Therapy. [#18943] + - Added mission Siberian Conflict 1: Fresh Tracks from Counterstrike. + [#18240] + - Added mission Sarin Gas 3: Controlled Burn from Counterstrike. [#18430] + - Added panicking civilians leaving houses in Soviet-01. [#18124] + - Added clarifying objective to Monster Tank Madness. [#19145] + - Fixed a crash in mission Evacuation when paratroopers are deployed. + [#18204] + - Fixed a performance bug in the Exodus mission. [#18979] + - Fixed aircraft sometimes getting stuck in campaign missions. [#18308] + - Fixed issues in Soviet Soldier Volkov and Chitzkoi. [#18195] + - Fixed scripting issues in Allies 05a. [#19105, #19113] + - Fixed the country palette remap for mission: [#18950] + - Fall of Greece 1: Personal War + - Siberian Conflict 1: Fresh Tracks + - Production Disruption + - Changed campaign Soviet-05 to use modular AI. [#17129] + - Removed redundant rules from the shellmap. [#18049] + - Removed manual paratrooper drops on Soviet-01. [#18124] + - Updated default map pool [#18617]: + - Removed Northwest Passage, Winter Storm, Poland Raid, Snow Off, Barracuda, + Icy Ridge, Decrepit Isles, East vs West, Puddles Redux, Tabula Rasa, + Vihaan Lunta, Cold Front, Encounter, Opposite Force, Six Below Zero, Rapa + Nui, Unconventional Warfare, All Connected, Caffeinated, Centre of + Attention Redux, Coastal Influence, North by Northwest, Regeneration + Basin, Hypothermia, Alaska Anarchy Redux, Engagement, Tainted Peak, Mass + Confliction. + - Added Shadowfiend 2, Marigold Town, Forgotten Plains, Blitz, Trapped, + Discovery, Chernobyl, Ridges, Collaboration, Progress, Fortified, + Altercation, Forward Progress, Archipelago, Ardennes, Ritual Circle, + Dusttown Battle, Code 19, Europe. + - Balance changes [#18236]: + - Chinook HP decreased from 20000 to 14000. + - Light Tank HP increased from 22000 to 26000. + - Medium Tank HP increased from 45000 to 46000. + - Radar Jammer speed decreased from 85 to 78. + - Removed Light Tank husk. + - Tesla vision and weapon range decreased from 8c0 to 7c0. + - Turret vision and weapon range decreased from 7c0 to 6c512. + - Tiberian Dawn + - Added "Harvester Lost" audio notification. [#18427] + - Added "Stealth Deliveries" lobby option. [#18687] + - Added new turret artwork for the APC. [#18193] + - Fixed several incorrect explosion/firing sound effects. [#18960, #18972, + #18977] + - Fixed SAM Sites changing state while powered down. [#18996, #19099] + - Fixed that Commandos could target visceroids despite dealing no damage. + [#19017] + - Fixed the hospital healing the civilians in mission Nod 7b. [#19078] + - Fixed unit artwork facing the wrong direction at some angles. [#18020, + #18200] + - Fixed some weapons not being able to force-fire on water. [#18066, #18128] + - Fixed several graphical glitches with harvester docking. [#18737] + - Fixed Nod vehicles not being refunded if the Airstrip is destroyed while + the plane is inbound. [#18599] + - Fixed selling an Airstrip during delivery preventing the building from + being sold or captured. [#18896] + - Fixed missing death animation for visceroids. [#18421] + - Fixed Civilians wandering onto Tiberium by themselves. [#18912] + - Changed Oil Derricks to only show money indicators when captured by a + player. [#18682] + - Improved weapon visual effects for several units/weapons. [#18629, #18712, + #18738] + - Mission fixes and additions: + - Added transforming blossom trees to some single-player missions. [#16827, + #18489] + - Fixed a scripting bug in Nod04b. [#18070] + - Fixed a crash in the mission N64 Special Ops - GDI 1 when a harvester is + rebuilt by the AI. [#18152] + - Fixed not all harvesters being rebuilt in the mission N64 Special Ops - + GDI 1. [#18152] + - Fixed the Gunboat triggers in GDI09. [#18043] + - Changed mission menu ordering to match the C&C Remastered Collection. + [#18726] + - Updated default map pool [#18752]: + - Removed Avocado, Contra, Dead in Motion, Letters from Lexington, Plan B, + The New Mandarins, Understanding Power, Desert Lakes, Winter's End, + Frostways, Thawed Front, Tiberium Canopy, Twisted peak. + - Added African Gambit, Badland Ridges, Desert Mandarins, Reaching Out, + Tiberium Rift, Deserted Outpost, Master Alert, Fight Win Prevail, Master + Of The Jungle Book, Desert Invasion, Tiberium Forest, Valley of Gold (6P), + Anvil of War, Elysian Expanse, Armageddon. + - Balance Changes [#18273, #18427, #18654, #18830, #18829, #18878, #19017, + #19142]: + - Increased speed of the Nod Airstrip delivery plane. + - Adjusted prices and build speeds of several units and structures to set a + consistent relationship between cost and build time. + - Reduced build speed penalty when low power to 150%. + - Decreased power usage of barracks and Hand of Nod. + - Increased power usage of Helipad. + - Reduced vehicle husk lifetime for Rocket Launcher, Mobile SAM, Artillery, + Supply truck. + - Increased vehicle husk lifetime for APC. + - Changed Bike terrain speed modifiers to match other wheeled units. + - Changed veterancy: + - Rank 1 is awarded after destroying 250% value, now gives +25% firepower. + - Rank 2 is awarded after destroying 500% value, now gives +25% health. + - Rank 3 (elite) is awarded after destroying 750% value, gives +25% speed, + vision, range and self-healing. + - Veterancy icons are now visible to enemy players. + - Destroying walls no longer gives experience. + - Increased timers of Airstrike and superweapons. + - Reduced Airstrike damage against light vehicles and infantry. + - Decreased spread of the flame thrower, increased range. + - Decreased delay between bursts of the flame tank, while increasing the + reload delay. + - Increased price, reduced missile range of the Mammoth tank. + - Changed default starting cash to $7500. + - Changed default starting units to MCV Only. + - Increased APC anti-air and vision ranges, reduced build time, increased + anti-air damage. + - Increased Stealth Tank minimum anti-air range, now decloaks when damaged + and repairing. + - Decreased SAM Site buildup speed, increased vision range. + - Increased Flame Tank vision. + - Increased Light Tank damage against structures. + - Increased Harvester vision. + - Reduced Orca range. + - Reduced Apache health and damage spread. + - Reduced Oil Derrick income. + - Increased Supply Truck cost and transfer amount, reduced build time. + - Made Stealth Tanks immune to Stealth Tank Husk explosions. + - Increased Bike reload delay from 50 to 60. + - Increased Apache HP from 12000 to 12500. + - Increased Apache Wood Damage from 50 to 75. + - Decreased APC AA Light Damage from 140 to 125. + - Decreased Stealth Tank Cost from 1000 to 900. + - Changed Visceroid armor from Wood to Light, increased HP from 30000 to + 40000. + - Changed husks to be less vulnerable to weapon damage. + - Dune 2000 + - Added "Automatic Concrete" lobby option. [#18562, #18686] + - Added missing turret build animations. [#17817] + - Fixed incorrect sound effects for building power down/up and radar. + [#19051] + - Fixed bugs caused by Sardaukars using wrong weapons. [#19061] + - Fixed Concrete being placed on invalid terrain. [#19100] + - Fixed mission briefing videos crashing the game. [#19161] + - Fixed audio track "The Waiting Game" getting skipped during installation. + [#19176] + - Fixed the Death Hand launch notification not playing for the enemy. + [#18214] + - Fixed Carryalls being unable to pick up harvesters waiting on the Repair + Pad. [#18350] + - Fixed incorrect damage being applied to concrete. [#19259] + - Changed the way damage is calculated to match the original game. [#18023] + - Changed the way actor build times are calculated to match the original + game. [#18120] + - Changed weapon inaccuracy and spread to better match the original game. + [#18009, #18010, #18362] + - Changed bots to no longer hunt down worms. [#17809, #17829, #17835] + - Removed screen flash from the Death Hand missile. [#17284] + - Map Editor + - Added a text field next to actor state sliders to allow precision values + to be set. [#18652] + - Added a 64 players limit for multiplayer due to technical constraints. + [#18768] + - Fixed the map editor adding Health: 100 to actors that are edited. [#18989] + - Fixed map editor minimap display showing trees and other decorations with + the wrong color. [#18283] + - Fixed the map editor sidebar selection not updating after deleting search + text. [#18037] + - Improved Undo/Redo support for the flood fill brush. [#18131] + - Engine and Modding + - Added a friendly description for optional types to the trait + documentation. [#18991] + - Added support for mod.yaml to including definitions from other yaml files. + [#18591] + - Added death types support to the Lua Kill() API. [#19038] + - Added support for burst-specific infantry attack animations. [#19064] + - Added visual support for voxel aircraft to pitch and roll while moving. + [#18231] + - Added support for dynamic terrain lighting. [#18310] + - Added additional notification support to infiltration. [#17815] + - Added player palette support to sidebar production icons. [#17620] + - Added new sequence blend modes LowAdditive, Screen and Translucent. + [#17722] + - Added support for mod-defined selection boxes and added a default + isometric selection box. [#17808, #17862, #17991, #18223, #18446] + - Added support for the AI to place plugs on buildings. [#18196] + - Added option to customize default player color in mod.yaml. [#17908] + - Added ability for mods to define their own news cache file. [#18395] + - Added default values for several UI metrics to the common metrics yaml. + [#18633] + - Added text alignment support to SupportPowerTimerWidget. [#18680] + - Added support for customizing cursors and target line colors in all traits + that use them. [#18110, #18483, #18832] + - Added support for OPENRA_DISPLAY_SCALE environment variable on Windows. + [#18589] + - Added support for pool-specific ammo pips decoration. [#19237] + - Fixed a crash when invalid data is returned when querying multiplayer + servers. [#19101] + - Fixed AI unit orders sending unnecessary amounts of network traffic. + [#19005] + - Fixed TransformsIntoAircraft transforming on all orders. [#18821] + - Fixed WithLandingCraftAnimation opening on non-horizontal movement. + [#18455] + - Fixed a crash when LeavesTrails is used on an aircraft that flys outside + the map. [#17965] + - Fixed a crash when a player-controlled Carryall attempts to pick up a unit + that has been killed. [#18302] + - Fixed crashes when multiple Replaceable or Replacement traits are used. + [#18688, #18689, [#18685, #18857] + - Fixed crashes when certain traits are defined on the Player actor. [#18182] + - Fixed crash when AmbientSound is defined on the World actor. [#18148] + - Fixed a potential divide by zero crash in movement code. [#18736] + - Fixed a modding-related crash in the attack code. [#17781] + - Fixed incorrect chance calculations and potential crashes in JamsMissiles + and ScaredyCat. [#17770] + - Fixed LeaveSmudgeWarhead causing a crash by querying invalid targets. + [#17966] + - Fixed a crash when GrantConditionOnTerrain is used on an aircraft that + moves outside the ap. [#18014] + - Fixed a collection of issues when using embedded png frame metadata. + [#17923, #17588, #18021] + - Fixed crates not appearing in the map editor if XmasImages is not set. + [#18377] + - Fixed a crash when multiple ResourceRenderer traits are used. [#17902] + - Fixed a crash in FireClusterWarhead. [#18453] + - Fixed import errors in the --tileset-import utility command. [#17720] + - Fixed the AI not working properly when no RefineryTypes are defined. + [#18484] + - Fixed a crash in the InstantHit projectile. [#18474] + - Fixed the "Furthest" battlefield camera option being displayed even if the + mod disables it. [#18627] + - Fixed absolute file paths being stamped into translation files. [#18650] + - Fixed UPnP port forwarding requests when creating local games. [#18700] + - Fixed free-of-charge repairing still costing credits. [#18748] + - Fixed the launch-game script for development builds showing an incorrect + path for the Logs directory. [#18289] + - Fixed visual glitches on range circles that define Visibile: Always. + [#18718] + - Fixed map UID mismatches between Linux and Windows filesystems. [#18532] + - Fixed a crash on maps that incorrectly place overlapping refineries. + [#18620] + - Fixed a crash in the Move activity especially if the Mobile trait is + paused. [#18615] + - Fixed spies ignoring the target's faction. [#17811] + - Fixed actors losing their experience points when transforming. [#17789] + - Exposed production and support power palette fonts to configuration. + [#18472, #18501] + - Changed docking angle be determined by the host building. [#18481] + - Changed the default value of SpawnActorPower.EffectSequence from "idle" to + unset. [#17953] + - Changed support power actor selection ranges to footprints. [#17786] + - Changed UI chrome definitions for checkboxes, dropdown buttons, and scroll + panels. [#17663] + - Changed facing values on traits from integers (0-255) to WAngle (0-1024). + [#18067, #18211, #18213, #18228, #18271, #18279, #18414, #18382, #18815, + #18856] + - Changed C# language version from 5 to 7.3 and updated code syntax. + [#18485, #18524, #18528, #18881, #18883] + - Changed several traits to be publicly accessible for custom trait + overrides [#17799, #18498] + - Improved reliability and accuracy of lint tests. [#17826, #17896, #17914, + #17957, #18229, #18399, #18572] + - Improved support for defining initial state on map-placed actors. [#18123, + #18164, #18201, #18271, #18264, #18419, #18527, #18595] + - Improved support for terrain height maps and slopes. [#17990, #18209, + #18224, #18396, , #18641, #18716, #18831] + - Moved UseClassicFacingFudge to Mods.Cnc and its own traits. [#17641] + - Removed update rules for releases older than release-20191117. [#18038] + - Removed unused TerrainTemplateInfo constructor. [#18663] + - Replaced per-color font caches with tinted rendering. [#18548] + - Replaced DecorationPosition with mod-defined string ids. [#18521] + - Reworked sequence linting. [#18514] + - Unified the BotDebug prefixes. [#18420] + - Changed internal "player stance(s)" terminology to "player + relationship(s)". [#18677, #18678, #18904] + - Weapon Changes: + - Fixed ChangeOwnerWarhead ignoring InvalidTargets. [#17976] + - Added BounceSound support to Bullet projectile. [#18133] + - Added DamageCalculationType to SpreadWarhead to support additional damage + calculation methods. [#18023] + - Added TargetTypeAir and AirThreshold to weapons so that they don't ignore + the altitude of the target. [#18166] + - Fixed inconsistencies in and issues with the implementation of Warhead + classes. [#18011, #18059, #18054, #17971, #18072] + - Added a FlashPaletteEffectWarhead and removed hardcoded nuke flashes. + [#17284] + - Added a configurable InaccuracyType (Maximum, PerCellIncrement, Absolute) + to weapon projectiles. [#18009] + - Added an InvalidBounceTerrain parameter to projectiles. [#18779, #18809] + - Added support for visual inaccuracy to effect warheads. [#18712] + - Fixed range modifiers not changing Missile's RangeLimit. + - Fixed SpiceBloom trait not initializing projectile range modifiers. + [#18041] + - Fixed FireClusterWarhead playing the wrong Report sound. [#18398] + - Lua API Changes: + - Added support for querying the Passengers of an actor via Lua. [#18577] + - Added a Panic function to the Lua API. [#18243] + - Added an IsCloaked actor property to the Lua API. [#18355] + - Added an optional Actor parameter to UnloadPassenger in the Lua API. + [#18431] + - Added a damage parameter to the Trigger.OnDamage Lua API callback. [#18323] + - Added actor experience to the Lua API. [#18447] + - Added Player.HomeLocation. [#18890] + - Fixed DisplaySystemMessage displaying messages twice if they do not define + a prefix. [#18286] + - Trait Changes: + - Aircraft: Added LeaveMapAtClosestEdge option for IdleBehaviour and + IdleSpeed. [#18320, #18351] + - Armament: Removed MuzzleSplitFacings, which can be implemented using + Combine sequences. [#17949] + - AttackAircraft: Fixed aircraft with CanSlide: true flying backwards after + an attack run. [#17935] + - AttackFollow: Added RangeMargin field to change the distance inside + maximum range that units will attempt to maintain. [#18560] + - AttackOrderPower: Added support for customizing the range circle display. + [#17919] + - Building: Added AllowPlacementOnResources field. [#17838] + - Burns: Renamed to ChangesHealth and rendering features removed (use + WithIdleOverlay instead). [#17987] + - BaseProvider: Added support for customizing the range circle display. + [#17919] + - Carryall: Added CarryCondition field to grant a condition to the carryall + while it is carrying a unit. [#18359] + - CashTricker: Improved exception message when added to the Player actor + without disabling ShowTicks. [#18181] + - ClassicParallelProductionQueue: New trait that provides parallel + production with multi-factory bonuses. [#17822] + - ConditionManager: Removed trait and merged its functionality directly into + Actor. [#17959, #18215] + - D2kEditorResourceLayer: Merged trait functionality into D2kResourceLayer. + [#18515] + - Demolition: Added DamageTypes support. [#18722] + - DropPodsPower: New trait that implements Tiberian Sun style drop pod + reinforcements. [#17876] + - EngineerRepairable: Added condition support. [#17791] + - Explodes: Added support for offsets. [#18782] + - InfiltrateForSupportPowerReset: New trait that allows infiltrator units to + reset the timer of support powers on the actor. [#17783, #18031] + - Minelayer: Added valid TerrainTypes and a configurable deploy cursor. + [#17843] + - NukePower: Added support for displaying damage range circles. [#17920] + - PlayerHighlightPalette: Added TransparentIndex field to support artwork + that uses a different transparent palette index. [#18097] + - PortableChrono: Added support for customizing the range circle display. + [#17919] + - RepairableBuilding: Added RepairDamageTypes support. [#17721] + - RepairsUnits: Added RepairDamageTypes support. [#17721] + - RenderDetectionCircle: Added support for customizing the range circle + display and moved to Mods.Common. [#17968, #17919] + - RenderJammerCircle: Added support for customizing the range circle display + and moved to Mods.Common. [#17968, #17919] + - RenderRangeCircle: Added support for customizing the range circle display. + [#17919] + - RenderShroudCircle: Added support for customizing the range circle display + and moved to Mods.Common. [#17968, #17919] + - HealUnitsCrateAction: Renamed to HealActorsCrateAction. [#17913] + - RevealsMap: New trait that reveals shroud from the entire map when + created. [#17718, #18610] + - ScaredyCat: Added PanicChance to support custom panic chances when + damaged. [#17785] + - ShakeOnDeath: Added DeathTypes to prevent the shake effect on certain + damage types. [#18632] + - SmudgeLayer: Renamed several fields and changed the defaults to null. + [#18554] + - SoundOnDamageTransition: Added DamageTypes to prevent the sound on certain + damage types. [#18632] + - TransformsNearResources: New trait that allows an actor to randomly + transform after a random time spent next to a resource type. [#16827] + - TurnOnIdle: New trait that makes units randomly change their facing when + idle. [#17758] + - WithIdleAnimation: Added support for a second Interval value to define a + random range. [#18326] + - WithNukeLaunchAnimation: Renamed to WithSupportPowerActivationAnimation as + it now works on every support power. [#17787] + - WithNukeLaunchOverlay: Renamed to WithSupportPowerActivationOverlay as it + now works on every support power. [#17787] + - WithRangeCircle: Added support for customizing the range circle display. + [#17919] + - Packaging + - Added a "Portable Windows" package that does not require installation. + [#18387] + - Added support for Python 3 in the development toolchain scripts. [#18375] + - Added automatic deployment to itch.io on release. [#18227, #19022] + - Fixed a reference to an outdated SDL 2 nuget package. [#19004] + - Removed obsolete DedicatedLoop reference from FreeBSD packaging. [#18019] + - Changed auto-generated documentation from the GitHub wiki to a dedicated + https://docs.openra.net. [#18175, #18546, #18676] + - Changed many aspects of the development toolchain and packaging to prepare + for .NET Core. [#17744, #18019, #18393, #18537, #18580, #18844, #18846, + #18847, #18861, #18865, #18884, #18899, #18999, #18953, #18968, #19110, + #19041, #19006, #19006, #19057, #19112, #19185, #18954, #18963, #19085, + #19031, #19102, #19156, #19231] + + -- Jhonny Oliveira Tue, 23 Mar 2021 12:26:34 +0000 + openra (20200503-1~xtradeb4) focal; urgency=medium * Yet another attempt diff -Nru openra-20200503/debian/control openra-20210321/debian/control --- openra-20200503/debian/control 2020-09-20 18:37:24.000000000 +0000 +++ openra-20210321/debian/control 2021-03-24 22:31:17.000000000 +0000 @@ -9,6 +9,7 @@ libsdl2-dev, libopenal-dev, liblua5.1-0-dev, + libfreetype-dev, curl, unzip Standards-Version: 4.5.0 @@ -20,6 +21,8 @@ ttf-openra (= ${source:Version}), fonts-freefont-ttf, mono-runtime, +# required to provide netstandard assembly + mono-devel, libsdl2-2.0-0, libopenal1, liblua5.1-0-dev diff -Nru openra-20200503/debian/debian.README openra-20210321/debian/debian.README --- openra-20200503/debian/debian.README 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/debian/debian.README 2021-03-26 06:29:34.000000000 +0000 @@ -0,0 +1,38 @@ +# Steps to package +# Inspired by https://github.com/flathub/net.openra.OpenRA +# install msbuild +sudo apt install software-properties-common + +sudo add-apt-repository ppa:eofla/mono-msbuild +sudo apt update + +make DEBUG=true TARGETPLATFORM=unix-generic + +make DEBUG=true TARGETPLATFORM=unix-generic DESTDIR=debian/tmp \ + prefix=/usr datadir=/usr/share/games libexecdir=/usr/share/games \ + bindir=/usr/games gameinstalldir=/usr/share/games/openra install + +# get a local copy of the nuget cache +cp -R ~/.nuget . + +# create patch to append "-p:RestoreConfigFile=.nuget/nuget.config -p:RestorePackagesPath=.nuget/packages" to every single msbuild line you find +tee .nuget/nuget.config < + + + + + +EOF + +mkdir -p debian/depends +# save the nuget cache and other depends +tar cJf debian/depends/nuget-cache.tar.xz .nuget nuget.config +cp IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP debian/depends/ + +# sbuild +sbuild -d focal openra_20200503-1~xtradeb1.dsc --extra-repository="deb [trusted=yes] http://ppa.launchpad.net/eofla/mono-msbuild/ubuntu focal main" + +Misc +rm -Rfv ~/.nuget ~/.config/NuGet +#Test Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/debian/depends/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/debian/depends/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/debian/depends/nuget-cache.tar.xz and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/debian/depends/nuget-cache.tar.xz differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/debian/depends/nuget-packages.tar.xz and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/debian/depends/nuget-packages.tar.xz differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/debian/depends/thirdparty-deps.tar.xz and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/debian/depends/thirdparty-deps.tar.xz differ diff -Nru openra-20200503/debian/openra.install openra-20210321/debian/openra.install --- openra-20200503/debian/openra.install 2020-09-20 18:37:24.000000000 +0000 +++ openra-20210321/debian/openra.install 2021-03-23 17:33:46.000000000 +0000 @@ -1,7 +1,6 @@ usr/games usr/share/applications +usr/share/metainfo usr/share/games usr/share/icons -usr/share/man usr/share/mime -usr/share/appdata/*.xml usr/share/metainfo diff -Nru openra-20200503/debian/patches/enable_restore_from_make_version openra-20210321/debian/patches/enable_restore_from_make_version --- openra-20200503/debian/patches/enable_restore_from_make_version 2021-01-14 06:24:20.000000000 +0000 +++ openra-20210321/debian/patches/enable_restore_from_make_version 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -Enable restoring from make version ---- a/Makefile -+++ b/Makefile -@@ -166,7 +166,7 @@ - @-$(RM_RF) ./*/bin ./*/obj - @-$(RM_RF) ./thirdparty/download - --distclean: clean -+distclean: clean undo-version - - cli-dependencies: - @./thirdparty/fetch-thirdparty-deps.sh -@@ -195,14 +195,23 @@ - - all-dependencies: cli-dependencies windows-dependencies osx-dependencies - --version: VERSION mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml -+version: undo-version do-version -+ -+do-version: mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml -+ @cp VERSION VERSION.ORIG - @echo "$(VERSION)" > VERSION - @for i in $? ; do \ -+ cp $${i} $${i}.ORIG && \ - awk '{sub("Version:.*$$","Version: $(VERSION)"); print $0}' $${i} > $${i}.tmp && \ - awk '{sub("/[^/]*: User$$", "/$(VERSION): User"); print $0}' $${i}.tmp > $${i} && \ - rm $${i}.tmp; \ - done - -+undo-version: VERSION mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml -+ @for i in $? ; do \ -+ test -f $${i}.ORIG && mv $${i}.ORIG $${i} || true; \ -+ done -+ - install: dependencies core install-core - - install-linux-shortcuts: install-linux-scripts install-linux-icons install-linux-desktop diff -Nru openra-20200503/debian/patches/series openra-20210321/debian/patches/series --- openra-20200503/debian/patches/series 2020-09-20 18:37:24.000000000 +0000 +++ openra-20210321/debian/patches/series 2021-03-25 12:31:06.000000000 +0000 @@ -1 +1 @@ -enable_restore_from_make_version +set_msbuildNugetRestoreConfigFile.patch diff -Nru openra-20200503/debian/patches/set_msbuildNugetRestoreConfigFile.patch openra-20210321/debian/patches/set_msbuildNugetRestoreConfigFile.patch --- openra-20200503/debian/patches/set_msbuildNugetRestoreConfigFile.patch 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/debian/patches/set_msbuildNugetRestoreConfigFile.patch 2021-03-25 20:26:48.000000000 +0000 @@ -0,0 +1,26 @@ +Index: openra-20210321/Makefile +=================================================================== +--- openra-20210321.orig/Makefile 2021-03-25 17:23:42.698767490 +0000 ++++ openra-20210321/Makefile 2021-03-25 20:25:38.962362160 +0000 +@@ -54,7 +54,7 @@ + + # Toolchain + CWD = $(shell pwd) +-MSBUILD = msbuild -verbosity:m -nologo ++MSBUILD = msbuild -verbosity:m -nologo -p:RestoreConfigFile=.nuget/nuget.config -p:RestorePackagesPath=.nuget/packages + MONO = mono + RM = rm + RM_R = $(RM) -r +Index: openra-20210321/packaging/functions.sh +=================================================================== +--- openra-20210321.orig/packaging/functions.sh 2021-03-25 17:23:42.698767490 +0000 ++++ openra-20210321/packaging/functions.sh 2021-03-25 20:26:45.783340556 +0000 +@@ -35,7 +35,7 @@ + cd "${SRC_PATH}" || exit 1 + msbuild -verbosity:m -nologo -t:Clean + rm -rf "${SRC_PATH:?}/bin" +- msbuild -verbosity:m -nologo -t:Build -restore -p:Configuration=Release -p:TargetPlatform="${TARGETPLATFORM}" ++ msbuild -verbosity:m -nologo -t:Build -restore -p:Configuration=Release -p:TargetPlatform="${TARGETPLATFORM}" -p:RestoreConfigFile=.nuget/nuget.config -p:RestorePackagesPath=.nuget/packages + if [ "${TARGETPLATFORM}" = "unix-generic" ]; then + ./configure-system-libraries.sh + fi diff -Nru openra-20200503/debian/README openra-20210321/debian/README --- openra-20200503/debian/README 2021-01-14 06:24:20.000000000 +0000 +++ openra-20210321/debian/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -# Prepare package for sbuild/launchpad -# I could not find another way to meet the nuget depends offline -# not even with msbuild -t:restore -p:RestoreSources=/.nuget -# -# Build the package it in the schroot, then within the obj directory -# remove the Release directory -rm -Rf OpenRA.*/obj/Release -# and replace all references to your system: "grep -R '/home/jd/' OpenRA.*/obj" -# with a known TAG for later replacement (.json, .cache, .props) -sed -i "s#$(pwd)#_REPLACEME_#g" OpenRA.*/obj/*.* -sed -i "s#${HOME}#_REPLACEME_#g" OpenRA.*/obj/*.* - -# pack the cached depends -tar cJf debian/depends/nuget-cache.tar.xz OpenRA.*/obj - -# pack the thirdparty downloads -tar cJf debian/depends/thirdparty-deps.tar.xz thirdparty/download - -# pack the dependency nuget package(s) -cd ~ && tar cJf ~/Workspace/xtradeb/play/openra/openra-20200503/debian/depends/nuget-packages.tar.xz .nuget - -## My tests, including extra dependency repo for Mono - -# inside the schroot -sudo cp ../eofla-ubuntu-mono-msbuild-focal.list /etc/apt/sources.list.d/; sudo cp ../eofla_ubuntu_mono-msbuild.gpg /etc/apt/trusted.gpg.d/; sudo apt update - -# sbuild -sbuild -d focal openra_20200503-1~xtradeb1.dsc --extra-repository="deb [trusted=yes] http://ppa.launchpad.net/eofla/mono-msbuild/ubuntu focal main" - -# Misc cmds -ls -liah ~/.local/share/NuGet ~/.config/NuGet ~/.nuget -rm -Rf ~/.local/share/NuGet ~/.config/NuGet ~/.nuget diff -Nru openra-20200503/debian/rules openra-20210321/debian/rules --- openra-20200503/debian/rules 2021-01-14 06:24:20.000000000 +0000 +++ openra-20210321/debian/rules 2021-03-26 06:24:38.000000000 +0000 @@ -2,26 +2,22 @@ include /usr/share/dpkg/pkg-info.mk +export TARGETPLATFORM=unix-generic + %: dh $@ override_dh_auto_clean: - rm -Rf OpenRA.*/obj - rm -Rf .nuget + debian/backuprestore.sh dh_auto_clean + rm -Rf .nuget override_dh_auto_configure: cp debian/depends/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP . - tar xJf debian/depends/thirdparty-deps.tar.xz tar xJf debian/depends/nuget-cache.tar.xz - sed -i "s#_REPLACEME_#$(CURDIR)#g" OpenRA.*/obj/*.* - tar xJf debian/depends/nuget-packages.tar.xz + debian/backuprestore.sh backup make version VERSION=release-$(DEB_VERSION_UPSTREAM) -override_dh_auto_build: - make dependencies - make core - override_dh_auto_install: # make install $(MAKE) DESTDIR=debian/tmp \ @@ -30,11 +26,9 @@ $(MAKE) DESTDIR=debian/tmp \ prefix=/usr libexecdir=/usr/share/games \ bindir=/usr/games gameinstalldir=/usr/share/games/openra install-linux-shortcuts - $(MAKE) DESTDIR=debian/tmp prefix=/usr install-linux-mime $(MAKE) DESTDIR=debian/tmp prefix=/usr install-linux-appdata - $(MAKE) DESTDIR=debian/tmp prefix=/usr install-man-page # Fixes perms find $(CURDIR)/debian/tmp/usr/share/games/openra -name "*.dll" -type f -exec chmod -x {} \; find $(CURDIR)/debian/tmp/usr/share/games/openra -name "*.shp" -type f -exec chmod -x {} \; # Remove system fonts, we will add them later as a link - rm -f $(CURDIR)/debian/tmp/usr/share/games/openra/mods/common/FreeSans*.ttf + rm -fv $(CURDIR)/debian/tmp/usr/share/games/openra/mods/common/FreeSans*.ttf diff -Nru openra-20200503/debian/source/include-binaries openra-20210321/debian/source/include-binaries --- openra-20200503/debian/source/include-binaries 2020-09-20 18:37:24.000000000 +0000 +++ openra-20210321/debian/source/include-binaries 2021-03-24 18:54:37.000000000 +0000 @@ -1,4 +1,2 @@ -debian/depends/nuget-packages.tar.xz -debian/depends/thirdparty-deps.tar.xz debian/depends/nuget-cache.tar.xz debian/depends/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP diff -Nru openra-20200503/debian/watch openra-20210321/debian/watch --- openra-20200503/debian/watch 2020-09-20 18:37:24.000000000 +0000 +++ openra-20210321/debian/watch 2021-03-23 12:25:28.000000000 +0000 @@ -1,3 +1,3 @@ version=3 https://github.com/OpenRA/OpenRA/tags \ - (?:.*/)?archive/release-([\d\.]+)(?:\.tar\.gz|\.tar\.bz2|\.tar\.xz) + (?:.*/)?archive/refs/tags/release-([\d\.]+)@ARCHIVE_EXT@ diff -Nru openra-20200503/.editorconfig openra-20210321/.editorconfig --- openra-20200503/.editorconfig 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/.editorconfig 2021-03-21 11:10:05.000000000 +0000 @@ -6,13 +6,101 @@ [*] end_of_line = LF insert_final_newline = true +trim_trailing_whitespace = true -; 4-column tab indentation +; 4-column tab indentation and .NET coding conventions [*.cs] indent_style = tab indent_size = 4 +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = true + +csharp_style_var_elsewhere = true:suggestion +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion + +csharp_prefer_braces = when_multiline:suggestion +csharp_using_directive_placement = outside_namespace:suggestion +csharp_new_line_before_open_brace = all +csharp_space_around_binary_operators = before_and_after + +#### Naming styles #### + +dotnet_naming_style.camel_case.capitalization = camel_case + +dotnet_naming_style.pascal_case.capitalization = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal + +dotnet_naming_symbols.const_private_field.applicable_kinds = field +dotnet_naming_symbols.const_private_field.required_modifiers = const +dotnet_naming_symbols.const_private_field.applicable_accessibilities = private + +dotnet_naming_symbols.internal_field.applicable_kinds = field +dotnet_naming_symbols.internal_field.applicable_accessibilities = internal + +dotnet_naming_symbols.static_private_or_internal_field.required_modifiers = static +dotnet_naming_symbols.static_private_or_internal_field.applicable_accessibilities = internal, private + +dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field +dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal + +# Naming rules + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + + +dotnet_naming_rule.static_private_or_internal_field_should_be_pascal_case.severity = none +dotnet_naming_rule.static_private_or_internal_field_should_be_pascal_case.symbols = static_private_or_internal_field +dotnet_naming_rule.static_private_or_internal_field_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.const_private_field_should_be_pascal_case.severity = warning +dotnet_naming_rule.const_private_field_should_be_pascal_case.symbols = const_private_field +dotnet_naming_rule.const_private_field_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.const_private_or_internal_field_should_be_pascal_case.severity = warning +dotnet_naming_rule.const_private_or_internal_field_should_be_pascal_case.symbols = internal_field +dotnet_naming_rule.const_private_or_internal_field_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.private_or_internal_field_should_be_camel_case.severity = warning +dotnet_naming_rule.private_or_internal_field_should_be_camel_case.symbols = private_or_internal_field +dotnet_naming_rule.private_or_internal_field_should_be_camel_case.style = camel_case + +# Naming rules + +#require a space before the colon for bases or interfaces in a type declaration +csharp_space_after_colon_in_inheritance_clause = true +#require a space after a keyword in a control flow statement such as a for loop +csharp_space_after_keywords_in_control_flow_statements = true +#require a space before the colon for bases or interfaces in a type declaration +csharp_space_before_colon_in_inheritance_clause = true + +#Formatting - wrapping options + +#leave code block on single line +csharp_preserve_single_line_blocks = true +#leave statements and member declarations on the same line +csharp_preserve_single_line_statements = true + +#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them +dotnet_style_predefined_type_for_member_access = true:suggestion + +#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion + ; 4-column tab indentation [*.yaml] indent_style = tab -indent_size = 4 \ No newline at end of file +indent_size = 4 diff -Nru openra-20200503/fetch-geoip.sh openra-20210321/fetch-geoip.sh --- openra-20200503/fetch-geoip.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/fetch-geoip.sh 2021-03-21 11:10:05.000000000 +0000 @@ -14,8 +14,8 @@ rm -f IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP echo "Downloading IP2Location GeoIP database." if command -v curl >/dev/null 2>&1; then - curl -s -L -O https://download.ip2location.com/lite/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP || echo "Warning: Download failed" + curl -s -L -O https://github.com/OpenRA/GeoIP-Database/releases/download/monthly/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP || echo "Warning: Download failed" else - wget -cq https://download.ip2location.com/lite/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP || echo "Warning: Download failed" + wget -cq https://github.com/OpenRA/GeoIP-Database/releases/download/monthly/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP || echo "Warning: Download failed" fi fi diff -Nru openra-20200503/.github/ISSUE_TEMPLATE/config.yml openra-20210321/.github/ISSUE_TEMPLATE/config.yml --- openra-20200503/.github/ISSUE_TEMPLATE/config.yml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/.github/ISSUE_TEMPLATE/config.yml 2021-03-21 11:10:05.000000000 +0000 @@ -1,11 +1,14 @@ blank_issues_enabled: false contact_links: + - name: Frequently Asked Questions + url: https://github.com/OpenRA/OpenRA/wiki/FAQ#frequently-asked-questions + about: Explanations for common problems and questions. - name: OpenRA Forum url: https://forum.openra.net/ - about: "Please ask questions about modding here." + about: Please ask questions about modding here. - name: OpenRA Discord server url: https://discord.openra.net/ - about: "Join the community Discord server for community discussion and support." + about: Join the community Discord server for community discussion and support. - name: OpenRA IRC Channel url: https://webchat.freenode.net/#openra - about: "Join our development IRC channel on freenode for discussion of development topics." + about: Join our development IRC channel on freenode for discussion of development topics. diff -Nru openra-20200503/.github/ISSUE_TEMPLATE/crash-report.md openra-20210321/.github/ISSUE_TEMPLATE/crash-report.md --- openra-20200503/.github/ISSUE_TEMPLATE/crash-report.md 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/.github/ISSUE_TEMPLATE/crash-report.md 2021-03-21 11:10:05.000000000 +0000 @@ -1,6 +1,6 @@ --- name: Crash report -about: Report a game crash. +about: Report a game crash. Check the FAQ first https://github.com/OpenRA/OpenRA/wiki/FAQ#common-issues title: My game crashed labels: Crash assignees: '' diff -Nru openra-20200503/.github/workflows/ci.yaml openra-20210321/.github/workflows/ci.yaml --- openra-20200503/.github/workflows/ci.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/.github/workflows/ci.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,49 @@ +name: Continuous Integration + +on: + push: + pull_request: + branches: [ bleed ] + +jobs: + linux-mono: + name: Linux (mono) + runs-on: ubuntu-20.04 + + steps: + - name: Clone Repository + uses: actions/checkout@v2 + + - name: Check Code + run: | + mono --version + make check + mono ~/.nuget/packages/nunit.consolerunner/3.11.1/tools/nunit3-console.exe --noresult bin/OpenRA.Test.dll + + - name: Check Mods + run: | + sudo apt-get install lua5.1 + make check-scripts + make test + + windows: + name: Windows (Framework 4.7) + runs-on: windows-2019 + + steps: + - name: Clone Repository + uses: actions/checkout@v2 + + - name: Check Code + shell: powershell + run: | + dotnet nuget locals all --clear + .\make.ps1 check + Invoke-Expression "$home\.nuget\packages\nunit.consolerunner\3.11.1\tools\nunit3-console.exe --noresult bin/OpenRA.Test.dll" + + - name: Check Mods + run: | + chocolatey install lua --version 5.1.5.52 + $ENV:Path = $ENV:Path + ";C:\Program Files (x86)\Lua\5.1\" + .\make.ps1 check-scripts + .\make.ps1 test diff -Nru openra-20200503/.github/workflows/documentation.yml openra-20210321/.github/workflows/documentation.yml --- openra-20200503/.github/workflows/documentation.yml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/.github/workflows/documentation.yml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,107 @@ +name: Deploy Documentation + +on: + workflow_dispatch: + inputs: + tag: + description: 'Git Tag' + required: true + default: 'release-xxxxxxxx' + +jobs: + wiki: + name: Update Wiki + if: github.repository == 'openra/openra' + runs-on: ubuntu-20.04 + steps: + - name: Clone Repository + uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.tag }} + + - name: Prepare Environment + run: | + make all + + - name: Clone Wiki + uses: actions/checkout@v2 + with: + repository: openra/openra.wiki + token: ${{ secrets.DOCS_TOKEN }} + path: wiki + + - name: Update Wiki (Playtest) + if: startsWith(github.event.inputs.tag, 'playtest-') + env: + GIT_TAG: ${{ github.event.inputs.tag }} + run: | + ./utility.sh all --settings-docs "${GIT_TAG}" > "wiki/Settings (playtest).md" + + - name: Update Wiki (Release) + if: startsWith(github.event.inputs.tag, 'release-') + env: + GIT_TAG: ${{ github.event.inputs.tag }} + run: | + ./utility.sh all --settings-docs "${GIT_TAG}" > "wiki/Settings.md" + + - name: Push Wiki + env: + GIT_TAG: ${{ github.event.inputs.tag }} + run: | + cd wiki + git config --local user.email "actions@github.com" + git config --local user.name "GitHub Actions" + git add --all + git commit -m "Update auto-generated documentation for ${GIT_TAG}" + git push origin master + + docs: + name: Update docs.openra.net + if: github.repository == 'openra/openra' + runs-on: ubuntu-20.04 + steps: + - name: Clone Repository + uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.tag }} + + - name: Prepare Environment + run: | + make all + + - name: Clone docs.openra.net + uses: actions/checkout@v2 + with: + repository: openra/docs + token: ${{ secrets.DOCS_TOKEN }} + path: docs + + - name: Update docs.openra.net (Playtest) + if: startsWith(github.event.inputs.tag, 'playtest-') + env: + GIT_TAG: ${{ github.event.inputs.tag }} + run: | + ./utility.sh all --docs "${GIT_TAG}" > "docs/api/playtest/traits.md" + ./utility.sh all --weapon-docs "${GIT_TAG}" > "docs/api/playtest/weapons.md" + ./utility.sh all --lua-docs "${GIT_TAG}" > "docs/api/playtest/lua.md" + + - name: Update docs.openra.net (Release) + if: startsWith(github.event.inputs.tag, 'release-') + env: + GIT_TAG: ${{ github.event.inputs.tag }} + run: | + ./utility.sh all --docs "${GIT_TAG}" > "docs/api/release/traits.md" + ./utility.sh all --weapon-docs "${GIT_TAG}" > "docs/api/release/weapons.md" + ./utility.sh all --lua-docs "${GIT_TAG}" > "docs/api/release/lua.md" + + - name: Push docs.openra.net + env: + GIT_TAG: ${{ github.event.inputs.tag }} + run: | + cd docs + git config --local user.email "actions@github.com" + git config --local user.name "GitHub Actions" + git add --all + git commit -m "Update auto-generated documentation for ${GIT_TAG}" + git push origin master + diff -Nru openra-20200503/.github/workflows/itch.yml openra-20210321/.github/workflows/itch.yml --- openra-20200503/.github/workflows/itch.yml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/.github/workflows/itch.yml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,86 @@ +name: Deploy itch.io Packages + +on: + workflow_dispatch: + inputs: + tag: + description: 'Git Tag' + required: true + default: 'release-xxxxxxxx' + +jobs: + itch: + name: Deploy to itch.io + runs-on: ubuntu-20.04 + if: github.repository == 'openra/openra' + steps: + - name: Download Packages + run: | + wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-${{ github.event.inputs.tag }}-x64.exe" + wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-${{ github.event.inputs.tag }}-x64-winportable.zip" -O "OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip" + wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-${{ github.event.inputs.tag }}.dmg" + wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-Dune-2000-x86_64.AppImage" + wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-Red-Alert-x86_64.AppImage" + wget -q "https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.tag }}/OpenRA-Tiberian-Dawn-x86_64.AppImage" + wget -q "https://raw.githubusercontent.com/${{ github.repository }}/${{ github.event.inputs.tag }}/packaging/.itch.toml" + zip -u "OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip" .itch.toml + + - name: Publish Windows Installer + uses: josephbmanley/butler-publish-itchio-action@master + env: + BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} + CHANNEL: win + ITCH_GAME: openra + ITCH_USER: openra-developers + VERSION: ${{ github.event.inputs.tag }} + PACKAGE: OpenRA-${{ github.event.inputs.tag }}}-x64.exe + + - name: Publish Windows Itch Bundle + uses: josephbmanley/butler-publish-itchio-action@master + env: + BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} + CHANNEL: itch + ITCH_GAME: openra + ITCH_USER: openra-developers + VERSION: ${{ github.event.inputs.tag }} + PACKAGE: OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip + + - name: Publish macOS Package + uses: josephbmanley/butler-publish-itchio-action@master + env: + BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} + CHANNEL: macos + ITCH_GAME: openra + ITCH_USER: openra-developers + VERSION: ${{ github.event.inputs.tag }} + PACKAGE: OpenRA-${{ github.event.inputs.tag }}}.dmg + + - name: Publish RA AppImage + uses: josephbmanley/butler-publish-itchio-action@master + env: + BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} + CHANNEL: linux-ra + ITCH_GAME: openra + ITCH_USER: openra-developers + VERSION: ${{ github.event.inputs.tag }} + PACKAGE: OpenRA-Red-Alert-x86_64.AppImage + + - name: Publish TD AppImage + uses: josephbmanley/butler-publish-itchio-action@master + env: + BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} + CHANNEL: linux-cnc + ITCH_GAME: openra + ITCH_USER: openra-developers + VERSION: ${{ github.event.inputs.tag }} + PACKAGE: OpenRA-Tiberian-Dawn-x86_64.AppImage + + - name: Publish D2k AppImage + uses: josephbmanley/butler-publish-itchio-action@master + env: + BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} + CHANNEL: linux-d2k + ITCH_GAME: openra + ITCH_USER: openra-developers + VERSION: ${{ github.event.inputs.tag }} + PACKAGE: OpenRA-Dune-2000-x86_64.AppImage diff -Nru openra-20200503/.github/workflows/packaging.yml openra-20210321/.github/workflows/packaging.yml --- openra-20200503/.github/workflows/packaging.yml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/.github/workflows/packaging.yml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,114 @@ +name: Release Packaging + +on: + push: + tags: + - 'release-*' + - 'playtest-*' + - 'devtest-*' + +jobs: + source: + name: Source Tarball + runs-on: ubuntu-20.04 + steps: + - name: Clone Repository + uses: actions/checkout@v2 + + - name: Prepare Environment + run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV} + + - name: Package Source + run: | + mkdir -p build/source + ./packaging/source/buildpackage.sh "${GIT_TAG}" "${PWD}/build/source" + + - name: Upload Packages + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ github.ref }} + overwrite: true + file_glob: true + file: build/source/* + + linux: + name: Linux AppImages + runs-on: ubuntu-20.04 + steps: + - name: Clone Repository + uses: actions/checkout@v2 + + - name: Prepare Environment + run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV} + + - name: Package AppImages + run: | + mkdir -p build/linux + ./packaging/linux/buildpackage.sh "${GIT_TAG}" "${PWD}/build/linux" + + - name: Upload Packages + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ github.ref }} + overwrite: true + file_glob: true + file: build/linux/* + + macos: + name: macOS Disk Images + runs-on: macos-10.15 + steps: + - name: Clone Repository + uses: actions/checkout@v2 + + - name: Prepare Environment + run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV} + + - name: Package Disk Images + env: + MACOS_DEVELOPER_IDENTITY: ${{ secrets.MACOS_DEVELOPER_IDENTITY }} + MACOS_DEVELOPER_CERTIFICATE_BASE64: ${{ secrets.MACOS_DEVELOPER_CERTIFICATE_BASE64 }} + MACOS_DEVELOPER_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_DEVELOPER_CERTIFICATE_PASSWORD }} + MACOS_DEVELOPER_USERNAME: ${{ secrets.MACOS_DEVELOPER_USERNAME }} + MACOS_DEVELOPER_PASSWORD: ${{ secrets.MACOS_DEVELOPER_PASSWORD }} + run: | + mkdir -p build/macos + ./packaging/macos/buildpackage.sh "${GIT_TAG}" "${PWD}/build/macos" + + - name: Upload Packages + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ github.ref }} + overwrite: true + file_glob: true + file: build/macos/* + + windows: + name: Windows Installers + runs-on: ubuntu-20.04 + steps: + - name: Clone Repository + uses: actions/checkout@v2 + + - name: Prepare Environment + run: | + echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV} + sudo apt-get update + sudo apt-get install nsis + + - name: Package Installers + run: | + mkdir -p build/windows + ./packaging/windows/buildpackage.sh "${GIT_TAG}" "${PWD}/build/windows" + + - name: Upload Packages + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ github.ref }} + overwrite: true + file_glob: true + file: build/windows/* diff -Nru openra-20200503/glsl/combined.frag openra-20210321/glsl/combined.frag --- openra-20200503/glsl/combined.frag 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/glsl/combined.frag 2021-03-21 11:10:05.000000000 +0000 @@ -26,6 +26,7 @@ varying vec4 vColorFraction; varying vec4 vRGBAFraction; varying vec4 vPalettedFraction; +varying vec4 vTint; uniform vec2 Texture0Size; uniform vec2 Texture1Size; @@ -46,6 +47,7 @@ in vec4 vColorFraction; in vec4 vRGBAFraction; in vec4 vPalettedFraction; +in vec4 vTint; out vec4 fragColor; #endif @@ -179,7 +181,7 @@ // Offset the sampling point to simulate bilinear intepolation in window coordinates instead of texture coordinates // https://csantosbh.wordpress.com/2014/01/25/manual-texture-filtering-for-pixelated-games-in-webgl/ // https://csantosbh.wordpress.com/2014/02/05/automatically-detecting-the-texture-filter-threshold-for-pixelated-magnifications/ - // ik is defined as 1/k from the articles, set to 1/0.7 because it looks good + // ik is defined as 1/k from the articles, set to 1/0.7 because it looks good float ik = 1.43; vec2 interp = clamp(offset * ik * AntialiasPixelsPerTexel, 0.0, .5) + clamp((offset - 1.0) * ik * AntialiasPixelsPerTexel + .5, 0.0, .5); coords = (floor(coords.st * textureSize) + interp) / textureSize; @@ -227,8 +229,8 @@ } else #if __VERSION__ == 120 - gl_FragColor = c; + gl_FragColor = c * vTint; #else - fragColor = c; + fragColor = c * vTint; #endif } diff -Nru openra-20200503/glsl/combined.vert openra-20210321/glsl/combined.vert --- openra-20200503/glsl/combined.vert 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/glsl/combined.vert 2021-03-21 11:10:05.000000000 +0000 @@ -7,6 +7,7 @@ attribute vec4 aVertexPosition; attribute vec4 aVertexTexCoord; attribute vec2 aVertexTexMetadata; +attribute vec3 aVertexTint; varying vec4 vTexCoord; varying vec2 vTexMetadata; @@ -17,10 +18,12 @@ varying vec4 vColorFraction; varying vec4 vRGBAFraction; varying vec4 vPalettedFraction; +varying vec4 vTint; #else in vec4 aVertexPosition; in vec4 aVertexTexCoord; in vec2 aVertexTexMetadata; +in vec3 aVertexTint; out vec4 vTexCoord; out vec2 vTexMetadata; @@ -31,6 +34,7 @@ out vec4 vColorFraction; out vec4 vRGBAFraction; out vec4 vPalettedFraction; +out vec4 vTint; #endif vec4 UnpackChannelAttributes(float x) @@ -61,7 +65,7 @@ if (x >= 32.0) { x -= 32.0; secondaryChannel += 4.0; } if (x >= 16.0) { x -= 16.0; secondaryChannel += 2.0; } if (x >= 8.0) { x -= 8.0; secondaryChannel += 1.0; } - + float primaryChannel = 0.0; if (x >= 4.0) { x -= 4.0; primaryChannel += 4.0; } if (x >= 2.0) { x -= 2.0; primaryChannel += 2.0; } @@ -115,7 +119,7 @@ gl_Position = vec4((aVertexPosition.xyz - Scroll.xyz) * r1 + r2, 1); vTexCoord = aVertexTexCoord; vTexMetadata = aVertexTexMetadata; - + vec4 attrib = UnpackChannelAttributes(aVertexTexMetadata.t); vChannelMask = SelectChannelMask(attrib.s); vColorFraction = SelectColorFraction(attrib.s); @@ -123,4 +127,5 @@ vPalettedFraction = SelectPalettedFraction(attrib.s); vDepthMask = SelectChannelMask(attrib.t); vTexSampler = attrib.pq; -} + vTint = vec4(aVertexTint, 1.0); +} diff -Nru openra-20200503/glsl/model.vert openra-20210321/glsl/model.vert --- openra-20200503/glsl/model.vert 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/glsl/model.vert 2021-03-21 11:10:05.000000000 +0000 @@ -7,6 +7,7 @@ attribute vec4 aVertexPosition; attribute vec4 aVertexTexCoord; attribute vec2 aVertexTexMetadata; +attribute vec3 aVertexTint; varying vec4 vTexCoord; varying vec4 vChannelMask; varying vec4 vNormalsMask; @@ -14,6 +15,7 @@ in vec4 aVertexPosition; in vec4 aVertexTexCoord; in vec2 aVertexTexMetadata; +in vec3 aVertexTint; out vec4 vTexCoord; out vec4 vChannelMask; out vec4 vNormalsMask; diff -Nru openra-20200503/INSTALL.md openra-20210321/INSTALL.md --- openra-20200503/INSTALL.md 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/INSTALL.md 2021-03-21 11:10:05.000000000 +0000 @@ -8,15 +8,9 @@ Compiling OpenRA requires the following dependencies: * [Windows PowerShell >= 4.0](http://microsoft.com/powershell) (included by default in recent Windows 10 versions) -* [.NET Framework 4.6.1 (Developer Pack)](https://dotnet.microsoft.com/download/dotnet-framework/net461) (or via Visual Studio 2017) +* [.NET Framework 4.7.2 (Developer Pack)](https://dotnet.microsoft.com/download/dotnet-framework/net472) (or via Visual Studio 2017) * [.NET Core 2.2 SDK](https://dotnet.microsoft.com/download/dotnet-core/2.2) (or via Visual Studio 2017) -Type `make dependencies` in a command terminal to download pre-compiled native libraries for: -* [SDL 2](http://www.libsdl.org/download-2.0.php) -* [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm) -* [zlib](http://gnuwin32.sourceforge.net/packages/zlib.htm) -* [OpenAL](http://kcat.strangesoft.net/openal.html) -* [liblua 5.1](http://luabinaries.sourceforge.net/download.html) To compile OpenRA, open the `OpenRA.sln` solution in the main folder, build it from the command-line with MSBuild or use the Makefile analogue command `make all` scripted in PowerShell syntax. @@ -25,13 +19,19 @@ Linux ===== -Mono, version 5.4 or later, is required to compile OpenRA. You can add the [upstream mono repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version if your system packages are not sufficient. +Mono, version 5.18 or later, is required to compile OpenRA. You can add the [upstream mono repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version if your system packages are not sufficient. -Use `make dependencies` to map the native libraries to your system and fetch the remaining CLI dependencies to place them at the appropriate places. +To compile OpenRA, run `make` from the command line. After this one can run the game with `./launch-game.sh`. It is also possible to specify the mod you wish to run from the command line, e.g. with `./launch-game.sh Game.Mod=ts` if you wish to try the experimental Tiberian Sun mod. -To compile OpenRA, run `make all` from the command line. After this one can run the game with `./launch-game.sh`. It is also possible to specify the mod you wish to run from the command line, e.g. with `./launch-game.sh Game.Mod=ts` if you wish to try the experimental Tiberian Sun mod. +The default behaviour on the x86_64 architecture is to download several pre-compiled native libraries using the Nuget packaging manager. If you prefer to use system libraries, compile instead using `make TARGETPLATFORM=unix-generic`. -Type `sudo make install` for system-wide installation. Run `sudo make install-linux-shortcuts` to get startup scripts, icons and desktop files. You can then run the Red Alert by executing the `openra-ra` command, the Dune 2000 mod by running the `openra-d2k` command and Tiberian Dawn by the `openra-cnc` command. Alternatively, you can also run these mods by clicking on their desktop shortcuts if you ran `sudo make install-linux-shortcuts`. +If you choose to use system libraries, or your system is not x86_64, you will need to install the following using your system package manager: +* [SDL 2](http://www.libsdl.org/download-2.0.php) +* [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm) +* [OpenAL](http://kcat.strangesoft.net/openal.html) +* [liblua 5.1](http://luabinaries.sourceforge.net/download.html) + +Type `sudo make install` for system-wide installation. Run `sudo make install-linux-shortcuts` to get startup scripts, icons and desktop files. You can then run the Red Alert by executing the `openra-ra` command, the Dune 2000 mod by running the `openra-d2k` command and Tiberian Dawn by the `openra-cnc` command. Alternatively, you can also run these mods by clicking on their desktop shortcuts if you ran `sudo make install-linux-shortcuts`. Arch Linux ---------- @@ -89,24 +89,23 @@ Red Hat Enterprise Linux (and rebuilds, e.g. CentOS) ---------------------------------------------------- -The EPEL repository is required in order for the following command to run properly. +The EPEL repository is required in order for the following command to run properly. ``` sudo yum install "pkgconfig(mono)" SDL2 freetype "lua = 5.1" openal-soft xdg-utils zenity ``` -OSX +macOS ===== Before compiling OpenRA you must install the following dependencies: -* [Mono >= 5.4](https://www.mono-project.com/download/stable/#download-mac) +* [Mono >= 5.18](https://www.mono-project.com/download/stable/#download-mac) -Use `make dependencies` to download pre-compiled native libraries for: -* [SDL 2](http://www.libsdl.org/download-2.0.php) -* [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm) -* [OpenAL](http://kcat.strangesoft.net/openal.html) -* [liblua 5.1](http://luabinaries.sourceforge.net/download.html) +To compile OpenRA, run `make` from the command line. Run with `./launch-game.sh`. -To compile OpenRA, run `make` from the command line. +The default behaviour is to download several pre-compiled native libraries using the Nuget packaging manager. If you prefer to use system libraries, compile instead using `make TARGETPLATFORM=unix-generic`. If you choose to use system libraries you will need to install: +* [SDL 2](http://www.libsdl.org/download-2.0.php) (`brew install sdl2`) +* [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm) (`brew install freetype`) +* [OpenAL](http://kcat.strangesoft.net/openal.html) (`brew install openal-soft`) +* [liblua 5.1](http://luabinaries.sourceforge.net/download.html) (`brew install lua@5.1`) -Run with `./launch-game.sh`. diff -Nru openra-20200503/launch-dedicated.cmd openra-20210321/launch-dedicated.cmd --- openra-20200503/launch-dedicated.cmd 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/launch-dedicated.cmd 2021-03-21 11:10:05.000000000 +0000 @@ -7,6 +7,7 @@ set ListenPort=1234 set AdvertiseOnline=True set Password="" +set RecordReplays=False set RequireAuthentication=False set ProfileIDBlacklist="" @@ -21,6 +22,6 @@ :loop -OpenRA.Server.exe Game.Mod=%Mod% Server.Name=%Name% Server.ListenPort=%ListenPort% Server.AdvertiseOnline=%AdvertiseOnline% Server.EnableSingleplayer=%EnableSingleplayer% Server.Password=%Password% Server.RequireAuthentication=%RequireAuthentication% Server.ProfileIDBlacklist=%ProfileIDBlacklist% Server.ProfileIDWhitelist=%ProfileIDWhitelist% Server.EnableSyncReports=%EnableSyncReports% Server.EnableGeoIP=%EnableGeoIP% Server.ShareAnonymizedIPs=%ShareAnonymizedIPs% Engine.SupportDir=%SupportDir% +bin\OpenRA.Server.exe Engine.EngineDir=".." Game.Mod=%Mod% Server.Name=%Name% Server.ListenPort=%ListenPort% Server.AdvertiseOnline=%AdvertiseOnline% Server.EnableSingleplayer=%EnableSingleplayer% Server.Password=%Password% Server.RecordReplays=%RecordReplays% Server.RequireAuthentication=%RequireAuthentication% Server.ProfileIDBlacklist=%ProfileIDBlacklist% Server.ProfileIDWhitelist=%ProfileIDWhitelist% Server.EnableSyncReports=%EnableSyncReports% Server.EnableGeoIP=%EnableGeoIP% Server.ShareAnonymizedIPs=%ShareAnonymizedIPs% Engine.SupportDir=%SupportDir% goto loop diff -Nru openra-20200503/launch-dedicated.sh openra-20210321/launch-dedicated.sh --- openra-20200503/launch-dedicated.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/launch-dedicated.sh 2021-03-21 11:10:05.000000000 +0000 @@ -11,6 +11,7 @@ ListenPort="${ListenPort:-"1234"}" AdvertiseOnline="${AdvertiseOnline:-"True"}" Password="${Password:-""}" +RecordReplays="${RecordReplays:-"False"}" RequireAuthentication="${RequireAuthentication:-"False"}" ProfileIDBlacklist="${ProfileIDBlacklist:-""}" @@ -24,12 +25,13 @@ SupportDir="${SupportDir:-""}" while true; do - mono --debug OpenRA.Server.exe Game.Mod="$Mod" \ + mono --debug bin/OpenRA.Server.exe Engine.EngineDir=".." Game.Mod="$Mod" \ Server.Name="$Name" \ Server.ListenPort="$ListenPort" \ Server.AdvertiseOnline="$AdvertiseOnline" \ Server.EnableSingleplayer="$EnableSingleplayer" \ Server.Password="$Password" \ + Server.RecordReplays="$RecordReplays" \ Server.GeoIPDatabase="$GeoIPDatabase" \ Server.RequireAuthentication="$RequireAuthentication" \ Server.ProfileIDBlacklist="$ProfileIDBlacklist" \ diff -Nru openra-20200503/launch-game.cmd openra-20210321/launch-game.cmd --- openra-20200503/launch-game.cmd 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/launch-game.cmd 2021-03-21 11:10:05.000000000 +0000 @@ -5,7 +5,7 @@ ) :choosemod -set /P mod=Select mod (ra, cnc, d2k, ts) or --exit: +set /P mod="Select mod (ra, cnc, d2k, ts) or --exit: " if /I "%mod%" EQU "--exit" (exit /b) if "%mod%" EQU "ra" (goto launchmod) if "%mod%" EQU "cnc" (goto launchmod) @@ -17,18 +17,23 @@ goto choosemod :launchmod -OpenRA.Game.exe Game.Mod=%mod% %* +bin\OpenRA.exe Engine.EngineDir=".." Game.Mod=%mod% %* goto end :launch -OpenRA.Game.exe %* +bin\OpenRA.exe Engine.EngineDir=".." %* :end if %errorlevel% neq 0 goto crashdialog exit /b + :crashdialog +set logs=%AppData%\OpenRA\Logs +if exist %USERPROFILE%\Documents\OpenRA\Logs (set logs=%USERPROFILE%\Documents\OpenRA\Logs) +if exist Support\Logs (set logs=%cd%\Support\Logs) + echo ---------------------------------------- echo OpenRA has encountered a fatal error. -echo * Log Files are available in Documents\OpenRA\Logs +echo * Log Files are available in %logs% echo * FAQ is available at https://github.com/OpenRA/OpenRA/wiki/FAQ echo ---------------------------------------- -pause \ No newline at end of file +pause diff -Nru openra-20200503/launch-game.sh openra-20210321/launch-game.sh --- openra-20200503/launch-game.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/launch-game.sh 2021-03-21 11:10:05.000000000 +0000 @@ -1,5 +1,9 @@ #!/bin/sh -MODLAUNCHER=$(python -c "import os; print(os.path.realpath('$0'))") +if command -v python3 >/dev/null 2>&1; then + MODLAUNCHER=$(python3 -c "import os; print(os.path.realpath('$0'))") +else + MODLAUNCHER=$(python -c "import os; print(os.path.realpath('$0'))") +fi # Prompt for a mod to launch if one is not already specified MODARG='' @@ -21,17 +25,27 @@ fi # Launch the engine with the appropriate arguments -mono OpenRA.Game.exe Engine.LaunchPath="$MODLAUNCHER" $MODARG "$@" +mono bin/OpenRA.exe Engine.EngineDir=".." Engine.LaunchPath="$MODLAUNCHER" $MODARG "$@" # Show a crash dialog if something went wrong if [ $? != 0 ] && [ $? != 1 ]; then - ERROR_MESSAGE="OpenRA has encountered a fatal error.\nPlease refer to the crash logs and FAQ for more information.\n\nLog files are located in ~/.openra/Logs\nThe FAQ is available at http://wiki.openra.net/FAQ" + if [ "$(uname -s)" = "Darwin" ]; then + LOGS="${HOME}/Library/Application Support/OpenRA/Logs/" + else + LOGS="${XDG_CONFIG_HOME:-${HOME}/.config}/openra/Logs" + if [ ! -d "${LOGS}" ] && [ -d "${HOME}/.openra/Logs" ]; then + LOGS="${HOME}/.openra/Logs" + fi + fi + + test -d Support/Logs && LOGS="${PWD}/Support/Logs" + ERROR_MESSAGE="OpenRA has encountered a fatal error.\nPlease refer to the crash logs and FAQ for more information.\n\nLog files are located in ${LOGS}\nThe FAQ is available at http://wiki.openra.net/FAQ" if command -v zenity > /dev/null; then - zenity --no-wrap --error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null + zenity --no-wrap --error --title "OpenRA" --text "${ERROR_MESSAGE}" 2> /dev/null elif command -v kdialog > /dev/null; then - kdialog --title "{MODNAME}" --error "${ERROR_MESSAGE}" + kdialog --title "OpenRA" --error "${ERROR_MESSAGE}" else - printf "%s\n" "${ERROR_MESSAGE}" + echo "${ERROR_MESSAGE}" fi exit 1 fi diff -Nru openra-20200503/lua/scriptwrapper.lua openra-20210321/lua/scriptwrapper.lua --- openra-20200503/lua/scriptwrapper.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/lua/scriptwrapper.lua 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,7 @@ environment = {} -- Reset package path -package.path = GameDir .. "/lua/?.lua" +package.path = EngineDir .. "/lua/?.lua" -- Note: sandbox has been customized to remove math.random local sandbox = require('sandbox') diff -Nru openra-20200503/Makefile openra-20210321/Makefile --- openra-20200503/Makefile 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/Makefile 2021-03-21 11:10:05.000000000 +0000 @@ -3,55 +3,47 @@ # to compile, run: # make [DEBUG=true] # -# to check unit tests (requires NUnit version >= 2.6), run: -# make nunit [NUNIT_CONSOLE=] [NUNIT_LIBS_PATH=] [NUNIT_LIBS=] -# Use NUNIT_CONSOLE if nunit[3|2]-console was not downloaded by `make dependencies` nor is it in bin search paths -# Use NUNIT_LIBS_PATH if NUnit libs are not in search paths. Include trailing / -# Use NUNIT_LIBS if NUnit libs have different names (such as including a prefix or suffix) +# to compile using system libraries for native dependencies, run: +# make [DEBUG=true] TARGETPLATFORM=unix-generic +# # to check the official mods for erroneous yaml files, run: # make test # -# to check the official mod dlls for StyleCop violations, run: +# to check the engine and official mod dlls for code style violations, run: # make check # -# to install, run: +# to compile and install Red Alert, Tiberian Dawn, and Dune 2000, run: # make [prefix=/foo] [bindir=/bar/bin] install # -# to install Linux startup scripts, desktop files and icons: -# make install-linux-shortcuts [DEBUG=false] +# to compile and install Red Alert, Tiberian Dawn, and Dune 2000 +# using system libraries for native dependencies, run: +# make [prefix=/foo] [bindir=/bar/bin] TARGETPLATFORM=unix-generic install # -# to install the engine and common mod files (omitting the default mods): -# make install-engine -# make install-common-mod-files +# to install Linux startup scripts, desktop files, icons, and MIME metadata +# make install-linux-shortcuts # -# to uninstall, run: -# make uninstall +# to install Linux AppStream metadata +# make install-linux-appdata # # for help, run: # make help # -# to start the game, run: -# openra ############################## TOOLCHAIN ############################### # # List of .NET assemblies that we can guarantee exist -# OpenRA.Game.dll is a harmless false positive that we can ignore -WHITELISTED_OPENRA_ASSEMBLIES = OpenRA.Game.exe OpenRA.Utility.exe OpenRA.Platforms.Default.dll OpenRA.Mods.Common.dll OpenRA.Mods.Cnc.dll OpenRA.Mods.D2k.dll OpenRA.Game.dll +WHITELISTED_OPENRA_ASSEMBLIES = OpenRA.exe OpenRA.Utility.exe OpenRA.Server.exe OpenRA.Platforms.Default.dll OpenRA.Game.dll OpenRA.Mods.Common.dll OpenRA.Mods.Cnc.dll OpenRA.Mods.D2k.dll # These are explicitly shipped alongside our core files by the packaging script -WHITELISTED_THIRDPARTY_ASSEMBLIES = ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll Eluant.dll rix0rrr.BeaconLib.dll Open.Nat.dll SDL2-CS.dll OpenAL-CS.dll +WHITELISTED_THIRDPARTY_ASSEMBLIES = ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll Eluant.dll BeaconLib.dll Open.Nat.dll SDL2-CS.dll OpenAL-CS.Core.dll DiscordRPC.dll Newtonsoft.Json.dll # These are shipped in our custom minimal mono runtime and also available in the full system-installed .NET/mono stack # This list *must* be kept in sync with the files packaged by the AppImageSupport and OpenRALauncherOSX repositories -WHITELISTED_CORE_ASSEMBLIES = mscorlib.dll System.dll System.Configuration.dll System.Core.dll System.Numerics.dll System.Security.dll System.Xml.dll Mono.Security.dll - -NUNIT_LIBS_PATH := -NUNIT_LIBS := $(NUNIT_LIBS_PATH)nunit.framework.dll +WHITELISTED_CORE_ASSEMBLIES = mscorlib.dll System.dll System.Configuration.dll System.Core.dll System.Numerics.dll System.Security.dll System.Xml.dll Mono.Security.dll netstandard.dll ######################### UTILITIES/SETTINGS ########################### # -# install locations +# Install locations for local installs and downstream packaging prefix ?= /usr/local datarootdir ?= $(prefix)/share datadir ?= $(datarootdir) @@ -60,322 +52,132 @@ libdir ?= $(prefix)/lib gameinstalldir ?= $(libdir)/openra -BIN_INSTALL_DIR = $(DESTDIR)$(bindir) -DATA_INSTALL_DIR = $(DESTDIR)$(gameinstalldir) - -# install tools +# Toolchain +CWD = $(shell pwd) +MSBUILD = msbuild -verbosity:m -nologo +MONO = mono RM = rm RM_R = $(RM) -r RM_F = $(RM) -f RM_RF = $(RM) -rf -CP = cp -CP_R = $(CP) -r -INSTALL = install -INSTALL_DIR = $(INSTALL) -d -INSTALL_PROGRAM = $(INSTALL) -m755 -INSTALL_DATA = $(INSTALL) -m644 - -# Toolchain -MSBUILD = msbuild -verbosity:m -nologo - -# Enable 32 bit builds while generating the windows installer -WIN32 = false -# program targets -VERSION = $(shell git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null || echo git-`git rev-parse --short HEAD`) +# Only for use in target version: +VERSION := $(shell git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null || (c=$$(git rev-parse --short HEAD 2>/dev/null) && echo git-$$c)) -# dependencies +# Detect target platform for dependencies if not given by the user +ifndef TARGETPLATFORM UNAME_S := $(shell uname -s) +UNAME_M := $(shell uname -m) ifeq ($(UNAME_S),Darwin) -os-dependencies = osx-dependencies +TARGETPLATFORM = osx-x64 else -os-dependencies = linux-dependencies +ifeq ($(UNAME_M),x86_64) +TARGETPLATFORM = linux-x64 +else +TARGETPLATFORM = unix-generic +endif +endif endif -check-scripts: - @echo - @echo "Checking for Lua syntax errors..." - @luac -p $(shell find mods/*/maps/* -iname '*.lua') - @luac -p $(shell find lua/* -iname '*.lua') +OPENRA_UTILITY = ENGINE_DIR=".." $(MONO) --debug bin/OpenRA.Utility.exe + +##################### DEVELOPMENT BUILDS AND TESTS ##################### +# +all: + @command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 5.18."; exit 1) + @$(MSBUILD) -t:Build -restore -p:Configuration=Release -p:TargetPlatform=$(TARGETPLATFORM) +ifeq ($(TARGETPLATFORM), unix-generic) + @./configure-system-libraries.sh +endif + @./fetch-geoip.sh + +clean: + @-$(RM_RF) ./bin ./*/bin ./*/obj + @$(MSBUILD) -t:Clean + @-$(RM_F) IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP -check: dependencies +check: @echo @echo "Compiling in debug mode..." - @$(MSBUILD) -t:build -p:Configuration=Debug + @$(MSBUILD) -t:build -restore -p:Configuration=Debug -p:TargetPlatform=$(TARGETPLATFORM) +ifeq ($(TARGETPLATFORM), unix-generic) + @./configure-system-libraries.sh +endif @echo @echo "Checking runtime assemblies..." - @mono --debug OpenRA.Utility.exe all --check-runtime-assemblies $(WHITELISTED_OPENRA_ASSEMBLIES) $(WHITELISTED_THIRDPARTY_ASSEMBLIES) $(WHITELISTED_CORE_ASSEMBLIES) + @$(OPENRA_UTILITY) all --check-runtime-assemblies $(WHITELISTED_OPENRA_ASSEMBLIES) $(WHITELISTED_THIRDPARTY_ASSEMBLIES) $(WHITELISTED_CORE_ASSEMBLIES) @echo @echo "Checking for explicit interface violations..." - @mono --debug OpenRA.Utility.exe all --check-explicit-interfaces + @$(OPENRA_UTILITY) all --check-explicit-interfaces @echo @echo "Checking for incorrect conditional trait interface overrides..." - @mono --debug OpenRA.Utility.exe all --check-conditional-trait-interface-overrides - + @$(OPENRA_UTILITY) all --check-conditional-trait-interface-overrides -NUNIT_CONSOLE := $(shell test -f thirdparty/download/nunit3-console.exe && echo mono thirdparty/download/nunit3-console.exe || \ - which nunit3-console 2>/dev/null || which nunit2-console 2>/dev/null || which nunit-console 2>/dev/null) -nunit: core - @echo - @echo "Checking unit tests..." - @if [ "$(NUNIT_CONSOLE)" = "" ] ; then \ - echo 'nunit[3|2]-console not found!'; \ - echo 'Was "make dependencies" called or is NUnit installed?'>&2; \ - echo 'See "make help".'; \ - exit 1; \ - fi - @if $(NUNIT_CONSOLE) --help | head -n 1 | grep -E "NUnit version (1|2\.[0-5])";then \ - echo 'NUnit version >= 2.6 required'>&2; \ - echo 'Try "make dependencies" first to use NUnit from NuGet.'>&2; \ - echo 'See "make help".'; \ - exit 1; \ - fi - @$(NUNIT_CONSOLE) --noresult OpenRA.Test.nunit +check-scripts: + @echo + @echo "Checking for Lua syntax errors..." + @luac -p $(shell find mods/*/maps/* -iname '*.lua') + @luac -p $(shell find lua/* -iname '*.lua') + @luac -p $(shell find mods/*/bits/scripts/* -iname '*.lua') -test: core +test: all @echo @echo "Testing Tiberian Sun mod MiniYAML..." - @mono --debug OpenRA.Utility.exe ts --check-yaml + @$(OPENRA_UTILITY) ts --check-yaml @echo @echo "Testing Dune 2000 mod MiniYAML..." - @mono --debug OpenRA.Utility.exe d2k --check-yaml + @$(OPENRA_UTILITY) d2k --check-yaml @echo @echo "Testing Tiberian Dawn mod MiniYAML..." - @mono --debug OpenRA.Utility.exe cnc --check-yaml + @$(OPENRA_UTILITY) cnc --check-yaml @echo @echo "Testing Red Alert mod MiniYAML..." - @mono --debug OpenRA.Utility.exe ra --check-yaml + @$(OPENRA_UTILITY) ra --check-yaml -########################## MAKE/INSTALL RULES ########################## +############# LOCAL INSTALLATION AND DOWNSTREAM PACKAGING ############## # -all: dependencies core - -core: - @command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 5.4."; exit 1) -ifeq ($(WIN32), $(filter $(WIN32),true yes y on 1)) - @$(MSBUILD) -t:build -p:Configuration="Release-x86" -else - @$(MSBUILD) -t:build -p:Configuration=Release -endif - @./fetch-geoip.sh - -clean: - @ $(MSBUILD) -t:clean - @-$(RM_F) *.config IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP - @-$(RM_F) *.exe *.dll *.dylib ./OpenRA*/*.dll *.pdb mods/**/*.dll mods/**/*.pdb *.resources - @-$(RM_RF) ./*/bin ./*/obj - @-$(RM_RF) ./thirdparty/download - -distclean: clean - -cli-dependencies: - @./thirdparty/fetch-thirdparty-deps.sh - @ $(CP_R) thirdparty/download/*.dll . - @ $(CP_R) thirdparty/download/*.dll.config . - @ test -f OpenRA.Game/obj/project.assets.json || $(MSBUILD) -t:restore - -linux-dependencies: cli-dependencies linux-native-dependencies - -linux-native-dependencies: - @./thirdparty/configure-native-deps.sh - -windows-dependencies: cli-dependencies -ifeq ($(WIN32), $(filter $(WIN32),true yes y on 1)) - @./thirdparty/fetch-thirdparty-deps-windows.sh x86 -else - @./thirdparty/fetch-thirdparty-deps-windows.sh x64 +version: VERSION mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml +ifeq ($(VERSION),) + $(error Unable to determine new version (requires git or override of variable VERSION)) endif + @sh -c '. ./packaging/functions.sh; set_engine_version "$(VERSION)" .' + @sh -c '. ./packaging/functions.sh; set_mod_version "$(VERSION)" mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml' -osx-dependencies: cli-dependencies - @./thirdparty/fetch-thirdparty-deps-osx.sh - @ $(CP_R) thirdparty/download/osx/*.dylib . - @ $(CP_R) thirdparty/download/osx/*.dll.config . +install: + @sh -c '. ./packaging/functions.sh; install_assemblies_mono $(CWD) $(DESTDIR)$(gameinstalldir) $(TARGETPLATFORM) True True True' + @sh -c '. ./packaging/functions.sh; install_data $(CWD) $(DESTDIR)$(gameinstalldir) cnc d2k ra' -dependencies: $(os-dependencies) - -all-dependencies: cli-dependencies windows-dependencies osx-dependencies - -version: VERSION mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml - @echo "$(VERSION)" > VERSION - @for i in $? ; do \ - awk '{sub("Version:.*$$","Version: $(VERSION)"); print $0}' $${i} > $${i}.tmp && \ - awk '{sub("/[^/]*: User$$", "/$(VERSION): User"); print $0}' $${i}.tmp > $${i} && \ - rm $${i}.tmp; \ - done - -install: dependencies core install-core - -install-linux-shortcuts: install-linux-scripts install-linux-icons install-linux-desktop - -install-engine: - @-echo "Installing OpenRA engine to $(DATA_INSTALL_DIR)" - @$(INSTALL_DIR) "$(DATA_INSTALL_DIR)" - @$(INSTALL_PROGRAM) OpenRA.Game.exe "$(DATA_INSTALL_DIR)" - @$(INSTALL_PROGRAM) OpenRA.Server.exe "$(DATA_INSTALL_DIR)" - @$(INSTALL_PROGRAM) OpenRA.Utility.exe "$(DATA_INSTALL_DIR)" - @$(INSTALL_PROGRAM) OpenRA.Platforms.Default.dll "$(DATA_INSTALL_DIR)" - - @$(INSTALL_DATA) OpenRA.Platforms.Default.dll.config "$(DATA_INSTALL_DIR)" - @$(INSTALL_DATA) VERSION "$(DATA_INSTALL_DIR)/VERSION" - @$(INSTALL_DATA) AUTHORS "$(DATA_INSTALL_DIR)/AUTHORS" - @$(INSTALL_DATA) COPYING "$(DATA_INSTALL_DIR)/COPYING" - @$(INSTALL_DATA) IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP "$(DATA_INSTALL_DIR)/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP" - - @$(CP_R) glsl "$(DATA_INSTALL_DIR)" - @$(CP_R) lua "$(DATA_INSTALL_DIR)" - @$(CP) SDL2-CS* "$(DATA_INSTALL_DIR)" - @$(CP) OpenAL-CS* "$(DATA_INSTALL_DIR)" - @$(CP) Eluant* "$(DATA_INSTALL_DIR)" - @$(INSTALL_PROGRAM) ICSharpCode.SharpZipLib.dll "$(DATA_INSTALL_DIR)" - @$(INSTALL_PROGRAM) FuzzyLogicLibrary.dll "$(DATA_INSTALL_DIR)" - @$(INSTALL_PROGRAM) Open.Nat.dll "$(DATA_INSTALL_DIR)" - @$(INSTALL_PROGRAM) rix0rrr.BeaconLib.dll "$(DATA_INSTALL_DIR)" - -install-common-mod-files: - @-echo "Installing OpenRA common mod files to $(DATA_INSTALL_DIR)" - @$(INSTALL_DIR) "$(DATA_INSTALL_DIR)/mods" - @$(CP_R) mods/common "$(DATA_INSTALL_DIR)/mods/" - @$(INSTALL_PROGRAM) mods/common/OpenRA.Mods.Common.dll "$(DATA_INSTALL_DIR)/mods/common" - @$(INSTALL_PROGRAM) mods/common/OpenRA.Mods.Cnc.dll "$(DATA_INSTALL_DIR)/mods/common" - @$(INSTALL_DATA) "global mix database.dat" "$(DATA_INSTALL_DIR)/global mix database.dat" - -install-default-mods: - @-echo "Installing OpenRA default mods to $(DATA_INSTALL_DIR)" - @$(INSTALL_DIR) "$(DATA_INSTALL_DIR)/mods" - @$(CP_R) mods/cnc "$(DATA_INSTALL_DIR)/mods/" - @$(CP_R) mods/ra "$(DATA_INSTALL_DIR)/mods/" - @$(CP_R) mods/d2k "$(DATA_INSTALL_DIR)/mods/" - @$(INSTALL_PROGRAM) mods/d2k/OpenRA.Mods.D2k.dll "$(DATA_INSTALL_DIR)/mods/d2k" - @$(CP_R) mods/modcontent "$(DATA_INSTALL_DIR)/mods/" - -install-core: install-engine install-common-mod-files install-default-mods - @$(CP) *.sh "$(DATA_INSTALL_DIR)" - -install-linux-icons: - for SIZE in 16x16 32x32 48x48 64x64 128x128; do \ - $(INSTALL_DIR) "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps"; \ - $(INSTALL_DATA) packaging/linux/icons/ra_$$SIZE.png "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-ra.png"; \ - $(INSTALL_DATA) packaging/linux/icons/cnc_$$SIZE.png "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-cnc.png"; \ - $(INSTALL_DATA) packaging/linux/icons/d2k_$$SIZE.png "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-d2k.png"; \ - done - $(INSTALL_DIR) "$(DESTDIR)$(datadir)/icons/hicolor/scalable/apps" - $(INSTALL_DATA) packaging/linux/icons/ra_scalable.svg "$(DESTDIR)$(datadir)/icons/hicolor/scalable/apps/openra-ra.svg" - $(INSTALL_DATA) packaging/linux/icons/cnc_scalable.svg "$(DESTDIR)$(datadir)/icons/hicolor/scalable/apps/openra-cnc.svg" - -install-linux-desktop: - @$(INSTALL_DIR) "$(DESTDIR)$(datadir)/applications" - @sed 's/{MODID}/ra/g' packaging/linux/openra.desktop.in | sed 's/{MODNAME}/Red Alert/g' | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-ra.desktop - @$(INSTALL_DATA) packaging/linux/openra-ra.desktop "$(DESTDIR)$(datadir)/applications" - @sed 's/{MODID}/cnc/g' packaging/linux/openra.desktop.in | sed 's/{MODNAME}/Tiberian Dawn/g' | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-cnc.desktop - @$(INSTALL_DATA) packaging/linux/openra-cnc.desktop "$(DESTDIR)$(datadir)/applications" - @sed 's/{MODID}/d2k/g' packaging/linux/openra.desktop.in | sed 's/{MODNAME}/Dune 2000/g' | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-d2k.desktop - @$(INSTALL_DATA) packaging/linux/openra-d2k.desktop "$(DESTDIR)$(datadir)/applications" - @-$(RM) packaging/linux/openra-ra.desktop packaging/linux/openra-cnc.desktop packaging/linux/openra-d2k.desktop - -install-linux-mime: - @$(INSTALL_DIR) "$(DESTDIR)$(datadir)/mime/packages/" - @sed 's/{MODID}/ra/g' packaging/linux/openra-mimeinfo.xml.in | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-mimeinfo.xml - @$(INSTALL_DATA) packaging/linux/openra-mimeinfo.xml "$(DESTDIR)$(datadir)/mime/packages/openra-ra.xml" - @sed 's/{MODID}/cnc/g' packaging/linux/openra-mimeinfo.xml.in | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-mimeinfo.xml - @$(INSTALL_DATA) packaging/linux/openra-mimeinfo.xml "$(DESTDIR)$(datadir)/mime/packages/openra-cnc.xml" - @sed 's/{MODID}/d2k/g' packaging/linux/openra-mimeinfo.xml.in | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-mimeinfo.xml - @$(INSTALL_DATA) packaging/linux/openra-mimeinfo.xml "$(DESTDIR)$(datadir)/mime/packages/openra-d2k.xml" +install-linux-shortcuts: + @sh -c '. ./packaging/functions.sh; install_linux_shortcuts $(CWD) "$(DESTDIR)" "$(gameinstalldir)" "$(bindir)" "$(datadir)" "$(shell head -n1 VERSION)" cnc d2k ra' install-linux-appdata: - @$(INSTALL_DIR) "$(DESTDIR)$(datadir)/appdata/" - @sed 's/{MODID}/ra/g' packaging/linux/openra.appdata.xml.in | sed 's/{MOD_NAME}/Red Alert/g' | sed 's/{SCREENSHOT_RA}/ type="default"/g' | sed 's/{SCREENSHOT_CNC}//g' | sed 's/{SCREENSHOT_D2K}//g'> packaging/linux/openra-ra.appdata.xml - @$(INSTALL_DATA) packaging/linux/openra-ra.appdata.xml "$(DESTDIR)$(datadir)/appdata/" - @sed 's/{MODID}/cnc/g' packaging/linux/openra.appdata.xml.in | sed 's/{MOD_NAME}/Tiberian Dawn/g' | sed 's/{SCREENSHOT_RA}//g' | sed 's/{SCREENSHOT_CNC}/ type="default"/g' | sed 's/{SCREENSHOT_D2K}//g'> packaging/linux/openra-cnc.appdata.xml - @$(INSTALL_DATA) packaging/linux/openra-cnc.appdata.xml "$(DESTDIR)$(datadir)/appdata/" - @sed 's/{MODID}/d2k/g' packaging/linux/openra.appdata.xml.in | sed 's/{MOD_NAME}/Dune 2000/g' | sed 's/{SCREENSHOT_RA}//g' | sed 's/{SCREENSHOT_CNC}//g' | sed 's/{SCREENSHOT_D2K}/ type="default"/g'> packaging/linux/openra-d2k.appdata.xml - @$(INSTALL_DATA) packaging/linux/openra-d2k.appdata.xml "$(DESTDIR)$(datadir)/appdata/" - @-$(RM) packaging/linux/openra-ra.appdata.xml packaging/linux/openra-cnc.appdata.xml packaging/linux/openra-d2k.appdata.xml - -install-man-page: - @$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man6/" - @mono --debug OpenRA.Utility.exe all --man-page > openra.6 - @$(INSTALL_DATA) openra.6 "$(DESTDIR)$(mandir)/man6/" - @-$(RM) openra.6 - -install-linux-scripts: -ifeq ($(DEBUG), $(filter $(DEBUG),false no n off 0)) - @sed 's/{DEBUG}//' packaging/linux/openra.in | sed 's|{GAME_INSTALL_DIR}|$(gameinstalldir)|' | sed 's|{BIN_DIR}|$(bindir)|' > packaging/linux/openra.debug.in - @sed 's/{DEBUG}//' packaging/linux/openra-server.in | sed 's|{GAME_INSTALL_DIR}|$(gameinstalldir)|' | sed 's|{BIN_DIR}|$(bindir)|' > packaging/linux/openra-server.debug.in -else - @sed 's/{DEBUG}/--debug/' packaging/linux/openra.in | sed 's|{GAME_INSTALL_DIR}|$(gameinstalldir)|' | sed 's|{BIN_DIR}|$(bindir)|' > packaging/linux/openra.debug.in - @sed 's/{DEBUG}/--debug/' packaging/linux/openra-server.in | sed 's|{GAME_INSTALL_DIR}|$(gameinstalldir)|' | sed 's|{BIN_DIR}|$(bindir)|' > packaging/linux/openra-server.debug.in -endif - - @sed 's/{MODID}/ra/g' packaging/linux/openra.debug.in | sed 's/{TAG}/$(VERSION)/g' | sed 's/{MODNAME}/Red Alert/g' > packaging/linux/openra-ra - @sed 's/{MODID}/cnc/g' packaging/linux/openra.debug.in | sed 's/{TAG}/$(VERSION)/g' | sed 's/{MODNAME}/Tiberian Dawn/g' > packaging/linux/openra-cnc - @sed 's/{MODID}/d2k/g' packaging/linux/openra.debug.in | sed 's/{TAG}/$(VERSION)/g' | sed 's/{MODNAME}/Dune 2000/g' > packaging/linux/openra-d2k - - @$(INSTALL_DIR) "$(BIN_INSTALL_DIR)" - @$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-ra "$(BIN_INSTALL_DIR)" - @$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-cnc "$(BIN_INSTALL_DIR)" - @$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-d2k "$(BIN_INSTALL_DIR)" - @-$(RM) packaging/linux/openra-ra packaging/linux/openra-cnc packaging/linux/openra-d2k packaging/linux/openra.debug.in - - @sed 's/{MODID}/ra/g' packaging/linux/openra-server.debug.in | sed 's/{MODNAME}/Red Alert/g' > packaging/linux/openra-ra-server - @sed 's/{MODID}/cnc/g' packaging/linux/openra-server.debug.in | sed 's/{MODNAME}/Tiberian Dawn/g' > packaging/linux/openra-cnc-server - @sed 's/{MODID}/d2k/g' packaging/linux/openra-server.debug.in | sed 's/{MODNAME}/Dune 2000/g' > packaging/linux/openra-d2k-server - - @$(INSTALL_DIR) "$(BIN_INSTALL_DIR)" - @$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-ra-server "$(BIN_INSTALL_DIR)" - @$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-cnc-server "$(BIN_INSTALL_DIR)" - @$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-d2k-server "$(BIN_INSTALL_DIR)" - @-$(RM) packaging/linux/openra-ra-server packaging/linux/openra-cnc-server packaging/linux/openra-d2k-server packaging/linux/openra-server.debug.in - -uninstall: - @-$(RM_R) "$(DATA_INSTALL_DIR)" - @-$(RM_F) "$(BIN_INSTALL_DIR)/openra-ra" - @-$(RM_F) "$(BIN_INSTALL_DIR)/openra-ra-server" - @-$(RM_F) "$(BIN_INSTALL_DIR)/openra-cnc" - @-$(RM_F) "$(BIN_INSTALL_DIR)/openra-cnc-server" - @-$(RM_F) "$(BIN_INSTALL_DIR)/openra-d2k" - @-$(RM_F) "$(BIN_INSTALL_DIR)/openra-d2k-server" - @-$(RM_F) "$(DESTDIR)$(datadir)/applications/openra-ra.desktop" - @-$(RM_F) "$(DESTDIR)$(datadir)/applications/openra-cnc.desktop" - @-$(RM_F) "$(DESTDIR)$(datadir)/applications/openra-d2k.desktop" - @-for SIZE in 16x16 32x32 48x48 64x64 128x128; do \ - $(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-ra.png"; \ - $(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-cnc.png"; \ - $(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-d2k.png"; \ - done - @-$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/scalable/apps/openra-ra.svg" - @-$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/scalable/apps/openra-cnc.svg" - @-$(RM_F) "$(DESTDIR)$(datadir)/mime/packages/openra-ra.xml" - @-$(RM_F) "$(DESTDIR)$(datadir)/mime/packages/openra-cnc.xml" - @-$(RM_F) "$(DESTDIR)$(datadir)/mime/packages/openra-d2k.xml" - @-$(RM_F) "$(DESTDIR)$(datadir)/appdata/openra-ra.appdata.xml" - @-$(RM_F) "$(DESTDIR)$(datadir)/appdata/openra-cnc.appdata.xml" - @-$(RM_F) "$(DESTDIR)$(datadir)/appdata/openra-d2k.appdata.xml" - @-$(RM_F) "$(DESTDIR)$(mandir)/man6/openra.6" + @sh -c '. ./packaging/functions.sh; install_linux_appdata $(CWD) "$(DESTDIR)" "$(datadir)" cnc d2k ra' help: @echo 'to compile, run:' - @echo ' make [DEBUG=false]' + @echo ' make [DEBUG=true]' @echo - @echo 'to check unit tests (requires NUnit version >= 2.6), run:' - @echo ' make nunit [NUNIT_CONSOLE=] [NUNIT_LIBS_PATH=] [NUNIT_LIBS=]' - @echo ' Use NUNIT_CONSOLE if nunit[3|2]-console was not downloaded by `make dependencies` nor is it in bin search paths' - @echo ' Use NUNIT_LIBS_PATH if NUnit libs are not in search paths. Include trailing /' - @echo ' Use NUNIT_LIBS if NUnit libs have different names (such as including a prefix or suffix)' + @echo 'to compile using system libraries for native dependencies, run:' + @echo ' make [DEBUG=true] TARGETPLATFORM=unix-generic' @echo @echo 'to check the official mods for erroneous yaml files, run:' @echo ' make test' @echo - @echo 'to install, run:' - @echo ' make [prefix=/foo] [bindir=/bar/bin] install' + @echo 'to check the engine and official mod dlls for code style violations, run:' + @echo ' make test' + @echo + @echo 'to compile and install Red Alert, Tiberian Dawn, and Dune 2000 run:' + @echo ' make [prefix=/foo] [TARGETPLATFORM=unix-generic] install' @echo - @echo 'to install Linux startup scripts, desktop files and icons' - @echo ' make install-linux-shortcuts [DEBUG=false]' + @echo 'to compile and install Red Alert, Tiberian Dawn, and Dune 2000' + @echo 'using system libraries for native dependencies, run:' + @echo ' make [prefix=/foo] [bindir=/bar/bin] TARGETPLATFORM=unix-generic install' @echo - @echo 'to uninstall, run:' - @echo ' make uninstall' + @echo 'to install Linux startup scripts, desktop files, icons, and MIME metadata' + @echo ' make install-linux-shortcuts' @echo - @echo 'to start the game, run:' - @echo ' openra' + @echo 'to install Linux AppStream metadata' + @echo ' make install-linux-appdata' ########################### MAKEFILE SETTINGS ########################## # @@ -383,4 +185,4 @@ .SUFFIXES: -.PHONY: check-scripts check nunit test all core clean distclean cli-dependencies linux-dependencies linux-native-dependencies windows-dependencies osx-dependencies dependencies all-dependencies version install install-linux-shortcuts install-engine install-common-mod-files install-default-mods install-core install-linux-icons install-linux-desktop install-linux-mime install-linux-appdata install-man-page install-linux-scripts uninstall help +.PHONY: all clean check check-scripts test version install install-linux-shortcuts install-linux-appdata help diff -Nru openra-20200503/make.ps1 openra-20210321/make.ps1 --- openra-20200503/make.ps1 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/make.ps1 2021-03-21 11:10:05.000000000 +0000 @@ -3,15 +3,13 @@ ############################################################### ########################## FUNCTIONS ########################## ############################################################### -function All-Command +function All-Command { if ((CheckForDotnet) -eq 1) { return } - Dependencies-Command - dotnet build /p:Configuration=Release /nologo if ($lastexitcode -ne 0) { @@ -26,11 +24,12 @@ { echo "Downloading IP2Location GeoIP database." $target = Join-Path $pwd.ToString() "IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP" - (New-Object System.Net.WebClient).DownloadFile("https://download.ip2location.com/lite/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP", $target) + [Net.ServicePointManager]::SecurityProtocol = 'Tls12' + (New-Object System.Net.WebClient).DownloadFile("https://github.com/OpenRA/GeoIP-Database/releases/download/monthly/IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP", $target) } } -function Clean-Command +function Clean-Command { if ((CheckForDotnet) -eq 1) { @@ -38,22 +37,12 @@ } dotnet clean /nologo - rm *.dll - rm mods/*/*.dll - rm *.config - rm *.pdb - rm mods/*/*.pdb - rm *.exe - rm ./*/bin -r - rm ./*/obj -r - if (Test-Path thirdparty/download/) - { - rmdir thirdparty/download -Recurse -Force - } + Remove-Item ./bin -Recurse -ErrorAction Ignore + Remove-Item ./*/obj -Recurse -ErrorAction Ignore Write-Host "Clean complete." -ForegroundColor Green } -function Version-Command +function Version-Command { if ($command.Length -gt 1) { @@ -76,10 +65,10 @@ } } else - { + { Write-Host "Unable to locate Git. The version will remain unchanged." -ForegroundColor Red } - + if ($version -ne $null) { $version | out-file ".\VERSION" @@ -101,27 +90,6 @@ } } -function Dependencies-Command -{ - cd thirdparty - ./fetch-thirdparty-deps.ps1 - cp download/*.dll .. - cp download/windows/*.dll .. - cd .. - Write-Host "Dependencies copied." -ForegroundColor Cyan - - if ((CheckForDotnet) -eq 1) - { - return - } - - dotnet restore /nologo - if ($lastexitcode -ne 0) - { - Write-Host "Project restoration failed." -ForegroundColor Red - } -} - function Test-Command { if ((CheckForUtility) -eq 1) @@ -131,13 +99,13 @@ Write-Host "Testing mods..." -ForegroundColor Cyan Write-Host "Testing Tiberian Sun mod MiniYAML..." -ForegroundColor Cyan - ./OpenRA.Utility.exe ts --check-yaml + InvokeCommand "$utilityPath ts --check-yaml" Write-Host "Testing Dune 2000 mod MiniYAML..." -ForegroundColor Cyan - ./OpenRA.Utility.exe d2k --check-yaml + InvokeCommand "$utilityPath d2k --check-yaml" Write-Host "Testing Tiberian Dawn mod MiniYAML..." -ForegroundColor Cyan - ./OpenRA.Utility.exe cnc --check-yaml + InvokeCommand "$utilityPath cnc --check-yaml" Write-Host "Testing Red Alert mod MiniYAML..." -ForegroundColor Cyan - ./OpenRA.Utility.exe ra --check-yaml + InvokeCommand "$utilityPath ra --check-yaml" } function Check-Command @@ -152,10 +120,10 @@ if ((CheckForUtility) -eq 0) { Write-Host "Checking for explicit interface violations..." -ForegroundColor Cyan - ./OpenRA.Utility.exe all --check-explicit-interfaces + InvokeCommand "$utilityPath all --check-explicit-interfaces" Write-Host "Checking for incorrect conditional trait interface overrides..." -ForegroundColor Cyan - ./OpenRA.Utility.exe all --check-conditional-trait-interface-overrides + InvokeCommand "$utilityPath all --check-conditional-trait-interface-overrides" } } @@ -172,6 +140,10 @@ { luac -p $script } + foreach ($script in ls "mods/*/bits/scripts/*.lua") + { + luac -p $script + } Write-Host "Check completed!" -ForegroundColor Green } else @@ -180,23 +152,9 @@ } } -function Docs-Command -{ - if ((CheckForUtility) -eq 1) - { - return - } - - ./make.ps1 version - ./OpenRA.Utility.exe all --docs | Out-File -Encoding "UTF8" DOCUMENTATION.md - ./OpenRA.Utility.exe all --weapon-docs | Out-File -Encoding "UTF8" WEAPONS.md - ./OpenRA.Utility.exe all --lua-docs | Out-File -Encoding "UTF8" Lua-API.md - ./OpenRA.Utility.exe all --settings-docs | Out-File -Encoding "UTF8" Settings.md -} - function CheckForUtility { - if (Test-Path OpenRA.Utility.exe) + if (Test-Path $utilityPath) { return 0 } @@ -207,7 +165,7 @@ function CheckForDotnet { - if ((Get-Command "dotnet" -ErrorAction SilentlyContinue) -eq $null) + if ((Get-Command "dotnet" -ErrorAction SilentlyContinue) -eq $null) { Write-Host "The 'dotnet' tool is required to compile OpenRA. Please install the .NET Core SDK or Visual Studio and try again. https://dotnet.microsoft.com/download" -ForegroundColor Red return 1 @@ -229,6 +187,20 @@ } } +function InvokeCommand +{ + param($expression) + # $? is the return value of the called expression + # Invoke-Expression itself will always succeed, even if the invoked expression fails + # So temporarily store the return value in $success + $expression += '; $success = $?' + Invoke-Expression $expression + if ($success -eq $False) + { + exit 1 + } +} + ############################################################### ############################ Main ############################# ############################################################### @@ -244,7 +216,6 @@ Write-Host "Command list:" Write-Host "" Write-Host " all, a Builds the game and its development tools." - Write-Host " dependencies, d Copies the game's dependencies into the main game folder." Write-Host " version, v Sets the version strings for the default mods to the" Write-Host " latest version for the current Git branch." Write-Host " clean, c Removes all built and copied files. Use the 'all' and" @@ -252,7 +223,6 @@ Write-Host " test, t Tests the default mods for errors." Write-Host " check, ck Checks .cs files for StyleCop violations." Write-Host " check-scripts, cs Checks .lua files for syntax errors." - Write-Host " docs Generates the trait and Lua API documentation." Write-Host "" $command = (Read-Host "Enter command").Split(' ', 2) } @@ -261,6 +231,9 @@ $command = $args } +$env:ENGINE_DIR = ".." +$utilityPath = "bin\OpenRA.Utility.exe" + $execute = $command if ($command.Length -gt 1) { @@ -270,17 +243,15 @@ switch ($execute) { {"all", "a" -contains $_} { All-Command } - {"dependencies", "d" -contains $_} { Dependencies-Command } {"version", "v" -contains $_} { Version-Command } {"clean", "c" -contains $_} { Clean-Command } {"test", "t" -contains $_} { Test-Command } {"check", "ck" -contains $_} { Check-Command } {"check-scripts", "cs" -contains $_} { Check-Scripts-Command } - "docs" { Docs-Command } Default { Write-Host ("Invalid command '{0}'" -f $command) } } -#In case the script was called without any parameters we keep the window open +#In case the script was called without any parameters we keep the window open if ($args.Length -eq 0) { WaitForInput diff -Nru openra-20200503/mods/all/mod.yaml openra-20210321/mods/all/mod.yaml --- openra-20200503/mods/all/mod.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/all/mod.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,16 +4,16 @@ Hidden: true Packages: - . + ^EngineDir Cursors: Chrome: Assemblies: - ./mods/common/OpenRA.Mods.Common.dll - ./mods/common/OpenRA.Mods.Cnc.dll - ./mods/d2k/OpenRA.Mods.D2k.dll + ^BinDir|OpenRA.Mods.Common.dll + ^BinDir|OpenRA.Mods.Cnc.dll + ^BinDir|OpenRA.Mods.D2k.dll ChromeLayout: @@ -32,3 +32,6 @@ SpriteSequenceFormat: DefaultSpriteSequence ModelSequenceFormat: PlaceholderModelSequence + +DiscordService: + ApplicationId: 699222659766026240 diff -Nru openra-20200503/mods/cnc/audio/notifications.yaml openra-20210321/mods/cnc/audio/notifications.yaml --- openra-20200503/mods/cnc/audio/notifications.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/audio/notifications.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -18,6 +18,7 @@ EnemyStructureDestroyed: estrucx EnemyPlanesApproaching: enemya HarvesterAttack: + HarvesterLost: harvlost InsufficientPower: nopower1 IonCannonCharging: ionchrg1 IonCannonReady: ionredy1 @@ -39,7 +40,7 @@ Repairing: repair1 SelectTarget: select1 SilosNeeded: silos1 - StartGame: + StartGame: GameLoaded: GameSaved: Training: bldging1 @@ -47,7 +48,7 @@ UnitLost: unitlost UnitReady: unitredy Win: accom1 - DisablePrefixes: AirstrikeReady, BaseAttack, Building, BuildingCannotPlaceAudio, BuildingInProgress, BuildingLost, Cancelled, CivilianBuildingCaptured, CivilianKilled, ConstructionComplete, EnemyUnitsApproaching, EnemyStructureDestroyed, EnemyPlanesApproaching, HarvesterAttack, InsufficientPower, IonCannonCharging, IonCannonReady, Leave, Lose, LowPower, MissionAccomplished, MissionFailed, NewOptions, NoBuild, NodStructureDestroyed, NotReady, NuclearWarheadApproaching, NuclearWeaponAvailable, NuclearWeaponLaunched, OnHold, PrimaryBuildingSelected, Reinforce, Repairing, SelectTarget, SilosNeeded, Training, UnitLost, UnitReady, Win + DisablePrefixes: AirstrikeReady, BaseAttack, Building, BuildingCannotPlaceAudio, BuildingInProgress, BuildingLost, Cancelled, CivilianBuildingCaptured, CivilianKilled, ConstructionComplete, EnemyUnitsApproaching, EnemyStructureDestroyed, EnemyPlanesApproaching, HarvesterAttack, HarvesterLost, InsufficientPower, IonCannonCharging, IonCannonReady, Leave, Lose, LowPower, MissionAccomplished, MissionFailed, NewOptions, NoBuild, NodStructureDestroyed, NotReady, NuclearWarheadApproaching, NuclearWeaponAvailable, NuclearWeaponLaunched, OnHold, PrimaryBuildingSelected, Reinforce, Repairing, SelectTarget, SilosNeeded, Training, UnitLost, UnitReady, Win Sounds: Notifications: Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/bits/apctur2.shp and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/bits/apctur2.shp differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/bits/apctur.shp and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/bits/apctur.shp differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/bits/harvlost.aud and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/bits/harvlost.aud differ diff -Nru openra-20200503/mods/cnc/bits/scripts/campaign-global.lua openra-20210321/mods/cnc/bits/scripts/campaign-global.lua --- openra-20200503/mods/cnc/bits/scripts/campaign-global.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/bits/scripts/campaign-global.lua 2021-03-21 11:10:05.000000000 +0000 @@ -40,7 +40,7 @@ end ReinforceWithLandingCraft = function(player, units, transportStart, transportUnload, rallypoint) - local transport = Actor.Create("oldlst", true, { Owner = player, Facing = 0, Location = transportStart }) + local transport = Actor.Create("oldlst", true, { Owner = player, Facing = Angle.North, Location = transportStart }) local subcell = 0 Utils.Do(units, function(a) transport.LoadPassenger(Actor.Create(a, false, { Owner = transport.Owner, Facing = transport.Facing, Location = transportUnload, SubCell = subcell })) diff -Nru openra-20200503/mods/cnc/chrome/dialogs.yaml openra-20210321/mods/cnc/chrome/dialogs.yaml --- openra-20200503/mods/cnc/chrome/dialogs.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/dialogs.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -142,7 +142,7 @@ Height: 16 Label@LABEL: X: 40 - Width: 60 + Width: PARENT_RIGHT Height: 25 Shadow: True Label@NOFLAG_LABEL: diff -Nru openra-20200503/mods/cnc/chrome/editor.yaml openra-20210321/mods/cnc/chrome/editor.yaml --- openra-20200503/mods/cnc/chrome/editor.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/editor.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -277,8 +277,14 @@ Slider@OPTION: X: 58 Y: 1 - Width: 207 + Width: 146 Height: 20 + TextField@VALUE: + X: 206 + Y: 1 + Width: 50 + Height: 20 + Type: Integer Container@DROPDOWN_OPTION_TEMPLATE: Width: PARENT_RIGHT Height: 27 diff -Nru openra-20200503/mods/cnc/chrome/ingame.yaml openra-20210321/mods/cnc/chrome/ingame.yaml --- openra-20200503/mods/cnc/chrome/ingame.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/ingame.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -271,7 +271,7 @@ Height: 16 Label@LABEL: X: 40 - Width: 60 + Width: PARENT_RIGHT Height: 25 Shadow: True Label@NOFLAG_LABEL: @@ -984,7 +984,7 @@ X: PARENT_RIGHT - 200 Y: 0 Width: 200 - Height: PARENT_BOTTOM + Height: PARENT_BOTTOM Image@FLAG: X: 5 Y: 4 diff -Nru openra-20200503/mods/cnc/chrome/lobby-music.yaml openra-20210321/mods/cnc/chrome/lobby-music.yaml --- openra-20200503/mods/cnc/chrome/lobby-music.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/lobby-music.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -20,12 +20,13 @@ Height: 25 Text: Track Font: Bold - Label@TYPE: - X: PARENT_RIGHT - 63 + Label@LENGTH: + X: PARENT_RIGHT - 80 Height: 25 Width: 50 Text: Length Font: Bold + Align: Right Background@CONTROLS: Background: panel-transparent Width: 308 diff -Nru openra-20200503/mods/cnc/chrome/lobby-options.yaml openra-20210321/mods/cnc/chrome/lobby-options.yaml --- openra-20200503/mods/cnc/chrome/lobby-options.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/lobby-options.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -23,21 +23,21 @@ Height: 34 Children: Checkbox@A: - Width: 175 + Width: 220 Height: 20 Font: Regular Visible: False TooltipContainer: TOOLTIP_CONTAINER Checkbox@B: - X: 195 - Width: 175 + X: 225 + Width: 220 Height: 20 Font: Regular Visible: False TooltipContainer: TOOLTIP_CONTAINER Checkbox@C: - X: 375 - Width: 175 + X: 450 + Width: 190 Height: 20 Font: Regular Visible: False @@ -47,26 +47,26 @@ Width: PARENT_RIGHT Children: Label@A_DESC: - Width: 80 + Width: 140 Height: 25 Align: Right Visible: False DropDownButton@A: - X: 85 - Width: 160 + X: 145 + Width: 180 Height: 25 Font: Regular Visible: False TooltipContainer: TOOLTIP_CONTAINER Label@B_DESC: - X: PARENT_RIGHT - WIDTH - 183 - Width: 160 + X: PARENT_RIGHT - WIDTH - 203 + Width: 140 Height: 25 Align: Right Visible: False DropDownButton@B: X: PARENT_RIGHT - WIDTH - 18 - Width: 160 + Width: 180 Height: 25 Font: Regular Visible: False diff -Nru openra-20200503/mods/cnc/chrome/lobby-players.yaml openra-20210321/mods/cnc/chrome/lobby-players.yaml --- openra-20200503/mods/cnc/chrome/lobby-players.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/lobby-players.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -16,34 +16,41 @@ Font: Bold Label@COLOR: X: 210 - Width: 76 + Width: 94 Height: 25 Text: Color Align: Center Font: Bold Label@FACTION: - X: 291 + X: 309 Width: 120 Height: 25 Text: Faction Align: Center Font: Bold Label@TEAM: - X: 416 + X: 460-25 Width: 50 Height: 25 Text: Team Align: Center Font: Bold + Label@HANDICAP: + X: 491 + Width: 75 + Height: 25 + Text: Handicap + Align: Center + Font: Bold Label@SPAWN: - X: 471 + X: 571 Width: 50 Height: 25 Text: Spawn Align: Left Font: Bold Label@STATUS: - X: 527 + X: 627 Width: 20 Height: 25 Text: Ready @@ -108,7 +115,7 @@ Visible: false DropDownButton@COLOR: X: 210 - Width: 76 + Width: 94 Height: 25 Font: Regular IgnoreChildMouseOver: true @@ -119,7 +126,7 @@ Width: PARENT_RIGHT - 35 Height: PARENT_BOTTOM - 12 DropDownButton@FACTION: - X: 291 + X: 309 Width: 120 Height: 25 Font: Regular @@ -138,17 +145,24 @@ Height: 25 Text: Faction DropDownButton@TEAM_DROPDOWN: - X: 416 + X: 435 Width: 50 Height: 25 Font: Regular + DropDownButton@HANDICAP_DROPDOWN: + X: 491 + Width: 75 + Height: 25 + Font: Regular + TooltipContainer: TOOLTIP_CONTAINER + TooltipText: A handicap decreases the combat effectiveness of the player's forces DropDownButton@SPAWN_DROPDOWN: - X: 471 + X: 571 Width: 50 Height: 25 Font: Regular Image@STATUS_IMAGE: - X: 529 + X: 629 Y: 4 Width: 20 Height: 20 @@ -156,7 +170,7 @@ ImageName: checked Visible: false Checkbox@STATUS_CHECKBOX: - X: 527 + X: 627 Y: 2 Width: 20 Height: 20 @@ -224,10 +238,10 @@ ColorBlock@COLORBLOCK: X: 215 Y: 6 - Width: 41 + Width: 59 Height: 13 Container@FACTION: - X: 291 + X: 309 Width: 120 Height: 25 Children: @@ -242,29 +256,41 @@ Height: 25 Text: Faction Label@TEAM: - X: 416 - Width: 25 - Height: 25 - Align: Center - Label@SPAWN: - X: 471 + X: 435 Width: 25 Height: 25 Align: Center DropDownButton@TEAM_DROPDOWN: - X: 416 + X: 435 Width: 50 Height: 25 Font: Regular Visible: false + Label@HANDICAP: + X: 491 + Width: 50 + Height: 25 + Align: Center + DropDownButton@HANDICAP_DROPDOWN: + X: 491 + Width: 75 + Height: 25 + Font: Regular + TooltipContainer: TOOLTIP_CONTAINER + TooltipText: A handicap decreases the combat effectiveness of the player's forces + Label@SPAWN: + X: 571 + Width: 25 + Height: 25 + Align: Center DropDownButton@SPAWN_DROPDOWN: - X: 471 + X: 571 Width: 50 Height: 25 Font: Regular Visible: false Image@STATUS_IMAGE: - X: 529 + X: 629 Y: 4 Width: 20 Height: 20 @@ -291,7 +317,7 @@ Visible: false Button@JOIN: X: 210 - Width: 338 + Width: 438 Height: 25 Text: Play in this slot Font: Regular @@ -340,13 +366,13 @@ Template: ANONYMOUS_PLAYER_TOOLTIP Label@SPECTATOR: X: 210 - Width: 341 + Width: 441 Height: 25 Text: Spectator Align: Center Font: Bold Image@STATUS_IMAGE: - X: 529 + X: 629 Y: 4 Width: 20 Height: 20 @@ -354,7 +380,7 @@ ImageName: checked Visible: false Checkbox@STATUS_CHECKBOX: - X: 527 + X: 627 Y: 2 Width: 20 Height: 20 @@ -421,13 +447,13 @@ Template: ANONYMOUS_PLAYER_TOOLTIP Label@SPECTATOR: X: 210 - Width: 341 + Width: 441 Height: 25 Text: Spectator Align: Center Font: Bold Image@STATUS_IMAGE: - X: 527 + X: 627 Y: 4 Width: 20 Height: 20 @@ -448,7 +474,7 @@ Text: Allow Spectators? Button@SPECTATE: X: 210 - Width: 338 + Width: 438 Height: 25 Text: Spectate Font: Regular diff -Nru openra-20200503/mods/cnc/chrome/lobby-servers.yaml openra-20210321/mods/cnc/chrome/lobby-servers.yaml --- openra-20200503/mods/cnc/chrome/lobby-servers.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/lobby-servers.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -9,32 +9,32 @@ Children: Label@NAME: X: 5 - Width: 255 + Width: 355 Height: 25 Text: Server Align: Center Font: Bold Label@PLAYERS: - X: 290 + X: 390 Width: 85 Height: 25 Text: Players Font: Bold Label@LOCATION: - X: 380 + X: 480 Width: 110 Height: 25 Text: Location Font: Bold Label@STATUS: - X: 495 + X: 595 Width: 50 Height: 25 Text: Status Font: Bold LogicTicker@NOTICE_WATCHER: Container@NOTICE_CONTAINER: - Width: 582 + Width: PARENT_RIGHT Height: 19 Children: Background@bg: @@ -87,12 +87,12 @@ Children: LabelWithTooltip@TITLE: X: 5 - Width: 245 + Width: 345 Height: 25 TooltipContainer: TOOLTIP_CONTAINER TooltipTemplate: SIMPLE_TOOLTIP Image@PASSWORD_PROTECTED: - X: 272 + X: 372 Y: 6 Width: 12 Height: 13 @@ -101,7 +101,7 @@ TooltipTemplate: SIMPLE_TOOLTIP TooltipText: Requires Password Image@REQUIRES_AUTHENTICATION: - X: 272 + X: 372 Y: 6 Width: 12 Height: 13 @@ -110,17 +110,17 @@ TooltipTemplate: SIMPLE_TOOLTIP TooltipText: Requires OpenRA forum account LabelWithTooltip@PLAYERS: - X: 290 + X: 390 Width: 85 Height: 25 TooltipContainer: TOOLTIP_CONTAINER TooltipTemplate: SIMPLE_TOOLTIP Label@LOCATION: - X: 380 + X: 480 Width: 110 Height: 25 Label@STATUS: - X: 495 + X: 595 Width: 50 Height: 25 Label@PROGRESS_LABEL: @@ -132,12 +132,12 @@ Visible: false DropDownButton@FILTERS_DROPDOWNBUTTON: Y: PARENT_BOTTOM + 5 - Width: 151 + Width: 180 Height: 25 Text: Filter Games Font: Bold Button@RELOAD_BUTTON: - X: 156 + X: 185 Y: PARENT_BOTTOM + 5 Width: 26 Height: 25 diff -Nru openra-20200503/mods/cnc/chrome/lobby.yaml openra-20210321/mods/cnc/chrome/lobby.yaml --- openra-20200503/mods/cnc/chrome/lobby.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/lobby.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,7 +2,7 @@ Logic: LobbyLogic X: (WINDOW_RIGHT - WIDTH) / 2 Y: (WINDOW_BOTTOM - 560) / 2 - Width: 800 + Width: 900 Height: 575 Children: ColorPreviewManager@COLOR_MANAGER: @@ -25,55 +25,57 @@ DropDownButton@SLOTS_DROPDOWNBUTTON: X: 15 Y: 254 - Width: 182 + Width: 211 Height: 25 Text: Slot Admin Container@SKIRMISH_TABS: + X: 697 - WIDTH + Width: 465 Visible: False Children: Button@PLAYERS_TAB: - X: 202 Y: 248 - Width: 129 + Width: 151 Height: 31 Text: Players Button@OPTIONS_TAB: - X: 336 + X: 157 Y: 248 - Width: 128 + Width: 151 Height: 31 Text: Options Button@MUSIC_TAB: - X: 469 + X: 314 Y: 248 - Width: 128 + Width: 151 Height: 31 Text: Music Container@MULTIPLAYER_TABS: + X: 697 - WIDTH + Width: 465 Visible: False Children: Button@PLAYERS_TAB: - X: 202 Y: 248 - Width: 95 + Width: 112 Height: 31 Text: Players Button@OPTIONS_TAB: - X: 302 + X: 118 Y: 248 - Width: 95 + Width: 112 Height: 31 Text: Options Button@MUSIC_TAB: - X: 402 + X: 236 Y: 248 - Width: 95 + Width: 112 Height: 31 Text: Music Button@SERVERS_TAB: - X: 502 + X: 354 Y: 248 - Width: 95 + Width: 111 Height: 31 Text: Servers Button@CHANGEMAP_BUTTON: @@ -85,7 +87,7 @@ Container@TOP_PANELS_ROOT: X: 15 Y: 30 - Width: 582 + Width: 682 Height: 219 Container@LOBBYCHAT: X: 15 diff -Nru openra-20200503/mods/cnc/chrome/mapchooser.yaml openra-20210321/mods/cnc/chrome/mapchooser.yaml --- openra-20200503/mods/cnc/chrome/mapchooser.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/mapchooser.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,7 +2,7 @@ Logic: MapChooserLogic X: (WINDOW_RIGHT - WIDTH) / 2 Y: (WINDOW_BOTTOM - 560) / 2 - Width: 800 + Width: 900 Height: 575 Children: Label@TITLE: @@ -64,7 +64,7 @@ ScrollPanel@MAP_LIST: Width: PARENT_RIGHT Height: PARENT_BOTTOM - Children: + ItemSpacing: 1 Container@USER_MAPS_TAB: X: 15 Y: 45 @@ -74,18 +74,18 @@ ScrollPanel@MAP_LIST: Width: PARENT_RIGHT Height: PARENT_BOTTOM - Children: + ItemSpacing: 1 ScrollItem@MAP_TEMPLATE: - Width: 183 - Height: 232 - X: 2 + Width: 210 + Height: 262 + X: 1 Visible: false Children: MapPreview@PREVIEW: X: (PARENT_RIGHT - WIDTH) / 2 - Y: 4 - Width: 173 - Height: 173 + Y: 3 + Width: 204 + Height: 204 IgnoreMouseOver: true IgnoreMouseInput: true Label@TITLE: diff -Nru openra-20200503/mods/cnc/chrome/multiplayer-browser.yaml openra-20210321/mods/cnc/chrome/multiplayer-browser.yaml --- openra-20200503/mods/cnc/chrome/multiplayer-browser.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/multiplayer-browser.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,7 +2,7 @@ Logic: MultiplayerLogic X: (WINDOW_RIGHT - WIDTH) / 2 Y: (WINDOW_BOTTOM - 560) / 2 - Width: 800 + Width: 900 Height: 575 Children: Label@TITLE: @@ -25,25 +25,25 @@ Children: Label@NAME: X: 5 - Width: 255 + Width: 355 Height: 25 Text: Server Align: Center Font: Bold Label@PLAYERS: - X: 290 + X: 390 Width: 85 Height: 25 Text: Players Font: Bold Label@LOCATION: - X: 380 + X: 480 Width: 110 Height: 25 Text: Location Font: Bold Label@STATUS: - X: 495 + X: 595 Width: 50 Height: 25 Text: Status @@ -52,7 +52,7 @@ Container@NOTICE_CONTAINER: X: 15 Y: 30 - Width: 582 + Width: 682 Height: 19 Children: Background@bg: @@ -84,7 +84,7 @@ ScrollPanel@SERVER_LIST: X: 15 Y: 30 - Width: 582 + Width: 682 Height: PARENT_BOTTOM - 75 TopBottomSpacing: 2 Children: @@ -107,12 +107,12 @@ Children: LabelWithTooltip@TITLE: X: 5 - Width: 245 + Width: 345 Height: 25 TooltipContainer: TOOLTIP_CONTAINER TooltipTemplate: SIMPLE_TOOLTIP Image@PASSWORD_PROTECTED: - X: 272 + X: 372 Y: 6 Width: 12 Height: 13 @@ -121,7 +121,7 @@ TooltipTemplate: SIMPLE_TOOLTIP TooltipText: Requires Password Image@REQUIRES_AUTHENTICATION: - X: 272 + X: 372 Y: 6 Width: 12 Height: 13 @@ -130,23 +130,23 @@ TooltipTemplate: SIMPLE_TOOLTIP TooltipText: Requires OpenRA forum account LabelWithTooltip@PLAYERS: - X: 290 + X: 390 Width: 85 Height: 25 TooltipContainer: TOOLTIP_CONTAINER TooltipTemplate: SIMPLE_TOOLTIP Label@LOCATION: - X: 380 + X: 480 Width: 110 Height: 25 Label@STATUS: - X: 495 + X: 595 Width: 50 Height: 25 Label@PROGRESS_LABEL: X: 15 Y: 31 + (PARENT_BOTTOM - 75 - HEIGHT) / 2 - Width: 582 + Width: 682 Height: 25 Font: Bold Align: Center @@ -231,20 +231,20 @@ Children: LogicTicker@ANIMATION: Label@PLAYER_COUNT: - X: 198 + X: 248 Y: PARENT_BOTTOM - 40 Width: 189 Height: 25 Align: Center Font: Bold Button@DIRECTCONNECT_BUTTON: - X: 387 + X: 487 Y: PARENT_BOTTOM - 40 Width: 100 Height: 25 Text: Direct IP Button@CREATE_BUTTON: - X: 492 + X: 592 Y: PARENT_BOTTOM - 40 Width: 105 Height: 25 diff -Nru openra-20200503/mods/cnc/chrome/settings.yaml openra-20210321/mods/cnc/chrome/settings.yaml --- openra-20200503/mods/cnc/chrome/settings.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome/settings.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -706,6 +706,12 @@ Font: Tiny Align: Left Text: This is already used for "{0}" + Button@OVERRIDE_HOTKEY_BUTTON: + X: PARENT_RIGHT - 50 - 15 - WIDTH - 20 + Y: 20 + Width: 70 + Height: 25 + Text: Override Button@CLEAR_HOTKEY_BUTTON: X: PARENT_RIGHT - 25 - 15 - WIDTH - 10 Y: 20 diff -Nru openra-20200503/mods/cnc/chrome.yaml openra-20210321/mods/cnc/chrome.yaml --- openra-20200503/mods/cnc/chrome.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/chrome.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -185,7 +185,7 @@ slider-thumb-pressed: Inherits: button-pressed Regions: - + checkbox: Inherits: button @@ -201,6 +201,15 @@ checkbox-highlighted: Inherits: button-highlighted-pressed +checkbox-highlighted-hover: + Inherits: button-highlighted-hover + +checkbox-highlighted-disabled: + Inherits: button-highlighted-disabled + +checkbox-highlighted-pressed: + Inherits: button-highlighted-pressed + # # Panels # === @@ -297,8 +306,9 @@ lobby-bits: Inherits: ^Chrome Regions: - spawn-unclaimed: 777, 423, 19, 19 - spawn-claimed: 777, 443, 19, 19 + spawn-claimed: 744, 215, 18, 18 + spawn-unclaimed: 744, 234, 18, 18 + spawn-disabled: 744, 253, 18, 18 admin: 938, 0, 6, 5 colorpicker: 887, 0, 14, 14 huepicker: 904, 0, 7, 15 @@ -337,18 +347,6 @@ crossed: 972, 0, 16, 16 crossed-disabled: 989, 0, 16, 16 -scrollbar: - Inherits: ^Chrome - Regions: - down_arrow: 836, 17, 16, 16 - down_pressed: 853, 17, 16, 16 - up_arrow: 870, 17, 16, 16 - up_pressed: 887, 17, 16, 16 - right_arrow: 904, 17, 16, 16 - right_pressed: 921, 17, 16, 16 - left_arrow: 938, 17, 16, 16 - left_pressed: 955, 17, 16, 16 - flags: Inherits: ^Chrome Regions: @@ -364,10 +362,36 @@ enemy_owned: 837, 223, 22, 22 player_owned: 883, 223, 22, 22 -dropdown: +scrollpanel-decorations: + Inherits: ^Chrome + Regions: + down: 836, 17, 16, 16 + down-pressed: 836, 17, 16, 16 + down-disabled: 853, 17, 16, 16 + up: 870, 17, 16, 16 + up-pressed: 870, 17, 16, 16 + up-disabled: 887, 17, 16, 16 + right: 904, 17, 16, 16 + right-pressed: 904, 17, 16, 16 + right-disabled: 921, 17, 16, 16 + left: 938, 17, 16, 16 + left-pressed: 938, 17, 16, 16 + left-disabled: 955, 17, 16, 16 + +dropdown-decorations: + Inherits: ^Chrome + Regions: + marker: 836, 17, 16, 16 + marker-pressed: 836, 17, 16, 16 + marker-disabled: 853, 17, 16, 16 + +dropdown-separators: Inherits: ^Chrome Regions: - separator: 65, 1, 1, 19 + separator: 129, 2, 1, 19 + separator-hover: 161, 2, 1, 19 + separator-pressed: 129, 34, 1, 19 + separator-disabled: 161, 34, 1, 19 # # Common chrome diff -Nru openra-20200503/mods/cnc/installer/covertops.yaml openra-20210321/mods/cnc/installer/covertops.yaml --- openra-20200503/mods/cnc/installer/covertops.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/installer/covertops.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,11 +4,11 @@ CONQUER.MIX: 713b53fa4c188ca9619c6bbeadbfc86513704266 Install: copy: . - ^Content/cnc/scores-covertops.mix: SCORES.MIX + ^SupportDir|Content/cnc/scores-covertops.mix: SCORES.MIX covertops-linux: Covert Operations Expansion (English) IDFiles: game/game.dat: be5a6c4c0a581da09e8f34a3bbf7bd17e525085c conquer.mix: 713b53fa4c188ca9619c6bbeadbfc86513704266 Install: copy: . - ^Content/cnc/scores-covertops.mix: scores.mix \ No newline at end of file + ^SupportDir|Content/cnc/scores-covertops.mix: scores.mix \ No newline at end of file diff -Nru openra-20200503/mods/cnc/installer/downloads.yaml openra-20210321/mods/cnc/installer/downloads.yaml --- openra-20200503/mods/cnc/installer/downloads.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/installer/downloads.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,18 +2,12 @@ SHA1: 72f337464963fa37d3688eb03e80eefd33669a3d MirrorList: http://www.openra.net/packages/cnc-mirrors.txt Extract: - ^Content/cnc/conquer.mix: conquer.mix - ^Content/cnc/desert.mix: desert.mix - ^Content/cnc/general.mix: general.mix - ^Content/cnc/sounds.mix: sounds.mix - ^Content/cnc/speech.mix: speech.mix - ^Content/cnc/temperat.mix: temperat.mix - ^Content/cnc/tempicnh.mix: tempicnh.mix - ^Content/cnc/transit.mix: transit.mix - ^Content/cnc/winter.mix: winter.mix - -music: Freeware Music - SHA1: c7f220aa59024f02932d5713b1aa6201113c03b5 - MirrorList: http://www.openra.net/packages/cnc-music-mirrors.txt - Extract: - ^Content/cnc/scores.mix: scores.mix + ^SupportDir|Content/cnc/conquer.mix: conquer.mix + ^SupportDir|Content/cnc/desert.mix: desert.mix + ^SupportDir|Content/cnc/general.mix: general.mix + ^SupportDir|Content/cnc/sounds.mix: sounds.mix + ^SupportDir|Content/cnc/speech.mix: speech.mix + ^SupportDir|Content/cnc/temperat.mix: temperat.mix + ^SupportDir|Content/cnc/tempicnh.mix: tempicnh.mix + ^SupportDir|Content/cnc/transit.mix: transit.mix + ^SupportDir|Content/cnc/winter.mix: winter.mix diff -Nru openra-20200503/mods/cnc/installer/firstdecade.yaml openra-20210321/mods/cnc/installer/firstdecade.yaml --- openra-20200503/mods/cnc/installer/firstdecade.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/installer/firstdecade.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -8,329 +8,329 @@ 2: data2.cab 3: data3.cab Extract: - ^Content/cnc/conquer.mix: CnC\\CONQUER.MIX - ^Content/cnc/desert.mix: CnC\\DESERT.MIX - ^Content/cnc/general.mix: CnC\\GENERAL.MIX - ^Content/cnc/scores.mix: CnC\\SCORES.MIX - ^Content/cnc/sounds.mix: CnC\\SOUNDS.MIX - ^Content/cnc/temperat.mix: CnC\\TEMPERAT.MIX - ^Content/cnc/winter.mix: CnC\\WINTER.MIX - ^Content/cnc/speech.mix: CnC\\SPEECH.MIX - ^Content/cnc/tempicnh.mix: CnC\\TEMPICNH.MIX - ^Content/cnc/transit.mix: CnC\\TRANSIT.MIX - ^Content/cnc/scores-covertops.mix: CnC\covert\SCORES.MIX - ^Content/cnc/movies.mix: CnC\\MOVIES.MIX - extract-raw: ^Content/cnc/movies.mix - ^Content/cnc/movies/airstrk.vqa: + ^SupportDir|Content/cnc/conquer.mix: CnC\\CONQUER.MIX + ^SupportDir|Content/cnc/desert.mix: CnC\\DESERT.MIX + ^SupportDir|Content/cnc/general.mix: CnC\\GENERAL.MIX + ^SupportDir|Content/cnc/scores.mix: CnC\\SCORES.MIX + ^SupportDir|Content/cnc/sounds.mix: CnC\\SOUNDS.MIX + ^SupportDir|Content/cnc/temperat.mix: CnC\\TEMPERAT.MIX + ^SupportDir|Content/cnc/winter.mix: CnC\\WINTER.MIX + ^SupportDir|Content/cnc/speech.mix: CnC\\SPEECH.MIX + ^SupportDir|Content/cnc/tempicnh.mix: CnC\\TEMPICNH.MIX + ^SupportDir|Content/cnc/transit.mix: CnC\\TRANSIT.MIX + ^SupportDir|Content/cnc/scores-covertops.mix: CnC\covert\SCORES.MIX + ^SupportDir|Content/cnc/movies.mix: CnC\\MOVIES.MIX + extract-raw: ^SupportDir|Content/cnc/movies.mix + ^SupportDir|Content/cnc/movies/airstrk.vqa: Offset: 1266 Length: 4444442 - ^Content/cnc/movies/akira.vqa: + ^SupportDir|Content/cnc/movies/akira.vqa: Offset: 4445708 Length: 7803444 - ^Content/cnc/movies/bkground.vqa: + ^SupportDir|Content/cnc/movies/bkground.vqa: Offset: 12249152 Length: 15267052 - ^Content/cnc/movies/burdet1.vqa: + ^SupportDir|Content/cnc/movies/burdet1.vqa: Offset: 27516204 Length: 10410614 - ^Content/cnc/movies/burdet2.vqa: + ^SupportDir|Content/cnc/movies/burdet2.vqa: Offset: 37926818 Length: 2062190 - ^Content/cnc/movies/gdi4a.vqa: + ^SupportDir|Content/cnc/movies/gdi4a.vqa: Offset: 39989008 Length: 4450582 - ^Content/cnc/movies/gdi4b.vqa: + ^SupportDir|Content/cnc/movies/gdi4b.vqa: Offset: 44439590 Length: 6603530 - ^Content/cnc/movies/gdifina.vqa: + ^SupportDir|Content/cnc/movies/gdifina.vqa: Offset: 51043120 Length: 12888650 - ^Content/cnc/movies/gdifinb.vqa: + ^SupportDir|Content/cnc/movies/gdifinb.vqa: Offset: 63931770 Length: 17769978 - ^Content/cnc/movies/nod7a.vqa: + ^SupportDir|Content/cnc/movies/nod7a.vqa: Offset: 81701748 Length: 4740470 - ^Content/cnc/movies/nod7b.vqa: + ^SupportDir|Content/cnc/movies/nod7b.vqa: Offset: 86442218 Length: 4671402 - ^Content/cnc/movies/visor.vqa: + ^SupportDir|Content/cnc/movies/visor.vqa: Offset: 91113620 Length: 4407162 - ^Content/cnc/movies/turtkill.vqa: + ^SupportDir|Content/cnc/movies/turtkill.vqa: Offset: 95520782 Length: 3323444 - ^Content/cnc/movies/trtkil_d.vqa: + ^SupportDir|Content/cnc/movies/trtkil_d.vqa: Offset: 98844226 Length: 3511836 - ^Content/cnc/movies/trailer.vqa: + ^SupportDir|Content/cnc/movies/trailer.vqa: Offset: 102356062 Length: 23163930 - ^Content/cnc/movies/tiberfx.vqa: + ^SupportDir|Content/cnc/movies/tiberfx.vqa: Offset: 125519992 Length: 8735102 - ^Content/cnc/movies/tbrinfo3.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo3.vqa: Offset: 134255094 Length: 14972046 - ^Content/cnc/movies/tbrinfo2.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo2.vqa: Offset: 149227140 Length: 16195290 - ^Content/cnc/movies/tbrinfo1.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo1.vqa: Offset: 165422430 Length: 23479052 - ^Content/cnc/movies/tankkill.vqa: + ^SupportDir|Content/cnc/movies/tankkill.vqa: Offset: 188901482 Length: 3298978 - ^Content/cnc/movies/tankgo.vqa: + ^SupportDir|Content/cnc/movies/tankgo.vqa: Offset: 192200460 Length: 1403876 - ^Content/cnc/movies/sundial.vqa: + ^SupportDir|Content/cnc/movies/sundial.vqa: Offset: 193604336 Length: 3653636 - ^Content/cnc/movies/stealth.vqa: + ^SupportDir|Content/cnc/movies/stealth.vqa: Offset: 197257972 Length: 4521860 - ^Content/cnc/movies/spycrash.vqa: + ^SupportDir|Content/cnc/movies/spycrash.vqa: Offset: 201779832 Length: 1886288 - ^Content/cnc/movies/sethpre.vqa: + ^SupportDir|Content/cnc/movies/sethpre.vqa: Offset: 203666120 Length: 10914610 - ^Content/cnc/movies/seige.vqa: + ^SupportDir|Content/cnc/movies/seige.vqa: Offset: 214580730 Length: 2705978 - ^Content/cnc/movies/samsite.vqa: + ^SupportDir|Content/cnc/movies/samsite.vqa: Offset: 217286708 Length: 1410418 - ^Content/cnc/movies/samdie.vqa: + ^SupportDir|Content/cnc/movies/samdie.vqa: Offset: 218697126 Length: 3741942 - ^Content/cnc/movies/sabotage.vqa: + ^SupportDir|Content/cnc/movies/sabotage.vqa: Offset: 222439068 Length: 1386202 - ^Content/cnc/movies/retro.vqa: + ^SupportDir|Content/cnc/movies/retro.vqa: Offset: 223825270 Length: 6434382 - ^Content/cnc/movies/refint.vqa: + ^SupportDir|Content/cnc/movies/refint.vqa: Offset: 230259652 Length: 5090040 - ^Content/cnc/movies/podium.vqa: + ^SupportDir|Content/cnc/movies/podium.vqa: Offset: 235349692 Length: 2790664 - ^Content/cnc/movies/planecra.vqa: + ^SupportDir|Content/cnc/movies/planecra.vqa: Offset: 238140356 Length: 5085426 - ^Content/cnc/movies/pintle.vqa: + ^SupportDir|Content/cnc/movies/pintle.vqa: Offset: 243225782 Length: 2757536 - ^Content/cnc/movies/paratrop.vqa: + ^SupportDir|Content/cnc/movies/paratrop.vqa: Offset: 245983318 Length: 3180272 - ^Content/cnc/movies/obel.vqa: + ^SupportDir|Content/cnc/movies/obel.vqa: Offset: 249163590 Length: 3851370 - ^Content/cnc/movies/nuke.vqa: + ^SupportDir|Content/cnc/movies/nuke.vqa: Offset: 253014960 Length: 3126662 - ^Content/cnc/movies/nodsweep.vqa: + ^SupportDir|Content/cnc/movies/nodsweep.vqa: Offset: 256141622 Length: 3642174 - ^Content/cnc/movies/nodlose.vqa: + ^SupportDir|Content/cnc/movies/nodlose.vqa: Offset: 259783796 Length: 5148924 - ^Content/cnc/movies/nodflees.vqa: + ^SupportDir|Content/cnc/movies/nodflees.vqa: Offset: 264932720 Length: 3056426 - ^Content/cnc/movies/nodfinal.vqa: + ^SupportDir|Content/cnc/movies/nodfinal.vqa: Offset: 267989146 Length: 23326586 - ^Content/cnc/movies/nodend4.vqa: + ^SupportDir|Content/cnc/movies/nodend4.vqa: Offset: 291315732 Length: 25535232 - ^Content/cnc/movies/nodend3.vqa: + ^SupportDir|Content/cnc/movies/nodend3.vqa: Offset: 316850964 Length: 25725824 - ^Content/cnc/movies/nodend2.vqa: + ^SupportDir|Content/cnc/movies/nodend2.vqa: Offset: 342576788 Length: 27214048 - ^Content/cnc/movies/nodend1.vqa: + ^SupportDir|Content/cnc/movies/nodend1.vqa: Offset: 369790836 Length: 27172272 - ^Content/cnc/movies/nod9.vqa: + ^SupportDir|Content/cnc/movies/nod9.vqa: Offset: 396963108 Length: 9357980 - ^Content/cnc/movies/nod8.vqa: + ^SupportDir|Content/cnc/movies/nod8.vqa: Offset: 406321088 Length: 11597940 - ^Content/cnc/movies/nod6.vqa: + ^SupportDir|Content/cnc/movies/nod6.vqa: Offset: 417919028 Length: 5007744 - ^Content/cnc/movies/nod5.vqa: + ^SupportDir|Content/cnc/movies/nod5.vqa: Offset: 422926772 Length: 6641700 - ^Content/cnc/movies/nod4b.vqa: + ^SupportDir|Content/cnc/movies/nod4b.vqa: Offset: 429568472 Length: 3867618 - ^Content/cnc/movies/nod4a.vqa: + ^SupportDir|Content/cnc/movies/nod4a.vqa: Offset: 433436090 Length: 3838924 - ^Content/cnc/movies/nod3.vqa: + ^SupportDir|Content/cnc/movies/nod3.vqa: Offset: 437275014 Length: 3603314 - ^Content/cnc/movies/nod2.vqa: + ^SupportDir|Content/cnc/movies/nod2.vqa: Offset: 440878328 Length: 7200720 - ^Content/cnc/movies/nod1pre.vqa: + ^SupportDir|Content/cnc/movies/nod1pre.vqa: Offset: 448079048 Length: 395720 - ^Content/cnc/movies/nod13.vqa: + ^SupportDir|Content/cnc/movies/nod13.vqa: Offset: 448474768 Length: 2746626 - ^Content/cnc/movies/nod12.vqa: + ^SupportDir|Content/cnc/movies/nod12.vqa: Offset: 451221394 Length: 6576562 - ^Content/cnc/movies/nod11.vqa: + ^SupportDir|Content/cnc/movies/nod11.vqa: Offset: 457797956 Length: 4629270 - ^Content/cnc/movies/nod10b.vqa: + ^SupportDir|Content/cnc/movies/nod10b.vqa: Offset: 462427226 Length: 6386444 - ^Content/cnc/movies/nod10a.vqa: + ^SupportDir|Content/cnc/movies/nod10a.vqa: Offset: 468813670 Length: 7205632 - ^Content/cnc/movies/nod1.vqa: + ^SupportDir|Content/cnc/movies/nod1.vqa: Offset: 476019302 Length: 4663258 - ^Content/cnc/movies/nitejump.vqa: + ^SupportDir|Content/cnc/movies/nitejump.vqa: Offset: 480682560 Length: 3702838 - ^Content/cnc/movies/napalm.vqa: + ^SupportDir|Content/cnc/movies/napalm.vqa: Offset: 484385398 Length: 4004146 - ^Content/cnc/movies/logo.vqa: + ^SupportDir|Content/cnc/movies/logo.vqa: Offset: 488389544 Length: 3562630 - ^Content/cnc/movies/landing.vqa: + ^SupportDir|Content/cnc/movies/landing.vqa: Offset: 491952174 Length: 1617094 - ^Content/cnc/movies/kanepre.vqa: + ^SupportDir|Content/cnc/movies/kanepre.vqa: Offset: 493569268 Length: 17220712 - ^Content/cnc/movies/intro2.vqa: + ^SupportDir|Content/cnc/movies/intro2.vqa: Offset: 510789980 Length: 21058732 - ^Content/cnc/movies/insites.vqa: + ^SupportDir|Content/cnc/movies/insites.vqa: Offset: 531848712 Length: 460482 - ^Content/cnc/movies/hellvaly.vqa: + ^SupportDir|Content/cnc/movies/hellvaly.vqa: Offset: 532309194 Length: 6658950 - ^Content/cnc/movies/gunboat.vqa: + ^SupportDir|Content/cnc/movies/gunboat.vqa: Offset: 538968144 Length: 3203706 - ^Content/cnc/movies/generic.vqa: + ^SupportDir|Content/cnc/movies/generic.vqa: Offset: 542171850 Length: 1452820 - ^Content/cnc/movies/gdilose.vqa: + ^SupportDir|Content/cnc/movies/gdilose.vqa: Offset: 543624670 Length: 2097912 - ^Content/cnc/movies/gdiend2.vqa: + ^SupportDir|Content/cnc/movies/gdiend2.vqa: Offset: 545722582 Length: 25242946 - ^Content/cnc/movies/gdiend1.vqa: + ^SupportDir|Content/cnc/movies/gdiend1.vqa: Offset: 570965528 Length: 25311636 - ^Content/cnc/movies/gdi9.vqa: + ^SupportDir|Content/cnc/movies/gdi9.vqa: Offset: 596277164 Length: 11806994 - ^Content/cnc/movies/gdi8b.vqa: + ^SupportDir|Content/cnc/movies/gdi8b.vqa: Offset: 608084158 Length: 5324410 - ^Content/cnc/movies/gdi8a.vqa: + ^SupportDir|Content/cnc/movies/gdi8a.vqa: Offset: 613408568 Length: 4672548 - ^Content/cnc/movies/gdi7.vqa: + ^SupportDir|Content/cnc/movies/gdi7.vqa: Offset: 618081116 Length: 4241952 - ^Content/cnc/movies/gdi6.vqa: + ^SupportDir|Content/cnc/movies/gdi6.vqa: Offset: 622323068 Length: 3959650 - ^Content/cnc/movies/gdi5.vqa: + ^SupportDir|Content/cnc/movies/gdi5.vqa: Offset: 626282718 Length: 3818244 - ^Content/cnc/movies/gdi3lose.vqa: + ^SupportDir|Content/cnc/movies/gdi3lose.vqa: Offset: 630100962 Length: 2265770 - ^Content/cnc/movies/gdi3.vqa: + ^SupportDir|Content/cnc/movies/gdi3.vqa: Offset: 632366732 Length: 5443848 - ^Content/cnc/movies/gdi2.vqa: + ^SupportDir|Content/cnc/movies/gdi2.vqa: Offset: 637810580 Length: 7883500 - ^Content/cnc/movies/gdi15.vqa: + ^SupportDir|Content/cnc/movies/gdi15.vqa: Offset: 645694080 Length: 11684610 - ^Content/cnc/movies/gdi14.vqa: + ^SupportDir|Content/cnc/movies/gdi14.vqa: Offset: 657378690 Length: 5282770 - ^Content/cnc/movies/gdi13.vqa: + ^SupportDir|Content/cnc/movies/gdi13.vqa: Offset: 662661460 Length: 6900914 - ^Content/cnc/movies/gdi12.vqa: + ^SupportDir|Content/cnc/movies/gdi12.vqa: Offset: 669562374 Length: 3669404 - ^Content/cnc/movies/gdi11.vqa: + ^SupportDir|Content/cnc/movies/gdi11.vqa: Offset: 673231778 Length: 5895754 - ^Content/cnc/movies/gdi10.vqa: + ^SupportDir|Content/cnc/movies/gdi10.vqa: Offset: 679127532 Length: 5761514 - ^Content/cnc/movies/gdi1.vqa: + ^SupportDir|Content/cnc/movies/gdi1.vqa: Offset: 684889046 Length: 6341298 - ^Content/cnc/movies/gameover.vqa: + ^SupportDir|Content/cnc/movies/gameover.vqa: Offset: 691230344 Length: 2087322 - ^Content/cnc/movies/forestkl.vqa: + ^SupportDir|Content/cnc/movies/forestkl.vqa: Offset: 693317666 Length: 1500986 - ^Content/cnc/movies/flyy.vqa: + ^SupportDir|Content/cnc/movies/flyy.vqa: Offset: 694818652 Length: 1373532 - ^Content/cnc/movies/flag.vqa: + ^SupportDir|Content/cnc/movies/flag.vqa: Offset: 696192184 Length: 4308680 - ^Content/cnc/movies/dino.vqa: + ^SupportDir|Content/cnc/movies/dino.vqa: Offset: 700500864 Length: 1347896 - ^Content/cnc/movies/dessweep.vqa: + ^SupportDir|Content/cnc/movies/dessweep.vqa: Offset: 701848760 Length: 3563646 - ^Content/cnc/movies/desolat.vqa: + ^SupportDir|Content/cnc/movies/desolat.vqa: Offset: 705412406 Length: 8385122 - ^Content/cnc/movies/deskill.vqa: + ^SupportDir|Content/cnc/movies/deskill.vqa: Offset: 713797528 Length: 1483634 - ^Content/cnc/movies/desflees.vqa: + ^SupportDir|Content/cnc/movies/desflees.vqa: Offset: 715281162 Length: 2698426 - ^Content/cnc/movies/consyard.vqa: + ^SupportDir|Content/cnc/movies/consyard.vqa: Offset: 717979588 Length: 7864652 - ^Content/cnc/movies/cc2tease.vqa: + ^SupportDir|Content/cnc/movies/cc2tease.vqa: Offset: 725844240 Length: 12506712 - ^Content/cnc/movies/bombflee.vqa: + ^SupportDir|Content/cnc/movies/bombflee.vqa: Offset: 738350952 Length: 2859726 - ^Content/cnc/movies/bombaway.vqa: + ^SupportDir|Content/cnc/movies/bombaway.vqa: Offset: 741210678 Length: 5579588 - ^Content/cnc/movies/bcanyon.vqa: + ^SupportDir|Content/cnc/movies/bcanyon.vqa: Offset: 746790266 Length: 5172288 - ^Content/cnc/movies/banner.vqa: + ^SupportDir|Content/cnc/movies/banner.vqa: Offset: 751962554 Length: 2229408 - delete: ^Content/cnc/movies.mix \ No newline at end of file + delete: ^SupportDir|Content/cnc/movies.mix \ No newline at end of file diff -Nru openra-20200503/mods/cnc/installer/gdi95.yaml openra-20210321/mods/cnc/installer/gdi95.yaml --- openra-20200503/mods/cnc/installer/gdi95.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/installer/gdi95.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,217 +4,217 @@ CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30 Install: copy: . - ^Content/cnc/conquer.mix: CONQUER.MIX - ^Content/cnc/desert.mix: DESERT.MIX - ^Content/cnc/general.mix: GENERAL.MIX - ^Content/cnc/scores.mix: SCORES.MIX - ^Content/cnc/sounds.mix: SOUNDS.MIX - ^Content/cnc/temperat.mix: TEMPERAT.MIX - ^Content/cnc/winter.mix: WINTER.MIX + ^SupportDir|Content/cnc/conquer.mix: CONQUER.MIX + ^SupportDir|Content/cnc/desert.mix: DESERT.MIX + ^SupportDir|Content/cnc/general.mix: GENERAL.MIX + ^SupportDir|Content/cnc/scores.mix: SCORES.MIX + ^SupportDir|Content/cnc/sounds.mix: SOUNDS.MIX + ^SupportDir|Content/cnc/temperat.mix: TEMPERAT.MIX + ^SupportDir|Content/cnc/winter.mix: WINTER.MIX extract-blast: INSTALL/SETUP.Z - ^Content/cnc/speech.mix: + ^SupportDir|Content/cnc/speech.mix: Offset: 10203213 Length: 603293 - ^Content/cnc/tempicnh.mix: + ^SupportDir|Content/cnc/tempicnh.mix: Offset: 10925941 Length: 119096 - ^Content/cnc/transit.mix: + ^SupportDir|Content/cnc/transit.mix: Offset: 11078017 Length: 3724462 extract-raw: MOVIES.MIX - ^Content/cnc/movies/visor.vqa: + ^SupportDir|Content/cnc/movies/visor.vqa: Offset: 786 Length: 4407162 - ^Content/cnc/movies/turtkill.vqa: + ^SupportDir|Content/cnc/movies/turtkill.vqa: Offset: 4407948 Length: 3323444 - ^Content/cnc/movies/trailer.vqa: + ^SupportDir|Content/cnc/movies/trailer.vqa: Offset: 7731392 Length: 23163930 - ^Content/cnc/movies/tbrinfo3.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo3.vqa: Offset: 30895322 Length: 14972046 - ^Content/cnc/movies/tbrinfo2.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo2.vqa: Offset: 45867368 Length: 16195290 - ^Content/cnc/movies/tbrinfo1.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo1.vqa: Offset: 62062658 Length: 23479052 - ^Content/cnc/movies/seige.vqa: + ^SupportDir|Content/cnc/movies/seige.vqa: Offset: 85541710 Length: 2705978 - ^Content/cnc/movies/samsite.vqa: + ^SupportDir|Content/cnc/movies/samsite.vqa: Offset: 88247688 Length: 1410418 - ^Content/cnc/movies/samdie.vqa: + ^SupportDir|Content/cnc/movies/samdie.vqa: Offset: 89658106 Length: 3741942 - ^Content/cnc/movies/sabotage.vqa: + ^SupportDir|Content/cnc/movies/sabotage.vqa: Offset: 93400048 Length: 1386202 - ^Content/cnc/movies/retro.vqa: + ^SupportDir|Content/cnc/movies/retro.vqa: Offset: 94786250 Length: 6434382 - ^Content/cnc/movies/podium.vqa: + ^SupportDir|Content/cnc/movies/podium.vqa: Offset: 101220632 Length: 2790664 - ^Content/cnc/movies/planecra.vqa: + ^SupportDir|Content/cnc/movies/planecra.vqa: Offset: 104011296 Length: 5085426 - ^Content/cnc/movies/pintle.vqa: + ^SupportDir|Content/cnc/movies/pintle.vqa: Offset: 109096722 Length: 2757536 - ^Content/cnc/movies/paratrop.vqa: + ^SupportDir|Content/cnc/movies/paratrop.vqa: Offset: 111854258 Length: 3180272 - ^Content/cnc/movies/nodsweep.vqa: + ^SupportDir|Content/cnc/movies/nodsweep.vqa: Offset: 115034530 Length: 3642174 - ^Content/cnc/movies/nodlose.vqa: + ^SupportDir|Content/cnc/movies/nodlose.vqa: Offset: 118676704 Length: 5148924 - ^Content/cnc/movies/nodflees.vqa: + ^SupportDir|Content/cnc/movies/nodflees.vqa: Offset: 123825628 Length: 3056426 - ^Content/cnc/movies/nod1.vqa: + ^SupportDir|Content/cnc/movies/nod1.vqa: Offset: 126882054 Length: 4663258 - ^Content/cnc/movies/nitejump.vqa: + ^SupportDir|Content/cnc/movies/nitejump.vqa: Offset: 131545312 Length: 3702838 - ^Content/cnc/movies/napalm.vqa: + ^SupportDir|Content/cnc/movies/napalm.vqa: Offset: 135248150 Length: 4004146 - ^Content/cnc/movies/logo.vqa: + ^SupportDir|Content/cnc/movies/logo.vqa: Offset: 139252296 Length: 3562630 - ^Content/cnc/movies/landing.vqa: + ^SupportDir|Content/cnc/movies/landing.vqa: Offset: 142814926 Length: 1617094 - ^Content/cnc/movies/intro2.vqa: + ^SupportDir|Content/cnc/movies/intro2.vqa: Offset: 144432020 Length: 21058732 - ^Content/cnc/movies/hellvaly.vqa: + ^SupportDir|Content/cnc/movies/hellvaly.vqa: Offset: 165490752 Length: 6658950 - ^Content/cnc/movies/gunboat.vqa: + ^SupportDir|Content/cnc/movies/gunboat.vqa: Offset: 172149702 Length: 3203706 - ^Content/cnc/movies/generic.vqa: + ^SupportDir|Content/cnc/movies/generic.vqa: Offset: 175353408 Length: 1452820 - ^Content/cnc/movies/gdilose.vqa: + ^SupportDir|Content/cnc/movies/gdilose.vqa: Offset: 176806228 Length: 2097912 - ^Content/cnc/movies/gdifinb.vqa: + ^SupportDir|Content/cnc/movies/gdifinb.vqa: Offset: 178904140 Length: 17769978 - ^Content/cnc/movies/gdifina.vqa: + ^SupportDir|Content/cnc/movies/gdifina.vqa: Offset: 196674118 Length: 12888650 - ^Content/cnc/movies/gdiend2.vqa: + ^SupportDir|Content/cnc/movies/gdiend2.vqa: Offset: 209562768 Length: 25242946 - ^Content/cnc/movies/gdiend1.vqa: + ^SupportDir|Content/cnc/movies/gdiend1.vqa: Offset: 234805714 Length: 25311636 - ^Content/cnc/movies/gdi9.vqa: + ^SupportDir|Content/cnc/movies/gdi9.vqa: Offset: 260117350 Length: 11806994 - ^Content/cnc/movies/gdi8b.vqa: + ^SupportDir|Content/cnc/movies/gdi8b.vqa: Offset: 271924344 Length: 5324410 - ^Content/cnc/movies/gdi8a.vqa: + ^SupportDir|Content/cnc/movies/gdi8a.vqa: Offset: 277248754 Length: 4672548 - ^Content/cnc/movies/gdi7.vqa: + ^SupportDir|Content/cnc/movies/gdi7.vqa: Offset: 281921302 Length: 4241952 - ^Content/cnc/movies/gdi6.vqa: + ^SupportDir|Content/cnc/movies/gdi6.vqa: Offset: 286163254 Length: 3959650 - ^Content/cnc/movies/gdi5.vqa: + ^SupportDir|Content/cnc/movies/gdi5.vqa: Offset: 290122904 Length: 3818244 - ^Content/cnc/movies/gdi4b.vqa: + ^SupportDir|Content/cnc/movies/gdi4b.vqa: Offset: 293941148 Length: 6603530 - ^Content/cnc/movies/gdi4a.vqa: + ^SupportDir|Content/cnc/movies/gdi4a.vqa: Offset: 300544678 Length: 4450582 - ^Content/cnc/movies/gdi3lose.vqa: + ^SupportDir|Content/cnc/movies/gdi3lose.vqa: Offset: 304995260 Length: 2265770 - ^Content/cnc/movies/gdi3.vqa: + ^SupportDir|Content/cnc/movies/gdi3.vqa: Offset: 307261030 Length: 5443848 - ^Content/cnc/movies/gdi2.vqa: + ^SupportDir|Content/cnc/movies/gdi2.vqa: Offset: 312704878 Length: 7883500 - ^Content/cnc/movies/gdi15.vqa: + ^SupportDir|Content/cnc/movies/gdi15.vqa: Offset: 320588378 Length: 11684610 - ^Content/cnc/movies/gdi14.vqa: + ^SupportDir|Content/cnc/movies/gdi14.vqa: Offset: 332272988 Length: 5282770 - ^Content/cnc/movies/gdi13.vqa: + ^SupportDir|Content/cnc/movies/gdi13.vqa: Offset: 337555758 Length: 6900914 - ^Content/cnc/movies/gdi12.vqa: + ^SupportDir|Content/cnc/movies/gdi12.vqa: Offset: 344456672 Length: 3669404 - ^Content/cnc/movies/gdi11.vqa: + ^SupportDir|Content/cnc/movies/gdi11.vqa: Offset: 348126076 Length: 5895754 - ^Content/cnc/movies/gdi10.vqa: + ^SupportDir|Content/cnc/movies/gdi10.vqa: Offset: 354021830 Length: 5761514 - ^Content/cnc/movies/gdi1.vqa: + ^SupportDir|Content/cnc/movies/gdi1.vqa: Offset: 359783344 Length: 6341298 - ^Content/cnc/movies/gameover.vqa: + ^SupportDir|Content/cnc/movies/gameover.vqa: Offset: 366124642 Length: 2087322 - ^Content/cnc/movies/forestkl.vqa: + ^SupportDir|Content/cnc/movies/forestkl.vqa: Offset: 368211964 Length: 1500986 - ^Content/cnc/movies/flyy.vqa: + ^SupportDir|Content/cnc/movies/flyy.vqa: Offset: 369712950 Length: 1373532 - ^Content/cnc/movies/flag.vqa: + ^SupportDir|Content/cnc/movies/flag.vqa: Offset: 371086482 Length: 4308680 - ^Content/cnc/movies/dino.vqa: + ^SupportDir|Content/cnc/movies/dino.vqa: Offset: 375395162 Length: 1347896 - ^Content/cnc/movies/desolat.vqa: + ^SupportDir|Content/cnc/movies/desolat.vqa: Offset: 376743058 Length: 8385122 - ^Content/cnc/movies/consyard.vqa: + ^SupportDir|Content/cnc/movies/consyard.vqa: Offset: 385128180 Length: 7864652 - ^Content/cnc/movies/cc2tease.vqa: + ^SupportDir|Content/cnc/movies/cc2tease.vqa: Offset: 392992832 Length: 12506712 - ^Content/cnc/movies/burdet2.vqa: + ^SupportDir|Content/cnc/movies/burdet2.vqa: Offset: 405499544 Length: 2062190 - ^Content/cnc/movies/burdet1.vqa: + ^SupportDir|Content/cnc/movies/burdet1.vqa: Offset: 407561734 Length: 10410614 - ^Content/cnc/movies/bombflee.vqa: + ^SupportDir|Content/cnc/movies/bombflee.vqa: Offset: 417972348 Length: 2859726 - ^Content/cnc/movies/bombaway.vqa: + ^SupportDir|Content/cnc/movies/bombaway.vqa: Offset: 420832074 Length: 5579588 - ^Content/cnc/movies/bkground.vqa: + ^SupportDir|Content/cnc/movies/bkground.vqa: Offset: 426411662 Length: 15267052 - ^Content/cnc/movies/bcanyon.vqa: + ^SupportDir|Content/cnc/movies/bcanyon.vqa: Offset: 441678714 Length: 5172288 - ^Content/cnc/movies/banner.vqa: + ^SupportDir|Content/cnc/movies/banner.vqa: Offset: 446851002 Length: 2229408 gdi95-linux: C&C Gold (GDI Disc, English) @@ -223,216 +223,216 @@ conquer.mix: 833e02a09aae694659eb312d3838367f681d1b30 Install: copy: . - ^Content/cnc/conquer.mix: conquer.mix - ^Content/cnc/desert.mix: desert.mix - ^Content/cnc/general.mix: general.mix - ^Content/cnc/scores.mix: scores.mix - ^Content/cnc/sounds.mix: sounds.mix - ^Content/cnc/temperat.mix: temperat.mix - ^Content/cnc/winter.mix: winter.mix + ^SupportDir|Content/cnc/conquer.mix: conquer.mix + ^SupportDir|Content/cnc/desert.mix: desert.mix + ^SupportDir|Content/cnc/general.mix: general.mix + ^SupportDir|Content/cnc/scores.mix: scores.mix + ^SupportDir|Content/cnc/sounds.mix: sounds.mix + ^SupportDir|Content/cnc/temperat.mix: temperat.mix + ^SupportDir|Content/cnc/winter.mix: winter.mix extract-blast: install/setup.z - ^Content/cnc/speech.mix: + ^SupportDir|Content/cnc/speech.mix: Offset: 10203213 Length: 603293 - ^Content/cnc/tempicnh.mix: + ^SupportDir|Content/cnc/tempicnh.mix: Offset: 10925941 Length: 119096 - ^Content/cnc/transit.mix: + ^SupportDir|Content/cnc/transit.mix: Offset: 11078017 Length: 3724462 extract-raw: movies.mix - ^Content/cnc/movies/visor.vqa: + ^SupportDir|Content/cnc/movies/visor.vqa: Offset: 786 Length: 4407162 - ^Content/cnc/movies/turtkill.vqa: + ^SupportDir|Content/cnc/movies/turtkill.vqa: Offset: 4407948 Length: 3323444 - ^Content/cnc/movies/trailer.vqa: + ^SupportDir|Content/cnc/movies/trailer.vqa: Offset: 7731392 Length: 23163930 - ^Content/cnc/movies/tbrinfo3.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo3.vqa: Offset: 30895322 Length: 14972046 - ^Content/cnc/movies/tbrinfo2.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo2.vqa: Offset: 45867368 Length: 16195290 - ^Content/cnc/movies/tbrinfo1.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo1.vqa: Offset: 62062658 Length: 23479052 - ^Content/cnc/movies/seige.vqa: + ^SupportDir|Content/cnc/movies/seige.vqa: Offset: 85541710 Length: 2705978 - ^Content/cnc/movies/samsite.vqa: + ^SupportDir|Content/cnc/movies/samsite.vqa: Offset: 88247688 Length: 1410418 - ^Content/cnc/movies/samdie.vqa: + ^SupportDir|Content/cnc/movies/samdie.vqa: Offset: 89658106 Length: 3741942 - ^Content/cnc/movies/sabotage.vqa: + ^SupportDir|Content/cnc/movies/sabotage.vqa: Offset: 93400048 Length: 1386202 - ^Content/cnc/movies/retro.vqa: + ^SupportDir|Content/cnc/movies/retro.vqa: Offset: 94786250 Length: 6434382 - ^Content/cnc/movies/podium.vqa: + ^SupportDir|Content/cnc/movies/podium.vqa: Offset: 101220632 Length: 2790664 - ^Content/cnc/movies/planecra.vqa: + ^SupportDir|Content/cnc/movies/planecra.vqa: Offset: 104011296 Length: 5085426 - ^Content/cnc/movies/pintle.vqa: + ^SupportDir|Content/cnc/movies/pintle.vqa: Offset: 109096722 Length: 2757536 - ^Content/cnc/movies/paratrop.vqa: + ^SupportDir|Content/cnc/movies/paratrop.vqa: Offset: 111854258 Length: 3180272 - ^Content/cnc/movies/nodsweep.vqa: + ^SupportDir|Content/cnc/movies/nodsweep.vqa: Offset: 115034530 Length: 3642174 - ^Content/cnc/movies/nodlose.vqa: + ^SupportDir|Content/cnc/movies/nodlose.vqa: Offset: 118676704 Length: 5148924 - ^Content/cnc/movies/nodflees.vqa: + ^SupportDir|Content/cnc/movies/nodflees.vqa: Offset: 123825628 Length: 3056426 - ^Content/cnc/movies/nod1.vqa: + ^SupportDir|Content/cnc/movies/nod1.vqa: Offset: 126882054 Length: 4663258 - ^Content/cnc/movies/nitejump.vqa: + ^SupportDir|Content/cnc/movies/nitejump.vqa: Offset: 131545312 Length: 3702838 - ^Content/cnc/movies/napalm.vqa: + ^SupportDir|Content/cnc/movies/napalm.vqa: Offset: 135248150 Length: 4004146 - ^Content/cnc/movies/logo.vqa: + ^SupportDir|Content/cnc/movies/logo.vqa: Offset: 139252296 Length: 3562630 - ^Content/cnc/movies/landing.vqa: + ^SupportDir|Content/cnc/movies/landing.vqa: Offset: 142814926 Length: 1617094 - ^Content/cnc/movies/intro2.vqa: + ^SupportDir|Content/cnc/movies/intro2.vqa: Offset: 144432020 Length: 21058732 - ^Content/cnc/movies/hellvaly.vqa: + ^SupportDir|Content/cnc/movies/hellvaly.vqa: Offset: 165490752 Length: 6658950 - ^Content/cnc/movies/gunboat.vqa: + ^SupportDir|Content/cnc/movies/gunboat.vqa: Offset: 172149702 Length: 3203706 - ^Content/cnc/movies/generic.vqa: + ^SupportDir|Content/cnc/movies/generic.vqa: Offset: 175353408 Length: 1452820 - ^Content/cnc/movies/gdilose.vqa: + ^SupportDir|Content/cnc/movies/gdilose.vqa: Offset: 176806228 Length: 2097912 - ^Content/cnc/movies/gdifinb.vqa: + ^SupportDir|Content/cnc/movies/gdifinb.vqa: Offset: 178904140 Length: 17769978 - ^Content/cnc/movies/gdifina.vqa: + ^SupportDir|Content/cnc/movies/gdifina.vqa: Offset: 196674118 Length: 12888650 - ^Content/cnc/movies/gdiend2.vqa: + ^SupportDir|Content/cnc/movies/gdiend2.vqa: Offset: 209562768 Length: 25242946 - ^Content/cnc/movies/gdiend1.vqa: + ^SupportDir|Content/cnc/movies/gdiend1.vqa: Offset: 234805714 Length: 25311636 - ^Content/cnc/movies/gdi9.vqa: + ^SupportDir|Content/cnc/movies/gdi9.vqa: Offset: 260117350 Length: 11806994 - ^Content/cnc/movies/gdi8b.vqa: + ^SupportDir|Content/cnc/movies/gdi8b.vqa: Offset: 271924344 Length: 5324410 - ^Content/cnc/movies/gdi8a.vqa: + ^SupportDir|Content/cnc/movies/gdi8a.vqa: Offset: 277248754 Length: 4672548 - ^Content/cnc/movies/gdi7.vqa: + ^SupportDir|Content/cnc/movies/gdi7.vqa: Offset: 281921302 Length: 4241952 - ^Content/cnc/movies/gdi6.vqa: + ^SupportDir|Content/cnc/movies/gdi6.vqa: Offset: 286163254 Length: 3959650 - ^Content/cnc/movies/gdi5.vqa: + ^SupportDir|Content/cnc/movies/gdi5.vqa: Offset: 290122904 Length: 3818244 - ^Content/cnc/movies/gdi4b.vqa: + ^SupportDir|Content/cnc/movies/gdi4b.vqa: Offset: 293941148 Length: 6603530 - ^Content/cnc/movies/gdi4a.vqa: + ^SupportDir|Content/cnc/movies/gdi4a.vqa: Offset: 300544678 Length: 4450582 - ^Content/cnc/movies/gdi3lose.vqa: + ^SupportDir|Content/cnc/movies/gdi3lose.vqa: Offset: 304995260 Length: 2265770 - ^Content/cnc/movies/gdi3.vqa: + ^SupportDir|Content/cnc/movies/gdi3.vqa: Offset: 307261030 Length: 5443848 - ^Content/cnc/movies/gdi2.vqa: + ^SupportDir|Content/cnc/movies/gdi2.vqa: Offset: 312704878 Length: 7883500 - ^Content/cnc/movies/gdi15.vqa: + ^SupportDir|Content/cnc/movies/gdi15.vqa: Offset: 320588378 Length: 11684610 - ^Content/cnc/movies/gdi14.vqa: + ^SupportDir|Content/cnc/movies/gdi14.vqa: Offset: 332272988 Length: 5282770 - ^Content/cnc/movies/gdi13.vqa: + ^SupportDir|Content/cnc/movies/gdi13.vqa: Offset: 337555758 Length: 6900914 - ^Content/cnc/movies/gdi12.vqa: + ^SupportDir|Content/cnc/movies/gdi12.vqa: Offset: 344456672 Length: 3669404 - ^Content/cnc/movies/gdi11.vqa: + ^SupportDir|Content/cnc/movies/gdi11.vqa: Offset: 348126076 Length: 5895754 - ^Content/cnc/movies/gdi10.vqa: + ^SupportDir|Content/cnc/movies/gdi10.vqa: Offset: 354021830 Length: 5761514 - ^Content/cnc/movies/gdi1.vqa: + ^SupportDir|Content/cnc/movies/gdi1.vqa: Offset: 359783344 Length: 6341298 - ^Content/cnc/movies/gameover.vqa: + ^SupportDir|Content/cnc/movies/gameover.vqa: Offset: 366124642 Length: 2087322 - ^Content/cnc/movies/forestkl.vqa: + ^SupportDir|Content/cnc/movies/forestkl.vqa: Offset: 368211964 Length: 1500986 - ^Content/cnc/movies/flyy.vqa: + ^SupportDir|Content/cnc/movies/flyy.vqa: Offset: 369712950 Length: 1373532 - ^Content/cnc/movies/flag.vqa: + ^SupportDir|Content/cnc/movies/flag.vqa: Offset: 371086482 Length: 4308680 - ^Content/cnc/movies/dino.vqa: + ^SupportDir|Content/cnc/movies/dino.vqa: Offset: 375395162 Length: 1347896 - ^Content/cnc/movies/desolat.vqa: + ^SupportDir|Content/cnc/movies/desolat.vqa: Offset: 376743058 Length: 8385122 - ^Content/cnc/movies/consyard.vqa: + ^SupportDir|Content/cnc/movies/consyard.vqa: Offset: 385128180 Length: 7864652 - ^Content/cnc/movies/cc2tease.vqa: + ^SupportDir|Content/cnc/movies/cc2tease.vqa: Offset: 392992832 Length: 12506712 - ^Content/cnc/movies/burdet2.vqa: + ^SupportDir|Content/cnc/movies/burdet2.vqa: Offset: 405499544 Length: 2062190 - ^Content/cnc/movies/burdet1.vqa: + ^SupportDir|Content/cnc/movies/burdet1.vqa: Offset: 407561734 Length: 10410614 - ^Content/cnc/movies/bombflee.vqa: + ^SupportDir|Content/cnc/movies/bombflee.vqa: Offset: 417972348 Length: 2859726 - ^Content/cnc/movies/bombaway.vqa: + ^SupportDir|Content/cnc/movies/bombaway.vqa: Offset: 420832074 Length: 5579588 - ^Content/cnc/movies/bkground.vqa: + ^SupportDir|Content/cnc/movies/bkground.vqa: Offset: 426411662 Length: 15267052 - ^Content/cnc/movies/bcanyon.vqa: + ^SupportDir|Content/cnc/movies/bcanyon.vqa: Offset: 441678714 Length: 5172288 - ^Content/cnc/movies/banner.vqa: + ^SupportDir|Content/cnc/movies/banner.vqa: Offset: 446851002 Length: 2229408 diff -Nru openra-20200503/mods/cnc/installer/nod95.yaml openra-20210321/mods/cnc/installer/nod95.yaml --- openra-20200503/mods/cnc/installer/nod95.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/installer/nod95.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,205 +4,205 @@ CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30 Install: copy: . - ^Content/cnc/conquer.mix: CONQUER.MIX - ^Content/cnc/desert.mix: DESERT.MIX - ^Content/cnc/general.mix: GENERAL.MIX - ^Content/cnc/scores.mix: SCORES.MIX - ^Content/cnc/sounds.mix: SOUNDS.MIX - ^Content/cnc/temperat.mix: TEMPERAT.MIX - ^Content/cnc/winter.mix: WINTER.MIX + ^SupportDir|Content/cnc/conquer.mix: CONQUER.MIX + ^SupportDir|Content/cnc/desert.mix: DESERT.MIX + ^SupportDir|Content/cnc/general.mix: GENERAL.MIX + ^SupportDir|Content/cnc/scores.mix: SCORES.MIX + ^SupportDir|Content/cnc/sounds.mix: SOUNDS.MIX + ^SupportDir|Content/cnc/temperat.mix: TEMPERAT.MIX + ^SupportDir|Content/cnc/winter.mix: WINTER.MIX extract-blast: INSTALL/SETUP.Z - ^Content/cnc/speech.mix: + ^SupportDir|Content/cnc/speech.mix: Offset: 10203213 Length: 603293 - ^Content/cnc/tempicnh.mix: + ^SupportDir|Content/cnc/tempicnh.mix: Offset: 10925941 Length: 119096 - ^Content/cnc/transit.mix: + ^SupportDir|Content/cnc/transit.mix: Offset: 11078017 Length: 3724462 extract-raw: MOVIES.MIX - ^Content/cnc/movies/visor.vqa: + ^SupportDir|Content/cnc/movies/visor.vqa: Offset: 738 Length: 4407162 - ^Content/cnc/movies/trtkil_d.vqa: + ^SupportDir|Content/cnc/movies/trtkil_d.vqa: Offset: 4407900 Length: 3511836 - ^Content/cnc/movies/trailer.vqa: + ^SupportDir|Content/cnc/movies/trailer.vqa: Offset: 7919736 Length: 23163930 - ^Content/cnc/movies/tiberfx.vqa: + ^SupportDir|Content/cnc/movies/tiberfx.vqa: Offset: 31083666 Length: 8735102 - ^Content/cnc/movies/tankkill.vqa: + ^SupportDir|Content/cnc/movies/tankkill.vqa: Offset: 39818768 Length: 3298978 - ^Content/cnc/movies/tankgo.vqa: + ^SupportDir|Content/cnc/movies/tankgo.vqa: Offset: 43117746 Length: 1403876 - ^Content/cnc/movies/sundial.vqa: + ^SupportDir|Content/cnc/movies/sundial.vqa: Offset: 44521622 Length: 3653636 - ^Content/cnc/movies/stealth.vqa: + ^SupportDir|Content/cnc/movies/stealth.vqa: Offset: 48175258 Length: 4521860 - ^Content/cnc/movies/spycrash.vqa: + ^SupportDir|Content/cnc/movies/spycrash.vqa: Offset: 52697118 Length: 1886288 - ^Content/cnc/movies/sethpre.vqa: + ^SupportDir|Content/cnc/movies/sethpre.vqa: Offset: 54583406 Length: 10914610 - ^Content/cnc/movies/seige.vqa: + ^SupportDir|Content/cnc/movies/seige.vqa: Offset: 65498016 Length: 2705978 - ^Content/cnc/movies/samsite.vqa: + ^SupportDir|Content/cnc/movies/samsite.vqa: Offset: 68203994 Length: 1410418 - ^Content/cnc/movies/retro.vqa: + ^SupportDir|Content/cnc/movies/retro.vqa: Offset: 69614412 Length: 6434382 - ^Content/cnc/movies/refint.vqa: + ^SupportDir|Content/cnc/movies/refint.vqa: Offset: 76048794 Length: 5090040 - ^Content/cnc/movies/obel.vqa: + ^SupportDir|Content/cnc/movies/obel.vqa: Offset: 81138834 Length: 3851370 - ^Content/cnc/movies/nuke.vqa: + ^SupportDir|Content/cnc/movies/nuke.vqa: Offset: 84990204 Length: 3126662 - ^Content/cnc/movies/nodlose.vqa: + ^SupportDir|Content/cnc/movies/nodlose.vqa: Offset: 88116866 Length: 5148924 - ^Content/cnc/movies/nodfinal.vqa: + ^SupportDir|Content/cnc/movies/nodfinal.vqa: Offset: 93265790 Length: 23326586 - ^Content/cnc/movies/nodend4.vqa: + ^SupportDir|Content/cnc/movies/nodend4.vqa: Offset: 116592376 Length: 25535232 - ^Content/cnc/movies/nodend3.vqa: + ^SupportDir|Content/cnc/movies/nodend3.vqa: Offset: 142127608 Length: 25725824 - ^Content/cnc/movies/nodend2.vqa: + ^SupportDir|Content/cnc/movies/nodend2.vqa: Offset: 167853432 Length: 27214048 - ^Content/cnc/movies/nodend1.vqa: + ^SupportDir|Content/cnc/movies/nodend1.vqa: Offset: 195067480 Length: 27172272 - ^Content/cnc/movies/nod9.vqa: + ^SupportDir|Content/cnc/movies/nod9.vqa: Offset: 222239752 Length: 9357980 - ^Content/cnc/movies/nod8.vqa: + ^SupportDir|Content/cnc/movies/nod8.vqa: Offset: 231597732 Length: 11597940 - ^Content/cnc/movies/nod7b.vqa: + ^SupportDir|Content/cnc/movies/nod7b.vqa: Offset: 243195672 Length: 4671402 - ^Content/cnc/movies/nod7a.vqa: + ^SupportDir|Content/cnc/movies/nod7a.vqa: Offset: 247867074 Length: 4740470 - ^Content/cnc/movies/nod6.vqa: + ^SupportDir|Content/cnc/movies/nod6.vqa: Offset: 252607544 Length: 5007744 - ^Content/cnc/movies/nod5.vqa: + ^SupportDir|Content/cnc/movies/nod5.vqa: Offset: 257615288 Length: 6641700 - ^Content/cnc/movies/nod4b.vqa: + ^SupportDir|Content/cnc/movies/nod4b.vqa: Offset: 264256988 Length: 3867618 - ^Content/cnc/movies/nod4a.vqa: + ^SupportDir|Content/cnc/movies/nod4a.vqa: Offset: 268124606 Length: 3838924 - ^Content/cnc/movies/nod3.vqa: + ^SupportDir|Content/cnc/movies/nod3.vqa: Offset: 271963530 Length: 3603314 - ^Content/cnc/movies/nod2.vqa: + ^SupportDir|Content/cnc/movies/nod2.vqa: Offset: 275566844 Length: 7200720 - ^Content/cnc/movies/nod1pre.vqa: + ^SupportDir|Content/cnc/movies/nod1pre.vqa: Offset: 282767564 Length: 395720 - ^Content/cnc/movies/nod13.vqa: + ^SupportDir|Content/cnc/movies/nod13.vqa: Offset: 283163284 Length: 2746626 - ^Content/cnc/movies/nod12.vqa: + ^SupportDir|Content/cnc/movies/nod12.vqa: Offset: 285909910 Length: 6576562 - ^Content/cnc/movies/nod11.vqa: + ^SupportDir|Content/cnc/movies/nod11.vqa: Offset: 292486472 Length: 4629270 - ^Content/cnc/movies/nod10b.vqa: + ^SupportDir|Content/cnc/movies/nod10b.vqa: Offset: 297115742 Length: 6386444 - ^Content/cnc/movies/nod10a.vqa: + ^SupportDir|Content/cnc/movies/nod10a.vqa: Offset: 303502186 Length: 7205632 - ^Content/cnc/movies/nod1.vqa: + ^SupportDir|Content/cnc/movies/nod1.vqa: Offset: 310707818 Length: 4663258 - ^Content/cnc/movies/logo.vqa: + ^SupportDir|Content/cnc/movies/logo.vqa: Offset: 315371076 Length: 3562630 - ^Content/cnc/movies/landing.vqa: + ^SupportDir|Content/cnc/movies/landing.vqa: Offset: 318933706 Length: 1617094 - ^Content/cnc/movies/kanepre.vqa: + ^SupportDir|Content/cnc/movies/kanepre.vqa: Offset: 320550800 Length: 17220712 - ^Content/cnc/movies/intro2.vqa: + ^SupportDir|Content/cnc/movies/intro2.vqa: Offset: 337771512 Length: 21058732 - ^Content/cnc/movies/insites.vqa: + ^SupportDir|Content/cnc/movies/insites.vqa: Offset: 358830244 Length: 460482 - ^Content/cnc/movies/generic.vqa: + ^SupportDir|Content/cnc/movies/generic.vqa: Offset: 359290726 Length: 1452820 - ^Content/cnc/movies/gdi1.vqa: + ^SupportDir|Content/cnc/movies/gdi1.vqa: Offset: 360743546 Length: 6341298 - ^Content/cnc/movies/gameover.vqa: + ^SupportDir|Content/cnc/movies/gameover.vqa: Offset: 367084844 Length: 2087322 - ^Content/cnc/movies/forestkl.vqa: + ^SupportDir|Content/cnc/movies/forestkl.vqa: Offset: 369172166 Length: 1500986 - ^Content/cnc/movies/flag.vqa: + ^SupportDir|Content/cnc/movies/flag.vqa: Offset: 370673152 Length: 4308680 - ^Content/cnc/movies/dino.vqa: + ^SupportDir|Content/cnc/movies/dino.vqa: Offset: 374981832 Length: 1347896 - ^Content/cnc/movies/dessweep.vqa: + ^SupportDir|Content/cnc/movies/dessweep.vqa: Offset: 376329728 Length: 3563646 - ^Content/cnc/movies/deskill.vqa: + ^SupportDir|Content/cnc/movies/deskill.vqa: Offset: 379893374 Length: 1483634 - ^Content/cnc/movies/desflees.vqa: + ^SupportDir|Content/cnc/movies/desflees.vqa: Offset: 381377008 Length: 2698426 - ^Content/cnc/movies/consyard.vqa: + ^SupportDir|Content/cnc/movies/consyard.vqa: Offset: 384075434 Length: 7864652 - ^Content/cnc/movies/cc2tease.vqa: + ^SupportDir|Content/cnc/movies/cc2tease.vqa: Offset: 391940086 Length: 12506712 - ^Content/cnc/movies/bombflee.vqa: + ^SupportDir|Content/cnc/movies/bombflee.vqa: Offset: 404446798 Length: 2859726 - ^Content/cnc/movies/bombaway.vqa: + ^SupportDir|Content/cnc/movies/bombaway.vqa: Offset: 407306524 Length: 5579588 - ^Content/cnc/movies/bcanyon.vqa: + ^SupportDir|Content/cnc/movies/bcanyon.vqa: Offset: 412886112 Length: 5172288 - ^Content/cnc/movies/banner.vqa: + ^SupportDir|Content/cnc/movies/banner.vqa: Offset: 418058400 Length: 2229408 - ^Content/cnc/movies/akira.vqa: + ^SupportDir|Content/cnc/movies/akira.vqa: Offset: 420287808 Length: 7803444 - ^Content/cnc/movies/airstrk.vqa: + ^SupportDir|Content/cnc/movies/airstrk.vqa: Offset: 428091252 Length: 4444442 nod95-linux: C&C Gold (Nod Disc, English) @@ -211,204 +211,204 @@ conquer.mix: 833e02a09aae694659eb312d3838367f681d1b30 Install: copy: . - ^Content/cnc/conquer.mix: conquer.mix - ^Content/cnc/desert.mix: desert.mix - ^Content/cnc/general.mix: general.mix - ^Content/cnc/scores.mix: scores.mix - ^Content/cnc/sounds.mix: sounds.mix - ^Content/cnc/temperat.mix: temperat.mix - ^Content/cnc/winter.mix: winter.mix + ^SupportDir|Content/cnc/conquer.mix: conquer.mix + ^SupportDir|Content/cnc/desert.mix: desert.mix + ^SupportDir|Content/cnc/general.mix: general.mix + ^SupportDir|Content/cnc/scores.mix: scores.mix + ^SupportDir|Content/cnc/sounds.mix: sounds.mix + ^SupportDir|Content/cnc/temperat.mix: temperat.mix + ^SupportDir|Content/cnc/winter.mix: winter.mix extract-blast: install/setup.z - ^Content/cnc/speech.mix: + ^SupportDir|Content/cnc/speech.mix: Offset: 10203213 Length: 603293 - ^Content/cnc/tempicnh.mix: + ^SupportDir|Content/cnc/tempicnh.mix: Offset: 10925941 Length: 119096 - ^Content/cnc/transit.mix: + ^SupportDir|Content/cnc/transit.mix: Offset: 11078017 Length: 3724462 extract-raw: movies.mix - ^Content/cnc/movies/visor.vqa: + ^SupportDir|Content/cnc/movies/visor.vqa: Offset: 738 Length: 4407162 - ^Content/cnc/movies/trtkil_d.vqa: + ^SupportDir|Content/cnc/movies/trtkil_d.vqa: Offset: 4407900 Length: 3511836 - ^Content/cnc/movies/trailer.vqa: + ^SupportDir|Content/cnc/movies/trailer.vqa: Offset: 7919736 Length: 23163930 - ^Content/cnc/movies/tiberfx.vqa: + ^SupportDir|Content/cnc/movies/tiberfx.vqa: Offset: 31083666 Length: 8735102 - ^Content/cnc/movies/tankkill.vqa: + ^SupportDir|Content/cnc/movies/tankkill.vqa: Offset: 39818768 Length: 3298978 - ^Content/cnc/movies/tankgo.vqa: + ^SupportDir|Content/cnc/movies/tankgo.vqa: Offset: 43117746 Length: 1403876 - ^Content/cnc/movies/sundial.vqa: + ^SupportDir|Content/cnc/movies/sundial.vqa: Offset: 44521622 Length: 3653636 - ^Content/cnc/movies/stealth.vqa: + ^SupportDir|Content/cnc/movies/stealth.vqa: Offset: 48175258 Length: 4521860 - ^Content/cnc/movies/spycrash.vqa: + ^SupportDir|Content/cnc/movies/spycrash.vqa: Offset: 52697118 Length: 1886288 - ^Content/cnc/movies/sethpre.vqa: + ^SupportDir|Content/cnc/movies/sethpre.vqa: Offset: 54583406 Length: 10914610 - ^Content/cnc/movies/seige.vqa: + ^SupportDir|Content/cnc/movies/seige.vqa: Offset: 65498016 Length: 2705978 - ^Content/cnc/movies/samsite.vqa: + ^SupportDir|Content/cnc/movies/samsite.vqa: Offset: 68203994 Length: 1410418 - ^Content/cnc/movies/retro.vqa: + ^SupportDir|Content/cnc/movies/retro.vqa: Offset: 69614412 Length: 6434382 - ^Content/cnc/movies/refint.vqa: + ^SupportDir|Content/cnc/movies/refint.vqa: Offset: 76048794 Length: 5090040 - ^Content/cnc/movies/obel.vqa: + ^SupportDir|Content/cnc/movies/obel.vqa: Offset: 81138834 Length: 3851370 - ^Content/cnc/movies/nuke.vqa: + ^SupportDir|Content/cnc/movies/nuke.vqa: Offset: 84990204 Length: 3126662 - ^Content/cnc/movies/nodlose.vqa: + ^SupportDir|Content/cnc/movies/nodlose.vqa: Offset: 88116866 Length: 5148924 - ^Content/cnc/movies/nodfinal.vqa: + ^SupportDir|Content/cnc/movies/nodfinal.vqa: Offset: 93265790 Length: 23326586 - ^Content/cnc/movies/nodend4.vqa: + ^SupportDir|Content/cnc/movies/nodend4.vqa: Offset: 116592376 Length: 25535232 - ^Content/cnc/movies/nodend3.vqa: + ^SupportDir|Content/cnc/movies/nodend3.vqa: Offset: 142127608 Length: 25725824 - ^Content/cnc/movies/nodend2.vqa: + ^SupportDir|Content/cnc/movies/nodend2.vqa: Offset: 167853432 Length: 27214048 - ^Content/cnc/movies/nodend1.vqa: + ^SupportDir|Content/cnc/movies/nodend1.vqa: Offset: 195067480 Length: 27172272 - ^Content/cnc/movies/nod9.vqa: + ^SupportDir|Content/cnc/movies/nod9.vqa: Offset: 222239752 Length: 9357980 - ^Content/cnc/movies/nod8.vqa: + ^SupportDir|Content/cnc/movies/nod8.vqa: Offset: 231597732 Length: 11597940 - ^Content/cnc/movies/nod7b.vqa: + ^SupportDir|Content/cnc/movies/nod7b.vqa: Offset: 243195672 Length: 4671402 - ^Content/cnc/movies/nod7a.vqa: + ^SupportDir|Content/cnc/movies/nod7a.vqa: Offset: 247867074 Length: 4740470 - ^Content/cnc/movies/nod6.vqa: + ^SupportDir|Content/cnc/movies/nod6.vqa: Offset: 252607544 Length: 5007744 - ^Content/cnc/movies/nod5.vqa: + ^SupportDir|Content/cnc/movies/nod5.vqa: Offset: 257615288 Length: 6641700 - ^Content/cnc/movies/nod4b.vqa: + ^SupportDir|Content/cnc/movies/nod4b.vqa: Offset: 264256988 Length: 3867618 - ^Content/cnc/movies/nod4a.vqa: + ^SupportDir|Content/cnc/movies/nod4a.vqa: Offset: 268124606 Length: 3838924 - ^Content/cnc/movies/nod3.vqa: + ^SupportDir|Content/cnc/movies/nod3.vqa: Offset: 271963530 Length: 3603314 - ^Content/cnc/movies/nod2.vqa: + ^SupportDir|Content/cnc/movies/nod2.vqa: Offset: 275566844 Length: 7200720 - ^Content/cnc/movies/nod1pre.vqa: + ^SupportDir|Content/cnc/movies/nod1pre.vqa: Offset: 282767564 Length: 395720 - ^Content/cnc/movies/nod13.vqa: + ^SupportDir|Content/cnc/movies/nod13.vqa: Offset: 283163284 Length: 2746626 - ^Content/cnc/movies/nod12.vqa: + ^SupportDir|Content/cnc/movies/nod12.vqa: Offset: 285909910 Length: 6576562 - ^Content/cnc/movies/nod11.vqa: + ^SupportDir|Content/cnc/movies/nod11.vqa: Offset: 292486472 Length: 4629270 - ^Content/cnc/movies/nod10b.vqa: + ^SupportDir|Content/cnc/movies/nod10b.vqa: Offset: 297115742 Length: 6386444 - ^Content/cnc/movies/nod10a.vqa: + ^SupportDir|Content/cnc/movies/nod10a.vqa: Offset: 303502186 Length: 7205632 - ^Content/cnc/movies/nod1.vqa: + ^SupportDir|Content/cnc/movies/nod1.vqa: Offset: 310707818 Length: 4663258 - ^Content/cnc/movies/logo.vqa: + ^SupportDir|Content/cnc/movies/logo.vqa: Offset: 315371076 Length: 3562630 - ^Content/cnc/movies/landing.vqa: + ^SupportDir|Content/cnc/movies/landing.vqa: Offset: 318933706 Length: 1617094 - ^Content/cnc/movies/kanepre.vqa: + ^SupportDir|Content/cnc/movies/kanepre.vqa: Offset: 320550800 Length: 17220712 - ^Content/cnc/movies/intro2.vqa: + ^SupportDir|Content/cnc/movies/intro2.vqa: Offset: 337771512 Length: 21058732 - ^Content/cnc/movies/insites.vqa: + ^SupportDir|Content/cnc/movies/insites.vqa: Offset: 358830244 Length: 460482 - ^Content/cnc/movies/generic.vqa: + ^SupportDir|Content/cnc/movies/generic.vqa: Offset: 359290726 Length: 1452820 - ^Content/cnc/movies/gdi1.vqa: + ^SupportDir|Content/cnc/movies/gdi1.vqa: Offset: 360743546 Length: 6341298 - ^Content/cnc/movies/gameover.vqa: + ^SupportDir|Content/cnc/movies/gameover.vqa: Offset: 367084844 Length: 2087322 - ^Content/cnc/movies/forestkl.vqa: + ^SupportDir|Content/cnc/movies/forestkl.vqa: Offset: 369172166 Length: 1500986 - ^Content/cnc/movies/flag.vqa: + ^SupportDir|Content/cnc/movies/flag.vqa: Offset: 370673152 Length: 4308680 - ^Content/cnc/movies/dino.vqa: + ^SupportDir|Content/cnc/movies/dino.vqa: Offset: 374981832 Length: 1347896 - ^Content/cnc/movies/dessweep.vqa: + ^SupportDir|Content/cnc/movies/dessweep.vqa: Offset: 376329728 Length: 3563646 - ^Content/cnc/movies/deskill.vqa: + ^SupportDir|Content/cnc/movies/deskill.vqa: Offset: 379893374 Length: 1483634 - ^Content/cnc/movies/desflees.vqa: + ^SupportDir|Content/cnc/movies/desflees.vqa: Offset: 381377008 Length: 2698426 - ^Content/cnc/movies/consyard.vqa: + ^SupportDir|Content/cnc/movies/consyard.vqa: Offset: 384075434 Length: 7864652 - ^Content/cnc/movies/cc2tease.vqa: + ^SupportDir|Content/cnc/movies/cc2tease.vqa: Offset: 391940086 Length: 12506712 - ^Content/cnc/movies/bombflee.vqa: + ^SupportDir|Content/cnc/movies/bombflee.vqa: Offset: 404446798 Length: 2859726 - ^Content/cnc/movies/bombaway.vqa: + ^SupportDir|Content/cnc/movies/bombaway.vqa: Offset: 407306524 Length: 5579588 - ^Content/cnc/movies/bcanyon.vqa: + ^SupportDir|Content/cnc/movies/bcanyon.vqa: Offset: 412886112 Length: 5172288 - ^Content/cnc/movies/banner.vqa: + ^SupportDir|Content/cnc/movies/banner.vqa: Offset: 418058400 Length: 2229408 - ^Content/cnc/movies/akira.vqa: + ^SupportDir|Content/cnc/movies/akira.vqa: Offset: 420287808 Length: 7803444 - ^Content/cnc/movies/airstrk.vqa: + ^SupportDir|Content/cnc/movies/airstrk.vqa: Offset: 428091252 Length: 4444442 \ No newline at end of file diff -Nru openra-20200503/mods/cnc/installer/origin.yaml openra-20210321/mods/cnc/installer/origin.yaml --- openra-20200503/mods/cnc/installer/origin.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/installer/origin.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,327 +7,327 @@ CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30 Install: copy: . - ^Content/cnc/conquer.mix: CONQUER.MIX - ^Content/cnc/desert.mix: DESERT.MIX - ^Content/cnc/general.mix: GENERAL.MIX - ^Content/cnc/scores.mix: SCORES.MIX - ^Content/cnc/sounds.mix: SOUNDS.MIX - ^Content/cnc/temperat.mix: TEMPERAT.MIX - ^Content/cnc/winter.mix: WINTER.MIX - ^Content/cnc/speech.mix: SPEECH.MIX - ^Content/cnc/tempicnh.mix: TEMPICNH.MIX - ^Content/cnc/transit.mix: TRANSIT.MIX - ^Content/cnc/scores-covertops.mix: covert/SCORES.MIX + ^SupportDir|Content/cnc/conquer.mix: CONQUER.MIX + ^SupportDir|Content/cnc/desert.mix: DESERT.MIX + ^SupportDir|Content/cnc/general.mix: GENERAL.MIX + ^SupportDir|Content/cnc/scores.mix: SCORES.MIX + ^SupportDir|Content/cnc/sounds.mix: SOUNDS.MIX + ^SupportDir|Content/cnc/temperat.mix: TEMPERAT.MIX + ^SupportDir|Content/cnc/winter.mix: WINTER.MIX + ^SupportDir|Content/cnc/speech.mix: SPEECH.MIX + ^SupportDir|Content/cnc/tempicnh.mix: TEMPICNH.MIX + ^SupportDir|Content/cnc/transit.mix: TRANSIT.MIX + ^SupportDir|Content/cnc/scores-covertops.mix: covert/SCORES.MIX extract-raw: movies.mix - ^Content/cnc/movies/akira.vqa: + ^SupportDir|Content/cnc/movies/akira.vqa: Offset: 4445708 Length: 7803444 - ^Content/cnc/movies/bkground.vqa: + ^SupportDir|Content/cnc/movies/bkground.vqa: Offset: 12249152 Length: 15267052 - ^Content/cnc/movies/burdet1.vqa: + ^SupportDir|Content/cnc/movies/burdet1.vqa: Offset: 27516204 Length: 10410614 - ^Content/cnc/movies/burdet2.vqa: + ^SupportDir|Content/cnc/movies/burdet2.vqa: Offset: 37926818 Length: 2062190 - ^Content/cnc/movies/gdi4a.vqa: + ^SupportDir|Content/cnc/movies/gdi4a.vqa: Offset: 39989008 Length: 4450582 - ^Content/cnc/movies/gdi4b.vqa: + ^SupportDir|Content/cnc/movies/gdi4b.vqa: Offset: 44439590 Length: 6603530 - ^Content/cnc/movies/gdifina.vqa: + ^SupportDir|Content/cnc/movies/gdifina.vqa: Offset: 51043120 Length: 12888650 - ^Content/cnc/movies/gdifinb.vqa: + ^SupportDir|Content/cnc/movies/gdifinb.vqa: Offset: 63931770 Length: 17769978 - ^Content/cnc/movies/nod7a.vqa: + ^SupportDir|Content/cnc/movies/nod7a.vqa: Offset: 81701748 Length: 4740470 - ^Content/cnc/movies/nod7b.vqa: + ^SupportDir|Content/cnc/movies/nod7b.vqa: Offset: 86442218 Length: 4671402 - ^Content/cnc/movies/visor.vqa: + ^SupportDir|Content/cnc/movies/visor.vqa: Offset: 91113620 Length: 4407162 - ^Content/cnc/movies/turtkill.vqa: + ^SupportDir|Content/cnc/movies/turtkill.vqa: Offset: 95520782 Length: 3323444 - ^Content/cnc/movies/trtkil_d.vqa: + ^SupportDir|Content/cnc/movies/trtkil_d.vqa: Offset: 98844226 Length: 3511836 - ^Content/cnc/movies/trailer.vqa: + ^SupportDir|Content/cnc/movies/trailer.vqa: Offset: 102356062 Length: 23163930 - ^Content/cnc/movies/tiberfx.vqa: + ^SupportDir|Content/cnc/movies/tiberfx.vqa: Offset: 125519992 Length: 8735102 - ^Content/cnc/movies/tbrinfo3.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo3.vqa: Offset: 134255094 Length: 14972046 - ^Content/cnc/movies/tbrinfo2.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo2.vqa: Offset: 149227140 Length: 16195290 - ^Content/cnc/movies/tbrinfo1.vqa: + ^SupportDir|Content/cnc/movies/tbrinfo1.vqa: Offset: 165422430 Length: 23479052 - ^Content/cnc/movies/tankkill.vqa: + ^SupportDir|Content/cnc/movies/tankkill.vqa: Offset: 188901482 Length: 3298978 - ^Content/cnc/movies/tankgo.vqa: + ^SupportDir|Content/cnc/movies/tankgo.vqa: Offset: 192200460 Length: 1403876 - ^Content/cnc/movies/sundial.vqa: + ^SupportDir|Content/cnc/movies/sundial.vqa: Offset: 193604336 Length: 3653636 - ^Content/cnc/movies/stealth.vqa: + ^SupportDir|Content/cnc/movies/stealth.vqa: Offset: 197257972 Length: 4521860 - ^Content/cnc/movies/spycrash.vqa: + ^SupportDir|Content/cnc/movies/spycrash.vqa: Offset: 201779832 Length: 1886288 - ^Content/cnc/movies/sethpre.vqa: + ^SupportDir|Content/cnc/movies/sethpre.vqa: Offset: 203666120 Length: 10914610 - ^Content/cnc/movies/seige.vqa: + ^SupportDir|Content/cnc/movies/seige.vqa: Offset: 214580730 Length: 2705978 - ^Content/cnc/movies/samsite.vqa: + ^SupportDir|Content/cnc/movies/samsite.vqa: Offset: 217286708 Length: 1410418 - ^Content/cnc/movies/samdie.vqa: + ^SupportDir|Content/cnc/movies/samdie.vqa: Offset: 218697126 Length: 3741942 - ^Content/cnc/movies/sabotage.vqa: + ^SupportDir|Content/cnc/movies/sabotage.vqa: Offset: 222439068 Length: 1386202 - ^Content/cnc/movies/retro.vqa: + ^SupportDir|Content/cnc/movies/retro.vqa: Offset: 223825270 Length: 6434382 - ^Content/cnc/movies/refint.vqa: + ^SupportDir|Content/cnc/movies/refint.vqa: Offset: 230259652 Length: 5090040 - ^Content/cnc/movies/podium.vqa: + ^SupportDir|Content/cnc/movies/podium.vqa: Offset: 235349692 Length: 2790664 - ^Content/cnc/movies/planecra.vqa: + ^SupportDir|Content/cnc/movies/planecra.vqa: Offset: 238140356 Length: 5085426 - ^Content/cnc/movies/pintle.vqa: + ^SupportDir|Content/cnc/movies/pintle.vqa: Offset: 243225782 Length: 2757536 - ^Content/cnc/movies/paratrop.vqa: + ^SupportDir|Content/cnc/movies/paratrop.vqa: Offset: 245983318 Length: 3180272 - ^Content/cnc/movies/obel.vqa: + ^SupportDir|Content/cnc/movies/obel.vqa: Offset: 249163590 Length: 3851370 - ^Content/cnc/movies/nuke.vqa: + ^SupportDir|Content/cnc/movies/nuke.vqa: Offset: 253014960 Length: 3126662 - ^Content/cnc/movies/nodsweep.vqa: + ^SupportDir|Content/cnc/movies/nodsweep.vqa: Offset: 256141622 Length: 3642174 - ^Content/cnc/movies/nodlose.vqa: + ^SupportDir|Content/cnc/movies/nodlose.vqa: Offset: 259783796 Length: 5148924 - ^Content/cnc/movies/nodflees.vqa: + ^SupportDir|Content/cnc/movies/nodflees.vqa: Offset: 264932720 Length: 3056426 - ^Content/cnc/movies/nodfinal.vqa: + ^SupportDir|Content/cnc/movies/nodfinal.vqa: Offset: 267989146 Length: 23326586 - ^Content/cnc/movies/nod9.vqa: + ^SupportDir|Content/cnc/movies/nod9.vqa: Offset: 396963108 Length: 9357980 - ^Content/cnc/movies/nod8.vqa: + ^SupportDir|Content/cnc/movies/nod8.vqa: Offset: 406321088 Length: 11597940 - ^Content/cnc/movies/nod6.vqa: + ^SupportDir|Content/cnc/movies/nod6.vqa: Offset: 417919028 Length: 5007744 - ^Content/cnc/movies/nod5.vqa: + ^SupportDir|Content/cnc/movies/nod5.vqa: Offset: 422926772 Length: 6641700 - ^Content/cnc/movies/nod4b.vqa: + ^SupportDir|Content/cnc/movies/nod4b.vqa: Offset: 429568472 Length: 3867618 - ^Content/cnc/movies/nod4a.vqa: + ^SupportDir|Content/cnc/movies/nod4a.vqa: Offset: 433436090 Length: 3838924 - ^Content/cnc/movies/nod3.vqa: + ^SupportDir|Content/cnc/movies/nod3.vqa: Offset: 437275014 Length: 3603314 - ^Content/cnc/movies/nod2.vqa: + ^SupportDir|Content/cnc/movies/nod2.vqa: Offset: 440878328 Length: 7200720 - ^Content/cnc/movies/nod1pre.vqa: + ^SupportDir|Content/cnc/movies/nod1pre.vqa: Offset: 448079048 Length: 395720 - ^Content/cnc/movies/nod13.vqa: + ^SupportDir|Content/cnc/movies/nod13.vqa: Offset: 448474768 Length: 2746626 - ^Content/cnc/movies/nod12.vqa: + ^SupportDir|Content/cnc/movies/nod12.vqa: Offset: 451221394 Length: 6576562 - ^Content/cnc/movies/nod11.vqa: + ^SupportDir|Content/cnc/movies/nod11.vqa: Offset: 457797956 Length: 4629270 - ^Content/cnc/movies/nod10b.vqa: + ^SupportDir|Content/cnc/movies/nod10b.vqa: Offset: 462427226 Length: 6386444 - ^Content/cnc/movies/nod10a.vqa: + ^SupportDir|Content/cnc/movies/nod10a.vqa: Offset: 468813670 Length: 7205632 - ^Content/cnc/movies/nod1.vqa: + ^SupportDir|Content/cnc/movies/nod1.vqa: Offset: 476019302 Length: 4663258 - ^Content/cnc/movies/nitejump.vqa: + ^SupportDir|Content/cnc/movies/nitejump.vqa: Offset: 480682560 Length: 3702838 - ^Content/cnc/movies/napalm.vqa: + ^SupportDir|Content/cnc/movies/napalm.vqa: Offset: 484385398 Length: 4004146 - ^Content/cnc/movies/logo.vqa: + ^SupportDir|Content/cnc/movies/logo.vqa: Offset: 488389544 Length: 3562630 - ^Content/cnc/movies/landing.vqa: + ^SupportDir|Content/cnc/movies/landing.vqa: Offset: 491952174 Length: 1617094 - ^Content/cnc/movies/kanepre.vqa: + ^SupportDir|Content/cnc/movies/kanepre.vqa: Offset: 493569268 Length: 17220712 - ^Content/cnc/movies/intro2.vqa: + ^SupportDir|Content/cnc/movies/intro2.vqa: Offset: 510789980 Length: 21058732 - ^Content/cnc/movies/insites.vqa: + ^SupportDir|Content/cnc/movies/insites.vqa: Offset: 531848712 Length: 460482 - ^Content/cnc/movies/hellvaly.vqa: + ^SupportDir|Content/cnc/movies/hellvaly.vqa: Offset: 532309194 Length: 6658950 - ^Content/cnc/movies/gunboat.vqa: + ^SupportDir|Content/cnc/movies/gunboat.vqa: Offset: 538968144 Length: 3203706 - ^Content/cnc/movies/generic.vqa: + ^SupportDir|Content/cnc/movies/generic.vqa: Offset: 542171850 Length: 1452820 - ^Content/cnc/movies/gdilose.vqa: + ^SupportDir|Content/cnc/movies/gdilose.vqa: Offset: 543624670 Length: 2097912 - ^Content/cnc/movies/gdiend2.vqa: + ^SupportDir|Content/cnc/movies/gdiend2.vqa: Offset: 545722582 Length: 25242946 - ^Content/cnc/movies/gdiend1.vqa: + ^SupportDir|Content/cnc/movies/gdiend1.vqa: Offset: 570965528 Length: 25311636 - ^Content/cnc/movies/gdi9.vqa: + ^SupportDir|Content/cnc/movies/gdi9.vqa: Offset: 596277164 Length: 11806994 - ^Content/cnc/movies/gdi8b.vqa: + ^SupportDir|Content/cnc/movies/gdi8b.vqa: Offset: 608084158 Length: 5324410 - ^Content/cnc/movies/gdi8a.vqa: + ^SupportDir|Content/cnc/movies/gdi8a.vqa: Offset: 613408568 Length: 4672548 - ^Content/cnc/movies/gdi7.vqa: + ^SupportDir|Content/cnc/movies/gdi7.vqa: Offset: 618081116 Length: 4241952 - ^Content/cnc/movies/gdi6.vqa: + ^SupportDir|Content/cnc/movies/gdi6.vqa: Offset: 622323068 Length: 3959650 - ^Content/cnc/movies/gdi5.vqa: + ^SupportDir|Content/cnc/movies/gdi5.vqa: Offset: 626282718 Length: 3818244 - ^Content/cnc/movies/gdi3lose.vqa: + ^SupportDir|Content/cnc/movies/gdi3lose.vqa: Offset: 630100962 Length: 2265770 - ^Content/cnc/movies/gdi3.vqa: + ^SupportDir|Content/cnc/movies/gdi3.vqa: Offset: 632366732 Length: 5443848 - ^Content/cnc/movies/gdi2.vqa: + ^SupportDir|Content/cnc/movies/gdi2.vqa: Offset: 637810580 Length: 7883500 - ^Content/cnc/movies/gdi15.vqa: + ^SupportDir|Content/cnc/movies/gdi15.vqa: Offset: 645694080 Length: 11684610 - ^Content/cnc/movies/gdi14.vqa: + ^SupportDir|Content/cnc/movies/gdi14.vqa: Offset: 657378690 Length: 5282770 - ^Content/cnc/movies/gdi13.vqa: + ^SupportDir|Content/cnc/movies/gdi13.vqa: Offset: 662661460 Length: 6900914 - ^Content/cnc/movies/gdi12.vqa: + ^SupportDir|Content/cnc/movies/gdi12.vqa: Offset: 669562374 Length: 3669404 - ^Content/cnc/movies/gdi11.vqa: + ^SupportDir|Content/cnc/movies/gdi11.vqa: Offset: 673231778 Length: 5895754 - ^Content/cnc/movies/gdi10.vqa: + ^SupportDir|Content/cnc/movies/gdi10.vqa: Offset: 679127532 Length: 5761514 - ^Content/cnc/movies/gdi1.vqa: + ^SupportDir|Content/cnc/movies/gdi1.vqa: Offset: 684889046 Length: 6341298 - ^Content/cnc/movies/gameover.vqa: + ^SupportDir|Content/cnc/movies/gameover.vqa: Offset: 691230344 Length: 2087322 - ^Content/cnc/movies/forestkl.vqa: + ^SupportDir|Content/cnc/movies/forestkl.vqa: Offset: 693317666 Length: 1500986 - ^Content/cnc/movies/flyy.vqa: + ^SupportDir|Content/cnc/movies/flyy.vqa: Offset: 694818652 Length: 1373532 - ^Content/cnc/movies/flag.vqa: + ^SupportDir|Content/cnc/movies/flag.vqa: Offset: 696192184 Length: 4308680 - ^Content/cnc/movies/dino.vqa: + ^SupportDir|Content/cnc/movies/dino.vqa: Offset: 700500864 Length: 1347896 - ^Content/cnc/movies/dessweep.vqa: + ^SupportDir|Content/cnc/movies/dessweep.vqa: Offset: 701848760 Length: 3563646 - ^Content/cnc/movies/desolat.vqa: + ^SupportDir|Content/cnc/movies/desolat.vqa: Offset: 705412406 Length: 8385122 - ^Content/cnc/movies/deskill.vqa: + ^SupportDir|Content/cnc/movies/deskill.vqa: Offset: 713797528 Length: 1483634 - ^Content/cnc/movies/desflees.vqa: + ^SupportDir|Content/cnc/movies/desflees.vqa: Offset: 715281162 Length: 2698426 - ^Content/cnc/movies/consyard.vqa: + ^SupportDir|Content/cnc/movies/consyard.vqa: Offset: 717979588 Length: 7864652 - ^Content/cnc/movies/cc2tease.vqa: + ^SupportDir|Content/cnc/movies/cc2tease.vqa: Offset: 725844240 Length: 12506712 - ^Content/cnc/movies/bombflee.vqa: + ^SupportDir|Content/cnc/movies/bombflee.vqa: Offset: 738350952 Length: 2859726 - ^Content/cnc/movies/bombaway.vqa: + ^SupportDir|Content/cnc/movies/bombaway.vqa: Offset: 741210678 Length: 5579588 - ^Content/cnc/movies/bcanyon.vqa: + ^SupportDir|Content/cnc/movies/bcanyon.vqa: Offset: 746790266 Length: 5172288 - ^Content/cnc/movies/banner.vqa: + ^SupportDir|Content/cnc/movies/banner.vqa: Offset: 751962554 Length: 2229408 - ^Content/cnc/movies/airstrk.vqa: + ^SupportDir|Content/cnc/movies/airstrk.vqa: Offset: 754191962 Length: 4444442 - ^Content/cnc/movies/nodend1.vqa: + ^SupportDir|Content/cnc/movies/nodend1.vqa: Offset: 758637638 Length: 24708735 - ^Content/cnc/movies/nodend2.vqa: + ^SupportDir|Content/cnc/movies/nodend2.vqa: Offset: 783346373 Length: 24700467 - ^Content/cnc/movies/nodend3.vqa: + ^SupportDir|Content/cnc/movies/nodend3.vqa: Offset: 808046840 Length: 23323681 - ^Content/cnc/movies/nodend4.vqa: + ^SupportDir|Content/cnc/movies/nodend4.vqa: Offset: 831370521 - Length: 23346753 \ No newline at end of file + Length: 23346753 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/african-gambit.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/african-gambit.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/aggressive-tendencies.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/aggressive-tendencies.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/alpha-juno-5.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/alpha-juno-5.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/antrax.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/antrax.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/anvil-of-war.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/anvil-of-war.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/armageddon.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/armageddon.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/avocado.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/avocado.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/badland-ridges.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/badland-ridges.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/burning-hammer.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/burning-hammer.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/carters-ridge.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/carters-ridge.oramap differ diff -Nru openra-20200503/mods/cnc/maps/cnc64gdi01/cnc64gdi01.lua openra-20210321/mods/cnc/maps/cnc64gdi01/cnc64gdi01.lua --- openra-20200503/mods/cnc/maps/cnc64gdi01/cnc64gdi01.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/cnc64gdi01/cnc64gdi01.lua 2021-03-21 11:10:05.000000000 +0000 @@ -81,9 +81,10 @@ RepairNamedActors(Nod, 0.9) Trigger.AfterDelay(0, function() - local harv = Nod.GetActorsByType("harv")[1] local toBuild = function() return { "harv" } end - RebuildHarvesters(harv, toBuild) + Utils.Do(Nod.GetActorsByType("harv"), function(harv) + RebuildHarvesters(harv, toBuild) + end) end) local vehicleToBuild = function() return Utils.Random(AutocreateSquads) end @@ -136,8 +137,8 @@ RebuildHarvesters = function(harv, toBuild) Trigger.OnRemovedFromWorld(harv, function() - ProduceUnits(Nod, Airfield, nil, toBuild, function(unit) - RebuildHarvesters(unit, toBuild) + ProduceUnits(Nod, Airfield, nil, toBuild, function(units) + RebuildHarvesters(units[1], toBuild) end) end) end Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/cnc64gdi01/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/cnc64gdi01/map.bin differ diff -Nru openra-20200503/mods/cnc/maps/cnc64gdi01/map.yaml openra-20210321/mods/cnc/maps/cnc64gdi01/map.yaml --- openra-20200503/mods/cnc/maps/cnc64gdi01/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/cnc64gdi01/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -277,7 +277,7 @@ Actor76: tc02 Location: 38,27 Owner: Neutral - Actor77: split3 + Actor77: t13.transformable Location: 31,28 Owner: Neutral Actor78: tc01 @@ -316,13 +316,13 @@ Actor89: t03 Location: 21,9 Owner: Neutral - Actor90: split2 + Actor90: t03.transformable Location: 19,60 Owner: Neutral - Actor91: split3 + Actor91: t13.transformable Location: 22,59 Owner: Neutral - Actor92: split3 + Actor92: t13.transformable Location: 42,57 Owner: Neutral Actor93: tc05 @@ -412,16 +412,16 @@ Actor121: t12 Location: 4,14 Owner: Neutral - Actor122: split3 + Actor122: t13.transformable Location: 7,29 Owner: Neutral - Actor123: split3 + Actor123: t13.transformable Location: 7,33 Owner: Neutral - Actor124: split3 + Actor124: t13.transformable Location: 3,34 Owner: Neutral - Actor125: split3 + Actor125: t13.transformable Location: 22,42 Owner: Neutral AttackTrigger1: proc @@ -436,11 +436,11 @@ Actor129: gun Location: 19,16 Owner: Nod - Facing: 96 + Facing: 384 Actor130: gun Location: 14,18 Owner: Nod - Facing: 96 + Facing: 384 Actor131: nuk2 Location: 39,21 Owner: Nod @@ -486,11 +486,11 @@ Actor145: gun Location: 45,50 Owner: Nod - Facing: 128 + Facing: 512 Actor146: gun Location: 42,50 Owner: Nod - Facing: 128 + Facing: 512 Actor147: fact Location: 34,22 Owner: Nod @@ -566,23 +566,23 @@ Actor171: ltnk Location: 16,19 Owner: Nod - Facing: 96 + Facing: 384 Actor172: ltnk Location: 19,18 Owner: Nod - Facing: 96 + Facing: 384 Actor173: arty Location: 41,22 Owner: Nod - Facing: 128 + Facing: 512 Actor174: arty Location: 38,22 Owner: Nod - Facing: 128 + Facing: 512 Actor175: arty Location: 33,22 Owner: Nod - Facing: 128 + Facing: 512 Actor176: stnk Location: 30,19 Owner: Nod @@ -592,34 +592,34 @@ Actor178: stnk Location: 24,12 Owner: Nod - Facing: 128 + Facing: 512 Actor179: stnk Location: 27,12 Owner: Nod - Facing: 128 + Facing: 512 Actor180: ftnk Location: 6,16 Owner: Nod - Facing: 96 + Facing: 384 Actor181: e4 Location: 23,32 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 0 Actor182: e4 Location: 22,31 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 1 Actor183: e4 Location: 23,31 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 2 Actor184: e4 Location: 36,50 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor185: c6 Location: 41,15 @@ -652,27 +652,27 @@ Actor192: e4 Location: 20,42 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 4 Actor193: e4 Location: 3,45 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 4 Actor194: e4 Location: 2,45 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 4 Actor195: e1 Location: 18,40 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 3 Actor196: e1 Location: 16,43 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 4 Flare: waypoint Location: 17,51 @@ -689,11 +689,11 @@ Apache1: heli Owner: Nod Location: 21,11 - Facing: 92 + Facing: 368 Apache2: heli Owner: Nod Location: 28,11 - Facing: 92 + Facing: 368 HeliPatrol1: waypoint Owner: Nod Location: 15,43 diff -Nru openra-20200503/mods/cnc/maps/cnc64gdi01/rules.yaml openra-20210321/mods/cnc/maps/cnc64gdi01/rules.yaml --- openra-20200503/mods/cnc/maps/cnc64gdi01/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/cnc64gdi01/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -41,8 +41,6 @@ Inherits: LST -WithRoof: -Selectable: - SelectionDecorations: - RenderSelectionBars: False RejectsOrders: Cargo: Types: disabled Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/collateral-chaos.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/collateral-chaos.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/contra.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/contra.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/control-and-chaos.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/control-and-chaos.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/dead-in-motion.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/dead-in-motion.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/deserted-outpost.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/deserted-outpost.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/desert-invasion.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/desert-invasion.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/desert-lakes.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/desert-lakes.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/desert-mandarins.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/desert-mandarins.oramap differ diff -Nru openra-20200503/mods/cnc/maps/desert-rats-cnc/map.yaml openra-20210321/mods/cnc/maps/desert-rats-cnc/map.yaml --- openra-20200503/mods/cnc/maps/desert-rats-cnc/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/desert-rats-cnc/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -112,7 +112,7 @@ Owner: Neutral Location: 49,11 SubCell: 3 - Facing: 92 + Facing: 368 Actor26: t18 Owner: Neutral Location: 47,10 @@ -297,7 +297,7 @@ Owner: Neutral Location: 22,60 SubCell: 3 - Facing: 92 + Facing: 368 Actor89: t18 Owner: Neutral Location: 43,65 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/elysian-expanse.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/elysian-expanse.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/fight-win-prevail.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/fight-win-prevail.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/frostways.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/frostways.oramap differ diff -Nru openra-20200503/mods/cnc/maps/funpark01/rules.yaml openra-20210321/mods/cnc/maps/funpark01/rules.yaml --- openra-20200503/mods/cnc/maps/funpark01/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/funpark01/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -42,8 +42,6 @@ Inherits: LST -WithRoof: -Selectable: - SelectionDecorations: - RenderSelectionBars: False RejectsOrders: Cargo: Types: disabled diff -Nru openra-20200503/mods/cnc/maps/gdi01/map.yaml openra-20210321/mods/cnc/maps/gdi01/map.yaml --- openra-20200503/mods/cnc/maps/gdi01/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi01/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -143,71 +143,71 @@ Location: 46,55 Owner: Nod Health: 50 - Facing: 160 + Facing: 640 Actor84: gun Location: 41,55 Owner: Nod Health: 50 - Facing: 160 + Facing: 640 Actor85: gun Location: 49,55 Owner: Nod Health: 19 - Facing: 160 + Facing: 640 Actor92: e1 Location: 57,45 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 2 Actor93: e1 Location: 56,41 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 2 Actor94: e1 Location: 48,41 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 3 Actor95: e1 Location: 59,45 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor96: e1 Location: 46,50 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 3 Actor97: e1 Location: 48,47 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 1 Actor98: e1 Location: 38,43 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 4 Actor99: e1 Location: 38,43 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 1 Actor100: e1 Location: 48,41 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 Actor101: e1 Location: 41,39 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Gunboat: boat Location: 51,59 Owner: GDI - Facing: 64 + Facing: 256 nod0: waypoint Location: 36,39 Owner: Neutral diff -Nru openra-20200503/mods/cnc/maps/gdi01/rules.yaml openra-20210321/mods/cnc/maps/gdi01/rules.yaml --- openra-20200503/mods/cnc/maps/gdi01/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi01/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -114,8 +114,6 @@ Inherits: LST -WithRoof: -Selectable: - SelectionDecorations: - RenderSelectionBars: False RejectsOrders: Cargo: Types: disabled diff -Nru openra-20200503/mods/cnc/maps/gdi02/map.yaml openra-20210321/mods/cnc/maps/gdi02/map.yaml --- openra-20200503/mods/cnc/maps/gdi02/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi02/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -298,79 +298,79 @@ Location: 52,39 Owner: Nod Health: 52 - Facing: 96 + Facing: 384 Actor87: jeep Location: 54,49 Owner: GDI Health: 33 - Facing: 96 + Facing: 384 Actor88: jeep Location: 57,49 Owner: GDI - Facing: 32 + Facing: 128 Actor89: bggy Location: 33,37 Owner: Nod Health: 58 - Facing: 96 + Facing: 384 Actor91: bggy Location: 59,39 Owner: Nod Health: 50 - Facing: 160 + Facing: 640 Actor92: jeep Location: 56,54 Owner: GDI - Facing: 160 + Facing: 640 Actor93: e1 Location: 48,32 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 3 Actor94: e1 Location: 35,31 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 0 Actor95: e1 Location: 39,31 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 4 Actor96: e1 Location: 49,32 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor97: e1 Location: 37,32 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 0 Actor98: e1 Location: 50,34 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 2 Actor99: e1 Location: 50,32 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 4 Actor100: e1 Location: 36,31 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 4 Actor101: e1 Location: 49,34 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 0 Actor102: e1 Location: 36,32 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 1 Actor103: e1 Location: 49,33 @@ -379,42 +379,42 @@ Actor104: e1 Location: 48,33 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 0 Actor105: e1 Location: 46,33 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 3 Actor106: e1 Location: 46,34 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor107: e1 Location: 40,37 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 1 Actor108: e1 Location: 40,38 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 0 Actor109: e1 Location: 41,37 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 1 Actor110: e1 Location: 41,38 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 3 Actor111: e1 Location: 50,39 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 0 Actor112: e1 Location: 60,36 @@ -431,22 +431,22 @@ Actor115: e1 Location: 35,39 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor116: e1 Location: 50,37 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 0 Actor117: e1 Location: 58,39 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 4 Actor118: e1 Location: 60,40 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 1 Actor119: e1 Location: 61,39 @@ -455,79 +455,79 @@ Actor120: e1 Location: 59,34 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor121: e1 Location: 60,34 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor122: e1 Location: 56,32 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 2 Actor123: e1 Location: 51,32 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 0 Actor124: e1 Location: 60,34 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 4 Actor126: e1 Location: 38,49 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 Actor127: e1 Location: 38,48 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 3 Actor128: e1 Location: 53,40 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 Actor129: e1 Location: 45,36 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 4 Actor130: e1 Location: 50,51 Owner: GDI - Facing: 32 + Facing: 128 SubCell: 2 Actor131: e1 Location: 50,50 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 0 Actor132: e1 Location: 53,49 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 3 Actor133: e1 Location: 51,49 Owner: GDI Health: 98 - Facing: 128 + Facing: 512 SubCell: 4 Actor134: e1 Location: 52,40 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 2 Actor135: e1 Location: 52,50 Owner: GDI Health: 52 - Facing: 224 + Facing: 896 SubCell: 4 Actor136: e1 Location: 56,49 @@ -536,52 +536,52 @@ Actor137: e1 Location: 55,42 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 0 Actor138: e1 Location: 56,42 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 4 Actor139: e1 Location: 45,36 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor140: e1 Location: 44,36 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor143: e1 Location: 48,37 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 4 Actor144: e1 Location: 37,37 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor145: e1 Location: 50,37 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 2 Actor146: e1 Location: 38,32 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 1 Actor147: e1 Location: 49,36 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 0 Actor148: e1 Location: 48,36 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 4 SiloA: silo Location: 57,32 @@ -596,23 +596,23 @@ Location: 51,50 Owner: Nod Health: 18 - Facing: 96 + Facing: 384 RushRifle1: e1 Location: 54,48 Owner: Nod Health: 48 - Facing: 128 + Facing: 512 SubCell: 3 RushRifle2: e1 Location: 52,52 Owner: Nod Health: 32 - Facing: 96 + Facing: 384 SubCell: 0 RushRifle3: e1 Location: 52,53 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 0 lstEnd: waypoint Location: 58,57 diff -Nru openra-20200503/mods/cnc/maps/gdi02/rules.yaml openra-20210321/mods/cnc/maps/gdi02/rules.yaml --- openra-20200503/mods/cnc/maps/gdi02/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi02/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -116,8 +116,6 @@ Inherits: LST -WithRoof: -Selectable: - SelectionDecorations: - RenderSelectionBars: False RejectsOrders: Cargo: Types: disabled diff -Nru openra-20200503/mods/cnc/maps/gdi03/map.yaml openra-20210321/mods/cnc/maps/gdi03/map.yaml --- openra-20200503/mods/cnc/maps/gdi03/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi03/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -400,7 +400,7 @@ Actor117: gun Location: 20,34 Owner: Nod - Facing: 160 + Facing: 640 Actor118: v07 Location: 40,55 Owner: Neutral @@ -416,140 +416,140 @@ Actor125: gun Location: 36,30 Owner: Nod - Facing: 96 + Facing: 384 Actor127: gun Location: 29,34 Owner: Nod - Facing: 96 + Facing: 384 Actor129: bggy Location: 22,29 Owner: Nod - Facing: 128 + Facing: 512 Actor134: bggy Location: 21,29 Owner: Nod - Facing: 128 + Facing: 512 Actor135: bggy Location: 28,50 Owner: Nod - Facing: 160 + Facing: 640 Actor137: bggy Location: 21,30 Owner: Nod - Facing: 128 + Facing: 512 Actor138: bggy Location: 22,30 Owner: Nod - Facing: 128 + Facing: 512 Actor139: e3 Location: 17,28 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 0 Actor140: e1 Location: 19,29 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 4 Actor141: e1 Location: 18,28 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 4 Actor142: e1 Location: 19,28 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 0 Actor143: e1 Location: 31,32 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor144: e1 Location: 34,32 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor145: e3 Location: 34,31 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor146: e3 Location: 34,32 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 1 Actor147: e3 Location: 18,29 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor148: e3 Location: 30,51 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor149: e1 Location: 20,42 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor150: e1 Location: 23,44 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 4 Actor151: e1 Location: 24,33 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 0 Actor152: e1 Location: 22,34 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor153: e1 Location: 27,33 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 Actor154: e1 Location: 30,34 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor155: e1 Location: 14,33 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor156: e1 Location: 34,45 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 1 Actor157: e1 Location: 36,45 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor158: e3 Location: 30,32 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor159: e3 Location: 21,32 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 3 Actor160: e3 Location: 14,32 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 3 Actor163: c6 Location: 42,56 @@ -570,52 +570,52 @@ Actor167: e3 Location: 19,45 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 2 Actor168: e3 Location: 43,33 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor177: e3 Location: 14,32 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 1 Actor179: e3 Location: 13,36 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 Actor180: e3 Location: 11,34 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 4 Actor181: e3 Location: 20,45 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor182: e1 Location: 25,51 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor183: e1 Location: 24,52 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor184: e3 Location: 33,46 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor185: e3 Location: 37,47 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor186: e3 Location: 37,28 @@ -632,7 +632,7 @@ Actor191: e3 Location: 24,46 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 1 Sam1: sam Location: 28,52 @@ -653,17 +653,17 @@ Sam4Guard0: e1 Location: 9,31 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 1 Sam4Guard1: e1 Location: 11,31 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Sam4Guard2: e1 Location: 10,31 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 Sam4Guard3: e1 Location: 10,31 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/gdi04a/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/gdi04a/map.png differ diff -Nru openra-20200503/mods/cnc/maps/gdi04a/map.yaml openra-20210321/mods/cnc/maps/gdi04a/map.yaml --- openra-20200503/mods/cnc/maps/gdi04a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi04a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -196,18 +196,18 @@ Actor54: bggy Location: 55,53 Owner: Nod - Facing: 32 + Facing: 128 Actor55: bggy Location: 38,43 Owner: Nod - Facing: 64 + Facing: 256 Actor56: jeep Location: 13,53 Owner: GDI Actor58: bggy Location: 31,57 Owner: Nod - Facing: 32 + Facing: 128 Actor59: apc Location: 14,53 Owner: GDI @@ -217,15 +217,15 @@ Actor61: bggy Location: 26,27 Owner: Nod - Facing: 160 + Facing: 640 Actor62: bggy Location: 51,27 Owner: Nod - Facing: 160 + Facing: 640 Actor63: ltnk Location: 44,53 Owner: Nod - Facing: 192 + Facing: 768 Actor64: e3 Location: 45,36 Owner: Nod @@ -237,22 +237,22 @@ Actor66: e3 Location: 36,41 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor67: e3 Location: 39,42 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor68: e3 Location: 12,24 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor69: e3 Location: 37,43 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 4 Actor70: e2 Location: 14,54 @@ -273,37 +273,37 @@ Actor73: e1 Location: 15,41 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor74: e1 Location: 24,35 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 4 Actor75: e1 Location: 36,29 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 1 Actor76: e1 Location: 28,27 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 4 Actor77: e1 Location: 32,30 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 0 Actor78: e1 Location: 33,44 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 4 Actor79: e1 Location: 45,36 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 2 Actor80: e3 Location: 52,44 @@ -320,17 +320,17 @@ Actor83: e1 Location: 13,27 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 2 Actor84: e1 Location: 13,36 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 3 Actor85: e1 Location: 11,29 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 4 Actor860: e2 Location: 14,54 @@ -359,37 +359,37 @@ Actor91: e3 Location: 55,41 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 2 Actor92: e3 Location: 48,42 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 2 Actor93: e1 Location: 50,26 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 4 Actor94: e1 Location: 50,28 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 0 Actor95: e1 Location: 52,26 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 3 Actor96: e1 Location: 25,43 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 4 Actor97: e1 Location: 25,26 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor98: e1 Location: 30,30 @@ -398,12 +398,12 @@ Actor99: e3 Location: 21,50 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 1 Actor100: e3 Location: 25,53 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 3 Actor101: moneycrate Location: 56,23 @@ -414,11 +414,11 @@ Hunter1: bggy Location: 35,43 Owner: Nod - Facing: 192 + Facing: 768 Hunter2: bggy Location: 32,43 Owner: Nod - Facing: 192 + Facing: 768 crate: CRATE.plain Location: 25,58 Owner: Neutral @@ -451,5 +451,3 @@ Owner: Neutral Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml - -Weapons: weapons.yaml diff -Nru openra-20200503/mods/cnc/maps/gdi04a/weapons.yaml openra-20210321/mods/cnc/maps/gdi04a/weapons.yaml --- openra-20200503/mods/cnc/maps/gdi04a/weapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi04a/weapons.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -Tiberium: - Warhead@1Dam: SpreadDamage - Damage: 600 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/gdi04b/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/gdi04b/map.png differ diff -Nru openra-20200503/mods/cnc/maps/gdi04b/map.yaml openra-20210321/mods/cnc/maps/gdi04b/map.yaml --- openra-20200503/mods/cnc/maps/gdi04b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi04b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -316,27 +316,27 @@ Actor92: jeep Location: 49,45 Owner: GDI - Facing: 224 + Facing: 896 Actor93: bggy Location: 10,23 Owner: Nod - Facing: 96 + Facing: 384 Actor94: apc Location: 48,46 Owner: GDI - Facing: 224 + Facing: 896 Actor95: apc Location: 51,45 Owner: GDI - Facing: 224 + Facing: 896 Actor96: bggy Location: 34,18 Owner: Nod - Facing: 64 + Facing: 256 Actor97: bggy Location: 53,26 Owner: Nod - Facing: 128 + Facing: 512 Actor99: e3 Location: 8,45 Owner: Nod @@ -348,17 +348,17 @@ Actor101: e2 Location: 51,46 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 1 Actor102: e3 Location: 36,15 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 2 Actor103: e1 Location: 50,47 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 1 Actor104: e3 Location: 25,33 @@ -367,32 +367,32 @@ Actor105: e1 Location: 11,46 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 3 Actor106: e1 Location: 30,37 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 3 Actor107: e3 Location: 17,44 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 0 Actor108: e1 Location: 23,33 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 0 Actor109: e1 Location: 28,31 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 1 Actor110: e1 Location: 10,31 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor111: e3 Location: 33,20 @@ -401,7 +401,7 @@ Actor112: e3 Location: 25,18 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 0 Actor113: e1 Location: 49,46 @@ -410,57 +410,57 @@ Actor114: e1 Location: 49,46 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 3 Actor115: e1 Location: 49,47 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 2 Actor116: e2 Location: 51,46 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 2 Actor117: e2 Location: 51,46 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 4 Actor118: e2 Location: 52,46 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 3 Actor119: e3 Location: 39,32 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor120: e3 Location: 12,16 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 Actor121: e1 Location: 10,35 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 4 Actor122: e1 Location: 12,20 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 4 Actor123: e1 Location: 14,20 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 4 Actor124: e3 Location: 52,29 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 3 Actor125: e3 Location: 8,31 @@ -473,7 +473,7 @@ tank: ltnk Location: 8,17 Owner: Nod - Facing: 96 + Facing: 384 HandOfNod: hand Location: 15,15 Owner: Nod @@ -483,7 +483,7 @@ Hunter2: bggy Location: 41,29 Owner: Nod - Facing: 128 + Facing: 512 Hunter3: e3 Location: 37,36 Owner: Nod @@ -528,5 +528,3 @@ Owner: Neutral Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml - -Weapons: weapons.yaml diff -Nru openra-20200503/mods/cnc/maps/gdi04b/weapons.yaml openra-20210321/mods/cnc/maps/gdi04b/weapons.yaml --- openra-20200503/mods/cnc/maps/gdi04b/weapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi04b/weapons.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -Tiberium: - Warhead@1Dam: SpreadDamage - Damage: 400 diff -Nru openra-20200503/mods/cnc/maps/gdi04c/map.yaml openra-20210321/mods/cnc/maps/gdi04c/map.yaml --- openra-20200503/mods/cnc/maps/gdi04c/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi04c/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -436,56 +436,56 @@ Actor136: bggy Location: 58,35 Owner: Nod - Facing: 224 + Facing: 896 Actor137: bggy Location: 52,33 Owner: Nod - Facing: 224 + Facing: 896 Actor138: bggy Location: 42,17 Owner: Nod - Facing: 224 + Facing: 896 Actor139: apc Location: 27,15 Owner: GDI - Facing: 128 + Facing: 512 Actor140: apc Location: 29,15 Owner: GDI - Facing: 128 + Facing: 512 Actor141: jeep Location: 28,15 Owner: GDI - Facing: 128 + Facing: 512 Actor142: e3 Location: 55,22 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 0 Actor143: e1 Location: 50,21 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 4 Actor144: e1 Location: 51,23 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 1 Actor145: e1 Location: 51,22 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 4 Actor146: e1 Location: 50,22 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 1 Actor147: e3 Location: 49,30 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor148: e3 Location: 23,28 @@ -502,7 +502,7 @@ Actor151: e3 Location: 22,23 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 0 Actor154: c2 Location: 23,56 @@ -511,12 +511,12 @@ Actor155: e1 Location: 55,29 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor156: e1 Location: 50,32 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor157: c4 Location: 24,48 @@ -529,22 +529,22 @@ Actor159: c9 Location: 22,54 Owner: Civilians - Facing: 128 + Facing: 512 SubCell: 1 Actor160: e3 Location: 49,29 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor161: e1 Location: 43,55 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 1 Actor162: e1 Location: 42,55 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 3 Actor163: e1 Location: 50,32 @@ -553,57 +553,57 @@ Actor164: e1 Location: 51,33 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 Actor165: e3 Location: 43,18 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 3 Actor166: e3 Location: 43,18 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 2 Actor167: e1 Location: 27,18 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 2 Actor168: e1 Location: 27,17 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 3 Actor169: e1 Location: 27,17 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 4 Actor170: e1 Location: 27,18 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 1 Actor171: e2 Location: 29,17 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 3 Actor172: e2 Location: 29,17 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 4 Actor173: e2 Location: 29,18 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 2 Actor174: e2 Location: 29,18 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 1 Actor175: e1 Location: 26,24 @@ -632,7 +632,7 @@ Actor184: e3 Location: 56,29 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor185: e1 Location: 32,21 diff -Nru openra-20200503/mods/cnc/maps/gdi05a/map.yaml openra-20210321/mods/cnc/maps/gdi05a/map.yaml --- openra-20200503/mods/cnc/maps/gdi05a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi05a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -463,11 +463,11 @@ Actor140: gun Location: 24,23 Owner: Nod - Facing: 96 + Facing: 384 Actor141: gun Location: 24,28 Owner: Nod - Facing: 96 + Facing: 384 Actor152: silo Location: 19,22 Owner: Nod @@ -492,11 +492,11 @@ Actor162: ltnk Location: 9,34 Owner: Nod - Facing: 192 + Facing: 768 Actor164: ltnk Location: 29,37 Owner: Nod - Facing: 96 + Facing: 384 Actor167: bggy Location: 19,27 Owner: Nod @@ -506,7 +506,7 @@ Actor169: bggy Location: 44,34 Owner: Nod - Facing: 32 + Facing: 128 Actor171: e3 Location: 21,28 Owner: Nod @@ -534,17 +534,17 @@ Actor177: e1 Location: 29,40 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 1 Actor178: e3 Location: 26,43 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 3 Actor187: e1 Location: 27,27 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 3 Actor188: e3 Location: 28,21 @@ -553,7 +553,7 @@ Actor189: e3 Location: 26,23 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 Actor190: e3 Location: 33,56 @@ -562,12 +562,12 @@ Actor191: e3 Location: 33,38 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 4 Actor192: e3 Location: 26,27 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 1 Actor193: e3 Location: 36,51 @@ -580,27 +580,27 @@ Actor195: e3 Location: 23,55 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 3 Actor196: e3 Location: 30,44 Owner: Nod - Facing: 192 + Facing: 768 SubCell: 0 Actor197: e3 Location: 32,49 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 4 Actor198: e3 Location: 28,48 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor199: e1 Location: 24,56 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 4 Actor200: e1 Location: 25,55 @@ -609,17 +609,17 @@ Actor201: e1 Location: 17,46 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 0 Actor202: e1 Location: 15,48 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 Actor203: e1 Location: 17,46 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 waypoint27: waypoint Location: 32,41 @@ -674,7 +674,7 @@ GdiHarv: harv Location: 48,53 Owner: AbandonedBase - Facing: 64 + Facing: 256 GdiWeap: weap Location: 50,55 Owner: AbandonedBase @@ -727,7 +727,7 @@ NodHarv: harv Location: 22,26 Owner: Nod - Facing: 64 + Facing: 256 GuardTank1: ltnk Location: 18,27 Owner: Nod @@ -757,5 +757,3 @@ Owner: Neutral Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml - -Weapons: weapons.yaml diff -Nru openra-20200503/mods/cnc/maps/gdi05a/weapons.yaml openra-20210321/mods/cnc/maps/gdi05a/weapons.yaml --- openra-20200503/mods/cnc/maps/gdi05a/weapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi05a/weapons.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -Tiberium: - Warhead@1Dam: SpreadDamage - Damage: 400 diff -Nru openra-20200503/mods/cnc/maps/gdi05b/map.yaml openra-20210321/mods/cnc/maps/gdi05b/map.yaml --- openra-20200503/mods/cnc/maps/gdi05b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi05b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -364,59 +364,59 @@ Actor121: gun Location: 50,27 Owner: Nod - Facing: 128 + Facing: 512 Actor122: gun Location: 45,27 Owner: Nod - Facing: 128 + Facing: 512 Actor127: gun Location: 36,24 Owner: Nod - Facing: 192 + Facing: 768 Actor128: bggy Location: 39,19 Owner: Nod - Facing: 128 + Facing: 512 Actor129: bggy Location: 38,23 Owner: Nod - Facing: 192 + Facing: 768 Actor130: ltnk Location: 38,24 Owner: Nod - Facing: 192 + Facing: 768 Actor131: ltnk Location: 45,21 Owner: Nod - Facing: 128 + Facing: 512 Actor132: ltnk Location: 44,21 Owner: Nod - Facing: 128 + Facing: 512 Actor133: bggy Location: 23,32 Owner: Nod - Facing: 224 + Facing: 896 Actor134: ltnk Location: 13,32 Owner: Nod - Facing: 224 + Facing: 896 Actor135: ltnk Location: 48,41 Owner: Nod - Facing: 96 + Facing: 384 Actor142: bggy Location: 53,27 Owner: Nod - Facing: 160 + Facing: 640 Actor143: bggy Location: 42,27 Owner: Nod - Facing: 96 + Facing: 384 Actor144: e3 Location: 23,29 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor145: e3 Location: 40,30 @@ -429,7 +429,7 @@ Actor147: e3 Location: 43,27 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 0 Actor148: e3 Location: 11,39 @@ -442,37 +442,37 @@ Actor150: e1 Location: 18,40 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor151: e3 Location: 12,38 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 4 Actor152: e3 Location: 12,40 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 1 Actor153: e3 Location: 44,43 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 1 Actor154: e1 Location: 17,27 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor163: e1 Location: 17,25 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 3 Actor164: e3 Location: 21,22 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 Actor165: e3 Location: 18,41 @@ -481,7 +481,7 @@ Actor166: e3 Location: 17,41 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 4 Actor167: moneycrate Location: 26,42 @@ -579,7 +579,7 @@ GdiHarv: harv Location: 27,55 Owner: AbandonedBase - Facing: 64 + Facing: 256 GdiWeap1: weap Location: 35,52 Owner: AbandonedBase diff -Nru openra-20200503/mods/cnc/maps/gdi06/map.yaml openra-20210321/mods/cnc/maps/gdi06/map.yaml --- openra-20200503/mods/cnc/maps/gdi06/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi06/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -673,11 +673,11 @@ Turret1: gun Location: 46,20 Owner: Nod - Facing: 128 + Facing: 512 Turret2: gun Location: 53,20 Owner: Nod - Facing: 128 + Facing: 512 Silo1: silo Location: 42,16 Owner: Nod @@ -784,11 +784,11 @@ Buggy1: bggy Location: 49,16 Owner: Nod - Facing: 128 + Facing: 512 Buggy2: bggy Location: 49,17 Owner: Nod - Facing: 128 + Facing: 512 Actor246: e1 Location: 44,7 Owner: Nod @@ -812,27 +812,27 @@ Actor251: e3 Location: 18,32 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 3 Actor252: e3 Location: 17,32 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 2 Actor253: e3 Location: 21,30 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 3 Actor254: e3.sticky Location: 16,6 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor255: e3.sticky Location: 15,7 Owner: Nod - Facing: 64 + Facing: 256 SubCell: 4 FlameGuy1: e4 Location: 48,15 @@ -853,7 +853,7 @@ Actor260: e3.sticky Location: 21,15 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 0 RocketSoldier1: e3 Location: 48,14 @@ -870,32 +870,32 @@ Actor264: e3 Location: 52,17 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 1 Actor265: e3 Location: 52,17 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 2 Actor266: e3 Location: 47,17 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 1 Actor267: e3 Location: 46,17 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 2 AttackTrigger2: e1 Location: 39,6 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 0 Actor269: e3.sticky Location: 40,25 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 0 Actor270: e1 Location: 53,42 @@ -904,32 +904,32 @@ Actor271: e3 Location: 43,40 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor272: e1 Location: 49,43 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 4 Actor273: e1 Location: 50,43 Owner: Nod - Facing: 128 + Facing: 512 SubCell: 1 Actor274: e1 Location: 53,47 Owner: Nod - Facing: 32 + Facing: 128 SubCell: 3 CivFleeTrigger: e1 Location: 23,36 Owner: Nod - Facing: 224 + Facing: 896 SubCell: 3 Civilian: c8 Location: 22,36 Owner: Neutral - Facing: 96 + Facing: 384 SubCell: 3 CivHideOut: waypoint Location: 26,32 diff -Nru openra-20200503/mods/cnc/maps/gdi06/rules.yaml openra-20210321/mods/cnc/maps/gdi06/rules.yaml --- openra-20200503/mods/cnc/maps/gdi06/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi06/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -61,8 +61,6 @@ Inherits: LST -WithRoof: -Selectable: - SelectionDecorations: - RenderSelectionBars: False RejectsOrders: Cargo: Types: disabled @@ -85,10 +83,10 @@ Inherits: RMBO Health: HP: 30000 - SelfHealing: + ChangesHealth: Step: 500 Delay: 10 - HealIfBelow: 50 + StartIfBelow: 50 DamageCooldown: 200 RenderSprites: Image: RMBO diff -Nru openra-20200503/mods/cnc/maps/gdi07/map.yaml openra-20210321/mods/cnc/maps/gdi07/map.yaml --- openra-20200503/mods/cnc/maps/gdi07/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi07/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -691,7 +691,7 @@ Actor214: gun Location: 41,33 Owner: Nod - Facing: 192 + Facing: 768 Actor215: gun Location: 53,20 Owner: Nod @@ -786,7 +786,7 @@ Actor243: gun Location: 37,14 Owner: Nod - Facing: 160 + Facing: 640 Actor244: bggy Location: 46,12 Owner: Nod @@ -802,19 +802,19 @@ Actor248: bggy Location: 20,3 Owner: Nod - Facing: 128 + Facing: 512 Actor249: bggy Location: 19,3 Owner: Nod - Facing: 128 + Facing: 512 Actor250: harv Location: 49,13 Owner: Nod - Facing: 128 + Facing: 512 Actor251: ltnk Location: 14,4 Owner: Nod - Facing: 128 + Facing: 512 Actor252: ltnk Location: 44,7 Owner: Nod @@ -830,11 +830,11 @@ Actor256: ltnk Location: 6,16 Owner: Nod - Facing: 96 + Facing: 384 Actor257: bggy Location: 23,27 Owner: Nod - Facing: 192 + Facing: 768 Actor258: e3 Location: 39,6 Owner: Nod @@ -846,22 +846,22 @@ Actor260: c6 Location: 29,32 Owner: Neutral - Facing: 96 + Facing: 384 SubCell: 3 Actor261: c4 Location: 34,32 Owner: Neutral - Facing: 160 + Facing: 640 SubCell: 2 Actor262: c3 Location: 29,37 Owner: Neutral - Facing: 224 + Facing: 896 SubCell: 3 Actor263: c2 Location: 27,36 Owner: Neutral - Facing: 32 + Facing: 128 SubCell: 1 Actor264: e1 Location: 48,20 @@ -918,17 +918,17 @@ Actor277: e4 Location: 13,28 Owner: Nod - Facing: 160 + Facing: 640 SubCell: 3 Actor278: e4 Location: 6,18 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 3 Actor279: e4 Location: 7,13 Owner: Nod - Facing: 96 + Facing: 384 SubCell: 1 waypoint27: waypoint Location: 32,32 diff -Nru openra-20200503/mods/cnc/maps/gdi07/rules.yaml openra-20210321/mods/cnc/maps/gdi07/rules.yaml --- openra-20200503/mods/cnc/maps/gdi07/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi07/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -112,8 +112,6 @@ Inherits: LST -WithRoof: -Selectable: - SelectionDecorations: - RenderSelectionBars: False RejectsOrders: Cargo: Types: disabled diff -Nru openra-20200503/mods/cnc/maps/gdi08a/gdi08a.lua openra-20210321/mods/cnc/maps/gdi08a/gdi08a.lua --- openra-20200503/mods/cnc/maps/gdi08a/gdi08a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi08a/gdi08a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -33,7 +33,7 @@ Auto2 = { units = { ['e3'] = 3, ['e4'] = 2 }, waypoints = WaypointGroup3, delay = 50 } Auto3 = { units = { ['ltnk'] = 1, ['bggy'] = 1 }, waypoints = WaypointGroup3, delay = 50 } Auto4 = { units = { ['bggy'] = 2 }, waypoints = WaypointGroup7, delay = 50 } -Auto5 = { units = { ['ltnk'] = 1 }, waypoints = WaypointGroup6, delay = 50 } +Auto5 = { units = { ['ltnk'] = 1 }, waypoints = WaypointGroup6, delay = 50 } Auto6 = { units = { ['arty'] = 1 }, waypoints = WaypointGroup4, delay = 50 } Auto7 = { units = { ['e3'] = 3, ['e4'] = 2 }, waypoints = WaypointGroup6, delay = 50 } Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/gdi08a/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/gdi08a/map.png differ diff -Nru openra-20200503/mods/cnc/maps/gdi08a/map.yaml openra-20210321/mods/cnc/maps/gdi08a/map.yaml --- openra-20200503/mods/cnc/maps/gdi08a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi08a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -523,7 +523,7 @@ Actor153: arty Location: 4,12 Owner: Nod - Facing: 127 + Facing: 508 Actor154: bggy Location: 20,18 Owner: Nod @@ -533,80 +533,80 @@ Actor156: bggy Location: 10,21 Owner: Nod - Facing: 95 + Facing: 380 Actor157: ltnk Location: 40,35 Owner: Nod - Facing: 159 + Facing: 636 Actor158: ltnk Location: 45,23 Owner: Nod - Facing: 95 + Facing: 380 Actor159: ltnk Location: 41,14 Owner: Nod - Facing: 159 + Facing: 636 Actor160: mtnk Location: 42,55 Owner: GDI Health: 35 - Facing: 223 + Facing: 892 Actor161: mtnk Location: 33,52 Owner: GDI Health: 43 - Facing: 31 + Facing: 124 Actor162: apc Location: 37,50 Owner: GDI Health: 68 - Facing: 127 + Facing: 508 Actor163: apc Location: 39,48 Owner: GDI Health: 45 - Facing: 127 + Facing: 508 Actor164: msam Location: 42,49 Owner: GDI Health: 40 - Facing: 95 + Facing: 380 Actor165: msam Location: 41,51 Owner: GDI Health: 50 - Facing: 159 + Facing: 636 Actor166: msam Location: 33,48 Owner: GDI Health: 65 - Facing: 159 + Facing: 636 Actor167: harv Location: 23,23 Owner: Nod - Facing: 95 + Facing: 380 Actor168: harv Location: 38,53 Owner: GDI Health: 51 - Facing: 31 + Facing: 124 Actor169: jeep Location: 36,52 Owner: GDI Health: 72 - Facing: 95 + Facing: 380 Actor170: jeep Location: 34,51 Owner: GDI Health: 31 - Facing: 159 + Facing: 636 Actor171: arty Location: 19,17 Owner: Nod Actor172: ltnk Location: 22,11 Owner: Nod - Facing: 159 + Facing: 636 Actor173: e1 Location: 45,36 Owner: Nod @@ -618,74 +618,74 @@ Actor175: e3 Location: 41,36 Owner: Nod - Facing: 159 + Facing: 636 SubCell: 2 Actor176: e3 Location: 41,36 Owner: Nod - Facing: 159 + Facing: 636 SubCell: 3 Actor177: e3 Location: 42,17 Owner: Nod - Facing: 159 + Facing: 636 SubCell: 0 Actor178: e3 Location: 40,17 Owner: Nod - Facing: 159 + Facing: 636 SubCell: 4 Actor179: e4 Location: 42,15 Owner: Nod - Facing: 159 + Facing: 636 SubCell: 2 Actor180: e4 Location: 42,15 Owner: Nod - Facing: 159 + Facing: 636 SubCell: 3 Actor181: e1 Location: 16,53 Owner: Nod - Facing: 191 + Facing: 764 SubCell: 3 Actor182: e1 Location: 15,53 Owner: Nod - Facing: 191 + Facing: 764 SubCell: 2 Actor183: e1 Location: 17,53 Owner: Nod - Facing: 191 + Facing: 764 SubCell: 3 Actor184: e1 Location: 16,53 Owner: Nod - Facing: 191 + Facing: 764 SubCell: 2 Actor185: c3 Location: 18,50 Owner: Neutral - Facing: 159 + Facing: 636 SubCell: 1 Actor186: e1 Location: 46,51 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 1 Actor187: e1 Location: 44,52 Owner: GDI Health: 87 - Facing: 223 + Facing: 892 SubCell: 2 Actor188: e1 Location: 43,53 Owner: GDI Health: 31 - Facing: 31 + Facing: 124 SubCell: 4 Actor189: e1 Location: 42,54 @@ -696,46 +696,46 @@ Location: 39,52 Owner: GDI Health: 77 - Facing: 159 + Facing: 636 SubCell: 4 Actor191: e1 Location: 42,53 Owner: GDI Health: 69 - Facing: 159 + Facing: 636 SubCell: 0 Actor192: e2 Location: 40,53 Owner: GDI Health: 75 - Facing: 31 + Facing: 124 SubCell: 2 Actor193: e2 Location: 45,51 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 1 Actor194: e2 Location: 38,50 Owner: GDI Health: 27 - Facing: 223 + Facing: 892 SubCell: 0 Actor195: e2 Location: 46,52 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 1 Actor196: e2 Location: 36,53 Owner: GDI Health: 57 - Facing: 159 + Facing: 636 SubCell: 0 Actor197: e2 Location: 37,54 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 1 Actor198: e3 Location: 27,40 diff -Nru openra-20200503/mods/cnc/maps/gdi08a/rules.yaml openra-20210321/mods/cnc/maps/gdi08a/rules.yaml --- openra-20200503/mods/cnc/maps/gdi08a/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi08a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -110,7 +110,7 @@ CYCL: Buildable: Prerequisites: ~disabled - + GTWR: Buildable: Prerequisites: ~disabled @@ -118,11 +118,11 @@ SBAG: Buildable: Queue: Defence.GDI, Defence.Nod - + GUN: Buildable: Queue: Defence.GDI, Defence.Nod - + C3: Tooltip: Name: Farmer Mike diff -Nru openra-20200503/mods/cnc/maps/gdi09/gdi09.lua openra-20210321/mods/cnc/maps/gdi09/gdi09.lua --- openra-20200503/mods/cnc/maps/gdi09/gdi09.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi09/gdi09.lua 2021-03-21 11:10:05.000000000 +0000 @@ -100,7 +100,7 @@ SpawnGunboat = function() Media.PlaySpeechNotification(GDI, "Reinforce") - Actor.Create("boat", true, { Owner = GDI, Facing = 0, Location = CPos.New(62,37) }) + Actor.Create("boat", true, { Owner = GDI, Facing = Angle.North, Location = CPos.New(62,37) }) end WorldLoaded = function() @@ -121,9 +121,10 @@ end) Trigger.OnEnteredFootprint(BoatEscapeTrigger, function(a, id) if a.Type == "boat" then + a.Stop() a.Destroy() Media.DisplayMessage("Part of Carter's convoy passed through!") - Media.PlaySoundNotification(GDI, "AlertBleep") + Media.PlaySoundNotification(GDI, "Beepy6") end end) diff -Nru openra-20200503/mods/cnc/maps/gdi09/map.yaml openra-20210321/mods/cnc/maps/gdi09/map.yaml --- openra-20200503/mods/cnc/maps/gdi09/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/gdi09/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -340,10 +340,10 @@ Actor97: tc04 Location: 45,24 Owner: Neutral - Actor98: split2 + Actor98: t03.transformable Location: 55,23 Owner: Neutral - Actor99: split2 + Actor99: t03.transformable Location: 60,28 Owner: Neutral Actor100: tc04 @@ -460,11 +460,11 @@ gun3: gun Location: 34,33 Owner: Nod - Facing: 159 + Facing: 636 gun4: gun Location: 32,33 Owner: Nod - Facing: 159 + Facing: 636 Actor139: v04 Location: 45,26 Owner: Neutral @@ -547,27 +547,27 @@ gun7: gun Location: 22,25 Owner: Nod - Facing: 191 + Facing: 764 gun8: gun Location: 22,31 Owner: Nod - Facing: 191 + Facing: 764 Actor167: harv Location: 20,28 Owner: Nod - Facing: 191 + Facing: 764 Actor168: ltnk Location: 19,26 Owner: Nod - Facing: 127 + Facing: 508 Actor169: ltnk Location: 18,26 Owner: Nod - Facing: 127 + Facing: 508 Actor170: ltnk Location: 8,28 Owner: Nod - Facing: 127 + Facing: 508 Actor171: bggy Location: 18,31 Owner: Nod @@ -580,11 +580,11 @@ Actor174: arty Location: 8,15 Owner: Nod - Facing: 31 + Facing: 124 Actor175: mcv Location: 54,4 Owner: GDI - Facing: 127 + Facing: 508 Actor176: e3 Location: 19,25 Owner: Nod @@ -612,22 +612,22 @@ Actor182: e4 Location: 7,14 Owner: Nod - Facing: 31 + Facing: 124 SubCell: 3 Actor183: e4 Location: 7,14 Owner: Nod - Facing: 31 + Facing: 124 SubCell: 2 Actor184: e4 Location: 25,6 Owner: Nod - Facing: 191 + Facing: 764 SubCell: 1 Actor185: e4 Location: 25,4 Owner: Nod - Facing: 191 + Facing: 764 SubCell: 3 Actor186: e3 Location: 33,9 @@ -652,72 +652,72 @@ Actor191: e2 Location: 53,6 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 4 Actor192: e2 Location: 54,6 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 3 Actor193: e2 Location: 53,7 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 2 Actor194: e3 Location: 54,6 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 4 Actor195: e3 Location: 55,6 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 3 Actor196: e3 Location: 55,7 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 1 Actor197: e3 Location: 54,7 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 2 Actor198: e2 Location: 54,7 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 1 Actor199: e3 Location: 25,34 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 4 Actor200: e3 Location: 25,34 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 3 Actor201: e3 Location: 24,34 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 4 Actor202: e3 Location: 25,34 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 1 Actor203: e3 Location: 24,34 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 2 Actor204: e3 Location: 25,34 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 2 GDIHeliEntryNorth: waypoint Location: 57,6 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/hattrix.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/hattrix.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/jungle-conflict.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/jungle-conflict.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/letters-from-lexington.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/letters-from-lexington.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/master-alert.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/master-alert.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/master-of-the-jungle-book.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/master-of-the-jungle-book.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/model-150.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/model-150.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/nod02a/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/nod02a/map.bin differ diff -Nru openra-20200503/mods/cnc/maps/nod02a/map.yaml openra-20210321/mods/cnc/maps/nod02a/map.yaml --- openra-20200503/mods/cnc/maps/nod02a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod02a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,7 @@ MapSize: 64,64 -Bounds: 27,34,36,26 +Bounds: 3,23,36,26 Visibility: MissionSelector @@ -23,6 +23,7 @@ Name: GDI Faction: gdi Color: F5D378 + Allies: GDI Enemies: Nod Bot: campaign PlayerReference@Nod: @@ -45,154 +46,192 @@ Actors: Actor0: t08 - Location: 30,52 + Location: 34,38 Owner: Neutral Actor1: t18 - Location: 34,52 + Location: 34,36 Owner: Neutral Actor2: t08 - Location: 57,47 + Location: 25,31 Owner: Neutral Actor3: t08 - Location: 38,59 + Location: 26,31 Owner: Neutral - Actor4: silo - Location: 33,40 + Actor4: t08 + Location: 21,40 + Owner: Neutral + Actor5: t08 + Location: 3,24 + Owner: Neutral + Actor6: t08 + Location: 3,42 + Owner: Neutral + Actor7: t08 + Location: 4,42 + Owner: Neutral + Actor8: t08 + Location: 6,48 + Owner: Neutral + Actor9: t08 + Location: 16,43 + Owner: Neutral + Actor10: t08 + Location: 26,48 + Owner: Neutral + Actor11: t08 + Location: 13,27 + Owner: Neutral + Actor12: t08 + Location: 6,40 + Owner: Neutral + Actor13: rock1 + Location: 22,32 + Owner: Neutral + Actor20: jeep + Location: 5,24 Owner: GDI - Actor9: silo - Location: 32,42 + Facing: 384 + Actor21: jeep + Location: 6,32 Owner: GDI - Actor10: jeep - Location: 30,46 + Facing: 640 + Actor22: jeep + Location: 12,27 Owner: GDI Facing: 128 - Actor11: jeep - Location: 31,35 - Owner: GDI - Facing: 64 - Actor17: e1 - Location: 34,56 + Actor28: e1 + Location: 10,24 Owner: GDI + Facing: 384 SubCell: 3 - Actor18: e1 - Location: 43,35 + Actor29: e1 + Location: 10,24 Owner: GDI - SubCell: 3 - Actor19: e1 - Location: 43,36 + Facing: 384 + SubCell: 1 + Actor30: e1 + Location: 9,24 Owner: GDI - SubCell: 3 + Facing: 384 + SubCell: 4 Actor31: e1 - Location: 47,53 + Location: 5,34 Owner: GDI - SubCell: 4 + SubCell: 3 Actor32: e1 - Location: 49,54 + Location: 5,35 + Owner: GDI + SubCell: 2 + Actor33: e1 + Location: 10,27 + Owner: GDI + SubCell: 2 + Actor34: e1 + Location: 11,27 Owner: GDI - Facing: 224 SubCell: 1 Actor35: e1 - Location: 34,57 + Location: 10,24 Owner: GDI - Facing: 64 - SubCell: 1 - waypoint27: waypoint - Location: 27,51 - Owner: Neutral + Facing: 384 + SubCell: 2 + Actor37: e1 + Location: 7,40 + Owner: GDI + SubCell: 2 waypoint26: waypoint - Location: 49,35 + Location: 26,41 Owner: Neutral - waypoint10: waypoint - Location: 30,44 + waypoint23: waypoint + Location: 33,45 + Owner: Neutral + waypoint21: waypoint + Location: 32,42 + Owner: Neutral + waypoint17: waypoint + Location: 32,26 Owner: Neutral waypoint9: waypoint - Location: 55,40 + Location: 29,47 Owner: Neutral waypoint8: waypoint - Location: 48,41 + Location: 16,28 Owner: Neutral waypoint7: waypoint - Location: 60,58 + Location: 23,40 Owner: Neutral waypoint6: waypoint - Location: 61,47 + Location: 20,47 Owner: Neutral waypoint5: waypoint - Location: 48,55 + Location: 10,44 Owner: Neutral waypoint4: waypoint - Location: 41,51 + Location: 13,36 Owner: Neutral waypoint3: waypoint - Location: 28,36 + Location: 36,41 Owner: Neutral waypoint2: waypoint - Location: 28,51 + Location: 31,28 Owner: Neutral waypoint1: waypoint - Location: 40,43 + Location: 18,25 Owner: Neutral waypoint0: waypoint - Location: 40,35 + Location: 4,26 Owner: Neutral Refinery: proc - Location: 30,38 + Location: 7,27 + Owner: GDI + FreeActor: false + Yard: fact + Location: 10,28 Owner: GDI Barracks: pyle - Location: 34,43 + Location: 7,32 Owner: GDI - Powerplant: nuke - Location: 35,40 + Plant: nuke + Location: 11,31 Owner: GDI - Yard: fact - Location: 33,37 + Silo1: silo + Location: 9,31 + Owner: GDI + Silo2: silo + Location: 9,33 Owner: GDI Guard1: e1 - Location: 42,39 + Location: 8,40 Owner: GDI - Facing: 64 - SubCell: 0 + SubCell: 1 Guard2: e1 - Location: 38,38 + Location: 37,24 Owner: GDI - Facing: 64 - SubCell: 2 + SubCell: 3 Guard3: e1 - Location: 35,49 + Location: 36,24 Owner: GDI - Facing: 96 - SubCell: 0 + SubCell: 2 Guard4: e1 - Location: 34,48 + Location: 27,31 Owner: GDI - Facing: 96 - SubCell: 3 - Guard5: e1 - Location: 39,40 - Owner: GDI - Facing: 64 SubCell: 1 - Guard6: e1 - Location: 40,56 - Owner: GDI - Facing: 96 - SubCell: 4 - Guard7: e1 - Location: 38,54 + Harvester: harv + Location: 5,29 Owner: GDI - Facing: 32 - SubCell: 3 + Health: 39 + Facing: 896 McvEntry: waypoint - Location: 62,43 + Location: 33,48 Owner: Neutral McvRally: waypoint - Location: 57,41 + Location: 33,46 Owner: Neutral UnitsEntry: waypoint - Location: 62,38 + Location: 30,48 Owner: Neutral UnitsRally: waypoint - Location: 56,38 + Location: 30,44 Owner: Neutral Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/cnc/maps/nod02a/nod02a.lua openra-20210321/mods/cnc/maps/nod02a/nod02a.lua --- openra-20200503/mods/cnc/maps/nod02a/nod02a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod02a/nod02a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -10,17 +10,10 @@ NodUnits = { "bggy", "e1", "e1", "e1", "e1", "e1", "bggy", "e1", "e1", "e1", "bggy" } NodBaseBuildings = { "hand", "fact", "nuke" } -GDIBase = { Refinery, Barracks, Powerplant, Yard } -Guards = { Guard1, Guard2, Guard3, Guard4, Guard5, Guard6, Guard7 } +GDIBase = { Refinery, Yard, Barracks, Plant, Silo1, Silo2 } -Atk1CellTriggerActivator = { CPos.New(45,37), CPos.New(44,37), CPos.New(45,36), CPos.New(44,36), CPos.New(45,35), CPos.New(44,35), CPos.New(45,34), CPos.New(44,34) } -Atk4CellTriggerActivator = { CPos.New(50,47), CPos.New(49,47), CPos.New(48,47), CPos.New(47,47), CPos.New(46,47), CPos.New(45,47), CPos.New(44,47), CPos.New(43,47), CPos.New(42,47), CPos.New(41,47), CPos.New(40,47), CPos.New(39,47), CPos.New(38,47), CPos.New(37,47), CPos.New(50,46), CPos.New(49,46), CPos.New(48,46), CPos.New(47,46), CPos.New(46,46), CPos.New(45,46), CPos.New(44,46), CPos.New(43,46), CPos.New(42,46), CPos.New(41,46), CPos.New(40,46), CPos.New(39,46), CPos.New(38,46) } - -Atk1Waypoints = { waypoint2, waypoint4, waypoint5, waypoint6 } -Atk2Waypoints = { waypoint2, waypoint5, waypoint7, waypoint6 } -Atk3Waypoints = { waypoint2, waypoint4, waypoint5, waypoint9 } -Atk4Waypoints = { waypoint0, waypoint8, waypoint9 } -Pat1Waypoints = { waypoint0, waypoint1, waypoint2, waypoint3 } +GDIWaypoints1 = { waypoint0, waypoint1, waypoint2, waypoint3 } +GDIWaypoints2 = { waypoint0, waypoint1, waypoint4, waypoint5, waypoint6, waypoint7, waypoint9 } GetAttackers = function(amount) local units = GDI.GetActorsByType("e1") @@ -38,57 +31,50 @@ InitObjectives(Nod) - BuildBase = Nod.AddObjective("Build a base.") - DestroyGDI = Nod.AddObjective("Destroy the GDI base.") GDIObjective = GDI.AddObjective("Kill all enemies.") + BuildBase = Nod.AddObjective("Build a base.") + DestroyGDI = Nod.AddObjective("Destroy all GDI units.") - Utils.Do(Guards, function(actor) + Utils.Do({ Refinery, Yard }, function(actor) Trigger.OnDamaged(actor, function() - if Atk3TriggerSwitch then - return + if not Grd2TriggerSwitch then + Grd2TriggerSwitch = true + Utils.Do(GetAttackers(5), IdleHunt) end - - Atk3TriggerSwitch = true - MoveAndHunt(GetAttackers(4), Atk3Waypoints) end) end) - Trigger.OnAllRemovedFromWorld(GDIBase, function() - Utils.Do(GDI.GetGroundAttackers(), IdleHunt) + Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(25), function() + MoveAndHunt(GetAttackers(2), GDIWaypoints1) end) - Trigger.AfterDelay(DateTime.Seconds(40), function() - MoveAndHunt(GetAttackers(3), Atk2Waypoints) + Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(20), function() + MoveAndHunt(GetAttackers(3), GDIWaypoints2) end) - Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(15), function() - MoveAndHunt(GetAttackers(3), Atk2Waypoints) + Trigger.OnKilled(Guard1, function() + MoveAndHunt(GetAttackers(3), GDIWaypoints2) end) - Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(20), function() - MoveAndHunt(GetAttackers(3), Atk3Waypoints) + Trigger.OnKilled(Guard4, function() + MoveAndHunt(GetAttackers(2), GDIWaypoints1) end) - Trigger.AfterDelay(DateTime.Seconds(50), function() - MoveAndHunt(GetAttackers(3), Atk4Waypoints) + Trigger.OnAllKilled({ Guard2, Guard3 }, function() + MoveAndHunt(GetAttackers(2), GDIWaypoints1) end) - Trigger.AfterDelay(DateTime.Seconds(30), function() - MoveAndHunt(GetAttackers(3), Pat1Waypoints) - end) - - Trigger.OnEnteredFootprint(Atk1CellTriggerActivator, function(a, id) - if a.Owner == Nod then - MoveAndHunt(GetAttackers(5), Atk1Waypoints) - Trigger.RemoveFootprintTrigger(id) + Trigger.OnDamaged(Harvester, function() + if Atk5TriggerSwitch then + return end + + Atk5TriggerSwitch = true + MoveAndHunt(GetAttackers(3), GDIWaypoints2) end) - Trigger.OnEnteredFootprint(Atk4CellTriggerActivator, function(a, id) - if a.Owner == Nod then - MoveAndHunt(GetAttackers(3), Atk2Waypoints) - Trigger.RemoveFootprintTrigger(id) - end + Trigger.OnAllRemovedFromWorld(GDIBase, function() + Utils.Do(GDI.GetGroundAttackers(), IdleHunt) end) Trigger.AfterDelay(0, function() @@ -103,14 +89,14 @@ end Tick = function() - if GDI.HasNoRequiredUnits() then - Nod.MarkCompletedObjective(DestroyGDI) - end - if DateTime.GameTime > 2 and Nod.HasNoRequiredUnits() then GDI.MarkCompletedObjective(GDIObjective) end + if GDI.HasNoRequiredUnits() then + Nod.MarkCompletedObjective(DestroyGDI) + end + if DateTime.GameTime % DateTime.Seconds(1) == 0 and not Nod.IsObjectiveCompleted(BuildBase) and CheckForBase(Nod, NodBaseBuildings) then Nod.MarkCompletedObjective(BuildBase) end diff -Nru openra-20200503/mods/cnc/maps/nod02a/rules.yaml openra-20210321/mods/cnc/maps/nod02a/rules.yaml --- openra-20200503/mods/cnc/maps/nod02a/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod02a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,7 +1,3 @@ -Player: - PlayerResources: - DefaultCash: 4000 - World: LuaScript: Scripts: campaign-global.lua, nod02a.lua @@ -15,60 +11,9 @@ WinVideo: airstrk.vqa LossVideo: deskill.vqa -^Vehicle: - Tooltip: - GenericVisibility: Enemy - ShowOwnerRow: false - RenderSprites: - PlayerPalette: player-units - -^Tank: - Tooltip: - GenericVisibility: Enemy - ShowOwnerRow: false - RenderSprites: - PlayerPalette: player-units - -^Helicopter: - Tooltip: - GenericVisibility: Enemy - ShowOwnerRow: false - RenderSprites: - PlayerPalette: player-units - -^Infantry: - Tooltip: - GenericVisibility: Enemy - ShowOwnerRow: false - RenderSprites: - PlayerPalette: player-units - -^Plane: - Tooltip: - GenericVisibility: Enemy - ShowOwnerRow: false - -^Ship: - Tooltip: - GenericVisibility: Enemy - ShowOwnerRow: false - -^Building: - Tooltip: - GenericVisibility: Enemy - ShowOwnerRow: false - -^Wall: - Tooltip: - ShowOwnerRow: false - -^CommonHuskDefaults: - Tooltip: - GenericVisibility: Enemy, Ally, Neutral - GenericStancePrefix: false - ShowOwnerRow: false - RenderSprites: - PlayerPalette: player-units +Player: + PlayerResources: + DefaultCash: 4000 NUK2: Buildable: @@ -129,20 +74,6 @@ MCV: Buildable: Prerequisites: ~disabled - RenderSprites: - PlayerPalette: player - -MCV.Husk: - RenderSprites: - PlayerPalette: player - -HARV: - RenderSprites: - PlayerPalette: player - -HARV.Husk: - RenderSprites: - PlayerPalette: player SAM: Buildable: Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/nod02b/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/nod02b/map.bin differ diff -Nru openra-20200503/mods/cnc/maps/nod02b/map.yaml openra-20210321/mods/cnc/maps/nod02b/map.yaml --- openra-20200503/mods/cnc/maps/nod02b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod02b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,7 @@ MapSize: 64,64 -Bounds: 3,23,36,26 +Bounds: 27,34,36,26 Visibility: MissionSelector @@ -23,7 +23,6 @@ Name: GDI Faction: gdi Color: F5D378 - Allies: GDI Enemies: Nod Bot: campaign PlayerReference@Nod: @@ -46,192 +45,154 @@ Actors: Actor0: t08 - Location: 34,38 + Location: 30,52 Owner: Neutral Actor1: t18 - Location: 34,36 + Location: 34,52 Owner: Neutral Actor2: t08 - Location: 25,31 + Location: 57,47 Owner: Neutral Actor3: t08 - Location: 26,31 + Location: 38,59 Owner: Neutral - Actor4: t08 - Location: 21,40 - Owner: Neutral - Actor5: t08 - Location: 3,24 - Owner: Neutral - Actor6: t08 - Location: 3,42 - Owner: Neutral - Actor7: t08 - Location: 4,42 - Owner: Neutral - Actor8: t08 - Location: 6,48 - Owner: Neutral - Actor9: t08 - Location: 16,43 - Owner: Neutral - Actor10: t08 - Location: 26,48 - Owner: Neutral - Actor11: t08 - Location: 13,27 - Owner: Neutral - Actor12: t08 - Location: 6,40 - Owner: Neutral - Actor13: rock1 - Location: 22,32 - Owner: Neutral - Actor20: jeep - Location: 5,24 + Actor4: silo + Location: 33,40 Owner: GDI - Facing: 96 - Actor21: jeep - Location: 6,32 + Actor9: silo + Location: 32,42 Owner: GDI - Facing: 160 - Actor22: jeep - Location: 12,27 + Actor10: jeep + Location: 30,46 Owner: GDI - Facing: 32 - Actor28: e1 - Location: 10,24 + Facing: 512 + Actor11: jeep + Location: 31,35 + Owner: GDI + Facing: 256 + Actor17: e1 + Location: 34,56 Owner: GDI - Facing: 96 SubCell: 3 - Actor29: e1 - Location: 10,24 + Actor18: e1 + Location: 43,35 Owner: GDI - Facing: 96 - SubCell: 1 - Actor30: e1 - Location: 9,24 + SubCell: 3 + Actor19: e1 + Location: 43,36 Owner: GDI - Facing: 96 - SubCell: 4 + SubCell: 3 Actor31: e1 - Location: 5,34 + Location: 47,53 Owner: GDI - SubCell: 3 + SubCell: 4 Actor32: e1 - Location: 5,35 - Owner: GDI - SubCell: 2 - Actor33: e1 - Location: 10,27 - Owner: GDI - SubCell: 2 - Actor34: e1 - Location: 11,27 + Location: 49,54 Owner: GDI + Facing: 896 SubCell: 1 Actor35: e1 - Location: 10,24 - Owner: GDI - Facing: 96 - SubCell: 2 - Actor37: e1 - Location: 7,40 + Location: 34,57 Owner: GDI - SubCell: 2 - waypoint26: waypoint - Location: 26,41 - Owner: Neutral - waypoint23: waypoint - Location: 33,45 + Facing: 256 + SubCell: 1 + waypoint27: waypoint + Location: 27,51 Owner: Neutral - waypoint21: waypoint - Location: 32,42 + waypoint26: waypoint + Location: 49,35 Owner: Neutral - waypoint17: waypoint - Location: 32,26 + waypoint10: waypoint + Location: 30,44 Owner: Neutral waypoint9: waypoint - Location: 29,47 + Location: 55,40 Owner: Neutral waypoint8: waypoint - Location: 16,28 + Location: 48,41 Owner: Neutral waypoint7: waypoint - Location: 23,40 + Location: 60,58 Owner: Neutral waypoint6: waypoint - Location: 20,47 + Location: 61,47 Owner: Neutral waypoint5: waypoint - Location: 10,44 + Location: 48,55 Owner: Neutral waypoint4: waypoint - Location: 13,36 + Location: 41,51 Owner: Neutral waypoint3: waypoint - Location: 36,41 + Location: 28,36 Owner: Neutral waypoint2: waypoint - Location: 31,28 + Location: 28,51 Owner: Neutral waypoint1: waypoint - Location: 18,25 + Location: 40,43 Owner: Neutral waypoint0: waypoint - Location: 4,26 + Location: 40,35 Owner: Neutral Refinery: proc - Location: 7,27 - Owner: GDI - FreeActor: false - Yard: fact - Location: 10,28 + Location: 30,38 Owner: GDI Barracks: pyle - Location: 7,32 - Owner: GDI - Plant: nuke - Location: 11,31 + Location: 34,43 Owner: GDI - Silo1: silo - Location: 9,31 + Powerplant: nuke + Location: 35,40 Owner: GDI - Silo2: silo - Location: 9,33 + Yard: fact + Location: 33,37 Owner: GDI Guard1: e1 - Location: 8,40 + Location: 42,39 Owner: GDI - SubCell: 1 + Facing: 256 + SubCell: 0 Guard2: e1 - Location: 37,24 + Location: 38,38 Owner: GDI - SubCell: 3 + Facing: 256 + SubCell: 2 Guard3: e1 - Location: 36,24 + Location: 35,49 Owner: GDI - SubCell: 2 + Facing: 384 + SubCell: 0 Guard4: e1 - Location: 27,31 + Location: 34,48 Owner: GDI + Facing: 384 + SubCell: 3 + Guard5: e1 + Location: 39,40 + Owner: GDI + Facing: 256 SubCell: 1 - Harvester: harv - Location: 5,29 + Guard6: e1 + Location: 40,56 + Owner: GDI + Facing: 384 + SubCell: 4 + Guard7: e1 + Location: 38,54 Owner: GDI - Health: 39 - Facing: 224 + Facing: 128 + SubCell: 3 McvEntry: waypoint - Location: 33,48 + Location: 62,43 Owner: Neutral McvRally: waypoint - Location: 33,46 + Location: 57,41 Owner: Neutral UnitsEntry: waypoint - Location: 30,48 + Location: 62,38 Owner: Neutral UnitsRally: waypoint - Location: 30,44 + Location: 56,38 Owner: Neutral Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/cnc/maps/nod02b/nod02b.lua openra-20210321/mods/cnc/maps/nod02b/nod02b.lua --- openra-20200503/mods/cnc/maps/nod02b/nod02b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod02b/nod02b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -10,10 +10,17 @@ NodUnits = { "bggy", "e1", "e1", "e1", "e1", "e1", "bggy", "e1", "e1", "e1", "bggy" } NodBaseBuildings = { "hand", "fact", "nuke" } -GDIBase = { Refinery, Yard, Barracks, Plant, Silo1, Silo2 } +GDIBase = { Refinery, Barracks, Powerplant, Yard } +Guards = { Guard1, Guard2, Guard3, Guard4, Guard5, Guard6, Guard7 } -GDIWaypoints1 = { waypoint0, waypoint1, waypoint2, waypoint3 } -GDIWaypoints2 = { waypoint0, waypoint1, waypoint4, waypoint5, waypoint6, waypoint7, waypoint9 } +Atk1CellTriggerActivator = { CPos.New(45,37), CPos.New(44,37), CPos.New(45,36), CPos.New(44,36), CPos.New(45,35), CPos.New(44,35), CPos.New(45,34), CPos.New(44,34) } +Atk4CellTriggerActivator = { CPos.New(50,47), CPos.New(49,47), CPos.New(48,47), CPos.New(47,47), CPos.New(46,47), CPos.New(45,47), CPos.New(44,47), CPos.New(43,47), CPos.New(42,47), CPos.New(41,47), CPos.New(40,47), CPos.New(39,47), CPos.New(38,47), CPos.New(37,47), CPos.New(50,46), CPos.New(49,46), CPos.New(48,46), CPos.New(47,46), CPos.New(46,46), CPos.New(45,46), CPos.New(44,46), CPos.New(43,46), CPos.New(42,46), CPos.New(41,46), CPos.New(40,46), CPos.New(39,46), CPos.New(38,46) } + +Atk1Waypoints = { waypoint2, waypoint4, waypoint5, waypoint6 } +Atk2Waypoints = { waypoint2, waypoint5, waypoint7, waypoint6 } +Atk3Waypoints = { waypoint2, waypoint4, waypoint5, waypoint9 } +Atk4Waypoints = { waypoint0, waypoint8, waypoint9 } +Pat1Waypoints = { waypoint0, waypoint1, waypoint2, waypoint3 } GetAttackers = function(amount) local units = GDI.GetActorsByType("e1") @@ -31,50 +38,57 @@ InitObjectives(Nod) - GDIObjective = GDI.AddObjective("Kill all enemies.") BuildBase = Nod.AddObjective("Build a base.") - DestroyGDI = Nod.AddObjective("Destroy all GDI units.") + DestroyGDI = Nod.AddObjective("Destroy the GDI base.") + GDIObjective = GDI.AddObjective("Kill all enemies.") - Utils.Do({ Refinery, Yard }, function(actor) + Utils.Do(Guards, function(actor) Trigger.OnDamaged(actor, function() - if not Grd2TriggerSwitch then - Grd2TriggerSwitch = true - Utils.Do(GetAttackers(5), IdleHunt) + if Atk3TriggerSwitch then + return end + + Atk3TriggerSwitch = true + MoveAndHunt(GetAttackers(4), Atk3Waypoints) end) end) - Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(25), function() - MoveAndHunt(GetAttackers(2), GDIWaypoints1) + Trigger.OnAllRemovedFromWorld(GDIBase, function() + Utils.Do(GDI.GetGroundAttackers(), IdleHunt) end) - Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(20), function() - MoveAndHunt(GetAttackers(3), GDIWaypoints2) + Trigger.AfterDelay(DateTime.Seconds(40), function() + MoveAndHunt(GetAttackers(3), Atk2Waypoints) end) - Trigger.OnKilled(Guard1, function() - MoveAndHunt(GetAttackers(3), GDIWaypoints2) + Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(15), function() + MoveAndHunt(GetAttackers(3), Atk2Waypoints) end) - Trigger.OnKilled(Guard4, function() - MoveAndHunt(GetAttackers(2), GDIWaypoints1) + Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(20), function() + MoveAndHunt(GetAttackers(3), Atk3Waypoints) end) - Trigger.OnAllKilled({ Guard2, Guard3 }, function() - MoveAndHunt(GetAttackers(2), GDIWaypoints1) + Trigger.AfterDelay(DateTime.Seconds(50), function() + MoveAndHunt(GetAttackers(3), Atk4Waypoints) end) - Trigger.OnDamaged(Harvester, function() - if Atk5TriggerSwitch then - return - end + Trigger.AfterDelay(DateTime.Seconds(30), function() + MoveAndHunt(GetAttackers(3), Pat1Waypoints) + end) - Atk5TriggerSwitch = true - MoveAndHunt(GetAttackers(3), GDIWaypoints2) + Trigger.OnEnteredFootprint(Atk1CellTriggerActivator, function(a, id) + if a.Owner == Nod then + MoveAndHunt(GetAttackers(5), Atk1Waypoints) + Trigger.RemoveFootprintTrigger(id) + end end) - Trigger.OnAllRemovedFromWorld(GDIBase, function() - Utils.Do(GDI.GetGroundAttackers(), IdleHunt) + Trigger.OnEnteredFootprint(Atk4CellTriggerActivator, function(a, id) + if a.Owner == Nod then + MoveAndHunt(GetAttackers(3), Atk2Waypoints) + Trigger.RemoveFootprintTrigger(id) + end end) Trigger.AfterDelay(0, function() @@ -89,14 +103,14 @@ end Tick = function() - if DateTime.GameTime > 2 and Nod.HasNoRequiredUnits() then - GDI.MarkCompletedObjective(GDIObjective) - end - if GDI.HasNoRequiredUnits() then Nod.MarkCompletedObjective(DestroyGDI) end + if DateTime.GameTime > 2 and Nod.HasNoRequiredUnits() then + GDI.MarkCompletedObjective(GDIObjective) + end + if DateTime.GameTime % DateTime.Seconds(1) == 0 and not Nod.IsObjectiveCompleted(BuildBase) and CheckForBase(Nod, NodBaseBuildings) then Nod.MarkCompletedObjective(BuildBase) end diff -Nru openra-20200503/mods/cnc/maps/nod02b/rules.yaml openra-20210321/mods/cnc/maps/nod02b/rules.yaml --- openra-20200503/mods/cnc/maps/nod02b/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod02b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,3 +1,7 @@ +Player: + PlayerResources: + DefaultCash: 4000 + World: LuaScript: Scripts: campaign-global.lua, nod02b.lua @@ -11,9 +15,60 @@ WinVideo: airstrk.vqa LossVideo: deskill.vqa -Player: - PlayerResources: - DefaultCash: 4000 +^Vehicle: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + RenderSprites: + PlayerPalette: player-units + +^Tank: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + RenderSprites: + PlayerPalette: player-units + +^Helicopter: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + RenderSprites: + PlayerPalette: player-units + +^Infantry: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + RenderSprites: + PlayerPalette: player-units + +^Plane: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + +^Ship: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + +^Building: + Tooltip: + GenericVisibility: Enemy + ShowOwnerRow: false + +^Wall: + Tooltip: + ShowOwnerRow: false + +^CommonHuskDefaults: + Tooltip: + GenericVisibility: Enemy, Ally, Neutral + GenericStancePrefix: false + ShowOwnerRow: false + RenderSprites: + PlayerPalette: player-units NUK2: Buildable: @@ -74,6 +129,20 @@ MCV: Buildable: Prerequisites: ~disabled + RenderSprites: + PlayerPalette: player + +MCV.Husk: + RenderSprites: + PlayerPalette: player + +HARV: + RenderSprites: + PlayerPalette: player + +HARV.Husk: + RenderSprites: + PlayerPalette: player SAM: Buildable: Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/nod03a/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/nod03a/map.png differ diff -Nru openra-20200503/mods/cnc/maps/nod03a/map.yaml openra-20210321/mods/cnc/maps/nod03a/map.yaml --- openra-20200503/mods/cnc/maps/nod03a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod03a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -286,28 +286,28 @@ Actor82: jeep Location: 21,22 Owner: GDI - Facing: 128 + Facing: 512 Actor83: jeep Location: 20,22 Owner: GDI - Facing: 128 + Facing: 512 Actor84: jeep Location: 18,17 Owner: GDI - Facing: 128 + Facing: 512 Actor89: jeep Location: 29,34 Owner: GDI - Facing: 96 + Facing: 384 Actor95: e1 Location: 33,20 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 2 Actor96: e1 Location: 34,19 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 3 Actor99: e1 Location: 14,44 @@ -316,48 +316,48 @@ Actor100: e1 Location: 33,31 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 4 Actor101: e1 Location: 34,23 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 2 Actor102: c1 Location: 19,40 Owner: Neutral - Facing: 96 + Facing: 384 SubCell: 1 Actor103: c3 Location: 19,39 Owner: Neutral - Facing: 96 + Facing: 384 SubCell: 3 Actor104: c5 Location: 15,42 Owner: Neutral - Facing: 32 + Facing: 128 SubCell: 2 Actor105: c6 Location: 14,37 Owner: Neutral Health: 60 - Facing: 96 + Facing: 384 SubCell: 1 Actor106: c7 Location: 15,41 Owner: Neutral - Facing: 224 + Facing: 896 SubCell: 0 Actor108: e1 Location: 34,31 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 3 Actor109: e1 Location: 34,25 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 2 Actor111: e1 Location: 39,31 @@ -366,27 +366,27 @@ Actor112: e1 Location: 40,37 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 0 Actor116: e2 Location: 34,22 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 3 Actor117: e2 Location: 34,23 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 4 Actor118: e2 Location: 42,18 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 4 Actor119: e2 Location: 33,19 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 0 TechCenter: miss Location: 14,17 @@ -397,17 +397,17 @@ VillageGuard01: e1 Location: 38,22 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 2 VillageGuard02: e1 Location: 38,22 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 3 VillageGuard03: e1 Location: 39,22 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 3 PlayerBase: waypoint Location: 50,38 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/nod03b/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/nod03b/map.png differ diff -Nru openra-20200503/mods/cnc/maps/nod03b/map.yaml openra-20210321/mods/cnc/maps/nod03b/map.yaml --- openra-20200503/mods/cnc/maps/nod03b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod03b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -49,47 +49,47 @@ Actor117: e1 Location: 41,21 Owner: GDI - Facing: 192 + Facing: 768 SubCell: 0 Actor118: e1 Location: 48,21 Owner: GDI - Facing: 192 + Facing: 768 SubCell: 4 Actor119: e2 Location: 27,25 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 0 Actor120: e2 Location: 36,30 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 4 Actor121: e2 Location: 41,39 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 1 Actor122: e2 Location: 42,49 Owner: GDI - Facing: 32 + Facing: 128 SubCell: 0 Actor123: e2 Location: 43,26 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 1 Actor111: e1 Location: 34,31 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 4 Actor106: e1 Location: 40,22 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 2 Actor107: e1 Location: 40,21 @@ -102,12 +102,12 @@ Actor109: e1 Location: 34,24 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 3 Actor86: e1 Location: 51,21 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 0 Actor87: e1 Location: 16,39 @@ -116,27 +116,27 @@ Actor88: e1 Location: 20,28 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 2 Actor89: e1 Location: 19,21 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 1 Actor90: e1 Location: 30,43 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 1 Actor91: e1 Location: 30,43 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 4 Actor92: e1 Location: 34,32 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 4 Actor93: e1 Location: 23,35 @@ -145,22 +145,22 @@ Actor94: e1 Location: 17,32 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 1 Actor95: e1 Location: 24,43 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 0 Actor96: e1 Location: 15,37 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 1 Actor97: e1 Location: 24,30 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 3 Actor98: e1 Location: 35,27 @@ -169,7 +169,7 @@ Actor82: e1 Location: 25,43 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 0 Actor0: sbag Location: 30,22 @@ -375,37 +375,37 @@ Actor72: jeep Location: 28,21 Owner: GDI - Facing: 128 + Facing: 512 Actor73: jeep Location: 35,30 Owner: GDI - Facing: 96 + Facing: 384 Actor74: jeep Location: 32,36 Owner: GDI - Facing: 96 + Facing: 384 Actor75: jeep Location: 29,21 Owner: GDI - Facing: 128 + Facing: 512 Actor77: jeep Location: 47,21 Owner: GDI - Facing: 160 + Facing: 640 Actor101: c1 Location: 16,36 Owner: Neutral - Facing: 192 + Facing: 768 SubCell: 4 Actor102: c3 Location: 17,40 Owner: Neutral - Facing: 224 + Facing: 896 SubCell: 2 Actor103: c5 Location: 16,40 Owner: Neutral - Facing: 224 + Facing: 896 SubCell: 1 Actor104: c6 Location: 14,36 @@ -415,7 +415,7 @@ Actor105: c7 Location: 18,38 Owner: Neutral - Facing: 224 + Facing: 896 SubCell: 4 TechCenter: miss Location: 14,17 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/nod04a/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/nod04a/map.bin differ diff -Nru openra-20200503/mods/cnc/maps/nod04a/map.yaml openra-20210321/mods/cnc/maps/nod04a/map.yaml --- openra-20200503/mods/cnc/maps/nod04a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod04a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,7 +2,7 @@ RequiresMod: cnc -Title: 04a: Mao Civil War +Title: 04a: Oum Hadjer Author: Westwood Studios @@ -10,7 +10,7 @@ MapSize: 64,64 -Bounds: 11,6,46,34 +Bounds: 7,17,52,44 Visibility: MissionSelector @@ -19,26 +19,21 @@ LockPreview: True Players: - PlayerReference@Neutral: - Name: Neutral - OwnsWorld: True - NonCombatant: True - Faction: gdi - PlayerReference@NodSupporter: - Name: NodSupporter - NonCombatant: True - Faction: nod - Bot: campaign PlayerReference@GDI: Name: GDI + Bot: campaign Faction: gdi Color: F5D378 Enemies: Nod - Bot: campaign + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: gdi PlayerReference@Nod: Name: Nod - Playable: True AllowBots: False + Playable: True Required: True LockFaction: True Faction: nod @@ -49,491 +44,437 @@ Enemies: GDI Actors: - Actor0: t08 - Location: 34,20 + Actor0: sbag + Location: 58,26 Owner: Neutral - Actor1: t18 - Location: 33,18 + Actor1: sbag + Location: 57,26 Owner: Neutral - Actor2: t18 - Location: 33,9 + Actor2: sbag + Location: 56,26 Owner: Neutral - Actor3: t08 - Location: 41,5 + Actor3: sbag + Location: 55,26 Owner: Neutral - Actor4: t18 - Location: 42,15 + Actor4: sbag + Location: 54,26 Owner: Neutral - Actor5: t08 - Location: 45,26 + Actor5: sbag + Location: 53,26 Owner: Neutral - Actor6: t08 - Location: 56,29 + Actor6: sbag + Location: 52,26 Owner: Neutral - Actor7: t08 - Location: 55,29 - Owner: Neutral - Actor8: t08 + Actor7: sbag Location: 51,26 Owner: Neutral - Actor9: t08 - Location: 56,18 + Actor8: sbag + Location: 50,26 Owner: Neutral - Actor10: t08 - Location: 52,16 + Actor9: sbag + Location: 49,26 Owner: Neutral - Actor11: t08 - Location: 45,21 + Actor10: sbag + Location: 48,26 Owner: Neutral - Actor12: t08 - Location: 38,19 - Owner: Neutral - Actor13: t08 - Location: 23,16 - Owner: Neutral - Actor14: t08 - Location: 14,22 - Owner: Neutral - Actor15: t08 - Location: 26,22 - Owner: Neutral - Actor16: t08 - Location: 21,26 - Owner: Neutral - Actor17: t08 - Location: 48,6 - Owner: Neutral - Actor18: t08 - Location: 15,19 - Owner: Neutral - Actor19: t08 - Location: 31,15 - Owner: Neutral - Actor20: t18 - Location: 49,34 - Owner: Neutral - Actor21: t18 - Location: 48,38 - Owner: Neutral - Actor22: t18 - Location: 42,35 - Owner: Neutral - Actor23: t18 - Location: 54,37 - Owner: Neutral - Actor24: t08 - Location: 51,35 - Owner: Neutral - Actor25: t08 - Location: 45,37 - Owner: Neutral - Actor26: t08 - Location: 47,33 - Owner: Neutral - Actor27: t18 - Location: 13,10 - Owner: Neutral - Actor28: t18 - Location: 20,7 - Owner: Neutral - Actor30: t08 - Location: 12,8 - Owner: Neutral - Actor31: t08 - Location: 23,9 - Owner: Neutral - Actor32: v35 - Location: 48,38 - Owner: NodSupporter - Actor33: v34 - Location: 46,33 - Owner: NodSupporter - Actor35: v32 - Location: 54,35 - Owner: NodSupporter - Actor36: v30 - Location: 48,32 - Owner: NodSupporter - Actor37: v30 - Location: 52,34 - Owner: NodSupporter - Actor38: v31 - Location: 52,35 - Owner: NodSupporter - Actor39: v32 - Location: 46,37 - Owner: NodSupporter - Health: 73 - Actor41: v34 - Location: 49,38 - Owner: NodSupporter - Actor42: v35 - Location: 46,32 - Owner: NodSupporter - Actor43: v36 - Location: 48,37 - Owner: NodSupporter - Actor44: v32 - Location: 49,33 - Owner: NodSupporter - Actor45: v34 - Location: 50,34 - Owner: NodSupporter - Actor46: v20 - Location: 15,10 - Owner: GDI - Actor47: v21 - Location: 12,10 - Owner: GDI - Actor48: v22 - Location: 21,11 - Owner: GDI - Actor49: v23 - Location: 22,8 - Owner: GDI - Actor50: v24 - Location: 18,8 - Owner: GDI - Actor51: v25 - Location: 13,7 - Owner: GDI - Actor52: v26 - Location: 20,9 - Owner: GDI - Actor53: v27 - Location: 15,9 - Owner: GDI - Actor54: v27 - Location: 14,9 - Owner: GDI - Actor55: v27 - Location: 13,9 - Owner: GDI - Actor56: v28 - Location: 21,7 - Owner: GDI - Actor57: v29 - Location: 22,7 - Owner: GDI - Actor58: v30 - Location: 21,10 - Owner: GDI - Actor59: v30 - Location: 23,8 - Owner: GDI - Actor61: jeep - Location: 15,23 - Owner: GDI - Facing: 160 - Actor62: jeep - Location: 36,6 - Owner: GDI - Facing: 96 - Actor65: mtnk - Location: 29,10 - Owner: GDI - Facing: 64 - Actor71: jeep - Location: 24,26 - Owner: GDI - Facing: 96 - Actor72: jeep - Location: 37,19 - Owner: GDI - Facing: 32 - Actor73: jeep - Location: 27,33 - Owner: GDI - Facing: 96 - Actor86: e1 - Location: 43,15 - Owner: GDI - Health: 88 - Facing: 32 - SubCell: 3 - Actor99: e1 - Location: 45,15 - Owner: GDI - SubCell: 3 - Actor100: e1 - Location: 43,15 + Actor11: sbag + Location: 47,26 + Owner: Neutral + Actor12: sbag + Location: 58,25 + Owner: Neutral + Actor13: sbag + Location: 47,25 + Owner: Neutral + Actor14: sbag + Location: 58,24 + Owner: Neutral + Actor15: sbag + Location: 47,24 + Owner: Neutral + Actor16: sbag + Location: 58,23 + Owner: Neutral + Actor17: sbag + Location: 58,22 + Owner: Neutral + Actor18: sbag + Location: 58,21 + Owner: Neutral + Actor19: sbag + Location: 47,21 + Owner: Neutral + Actor20: sbag + Location: 58,20 + Owner: Neutral + Actor21: sbag + Location: 47,20 + Owner: Neutral + Actor22: sbag + Location: 58,19 + Owner: Neutral + Actor23: sbag + Location: 47,19 + Owner: Neutral + Actor24: sbag + Location: 58,18 + Owner: Neutral + Actor25: sbag + Location: 57,18 + Owner: Neutral + Actor26: sbag + Location: 48,18 + Owner: Neutral + Actor27: sbag + Location: 47,18 + Owner: Neutral + Actor28: sbag + Location: 58,17 + Owner: Neutral + Actor29: sbag + Location: 57,17 + Owner: Neutral + Actor30: sbag + Location: 56,17 + Owner: Neutral + Actor31: sbag + Location: 55,17 + Owner: Neutral + Actor32: sbag + Location: 54,17 + Owner: Neutral + Actor33: sbag + Location: 53,17 + Owner: Neutral + Actor34: sbag + Location: 52,17 + Owner: Neutral + Actor35: sbag + Location: 51,17 + Owner: Neutral + Actor36: sbag + Location: 50,17 + Owner: Neutral + Actor37: sbag + Location: 49,17 + Owner: Neutral + Actor38: sbag + Location: 48,17 + Owner: Neutral + Actor39: sbag + Location: 47,17 + Owner: Neutral + Actor40: t18 + Location: 47,50 + Owner: Neutral + Actor41: t18 + Location: 46,31 + Owner: Neutral + Actor42: t08 + Location: 39,26 + Owner: Neutral + Actor43: t18 + Location: 37,25 + Owner: Neutral + Actor44: t18 + Location: 27,28 + Owner: Neutral + Actor45: t18 + Location: 54,26 + Owner: Neutral + Actor46: t18 + Location: 49,18 + Owner: Neutral + Actor47: t18 + Location: 23,54 + Owner: Neutral + Actor48: t18 + Location: 34,40 + Owner: Neutral + Actor49: t08 + Location: 16,45 + Owner: Neutral + Actor50: t08 + Location: 14,53 + Owner: Neutral + Actor52: t18 + Location: 13,44 + Owner: Neutral + Actor57: t18 + Location: 36,49 + Owner: Neutral + Actor58: t18 + Location: 44,59 + Owner: Neutral + Actor59: t18 + Location: 11,37 + Owner: Neutral + Actor60: t18 + Location: 25,20 + Owner: Neutral + Actor61: gtwr + Location: 46,21 Owner: GDI - Health: 94 - Facing: 32 - SubCell: 4 - Actor105: e1 - Location: 46,14 + Actor62: gtwr + Location: 46,24 Owner: GDI - SubCell: 2 - Actor106: e1 - Location: 18,29 + Actor63: hosp + Location: 48,19 Owner: GDI - Facing: 96 - SubCell: 4 - Actor107: e1 - Location: 12,20 + Actor64: pyle + Location: 50,20 Owner: GDI - SubCell: 1 - Actor108: e1 - Location: 39,23 + Actor65: nuke + Location: 53,21 Owner: GDI - SubCell: 1 - Actor119: e2 - Location: 18,8 + Actor66: nuke + Location: 52,23 Owner: GDI - Facing: 128 - SubCell: 3 - Actor120: e2 - Location: 16,10 + Actor67: silo + Location: 56,24 Owner: GDI - Facing: 96 - SubCell: 2 - Actor121: e2 - Location: 27,19 + Actor68: silo + Location: 55,22 Owner: GDI - Facing: 128 - SubCell: 1 - Actor122: e2 - Location: 25,34 + Actor69: fact + Location: 53,18 Owner: GDI - SubCell: 4 - Actor123: e1 - Location: 13,13 + Actor70: hq + Location: 56,19 Owner: GDI - Facing: 128 - SubCell: 1 - Actor124: e1 - Location: 13,13 + Actor72: v36 + Location: 12,54 + Owner: Neutral + Actor73: v35 + Location: 10,54 + Owner: Neutral + Actor74: v34 + Location: 11,53 + Owner: Neutral + Actor75: v33 + Location: 15,53 + Owner: Neutral + Actor76: v32 + Location: 12,53 + Owner: Neutral + Actor77: v31 + Location: 10,52 + Owner: Neutral + Actor87: v23 + Location: 9,59 + Owner: Neutral + Jeep1: jeep + Location: 51,25 Owner: GDI - Facing: 128 - SubCell: 2 - Actor125: e2 - Location: 13,13 + Jeep2: jeep + Location: 50,25 Owner: GDI - Facing: 128 - SubCell: 4 - Actor126: e2 - Location: 13,13 + Actor94: jeep + Location: 39,48 Owner: GDI - Facing: 128 - SubCell: 3 - Actor127: e2 - Location: 29,18 + Facing: 384 + Actor110: e1 + Location: 40,49 Owner: GDI - Facing: 64 - SubCell: 3 - Actor128: e2 - Location: 27,22 + Facing: 896 + SubCell: 0 + Actor111: e2 + Location: 38,50 Owner: GDI - Facing: 64 - SubCell: 1 - Actor129: e2 - Location: 36,10 + Facing: 896 + SubCell: 2 + Actor112: e2 + Location: 38,49 Owner: GDI - Health: 38 - Facing: 64 + Facing: 512 SubCell: 0 - Actor131: e1 - Location: 21,12 + Actor113: e2 + Location: 35,40 Owner: GDI - Facing: 128 - SubCell: 4 - Actor132: e1 - Location: 22,12 + SubCell: 0 + Actor114: e2 + Location: 35,40 Owner: GDI - Facing: 128 - SubCell: 3 - Actor29: t18 - Location: 14,7 - Owner: Neutral + SubCell: 1 waypoint27: waypoint - Location: 35,25 + Location: 31,36 + Owner: Neutral + waypoint25: waypoint + Location: 40,43 Owner: Neutral waypoint26: waypoint - Location: 44,6 + Location: 28,27 Owner: Neutral - waypoint9: waypoint - Location: 26,19 + waypoint11: waypoint + Location: 54,29 + Owner: Neutral + waypoint10: waypoint + Location: 45,28 + Owner: Neutral + GDIBase: waypoint + Location: 52,22 Owner: Neutral waypoint8: waypoint - Location: 53,37 + Location: 43,22 Owner: Neutral waypoint7: waypoint - Location: 47,35 + Location: 31,22 Owner: Neutral waypoint6: waypoint - Location: 45,11 + Location: 21,25 Owner: Neutral waypoint5: waypoint - Location: 40,17 + Location: 18,39 Owner: Neutral waypoint4: waypoint - Location: 39,34 + Location: 10,48 Owner: Neutral waypoint3: waypoint - Location: 21,38 + Location: 19,48 Owner: Neutral waypoint2: waypoint - Location: 20,28 + Location: 27,55 Owner: Neutral waypoint1: waypoint - Location: 13,26 + Location: 48,56 Owner: Neutral waypoint0: waypoint - Location: 13,14 - Owner: Neutral - Civilian1: v33 - Location: 48,34 + Location: 54,42 Owner: Neutral - Health: 62 - Civilian2: v33 - Location: 54,37 - Owner: Neutral - Soldier1: e2 - Location: 22,15 + Convoi: apc + Location: 24,53 Owner: GDI - Facing: 96 - SubCell: 2 - Soldier2: e1 - Location: 17,14 + CivBuilding1: v26 + Location: 8,51 Owner: GDI - Facing: 96 - SubCell: 4 - Soldier3: e2 - Location: 13,16 + CivBuilding2: v30 + Location: 17,46 Owner: GDI - Facing: 96 - SubCell: 1 - GDICiv1: c9 - Location: 20,12 + CivBuilding3: v29 + Location: 16,46 Owner: GDI - SubCell: 3 - GDICiv2: c4 - Location: 18,7 + CivBuilding4: v28 + Location: 15,45 Owner: GDI - SubCell: 0 - GDICiv3: c9 - Location: 19,12 + CivBuilding5: v27 + Location: 14,51 Owner: GDI - SubCell: 1 - GDICiv4: c8 - Location: 16,8 + CivBuilding6: v27 + Location: 13,51 Owner: GDI - SubCell: 3 - GDICiv5: c7 - Location: 17,9 + CivBuilding7: v27 + Location: 12,51 Owner: GDI - SubCell: 1 - GDICiv6: c6 - Location: 24,13 + CivBuilding8: v26 + Location: 14,46 Owner: GDI - SubCell: 2 - GDICiv7: c5 - Location: 20,7 + CivBuilding9: v25 + Location: 19,46 Owner: GDI - SubCell: 4 - GDICiv8: c4 - Location: 14,12 + CivBuilding10: v24 + Location: 8,47 Owner: GDI - SubCell: 1 - GDICiv9: c3 - Location: 15,10 + CivBuilding11: v22 + Location: 9,45 + Owner: GDI + CivBuilding12: v22 + Location: 18,52 Owner: GDI + CivBuilding13: v21 + Location: 16,51 + Owner: GDI + CivBuilding14: v20 + Location: 8,45 + Owner: GDI + Civilian1: c2 + Location: 11,50 + Owner: GDI + Facing: 896 + SubCell: 0 + Civilian2: c9 + Location: 12,49 + Owner: GDI + Facing: 896 SubCell: 2 - GDICiv10: c2 - Location: 14,10 + Civilian3: c8 + Location: 14,49 Owner: GDI - SubCell: 1 - GDICiv11: c1 - Location: 17,7 + Facing: 256 + SubCell: 3 + Civilian4: c7 + Location: 13,50 Owner: GDI + Facing: 896 + SubCell: 0 + Civilian5: c6 + Location: 11,49 + Owner: GDI + Facing: 128 + SubCell: 0 + Civilian6: c5 + Location: 12,50 + Owner: GDI + Facing: 896 SubCell: 2 - GDICiv12: c1 - Location: 20,10 + Civilian7: c4 + Location: 10,50 Owner: GDI + Facing: 128 SubCell: 1 - GDICiv13: c1 - Location: 20,11 + Civilian8: c3 + Location: 10,51 Owner: GDI - SubCell: 3 - UnitsEntryBuggy: waypoint - Location: 52,6 - Owner: Neutral - UnitsRallyBuggy: waypoint - Location: 52,10 - Owner: Neutral - UnitsEntryBikes: waypoint - Location: 50,6 - Owner: Neutral - UnitsRallyBikes: waypoint - Location: 50,10 + Facing: 128 + SubCell: 1 + Actor56: t18 + Location: 19,51 Owner: Neutral - UnitsEntryGunner: waypoint - Location: 54,6 + Actor55: t18 + Location: 20,46 Owner: Neutral - UnitsRallyGunner: waypoint - Location: 54,10 + Actor51: t08 + Location: 13,46 Owner: Neutral - UnitsEntryRocket: waypoint - Location: 56,12 + Actor53: t18 + Location: 7,46 Owner: Neutral - UnitsRallyRocket: waypoint - Location: 54,12 + Actor54: t18 + Location: 11,51 Owner: Neutral - NodCiv1: c8 - Location: 46,36 - Owner: NodSupporter - Facing: 128 - SubCell: 2 - NodCiv2: e3 - Location: 48,36 - Owner: NodSupporter - Facing: 192 - SubCell: 4 - NodCiv3: c4 - Location: 52,38 - Owner: NodSupporter - Facing: 192 - SubCell: 1 - NodCiv4: c3 - Location: 45,35 - Owner: NodSupporter - Facing: 32 - SubCell: 4 - NodCiv5: c1 - Location: 51,36 - Owner: NodSupporter - Facing: 224 - SubCell: 2 - NodCiv6: c2 - Location: 45,34 - Owner: NodSupporter - Facing: 0 - SubCell: 1 - NodCiv7: c4 - Location: 54,36 - Owner: NodSupporter - Facing: 160 - SubCell: 0 - NodCiv8: c5 - Location: 50,37 - Owner: NodSupporter - Facing: 96 - SubCell: 2 - NodCiv9: c9 - Location: 47,34 - Owner: NodSupporter - Facing: 192 + GDIGunner1: e1 + Location: 41,50 + Owner: GDI + Facing: 768 SubCell: 2 - Gciv1: e1 - Location: 38,9 + GDIGunner2: e1 + Location: 39,50 Owner: GDI - Facing: 128 SubCell: 0 - Gciv2: e1 - Location: 18,10 + GDIGunner3: e1 + Location: 40,50 Owner: GDI - Facing: 160 - SubCell: 2 + Facing: 256 + SubCell: 0 + EntryPointVehicle: waypoint + Location: 33,17 + Owner: Neutral + RallyPointVehicle: waypoint + Location: 33,30 + Owner: Neutral + EntryPointRocket: waypoint + Location: 35,17 + Owner: Neutral + RallyPointRocket: waypoint + Location: 35,32 + Owner: Neutral + EntryPointGunner: waypoint + Location: 31,17 + Owner: Neutral + RallyPointGunner: waypoint + Location: 31,32 + Owner: Neutral + CameraPoint: waypoint + Location: 32,22 + Owner: Neutral Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/cnc/maps/nod04a/nod04a.lua openra-20210321/mods/cnc/maps/nod04a/nod04a.lua --- openra-20200503/mods/cnc/maps/nod04a/nod04a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod04a/nod04a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -7,201 +7,124 @@ information, see COPYING. ]] -NodUnitsBuggy = { "bggy", "bggy", "bggy", "bggy", "bggy" } -NodUnitsBikes = { "bike", "bike", "bike" } -NodUnitsGunner = { "e1", "e1", "e1", "e1", "e1", "e1" } +NodUnitsBuggy = { "bggy", "bggy", "bike", "bike" } NodUnitsRocket = { "e3", "e3", "e3", "e3", "e3", "e3" } +NodUnitsGunner = { "e1", "e1", "e1", "e1", "e1", "e1" } -Atk6Units = { "c1", "c2", "c3" } -Atk5Units = { "e1", "e1", "e2", "e2" } -Atk1Units = { "e1", "e1" } -JeepReinforcements = { "jeep" } -GDIUnits = { "e1", "e1", "e2" } -ApcUnits = { "e1", "e1", "e2", "e2" } - -Spawnpoint = { waypoint0.Location } -Atk6WaypointsPart1 = { waypoint1.Location, waypoint2.Location, waypoint3.Location, waypoint4.Location } -Atk6WaypointsPart2 = { waypoint7.Location, waypoint8.Location, waypoint7.Location } -Atk5Waypoints = { waypoint0.Location, waypoint9.Location} -Atk3Waypoints = { waypoint0 } -Atk2Waypoints = { waypoint6 } -GcivWaypoints = { waypoint0, waypoint1, waypoint2, waypoint3, waypoint4 } -Atk1Waypoints = { waypoint0, waypoint1, waypoint2, waypoint3, waypoint4, waypoint5, waypoint6 } -Atk4Waypoints = { waypoint0, waypoint9 } - -Atk6ActorTriggerActivator = { Civilian1, Civilian2 } -Atk5ActorTriggerActivator = { Soldier1, Soldier2, Soldier3, Actor105 } -WinActorTriggerActivator = { GDICiv1, GDICiv2, GDICiv3, GDICiv4, GDICiv5, GDICiv6, GDICiv7, GDICiv8, GDICiv9, GDICiv11, GDICiv12, GDICiv13 } -GcivActors = { Gcvi1, Gciv2, GDICiv2, GDICiv9, GDICiv10, GDICiv11 } - -Atk2CellTriggerActivator = { CPos.New(41,22), CPos.New(40,22), CPos.New(39,22), CPos.New(41,21), CPos.New(40,21), CPos.New(39,21) } -Atk3CellTriggerActivator = { CPos.New(18,18), CPos.New(17,18), CPos.New(16,18), CPos.New(15,18), CPos.New(14,18), CPos.New(13,18), CPos.New(12,18), CPos.New(11,18), CPos.New(24,17), CPos.New(23,17), CPos.New(22,17), CPos.New(21,17), CPos.New(20,17), CPos.New(19,17), CPos.New(17,17), CPos.New(16,17), CPos.New(15,17), CPos.New(14,17), CPos.New(13,17), CPos.New(12,17), CPos.New(11,17) } -Atk4CellTriggerActivator = { CPos.New(29,28), CPos.New(28,28), CPos.New(29,27), CPos.New(28,27), CPos.New(29,26), CPos.New(28,26), CPos.New(29,25), CPos.New(28,25), CPos.New(29,24), CPos.New(28,24), CPos.New(29,23), CPos.New(28,23), CPos.New(29,22), CPos.New(28,22) } -GcivCellTriggerActivator = { CPos.New(51,17), CPos.New(50,17), CPos.New(49,17), CPos.New(48,17), CPos.New(47,17), CPos.New(46,17), CPos.New(45,17), CPos.New(44,17), CPos.New(43,17), CPos.New(42,17), CPos.New(41,17), CPos.New(40,17), CPos.New(39,17), CPos.New(38,17), CPos.New(37,17), CPos.New(36,17), CPos.New(35,17), CPos.New(52,16), CPos.New(51,16), CPos.New(50,16), CPos.New(49,16), CPos.New(48,16), CPos.New(47,16), CPos.New(46,16), CPos.New(45,16), CPos.New(44,16), CPos.New(43,16), CPos.New(42,16), CPos.New(41,16), CPos.New(40,16), CPos.New(39,16), CPos.New(38,16), CPos.New(37,16), CPos.New(36,16), CPos.New(35,16) } -DelxCellTriggerActivator = { CPos.New(42,20), CPos.New(41,20), CPos.New(40,20), CPos.New(39,20), CPos.New(38,20) } -DelyCellTriggerActivator = { CPos.New(31,28), CPos.New(30,28), CPos.New(31,27), CPos.New(30,27), CPos.New(31,26), CPos.New(30,26), CPos.New(31,25), CPos.New(30,25), CPos.New(31,24), CPos.New(30,24) } -DelzCellTriggerActivator = { CPos.New(18,20), CPos.New(17,20), CPos.New(16,20), CPos.New(15,20), CPos.New(14,20), CPos.New(13,20), CPos.New(12,20), CPos.New(11,20), CPos.New(25,19), CPos.New(24,19), CPos.New(23,19), CPos.New(22,19), CPos.New(21,19), CPos.New(20,19), CPos.New(19,19), CPos.New(18,19), CPos.New(17,19), CPos.New(16,19), CPos.New(15,19), CPos.New(14,19), CPos.New(13,19), CPos.New(12,19), CPos.New(11,19), CPos.New(25,18), CPos.New(24,18), CPos.New(23,18), CPos.New(22,18), CPos.New(21,18), CPos.New(20,18), CPos.New(19,18) } - -NodCiviliansActors = { NodCiv1, NodCiv2, NodCiv3, NodCiv4, NodCiv5, NodCiv6, NodCiv7, NodCiv8, NodCiv9 } - -SendJeepReinforcements = function() - if not PreventJeepReinforcements then - local units = Reinforcements.Reinforce(GDI, JeepReinforcements, Spawnpoint, 15) - MoveAndHunt(units, Atk2Waypoints) - end -end - -SendGDIReinforcements = function() - if not PreventGDIReinforcements then - local units = Reinforcements.Reinforce(GDI, GDIUnits, Spawnpoint, 15) - MoveAndHunt(units, Atk4Waypoints) - end -end - -SendApcReinforcements = function() - if not PreventApcReinforcements then - Reinforcements.ReinforceWithTransport(GDI, "apc", ApcUnits, Atk5Waypoints, nil, - function(transport, cargo) - transport.UnloadPassengers() - Utils.Do(cargo, IdleHunt) - end, IdleHunt) - end -end - -CreateCivilians = function(actor, discoverer) - Utils.Do(NodCiviliansActors, function(actor) - actor.Owner = Nod - end) - - ProtectCivilians = Nod.AddPrimaryObjective("Protect the civilians that support Nod.") - Trigger.OnAllKilled(NodCiviliansActors, function() - Nod.MarkFailedObjective(ProtectCivilians) - end) - - Utils.Do(GcivActors, function(actor) - if not actor.IsDead then - actor.AttackMove(waypoint7.Location) - actor.AttackMove(waypoint8.Location) - IdleHunt(actor) - end - end) -end +Apc3Trigger = { CPos.New(28,58), CPos.New(27,58), CPos.New(28,57), CPos.New(27,57), CPos.New(28,56), CPos.New(27,56), CPos.New(28,55), CPos.New(27,55), CPos.New(28,54), CPos.New(27,54), CPos.New(28,53), CPos.New(27,53) } +NorthernBridgeTrigger = { CPos.New(13,41), CPos.New(14,41), CPos.New(15,41), CPos.New(14,42), CPos.New(15,42), CPos.New(16,42) } +SouthernBridgeTrigger = { CPos.New(26,54), CPos.New(25,54), CPos.New(24,54), CPos.New(25,53), CPos.New(24,53), CPos.New(23,53) } + +Apc1Units = { "c2", "c3", "c4", "c5" } + +Civilians = { Civilian1, Civilian2, Civilian3, Civilian4, Civilian5, Civilian6, Civilian7, Civilian8 } +TargetActors = { Civilian1, Civilian2, Civilian3, Civilian4, Civilian5, Civilian6, Civilian7, Civilian8, CivBuilding1, CivBuilding2, CivBuilding3, CivBuilding4, CivBuilding5, CivBuilding6, CivBuilding7, CivBuilding8, CivBuilding9, CivBuilding10, CivBuilding11, CivBuilding12, CivBuilding13, CivBuilding14 } +Apc2Trigger = { GDIGunner1, GDIGunner2, GDIGunner3 } + +Apc1Waypoints = { waypoint0.Location, waypoint11.Location, waypoint10.Location, waypoint8.Location, GDIBase.Location } +Apc2Waypoints = { waypoint8, waypoint7, waypoint6, waypoint5, waypoint4 } +Apc3Waypoints = { waypoint3, waypoint2, waypoint1, waypoint0, waypoint11, waypoint10, waypoint8, GDIBase } +FlightRouteTop = { waypoint4, waypoint5, waypoint6, waypoint7, waypoint8, GDIBase } +FlightRouteBottom = { waypoint3, waypoint2, waypoint1, waypoint11, waypoint10, waypoint8, GDIBase } +Hummer1Waypoints = { waypoint8, waypoint7, waypoint6, waypoint5, waypoint4, waypoint3, waypoint2, waypoint1, waypoint0, waypoint11, waypoint10, waypoint8 } WorldLoaded = function() Nod = Player.GetPlayer("Nod") - NodSupporter = Player.GetPlayer("NodSupporter") GDI = Player.GetPlayer("GDI") - InitObjectives(Nod) - - Trigger.OnAnyKilled(Atk6ActorTriggerActivator, function() - Reinforcements.ReinforceWithTransport(GDI, "apc", Atk6Units, Atk6WaypointsPart1, Atk6WaypointsPart2, - function(transport, cargo) - Utils.Do(cargo, IdleHunt) - end, IdleHunt) - end) + Trigger.AfterDelay(DateTime.Seconds(3), function() + local apc = Actor.Create("apc", true, { Owner = GDI, Location = Apc1Waypoints[1], Cargo = Apc1Units }) + Utils.Do(Apc1Waypoints, function(waypoint) + apc.AttackMove(waypoint) + end) - Utils.Do(Atk5ActorTriggerActivator, function(actor) - Trigger.OnDamaged(actor, function() - if Atk5TriggerSwitch then - return + Trigger.OnEnteredFootprint(Apc3Trigger, function(a, id) + if a.Owner == Nod then + MoveAndHunt({ apc }, Apc3Waypoints) + Trigger.RemoveFootprintTrigger(id) end - - Atk5TriggerSwitch = true - Reinforcements.ReinforceWithTransport(GDI, "apc", Atk5Units, Atk5Waypoints, nil, - function(transport, cargo) - transport.UnloadPassengers() - Utils.Do(cargo, IdleHunt) - end, IdleHunt) end) end) - Trigger.OnEnteredFootprint(Atk3CellTriggerActivator, function(a, id) + Trigger.OnEnteredFootprint(NorthernBridgeTrigger, function(a, id) if a.Owner == Nod then - Trigger.RemoveFootprintTrigger(id) - - for type, count in pairs({ ["e1"] = 3, ["e2"] = 2, ["mtnk"] = 1 }) do - MoveAndHunt(Utils.Take(count, GDI.GetActorsByType(type)), Atk3Waypoints) + if not CiviliansEvacuated then + CiviliansEvacuated = true + Utils.Do(Civilians, function(civ) + Utils.Do(FlightRouteBottom, function(waypoint) + civ.Move(waypoint.Location) + end) + + Trigger.OnIdle(civ, function() + if civ.Location == GDIBase.Location then + Trigger.Clear(civ, "OnIdle") + else + civ.Move(GDIBase.Location) + end + end) + end) end - end - end) - - Trigger.OnEnteredFootprint(Atk2CellTriggerActivator, function(a, id) - if a.Owner == Nod then - MoveAndHunt(Utils.Take(1, GDI.GetActorsByType("jeep")), Atk2Waypoints) - Trigger.RemoveFootprintTrigger(id) - end - end) - Trigger.OnEnteredFootprint(GcivCellTriggerActivator, function(a, id) - if a.Owner == Nod then - MoveAndHunt(GcivActors, GcivWaypoints) Trigger.RemoveFootprintTrigger(id) end end) - Trigger.OnEnteredFootprint(Atk4CellTriggerActivator, function(a, id) + Trigger.OnEnteredFootprint(SouthernBridgeTrigger, function(a, id) if a.Owner == Nod then - for type, count in pairs({ ["e1"] = 2,["e2"] = 1 }) do - MoveAndHunt(Utils.Take(count, GDI.GetActorsByType(type)), Atk4Waypoints) + if not CiviliansEvacuated then + CiviliansEvacuated = true + Utils.Do(Civilians, function(civ) + Utils.Do(FlightRouteTop, function(waypoint) + civ.Move(waypoint.Location) + end) + + Trigger.OnIdle(civ, function() + if civ.Location == GDIBase.Location then + Trigger.Clear(civ, "OnIdle") + else + civ.Move(GDIBase.Location) + end + end) + end) end - Trigger.RemoveFootprintTrigger(id) - end - end) - - Trigger.AfterDelay(DateTime.Seconds(20), function() - local units = Reinforcements.Reinforce(GDI, Atk1Units, Spawnpoint, 15) - MoveAndHunt(units, Atk1Waypoints) - end) - - Trigger.AfterDelay(DateTime.Seconds(50), SendJeepReinforcements) - Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(40), SendGDIReinforcements) - Trigger.AfterDelay(DateTime.Minutes(2) + DateTime.Seconds(30), SendApcReinforcements) - Trigger.OnEnteredFootprint(DelxCellTriggerActivator, function(a, id) - if a.Owner == Nod then - PreventJeepReinforcements = true Trigger.RemoveFootprintTrigger(id) end end) - Trigger.OnEnteredFootprint(DelyCellTriggerActivator, function(a, id) - if a.Owner == Nod then - PreventGDIReinforcements = true - Trigger.RemoveFootprintTrigger(id) - end + Trigger.OnDiscovered(Convoi, function() + MoveAndHunt({ Jeep1, Jeep2 }, Hummer1Waypoints) end) - Trigger.OnEnteredFootprint(DelzCellTriggerActivator, function(a, id) - if a.Owner == Nod then - PreventApcReinforcements = true - Trigger.RemoveFootprintTrigger(id) - end + Trigger.OnAllRemovedFromWorld(Apc2Trigger, function() + MoveAndHunt({ Convoi }, Apc2Waypoints) end) - Trigger.OnPlayerDiscovered(NodSupporter, CreateCivilians) + Trigger.OnAllRemovedFromWorld(TargetActors, function() + Nod.MarkCompletedObjective(KillCivilians) + end) - Trigger.OnAllKilled(WinActorTriggerActivator, function() - Nod.MarkCompletedObjective(KillGDI) + InitObjectives(Nod) - if ProtectCivilians then - Nod.MarkCompletedObjective(ProtectCivilians) - end - end) + KillCivilians = Nod.AddObjective("Destroy the village and kill all civilians.") + KillGDI = Nod.AddObjective("Kill all GDI units in the area.", "Secondary", false) - KillGDI = Nod.AddObjective("Kill all civilian GDI supporters.") + Camera.Position = CameraPoint.CenterPosition Media.PlaySpeechNotification(Nod, "Reinforce") - Reinforcements.Reinforce(Nod, NodUnitsBuggy, { UnitsEntryBuggy.Location, UnitsRallyBuggy.Location }, 11) - Reinforcements.Reinforce(Nod, NodUnitsBikes, { UnitsEntryBikes.Location, UnitsRallyBikes.Location }, 15) - Reinforcements.Reinforce(Nod, NodUnitsGunner, { UnitsEntryGunner.Location, UnitsRallyGunner.Location }, 15) - Reinforcements.Reinforce(Nod, NodUnitsRocket, { UnitsEntryRocket.Location, UnitsRallyRocket.Location }, 15) - - Camera.Position = waypoint6.CenterPosition + Trigger.AfterDelay(DateTime.Seconds(1), function() + Reinforcements.ReinforceWithTransport(Nod, "tran", NodUnitsBuggy, { EntryPointVehicle.Location, RallyPointVehicle.Location }, { EntryPointVehicle.Location }) + end) + Reinforcements.ReinforceWithTransport(Nod, "tran", NodUnitsRocket, { EntryPointRocket.Location, RallyPointRocket.Location }, { EntryPointRocket.Location }) + Reinforcements.ReinforceWithTransport(Nod, "tran", NodUnitsGunner, { EntryPointGunner.Location, RallyPointGunner.Location }, { EntryPointGunner.Location }) end Tick = function() if DateTime.GameTime > 2 and Nod.HasNoRequiredUnits() then - Nod.MarkFailedObjective(KillGDI) + Nod.MarkFailedObjective(KillCivilians) + end + + if GDI.HasNoRequiredUnits() then + Nod.MarkCompletedObjective(KillGDI) end end diff -Nru openra-20200503/mods/cnc/maps/nod04a/rules.yaml openra-20210321/mods/cnc/maps/nod04a/rules.yaml --- openra-20200503/mods/cnc/maps/nod04a/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod04a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,128 +2,27 @@ LuaScript: Scripts: campaign-global.lua, nod04a.lua MusicPlaylist: - StartingMusic: valkyrie + StartingMusic: warfare VictoryMusic: nod_win1 MissionData: - Briefing: A small village friendly to our cause has been increasingly harassed by GDI, and the Brotherhood wishes you to assist them in their efforts.\n\nSeek out the enemy village and destroy it. The event will be disguised as a GDI attack. - BriefingVideo: nod4b.vqa - StartVideo: retro.vqa - LossVideo: deskill.vqa - SmudgeLayer@SCORCH: - InitialSmudges: - 37,24: sc6,0 - 36,18: sc6,0 + Briefing: GDI is attempting to relocate a village of sympathetic civilians. Intercept the convoy and destroy it. It is imperative that the villagers be totally destroyed as a lesson to any other natives who may oppose us. + BriefingVideo: nod4a.vqa + LossVideo: nodlose.vqa Player: EnemyWatcher: PlayerResources: DefaultCash: 0 -^Palettes: - IndexedPlayerPalette: - PlayerIndex: - NodSupporter: 192, 164, 132, 155, 133, 197, 112, 12, 163, 132, 155, 133, 134, 197, 154, 198 - IndexedPlayerPalette@units: - PlayerIndex: - NodSupporter: 192, 164, 132, 155, 133, 197, 112, 12, 163, 132, 155, 133, 134, 197, 154, 198 - -^Infantry: - AnnounceOnSeen: - -^CivBuilding: +^Vehicle: AnnounceOnSeen: -^CivBuildingHusk: +^Tank: AnnounceOnSeen: -NUK2: - Buildable: - Prerequisites: ~disabled - -GUN: - Buildable: - Prerequisites: ~disabled - -CYCL: - Buildable: - Prerequisites: ~disabled - -FIX: - Buildable: - Prerequisites: ~disabled - -HPAD: - Buildable: - Prerequisites: ~disabled - -OBLI: - Buildable: - Prerequisites: ~disabled - -BRIK: - Buildable: - Prerequisites: ~disabled - -TMPL: - Buildable: - Prerequisites: ~disabled - -FTNK: - Buildable: - Prerequisites: ~disabled - -STNK: - Buildable: - Prerequisites: ~disabled - -ARTY: - Buildable: - Prerequisites: ~disabled - -E5: - Buildable: - Prerequisites: ~disabled - -RMBO: - Buildable: - Prerequisites: ~disabled - -MLRS: - Buildable: - Prerequisites: ~disabled - -MCV: - Buildable: - Prerequisites: ~disabled - -SAM: - Buildable: - Prerequisites: ~disabled - -AFLD: - Buildable: - Prerequisites: ~disabled - -E4: - Buildable: - Prerequisites: ~disabled - -SBAG: - Buildable: - Prerequisites: ~disabled - -GTWR: - Buildable: - Prerequisites: ~disabled - -WEAP: - Buildable: - Prerequisites: ~disabled - -EYE: - Buildable: - Prerequisites: ~disabled - -ATWR: - Buildable: - Prerequisites: ~disabled +TRAN: + RejectsOrders: + -Selectable: + RevealsShroud: + Range: 5c0 + Interactable: Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/nod04b/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/nod04b/map.bin differ diff -Nru openra-20200503/mods/cnc/maps/nod04b/map.yaml openra-20210321/mods/cnc/maps/nod04b/map.yaml --- openra-20200503/mods/cnc/maps/nod04b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod04b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,7 +2,7 @@ RequiresMod: cnc -Title: 04b: Oum Hadjer +Title: 04b: Mao Civil War Author: Westwood Studios @@ -10,7 +10,7 @@ MapSize: 64,64 -Bounds: 7,17,52,44 +Bounds: 11,6,46,34 Visibility: MissionSelector @@ -19,17 +19,22 @@ LockPreview: True Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: gdi + PlayerReference@NodSupporter: + Name: NodSupporter + NonCombatant: True + Faction: nod + Bot: campaign PlayerReference@GDI: Name: GDI Faction: gdi Color: F5D378 Enemies: Nod Bot: campaign - PlayerReference@Neutral: - Name: Neutral - OwnsWorld: True - NonCombatant: True - Faction: gdi PlayerReference@Nod: Name: Nod Playable: True @@ -44,437 +49,491 @@ Enemies: GDI Actors: - Actor0: sbag - Location: 58,26 - Owner: Neutral - Actor1: sbag - Location: 57,26 - Owner: Neutral - Actor2: sbag - Location: 56,26 - Owner: Neutral - Actor3: sbag - Location: 55,26 - Owner: Neutral - Actor4: sbag - Location: 54,26 - Owner: Neutral - Actor5: sbag - Location: 53,26 - Owner: Neutral - Actor6: sbag - Location: 52,26 - Owner: Neutral - Actor7: sbag - Location: 51,26 - Owner: Neutral - Actor8: sbag - Location: 50,26 - Owner: Neutral - Actor9: sbag - Location: 49,26 - Owner: Neutral - Actor10: sbag - Location: 48,26 - Owner: Neutral - Actor11: sbag - Location: 47,26 - Owner: Neutral - Actor12: sbag - Location: 58,25 - Owner: Neutral - Actor13: sbag - Location: 47,25 - Owner: Neutral - Actor14: sbag - Location: 58,24 - Owner: Neutral - Actor15: sbag - Location: 47,24 - Owner: Neutral - Actor16: sbag - Location: 58,23 - Owner: Neutral - Actor17: sbag - Location: 58,22 - Owner: Neutral - Actor18: sbag - Location: 58,21 - Owner: Neutral - Actor19: sbag - Location: 47,21 - Owner: Neutral - Actor20: sbag - Location: 58,20 - Owner: Neutral - Actor21: sbag - Location: 47,20 + Actor0: t08 + Location: 34,20 Owner: Neutral - Actor22: sbag - Location: 58,19 + Actor1: t18 + Location: 33,18 Owner: Neutral - Actor23: sbag - Location: 47,19 + Actor2: t18 + Location: 33,9 Owner: Neutral - Actor24: sbag - Location: 58,18 + Actor3: t08 + Location: 41,5 Owner: Neutral - Actor25: sbag - Location: 57,18 + Actor4: t18 + Location: 42,15 Owner: Neutral - Actor26: sbag - Location: 48,18 + Actor5: t08 + Location: 45,26 Owner: Neutral - Actor27: sbag - Location: 47,18 + Actor6: t08 + Location: 56,29 Owner: Neutral - Actor28: sbag - Location: 58,17 + Actor7: t08 + Location: 55,29 Owner: Neutral - Actor29: sbag - Location: 57,17 - Owner: Neutral - Actor30: sbag - Location: 56,17 - Owner: Neutral - Actor31: sbag - Location: 55,17 - Owner: Neutral - Actor32: sbag - Location: 54,17 - Owner: Neutral - Actor33: sbag - Location: 53,17 - Owner: Neutral - Actor34: sbag - Location: 52,17 - Owner: Neutral - Actor35: sbag - Location: 51,17 - Owner: Neutral - Actor36: sbag - Location: 50,17 - Owner: Neutral - Actor37: sbag - Location: 49,17 - Owner: Neutral - Actor38: sbag - Location: 48,17 - Owner: Neutral - Actor39: sbag - Location: 47,17 - Owner: Neutral - Actor40: t18 - Location: 47,50 - Owner: Neutral - Actor41: t18 - Location: 46,31 - Owner: Neutral - Actor42: t08 - Location: 39,26 - Owner: Neutral - Actor43: t18 - Location: 37,25 - Owner: Neutral - Actor44: t18 - Location: 27,28 - Owner: Neutral - Actor45: t18 - Location: 54,26 - Owner: Neutral - Actor46: t18 - Location: 49,18 - Owner: Neutral - Actor47: t18 - Location: 23,54 - Owner: Neutral - Actor48: t18 - Location: 34,40 - Owner: Neutral - Actor49: t08 - Location: 16,45 - Owner: Neutral - Actor50: t08 - Location: 14,53 - Owner: Neutral - Actor52: t18 - Location: 13,44 - Owner: Neutral - Actor57: t18 - Location: 36,49 + Actor8: t08 + Location: 51,26 Owner: Neutral - Actor58: t18 - Location: 44,59 + Actor9: t08 + Location: 56,18 Owner: Neutral - Actor59: t18 - Location: 11,37 + Actor10: t08 + Location: 52,16 Owner: Neutral - Actor60: t18 - Location: 25,20 + Actor11: t08 + Location: 45,21 Owner: Neutral - Actor61: gtwr - Location: 46,21 + Actor12: t08 + Location: 38,19 + Owner: Neutral + Actor13: t08 + Location: 23,16 + Owner: Neutral + Actor14: t08 + Location: 14,22 + Owner: Neutral + Actor15: t08 + Location: 26,22 + Owner: Neutral + Actor16: t08 + Location: 21,26 + Owner: Neutral + Actor17: t08 + Location: 48,6 + Owner: Neutral + Actor18: t08 + Location: 15,19 + Owner: Neutral + Actor19: t08 + Location: 31,15 + Owner: Neutral + Actor20: t18 + Location: 49,34 + Owner: Neutral + Actor21: t18 + Location: 48,38 + Owner: Neutral + Actor22: t18 + Location: 42,35 + Owner: Neutral + Actor23: t18 + Location: 54,37 + Owner: Neutral + Actor24: t08 + Location: 51,35 + Owner: Neutral + Actor25: t08 + Location: 45,37 + Owner: Neutral + Actor26: t08 + Location: 47,33 + Owner: Neutral + Actor27: t18 + Location: 13,10 + Owner: Neutral + Actor28: t18 + Location: 20,7 + Owner: Neutral + Actor30: t08 + Location: 12,8 + Owner: Neutral + Actor31: t08 + Location: 23,9 + Owner: Neutral + Actor32: v35 + Location: 48,38 + Owner: NodSupporter + Actor33: v34 + Location: 46,33 + Owner: NodSupporter + Actor35: v32 + Location: 54,35 + Owner: NodSupporter + Actor36: v30 + Location: 48,32 + Owner: NodSupporter + Actor37: v30 + Location: 52,34 + Owner: NodSupporter + Actor38: v31 + Location: 52,35 + Owner: NodSupporter + Actor39: v32 + Location: 46,37 + Owner: NodSupporter + Health: 73 + Actor41: v34 + Location: 49,38 + Owner: NodSupporter + Actor42: v35 + Location: 46,32 + Owner: NodSupporter + Actor43: v36 + Location: 48,37 + Owner: NodSupporter + Actor44: v32 + Location: 49,33 + Owner: NodSupporter + Actor45: v34 + Location: 50,34 + Owner: NodSupporter + Actor46: v20 + Location: 15,10 + Owner: GDI + Actor47: v21 + Location: 12,10 + Owner: GDI + Actor48: v22 + Location: 21,11 + Owner: GDI + Actor49: v23 + Location: 22,8 + Owner: GDI + Actor50: v24 + Location: 18,8 + Owner: GDI + Actor51: v25 + Location: 13,7 + Owner: GDI + Actor52: v26 + Location: 20,9 + Owner: GDI + Actor53: v27 + Location: 15,9 + Owner: GDI + Actor54: v27 + Location: 14,9 + Owner: GDI + Actor55: v27 + Location: 13,9 + Owner: GDI + Actor56: v28 + Location: 21,7 + Owner: GDI + Actor57: v29 + Location: 22,7 + Owner: GDI + Actor58: v30 + Location: 21,10 + Owner: GDI + Actor59: v30 + Location: 23,8 + Owner: GDI + Actor61: jeep + Location: 15,23 + Owner: GDI + Facing: 640 + Actor62: jeep + Location: 36,6 + Owner: GDI + Facing: 384 + Actor65: mtnk + Location: 29,10 + Owner: GDI + Facing: 256 + Actor71: jeep + Location: 24,26 + Owner: GDI + Facing: 384 + Actor72: jeep + Location: 37,19 Owner: GDI - Actor62: gtwr - Location: 46,24 + Facing: 128 + Actor73: jeep + Location: 27,33 Owner: GDI - Actor63: hosp - Location: 48,19 + Facing: 384 + Actor86: e1 + Location: 43,15 Owner: GDI - Actor64: pyle - Location: 50,20 + Health: 88 + Facing: 128 + SubCell: 3 + Actor99: e1 + Location: 45,15 Owner: GDI - Actor65: nuke - Location: 53,21 + SubCell: 3 + Actor100: e1 + Location: 43,15 Owner: GDI - Actor66: nuke - Location: 52,23 + Health: 94 + Facing: 128 + SubCell: 4 + Actor105: e1 + Location: 46,14 Owner: GDI - Actor67: silo - Location: 56,24 + SubCell: 2 + Actor106: e1 + Location: 18,29 Owner: GDI - Actor68: silo - Location: 55,22 + Facing: 384 + SubCell: 4 + Actor107: e1 + Location: 12,20 Owner: GDI - Actor69: fact - Location: 53,18 + SubCell: 1 + Actor108: e1 + Location: 39,23 Owner: GDI - Actor70: hq - Location: 56,19 + SubCell: 1 + Actor119: e2 + Location: 18,8 Owner: GDI - Actor72: v36 - Location: 12,54 - Owner: Neutral - Actor73: v35 - Location: 10,54 - Owner: Neutral - Actor74: v34 - Location: 11,53 - Owner: Neutral - Actor75: v33 - Location: 15,53 - Owner: Neutral - Actor76: v32 - Location: 12,53 - Owner: Neutral - Actor77: v31 - Location: 10,52 - Owner: Neutral - Actor87: v23 - Location: 9,59 - Owner: Neutral - Actor92: jeep - Location: 51,25 + Facing: 512 + SubCell: 3 + Actor120: e2 + Location: 16,10 Owner: GDI - Actor93: jeep - Location: 50,25 + Facing: 384 + SubCell: 2 + Actor121: e2 + Location: 27,19 Owner: GDI - Actor94: jeep - Location: 39,48 + Facing: 512 + SubCell: 1 + Actor122: e2 + Location: 25,34 Owner: GDI - Facing: 96 - Actor110: e1 - Location: 40,49 + SubCell: 4 + Actor123: e1 + Location: 13,13 Owner: GDI - Facing: 224 - SubCell: 0 - Actor111: e2 - Location: 38,50 + Facing: 512 + SubCell: 1 + Actor124: e1 + Location: 13,13 Owner: GDI - Facing: 224 + Facing: 512 SubCell: 2 - Actor112: e2 - Location: 38,49 + Actor125: e2 + Location: 13,13 Owner: GDI - Facing: 128 - SubCell: 0 - Actor113: e2 - Location: 35,40 + Facing: 512 + SubCell: 4 + Actor126: e2 + Location: 13,13 Owner: GDI - SubCell: 0 - Actor114: e2 - Location: 35,40 + Facing: 512 + SubCell: 3 + Actor127: e2 + Location: 29,18 Owner: GDI + Facing: 256 + SubCell: 3 + Actor128: e2 + Location: 27,22 + Owner: GDI + Facing: 256 SubCell: 1 - waypoint27: waypoint - Location: 31,36 + Actor129: e2 + Location: 36,10 + Owner: GDI + Health: 38 + Facing: 256 + SubCell: 0 + Actor131: e1 + Location: 21,12 + Owner: GDI + Facing: 512 + SubCell: 4 + Actor132: e1 + Location: 22,12 + Owner: GDI + Facing: 512 + SubCell: 3 + Actor29: t18 + Location: 14,7 Owner: Neutral - waypoint25: waypoint - Location: 40,43 + waypoint27: waypoint + Location: 35,25 Owner: Neutral waypoint26: waypoint - Location: 28,27 - Owner: Neutral - waypoint11: waypoint - Location: 54,29 - Owner: Neutral - waypoint10: waypoint - Location: 45,28 + Location: 44,6 Owner: Neutral waypoint9: waypoint - Location: 52,22 + Location: 26,19 Owner: Neutral waypoint8: waypoint - Location: 43,22 + Location: 53,37 Owner: Neutral waypoint7: waypoint - Location: 31,22 + Location: 47,35 Owner: Neutral waypoint6: waypoint - Location: 21,25 + Location: 45,11 Owner: Neutral waypoint5: waypoint - Location: 18,39 + Location: 40,17 Owner: Neutral waypoint4: waypoint - Location: 10,48 + Location: 39,34 Owner: Neutral waypoint3: waypoint - Location: 19,48 + Location: 21,38 Owner: Neutral waypoint2: waypoint - Location: 27,55 + Location: 20,28 Owner: Neutral waypoint1: waypoint - Location: 48,56 + Location: 13,26 Owner: Neutral waypoint0: waypoint - Location: 54,42 + Location: 13,14 Owner: Neutral - Convoi: apc - Location: 24,53 - Owner: GDI - CivBuilding1: v26 - Location: 8,51 - Owner: GDI - CivBuilding2: v30 - Location: 17,46 - Owner: GDI - CivBuilding3: v29 - Location: 16,46 - Owner: GDI - CivBuilding4: v28 - Location: 15,45 - Owner: GDI - CivBuilding5: v27 - Location: 14,51 + Civilian1: v33 + Location: 48,34 + Owner: Neutral + Health: 62 + Civilian2: v33 + Location: 54,37 + Owner: Neutral + Soldier1: e2 + Location: 22,15 Owner: GDI - CivBuilding6: v27 - Location: 13,51 + Facing: 384 + SubCell: 2 + Soldier2: e1 + Location: 17,14 Owner: GDI - CivBuilding7: v27 - Location: 12,51 + Facing: 384 + SubCell: 4 + Soldier3: e2 + Location: 13,16 Owner: GDI - CivBuilding8: v26 - Location: 14,46 + Facing: 384 + SubCell: 1 + GDICiv1: c9 + Location: 20,12 Owner: GDI - CivBuilding9: v25 - Location: 19,46 + SubCell: 3 + GDICiv2: c4 + Location: 18,7 Owner: GDI - CivBuilding10: v24 - Location: 8,47 + SubCell: 0 + GDICiv3: c9 + Location: 19,12 Owner: GDI - CivBuilding11: v22 - Location: 9,45 + SubCell: 1 + GDICiv4: c8 + Location: 16,8 Owner: GDI - CivBuilding12: v22 - Location: 18,52 + SubCell: 3 + GDICiv5: c7 + Location: 17,9 Owner: GDI - CivBuilding13: v21 - Location: 16,51 + SubCell: 1 + GDICiv6: c6 + Location: 24,13 Owner: GDI - CivBuilding14: v20 - Location: 8,45 + SubCell: 2 + GDICiv7: c5 + Location: 20,7 Owner: GDI - Civilian1: c2 - Location: 11,50 + SubCell: 4 + GDICiv8: c4 + Location: 14,12 Owner: GDI - Facing: 224 - SubCell: 0 - Civilian2: c9 - Location: 12,49 + SubCell: 1 + GDICiv9: c3 + Location: 15,10 Owner: GDI - Facing: 224 SubCell: 2 - Civilian3: c8 - Location: 14,49 - Owner: GDI - Facing: 64 - SubCell: 3 - Civilian4: c7 - Location: 13,50 + GDICiv10: c2 + Location: 14,10 Owner: GDI - Facing: 224 - SubCell: 0 - Civilian5: c6 - Location: 11,49 - Owner: GDI - Facing: 32 - SubCell: 0 - Civilian6: c5 - Location: 12,50 + SubCell: 1 + GDICiv11: c1 + Location: 17,7 Owner: GDI - Facing: 224 SubCell: 2 - Civilian7: c4 - Location: 10,50 + GDICiv12: c1 + Location: 20,10 Owner: GDI - Facing: 32 SubCell: 1 - Civilian8: c3 - Location: 10,51 + GDICiv13: c1 + Location: 20,11 Owner: GDI - Facing: 32 - SubCell: 1 - Actor56: t18 - Location: 19,51 + SubCell: 3 + UnitsEntryBuggy: waypoint + Location: 52,6 Owner: Neutral - Actor55: t18 - Location: 20,46 + UnitsRallyBuggy: waypoint + Location: 52,10 Owner: Neutral - Actor51: t08 - Location: 13,46 + UnitsEntryBikes: waypoint + Location: 50,6 Owner: Neutral - Actor53: t18 - Location: 7,46 + UnitsRallyBikes: waypoint + Location: 50,10 Owner: Neutral - Actor54: t18 - Location: 11,51 + UnitsEntryGunner: waypoint + Location: 54,6 Owner: Neutral - NodGunner1: e1 - Location: 41,50 - Owner: GDI - Facing: 192 + UnitsRallyGunner: waypoint + Location: 54,10 + Owner: Neutral + UnitsEntryRocket: waypoint + Location: 56,12 + Owner: Neutral + UnitsRallyRocket: waypoint + Location: 54,12 + Owner: Neutral + NodCiv1: c8 + Location: 46,36 + Owner: NodSupporter + Facing: 512 SubCell: 2 - NodGunner2: e1 - Location: 39,50 - Owner: GDI + NodCiv2: e3 + Location: 48,36 + Owner: NodSupporter + Facing: 768 + SubCell: 4 + NodCiv3: c4 + Location: 52,38 + Owner: NodSupporter + Facing: 768 + SubCell: 1 + NodCiv4: c3 + Location: 45,35 + Owner: NodSupporter + Facing: 128 + SubCell: 4 + NodCiv5: c1 + Location: 51,36 + Owner: NodSupporter + Facing: 896 + SubCell: 2 + NodCiv6: c2 + Location: 45,34 + Owner: NodSupporter + Facing: 0 + SubCell: 1 + NodCiv7: c4 + Location: 54,36 + Owner: NodSupporter + Facing: 640 SubCell: 0 - NodGunner3: e1 - Location: 40,50 + NodCiv8: c5 + Location: 50,37 + Owner: NodSupporter + Facing: 384 + SubCell: 2 + NodCiv9: c9 + Location: 47,34 + Owner: NodSupporter + Facing: 768 + SubCell: 2 + Gciv1: e1 + Location: 38,9 Owner: GDI - Facing: 64 + Facing: 512 SubCell: 0 - EntryPointVehicle: waypoint - Location: 33,17 - Owner: Neutral - RallyPointVehicle: waypoint - Location: 33,30 - Owner: Neutral - EntryPointRocket: waypoint - Location: 35,17 - Owner: Neutral - RallyPointRocket: waypoint - Location: 35,32 - Owner: Neutral - EntryPointGunner: waypoint - Location: 31,17 - Owner: Neutral - RallyPointGunner: waypoint - Location: 31,32 - Owner: Neutral - CameraPoint: waypoint - Location: 32,22 - Owner: Neutral + Gciv2: e1 + Location: 18,10 + Owner: GDI + Facing: 640 + SubCell: 2 Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/cnc/maps/nod04b/nod04b.lua openra-20210321/mods/cnc/maps/nod04b/nod04b.lua --- openra-20200503/mods/cnc/maps/nod04b/nod04b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod04b/nod04b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -7,95 +7,201 @@ information, see COPYING. ]] -NodUnitsBuggy = { "bggy", "bggy", "bike", "bike" } -NodUnitsRocket = { "e3", "e3", "e3", "e3", "e3", "e3" } +NodUnitsBuggy = { "bggy", "bggy", "bggy", "bggy", "bggy" } +NodUnitsBikes = { "bike", "bike", "bike" } NodUnitsGunner = { "e1", "e1", "e1", "e1", "e1", "e1" } +NodUnitsRocket = { "e3", "e3", "e3", "e3", "e3", "e3" } + +Atk6Units = { "c1", "c2", "c3" } +Atk5Units = { "e1", "e1", "e2", "e2" } +Atk1Units = { "e1", "e1" } +JeepReinforcements = { "jeep" } +GDIUnits = { "e1", "e1", "e2" } +ApcUnits = { "e1", "e1", "e2", "e2" } + +Spawnpoint = { waypoint0.Location } +Atk6WaypointsPart1 = { waypoint1.Location, waypoint2.Location, waypoint3.Location, waypoint4.Location } +Atk6WaypointsPart2 = { waypoint7.Location, waypoint8.Location, waypoint7.Location } +Atk5Waypoints = { waypoint0.Location, waypoint9.Location} +Atk3Waypoints = { waypoint0 } +Atk2Waypoints = { waypoint6 } +GcivWaypoints = { waypoint0, waypoint1, waypoint2, waypoint3, waypoint4 } +Atk1Waypoints = { waypoint0, waypoint1, waypoint2, waypoint3, waypoint4, waypoint5, waypoint6 } +Atk4Waypoints = { waypoint0, waypoint9 } + +Atk6ActorTriggerActivator = { Civilian1, Civilian2 } +Atk5ActorTriggerActivator = { Soldier1, Soldier2, Soldier3, Actor105 } +WinActorTriggerActivator = { GDICiv1, GDICiv2, GDICiv3, GDICiv4, GDICiv5, GDICiv6, GDICiv7, GDICiv8, GDICiv9, GDICiv11, GDICiv12, GDICiv13 } +GcivActors = { Gcvi1, Gciv2, GDICiv2, GDICiv9, GDICiv10, GDICiv11 } + +Atk2CellTriggerActivator = { CPos.New(41,22), CPos.New(40,22), CPos.New(39,22), CPos.New(41,21), CPos.New(40,21), CPos.New(39,21) } +Atk3CellTriggerActivator = { CPos.New(18,18), CPos.New(17,18), CPos.New(16,18), CPos.New(15,18), CPos.New(14,18), CPos.New(13,18), CPos.New(12,18), CPos.New(11,18), CPos.New(24,17), CPos.New(23,17), CPos.New(22,17), CPos.New(21,17), CPos.New(20,17), CPos.New(19,17), CPos.New(17,17), CPos.New(16,17), CPos.New(15,17), CPos.New(14,17), CPos.New(13,17), CPos.New(12,17), CPos.New(11,17) } +Atk4CellTriggerActivator = { CPos.New(29,28), CPos.New(28,28), CPos.New(29,27), CPos.New(28,27), CPos.New(29,26), CPos.New(28,26), CPos.New(29,25), CPos.New(28,25), CPos.New(29,24), CPos.New(28,24), CPos.New(29,23), CPos.New(28,23), CPos.New(29,22), CPos.New(28,22) } +GcivCellTriggerActivator = { CPos.New(51,17), CPos.New(50,17), CPos.New(49,17), CPos.New(48,17), CPos.New(47,17), CPos.New(46,17), CPos.New(45,17), CPos.New(44,17), CPos.New(43,17), CPos.New(42,17), CPos.New(41,17), CPos.New(40,17), CPos.New(39,17), CPos.New(38,17), CPos.New(37,17), CPos.New(36,17), CPos.New(35,17), CPos.New(52,16), CPos.New(51,16), CPos.New(50,16), CPos.New(49,16), CPos.New(48,16), CPos.New(47,16), CPos.New(46,16), CPos.New(45,16), CPos.New(44,16), CPos.New(43,16), CPos.New(42,16), CPos.New(41,16), CPos.New(40,16), CPos.New(39,16), CPos.New(38,16), CPos.New(37,16), CPos.New(36,16), CPos.New(35,16) } +DelxCellTriggerActivator = { CPos.New(42,20), CPos.New(41,20), CPos.New(40,20), CPos.New(39,20), CPos.New(38,20) } +DelyCellTriggerActivator = { CPos.New(31,28), CPos.New(30,28), CPos.New(31,27), CPos.New(30,27), CPos.New(31,26), CPos.New(30,26), CPos.New(31,25), CPos.New(30,25), CPos.New(31,24), CPos.New(30,24) } +DelzCellTriggerActivator = { CPos.New(18,20), CPos.New(17,20), CPos.New(16,20), CPos.New(15,20), CPos.New(14,20), CPos.New(13,20), CPos.New(12,20), CPos.New(11,20), CPos.New(25,19), CPos.New(24,19), CPos.New(23,19), CPos.New(22,19), CPos.New(21,19), CPos.New(20,19), CPos.New(19,19), CPos.New(18,19), CPos.New(17,19), CPos.New(16,19), CPos.New(15,19), CPos.New(14,19), CPos.New(13,19), CPos.New(12,19), CPos.New(11,19), CPos.New(25,18), CPos.New(24,18), CPos.New(23,18), CPos.New(22,18), CPos.New(21,18), CPos.New(20,18), CPos.New(19,18) } + +NodCiviliansActors = { NodCiv1, NodCiv2, NodCiv3, NodCiv4, NodCiv5, NodCiv6, NodCiv7, NodCiv8, NodCiv9 } + +SendJeepReinforcements = function() + if not PreventJeepReinforcements then + local units = Reinforcements.Reinforce(GDI, JeepReinforcements, Spawnpoint, 15) + MoveAndHunt(units, Atk2Waypoints) + end +end + +SendGDIReinforcements = function() + if not PreventGDIReinforcements then + local units = Reinforcements.Reinforce(GDI, GDIUnits, Spawnpoint, 15) + MoveAndHunt(units, Atk4Waypoints) + end +end + +SendApcReinforcements = function() + if not PreventApcReinforcements then + Reinforcements.ReinforceWithTransport(GDI, "apc", ApcUnits, Atk5Waypoints, nil, + function(transport, cargo) + transport.UnloadPassengers() + Utils.Do(cargo, IdleHunt) + end, IdleHunt) + end +end + +CreateCivilians = function(actor, discoverer) + Utils.Do(NodCiviliansActors, function(actor) + actor.Owner = Nod + end) -Apc3Trigger = { CPos.New(28,58), CPos.New(27,58), CPos.New(28,57), CPos.New(27,57), CPos.New(28,56), CPos.New(27,56), CPos.New(28,55), CPos.New(27,55), CPos.New(28,54), CPos.New(27,54), CPos.New(28,53), CPos.New(27,53) } -Civ1CellTriggerActivator = { CPos.New(24,52), CPos.New(23,52), CPos.New(22,52), CPos.New(23,51), CPos.New(22,51), CPos.New(21,51) } -Civ2CellTriggerActivator = { CPos.New(26,54), CPos.New(25,54), CPos.New(24,54), CPos.New(25,53), CPos.New(24,53), CPos.New(23,53) } - -Apc1Units = { "c2", "c3", "c4", "c5" } - -TargetActors = { Civilian1, Civilian2, Civilian3, Civilian4, Civilian5, Civilian6, Civilian7, Civilian8, CivBuilding1, CivBuilding2, CivBuilding3, CivBuilding4, CivBuilding5, CivBuilding6, CivBuilding7, CivBuilding8, CivBuilding9, CivBuilding10, CivBuilding11, CivBuilding12, CivBuilding13, CivBuilding14 } -Apc2Trigger = { NodGunner1, NodGunner2, NodGunner3 } - -Apc1Waypoints = { waypoint0.Location, waypoint11.Location, waypoint10.Location, waypoint8.Location, waypoint9.Location } -Apc2Waypoints = { waypoint8, waypoint7, waypoint6, waypoint5, waypoint4 } -Apc3Waypoints = { waypoint3, waypoint2, waypoint1, waypoint0, waypoint11, waypoint10, waypoint8, waypoint9 } -Civ1Waypoints = { waypoint3, waypoint2, waypoint3, waypoint1, waypoint2, waypoint11, waypoint10, waypoint8, waypoint9 } -Civ2Waypoints = { waypoint3, waypoint2, waypoint1, waypoint11, waypoint10, waypoint8, waypoint9 } -Hummer1Waypoints = { waypoint8, waypoint7, waypoint6, waypoint5, waypoint4, waypoint3, waypoint2, waypoint1, waypoint0, waypoint11, waypoint10, waypoint8 } + ProtectCivilians = Nod.AddPrimaryObjective("Protect the civilians that support Nod.") + Trigger.OnAllKilled(NodCiviliansActors, function() + Nod.MarkFailedObjective(ProtectCivilians) + end) + + Utils.Do(GcivActors, function(actor) + if not actor.IsDead then + actor.AttackMove(waypoint7.Location) + actor.AttackMove(waypoint8.Location) + IdleHunt(actor) + end + end) +end WorldLoaded = function() Nod = Player.GetPlayer("Nod") + NodSupporter = Player.GetPlayer("NodSupporter") GDI = Player.GetPlayer("GDI") - Trigger.AfterDelay(DateTime.Seconds(3), function() - Reinforcements.ReinforceWithTransport(GDI, "apc", Apc1Units, Apc1Waypoints, nil, + InitObjectives(Nod) + + Trigger.OnAnyKilled(Atk6ActorTriggerActivator, function() + Reinforcements.ReinforceWithTransport(GDI, "apc", Atk6Units, Atk6WaypointsPart1, Atk6WaypointsPart2, function(transport, cargo) Utils.Do(cargo, IdleHunt) - end) + end, IdleHunt) end) - Trigger.OnEnteredFootprint(Civ2CellTriggerActivator, function(a, id) + Utils.Do(Atk5ActorTriggerActivator, function(actor) + Trigger.OnDamaged(actor, function() + if Atk5TriggerSwitch then + return + end + + Atk5TriggerSwitch = true + Reinforcements.ReinforceWithTransport(GDI, "apc", Atk5Units, Atk5Waypoints, nil, + function(transport, cargo) + transport.UnloadPassengers() + Utils.Do(cargo, IdleHunt) + end, IdleHunt) + end) + end) + + Trigger.OnEnteredFootprint(Atk3CellTriggerActivator, function(a, id) if a.Owner == Nod then - for type, count in pairs({ ["c6"] = 1, ["c7"] = 1, ["c8"] = 1, ["c9"] = 1 }) do - MoveAndHunt(Utils.Take(count, GDI.GetActorsByType(type)), Civ2Waypoints) + Trigger.RemoveFootprintTrigger(id) + + for type, count in pairs({ ["e1"] = 3, ["e2"] = 2, ["mtnk"] = 1 }) do + MoveAndHunt(Utils.Take(count, GDI.GetActorsByType(type)), Atk3Waypoints) end + end + end) + + Trigger.OnEnteredFootprint(Atk2CellTriggerActivator, function(a, id) + if a.Owner == Nod then + MoveAndHunt(Utils.Take(1, GDI.GetActorsByType("jeep")), Atk2Waypoints) Trigger.RemoveFootprintTrigger(id) end end) - Trigger.OnEnteredFootprint(Civ1CellTriggerActivator, function(a, id) + Trigger.OnEnteredFootprint(GcivCellTriggerActivator, function(a, id) if a.Owner == Nod then - for type, count in pairs({ ["c2"] = 1, ["c3"] = 1, ["c4"] = 1, ["c5"] = 1 }) do - MoveAndHunt(Utils.Take(count, GDI.GetActorsByType(type)), Civ1Waypoints) + MoveAndHunt(GcivActors, GcivWaypoints) + Trigger.RemoveFootprintTrigger(id) + end + end) + + Trigger.OnEnteredFootprint(Atk4CellTriggerActivator, function(a, id) + if a.Owner == Nod then + for type, count in pairs({ ["e1"] = 2,["e2"] = 1 }) do + MoveAndHunt(Utils.Take(count, GDI.GetActorsByType(type)), Atk4Waypoints) end Trigger.RemoveFootprintTrigger(id) end end) - Trigger.OnDiscovered(Convoi, function() - MoveAndHunt(Utils.Take(2, GDI.GetActorsByType("jeep")), Hummer1Waypoints) + Trigger.AfterDelay(DateTime.Seconds(20), function() + local units = Reinforcements.Reinforce(GDI, Atk1Units, Spawnpoint, 15) + MoveAndHunt(units, Atk1Waypoints) end) - Trigger.OnAllRemovedFromWorld(Apc2Trigger, function() - MoveAndHunt(Utils.Take(1, GDI.GetActorsByType("apc")), Apc2Waypoints) + Trigger.AfterDelay(DateTime.Seconds(50), SendJeepReinforcements) + Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(40), SendGDIReinforcements) + Trigger.AfterDelay(DateTime.Minutes(2) + DateTime.Seconds(30), SendApcReinforcements) + + Trigger.OnEnteredFootprint(DelxCellTriggerActivator, function(a, id) + if a.Owner == Nod then + PreventJeepReinforcements = true + Trigger.RemoveFootprintTrigger(id) + end end) - Trigger.OnEnteredFootprint(Apc3Trigger, function(a, id) + Trigger.OnEnteredFootprint(DelyCellTriggerActivator, function(a, id) if a.Owner == Nod then - MoveAndHunt(Utils.Take(1, GDI.GetActorsByType("apc"), Apc3Waypoints)) + PreventGDIReinforcements = true Trigger.RemoveFootprintTrigger(id) end end) - Trigger.OnAllRemovedFromWorld(TargetActors, function() - Nod.MarkCompletedObjective(KillCivilians) + Trigger.OnEnteredFootprint(DelzCellTriggerActivator, function(a, id) + if a.Owner == Nod then + PreventApcReinforcements = true + Trigger.RemoveFootprintTrigger(id) + end end) - InitObjectives(Nod) + Trigger.OnPlayerDiscovered(NodSupporter, CreateCivilians) - KillCivilians = Nod.AddObjective("Destroy the village and kill all civilians.") - KillGDI = Nod.AddObjective("Kill all GDI units in the area.", "Secondary", false) + Trigger.OnAllKilled(WinActorTriggerActivator, function() + Nod.MarkCompletedObjective(KillGDI) - Camera.Position = CameraPoint.CenterPosition + if ProtectCivilians then + Nod.MarkCompletedObjective(ProtectCivilians) + end + end) + + KillGDI = Nod.AddObjective("Kill all civilian GDI supporters.") Media.PlaySpeechNotification(Nod, "Reinforce") - Trigger.AfterDelay(DateTime.Seconds(1), function() - Reinforcements.ReinforceWithTransport(Nod, "tran", NodUnitsBuggy, { EntryPointVehicle.Location, RallyPointVehicle.Location }, { EntryPointVehicle.Location }, nil, nil) - end) - Reinforcements.ReinforceWithTransport(Nod, "tran", NodUnitsRocket, { EntryPointRocket.Location, RallyPointRocket.Location }, { EntryPointRocket.Location }, nil, nil) - Reinforcements.ReinforceWithTransport(Nod, "tran", NodUnitsGunner, { EntryPointGunner.Location, RallyPointGunner.Location }, { EntryPointGunner.Location }, nil, nil) + Reinforcements.Reinforce(Nod, NodUnitsBuggy, { UnitsEntryBuggy.Location, UnitsRallyBuggy.Location }, 11) + Reinforcements.Reinforce(Nod, NodUnitsBikes, { UnitsEntryBikes.Location, UnitsRallyBikes.Location }, 15) + Reinforcements.Reinforce(Nod, NodUnitsGunner, { UnitsEntryGunner.Location, UnitsRallyGunner.Location }, 15) + Reinforcements.Reinforce(Nod, NodUnitsRocket, { UnitsEntryRocket.Location, UnitsRallyRocket.Location }, 15) + + Camera.Position = waypoint6.CenterPosition end Tick = function() if DateTime.GameTime > 2 and Nod.HasNoRequiredUnits() then - Nod.MarkFailedObjective(KillCivilians) - end - - if GDI.HasNoRequiredUnits() then - Nod.MarkCompletedObjective(KillGDI) + Nod.MarkFailedObjective(KillGDI) end end diff -Nru openra-20200503/mods/cnc/maps/nod04b/rules.yaml openra-20210321/mods/cnc/maps/nod04b/rules.yaml --- openra-20200503/mods/cnc/maps/nod04b/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod04b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,27 +2,128 @@ LuaScript: Scripts: campaign-global.lua, nod04b.lua MusicPlaylist: - StartingMusic: warfare + StartingMusic: valkyrie VictoryMusic: nod_win1 MissionData: Briefing: A small village friendly to our cause has been increasingly harassed by GDI, and the Brotherhood wishes you to assist them in their efforts.\n\nSeek out the enemy village and destroy it. The event will be disguised as a GDI attack. BriefingVideo: nod4b.vqa - LossVideo: nodlose.vqa + StartVideo: retro.vqa + LossVideo: deskill.vqa + SmudgeLayer@SCORCH: + InitialSmudges: + 37,24: sc6,0 + 36,18: sc6,0 Player: EnemyWatcher: PlayerResources: DefaultCash: 0 -^Vehicle: +^Palettes: + IndexedPlayerPalette: + PlayerIndex: + NodSupporter: 192, 164, 132, 155, 133, 197, 112, 12, 163, 132, 155, 133, 134, 197, 154, 198 + IndexedPlayerPalette@units: + PlayerIndex: + NodSupporter: 192, 164, 132, 155, 133, 197, 112, 12, 163, 132, 155, 133, 134, 197, 154, 198 + +^Infantry: + AnnounceOnSeen: + +^CivBuilding: AnnounceOnSeen: -^Tank: +^CivBuildingHusk: AnnounceOnSeen: -TRAN: - RejectsOrders: - -Selectable: - RevealsShroud: - Range: 5c0 - Interactable: +NUK2: + Buildable: + Prerequisites: ~disabled + +GUN: + Buildable: + Prerequisites: ~disabled + +CYCL: + Buildable: + Prerequisites: ~disabled + +FIX: + Buildable: + Prerequisites: ~disabled + +HPAD: + Buildable: + Prerequisites: ~disabled + +OBLI: + Buildable: + Prerequisites: ~disabled + +BRIK: + Buildable: + Prerequisites: ~disabled + +TMPL: + Buildable: + Prerequisites: ~disabled + +FTNK: + Buildable: + Prerequisites: ~disabled + +STNK: + Buildable: + Prerequisites: ~disabled + +ARTY: + Buildable: + Prerequisites: ~disabled + +E5: + Buildable: + Prerequisites: ~disabled + +RMBO: + Buildable: + Prerequisites: ~disabled + +MLRS: + Buildable: + Prerequisites: ~disabled + +MCV: + Buildable: + Prerequisites: ~disabled + +SAM: + Buildable: + Prerequisites: ~disabled + +AFLD: + Buildable: + Prerequisites: ~disabled + +E4: + Buildable: + Prerequisites: ~disabled + +SBAG: + Buildable: + Prerequisites: ~disabled + +GTWR: + Buildable: + Prerequisites: ~disabled + +WEAP: + Buildable: + Prerequisites: ~disabled + +EYE: + Buildable: + Prerequisites: ~disabled + +ATWR: + Buildable: + Prerequisites: ~disabled diff -Nru openra-20200503/mods/cnc/maps/nod05/map.yaml openra-20210321/mods/cnc/maps/nod05/map.yaml --- openra-20200503/mods/cnc/maps/nod05/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod05/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -262,17 +262,17 @@ Actor89: e1 Location: 7,30 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 3 Actor90: e2 Location: 6,30 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 1 Actor91: e2 Location: 8,28 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 3 Actor92: e2 Location: 39,43 diff -Nru openra-20200503/mods/cnc/maps/nod05/nod05.lua openra-20210321/mods/cnc/maps/nod05/nod05.lua --- openra-20200503/mods/cnc/maps/nod05/nod05.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod05/nod05.lua 2021-03-21 11:10:05.000000000 +0000 @@ -46,7 +46,7 @@ local target = GetAirstrikeTarget(Nod) if target then - CommCenter.SendAirstrike(target, false, Facing.NorthEast + 4) + CommCenter.TargetAirstrike(target, Angle.NorthEast + Angle.New(16)) Trigger.AfterDelay(AirstrikeDelay, SendGDIAirstrike) else Trigger.AfterDelay(AirstrikeDelay/4, SendGDIAirstrike) diff -Nru openra-20200503/mods/cnc/maps/nod06a/map.yaml openra-20210321/mods/cnc/maps/nod06a/map.yaml --- openra-20200503/mods/cnc/maps/nod06a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod06a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -386,15 +386,15 @@ Actor125: jeep Location: 59,25 Owner: GDI - Facing: 160 + Facing: 640 Actor126: jeep Location: 50,42 Owner: GDI - Facing: 128 + Facing: 512 Actor127: mtnk Location: 53,45 Owner: GDI - Facing: 160 + Facing: 640 Actor128: mtnk Location: 59,38 Owner: GDI @@ -410,23 +410,23 @@ Actor134: mtnk Location: 38,38 Owner: GDI - Facing: 160 + Facing: 640 Actor135: jeep Location: 60,37 Owner: GDI Actor139: mtnk Location: 28,33 Owner: GDI - Facing: 224 + Facing: 896 Actor140: e2 Location: 24,29 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 1 Actor141: e2 Location: 24,28 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 3 Actor142: e1 Location: 58,38 @@ -475,17 +475,17 @@ Actor154: c3 Location: 40,22 Owner: Neutral - Facing: 192 + Facing: 768 SubCell: 4 Actor155: c5 Location: 40,19 Owner: Neutral - Facing: 96 + Facing: 384 SubCell: 1 Actor156: c6 Location: 39,21 Owner: Neutral - Facing: 96 + Facing: 384 SubCell: 0 Actor157: e1 Location: 30,57 @@ -599,7 +599,7 @@ Atk1Activator2: e1 Location: 50,46 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 4 Atk2Activator1: gtwr Location: 51,46 @@ -607,7 +607,7 @@ Atk2Activator2: e1 Location: 48,44 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 4 Atk3Activator: v25 Location: 41,19 @@ -645,31 +645,26 @@ Actor187: jeep Owner: GDI Location: 40,21 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor188: e1 Owner: GDI Location: 41,22 SubCell: 3 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor189: e1 Owner: GDI Location: 39,20 SubCell: 3 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor190: e3 Owner: GDI Location: 40,20 SubCell: 3 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor191: e3 Owner: GDI Location: 40,20 SubCell: 1 - Facing: 92 - TurretFacing: 92 + Facing: 368 Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/cnc/maps/nod06a/nod06a.lua openra-20210321/mods/cnc/maps/nod06a/nod06a.lua --- openra-20200503/mods/cnc/maps/nod06a/nod06a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod06a/nod06a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -81,7 +81,7 @@ local target = targets[DateTime.GameTime % #targets + 1].CenterPosition if target then - CommCenter.SendAirstrike(target, false, Facing.NorthEast + 4) + CommCenter.TargetAirstrike(target, Angle.NorthEast + Angle.New(16)) end end end diff -Nru openra-20200503/mods/cnc/maps/nod06b/map.yaml openra-20210321/mods/cnc/maps/nod06b/map.yaml --- openra-20200503/mods/cnc/maps/nod06b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod06b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -383,19 +383,19 @@ Actor115: mtnk Location: 36,37 Owner: GDI - Facing: 160 + Facing: 640 Actor116: jeep Location: 29,24 Owner: GDI - Facing: 96 + Facing: 384 Actor117: mtnk Location: 24,48 Owner: GDI - Facing: 192 + Facing: 768 Actor118: mtnk Location: 28,42 Owner: GDI - Facing: 160 + Facing: 640 Actor128: e2 Location: 18,41 Owner: GDI @@ -435,12 +435,12 @@ Actor137: e3 Location: 27,45 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 4 Actor138: e1 Location: 25,58 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 3 Actor139: c3 Location: 36,58 @@ -453,7 +453,7 @@ Actor141: e1 Location: 31,59 Owner: GDI - Facing: 192 + Facing: 768 SubCell: 4 Actor142: e2 Location: 31,57 @@ -466,7 +466,7 @@ Actor144: e2 Location: 34,60 Owner: GDI - Facing: 192 + Facing: 768 SubCell: 3 Actor157: e1 Location: 22,60 @@ -479,17 +479,17 @@ Actor160: e3 Location: 27,46 Owner: GDI - Facing: 32 + Facing: 128 SubCell: 1 Actor161: e3 Location: 33,45 Owner: GDI - Facing: 192 + Facing: 768 SubCell: 4 Actor162: e2 Location: 34,45 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 0 waypoint27: waypoint Location: 60,18 @@ -595,7 +595,6 @@ Actor169: mtnk Owner: GDI Location: 33,54 - Facing: 92 - TurretFacing: 92 + Facing: 368 Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/cnc/maps/nod06c/map.yaml openra-20210321/mods/cnc/maps/nod06c/map.yaml --- openra-20200503/mods/cnc/maps/nod06c/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod06c/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -256,11 +256,11 @@ Actor72: jeep Location: 37,40 Owner: GDI - Facing: 96 + Facing: 384 Actor73: jeep Location: 47,18 Owner: GDI - Facing: 160 + Facing: 640 Actor74: mtnk Location: 17,39 Owner: GDI @@ -273,11 +273,11 @@ Actor83: mtnk Location: 39,27 Owner: GDI - Facing: 96 + Facing: 384 Actor85: jeep Location: 29,30 Owner: GDI - Facing: 224 + Facing: 896 Actor86: e3 Location: 35,36 Owner: GDI @@ -293,7 +293,7 @@ Actor89: e1 Location: 49,22 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 1 Actor92: e2 Location: 16,25 @@ -306,32 +306,32 @@ Actor96: e3 Location: 36,25 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 2 Actor99: e1 Location: 30,26 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 4 Actor100: e1 Location: 48,21 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 4 Actor101: e3 Location: 51,42 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 2 Actor102: e3 Location: 52,42 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 2 Actor103: e1 Location: 40,30 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 2 Actor104: e2 Location: 47,35 @@ -340,7 +340,7 @@ Actor105: e2 Location: 35,46 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 1 Actor114: e2 Location: 43,29 @@ -357,12 +357,12 @@ Actor120: e2 Location: 23,24 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 4 Actor121: e2 Location: 25,24 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 3 Actor122: e2 Location: 27,31 @@ -432,7 +432,7 @@ Atk2Actor2: e1 Location: 42,29 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 2 Atk2Actor3: e3 Location: 41,29 @@ -441,17 +441,17 @@ Atk2Actor4: e1 Location: 40,30 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 1 Atk2Actor5: e1 Location: 43,29 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 1 Atk2Actor6: mtnk Location: 42,30 Owner: GDI - Facing: 96 + Facing: 384 Detonator: CRATE.plain Location: 24, 22 Owner: GDI diff -Nru openra-20200503/mods/cnc/maps/nod07a/map.yaml openra-20210321/mods/cnc/maps/nod07a/map.yaml --- openra-20200503/mods/cnc/maps/nod07a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod07a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -340,11 +340,11 @@ Actor115: mtnk Location: 18,28 Owner: GDI - Facing: 32 + Facing: 128 Actor116: mtnk Location: 17,21 Owner: GDI - Facing: 96 + Facing: 384 Actor117: e2 Location: 20,52 Owner: GDI @@ -384,22 +384,22 @@ Actor126: c6 Location: 18,51 Owner: Civilians - Facing: 32 + Facing: 128 SubCell: 4 Actor127: c5 Location: 10,48 Owner: Civilians - Facing: 224 + Facing: 896 SubCell: 0 Actor142: c8 Location: 48,52 Owner: Civilians - Facing: 224 + Facing: 896 SubCell: 4 Actor143: c4 Location: 52,57 Owner: Civilians - Facing: 32 + Facing: 128 SubCell: 1 Actor144: c3 Location: 11,46 @@ -408,7 +408,7 @@ Actor145: c9 Location: 15,44 Owner: Civilians - Facing: 64 + Facing: 256 SubCell: 0 Actor146: e2 Location: 12,57 @@ -519,7 +519,7 @@ GDIHarvester: harv Location: 13,55 Owner: GDI - Facing: 192 + Facing: 768 GDIHQ: hq Location: 20,57 Owner: GDI @@ -564,7 +564,7 @@ NodHarvester: harv Owner: NodBase Location: 46,31 - Facing: 92 + Facing: 368 ReinforcementsBottomSpawn: waypoint Owner: Neutral Location: 59,41 diff -Nru openra-20200503/mods/cnc/maps/nod07a/nod07a.lua openra-20210321/mods/cnc/maps/nod07a/nod07a.lua --- openra-20200503/mods/cnc/maps/nod07a/nod07a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod07a/nod07a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -76,7 +76,7 @@ local target = GetAirstrikeTarget(Nod) if target then - hq.SendAirstrike(target, false, Facing.NorthEast + 4) + hq.TargetAirstrike(target, Angle.NorthEast + Angle.New(16)) Trigger.AfterDelay(delay, function() SendGDIAirstrike(hq, delay) end) else Trigger.AfterDelay(delay/4, function() SendGDIAirstrike(hq, delay) end) diff -Nru openra-20200503/mods/cnc/maps/nod07b/map.yaml openra-20210321/mods/cnc/maps/nod07b/map.yaml --- openra-20200503/mods/cnc/maps/nod07b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod07b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -552,46 +552,46 @@ Health: 99 Actor171: hosp Location: 55,28 - Owner: Civilians + Owner: GDI Actor172: mtnk Location: 51,40 Owner: GDI Actor173: jeep Location: 17,31 Owner: GDI - Facing: 224 + Facing: 896 Actor174: mtnk Location: 21,36 Owner: GDI - Facing: 224 + Facing: 896 Actor175: mtnk Location: 42,52 Owner: GDI - Facing: 160 + Facing: 640 Actor176: jeep Location: 14,26 Owner: GDI - Facing: 32 + Facing: 128 Actor177: mtnk Location: 50,47 Owner: GDI - Facing: 96 + Facing: 384 Actor188: mtnk Location: 51,53 Owner: GDI - Facing: 160 + Facing: 640 Actor189: mtnk Location: 24,26 Owner: GDI - Facing: 224 + Facing: 896 Actor190: mtnk Location: 29,36 Owner: GDI - Facing: 128 + Facing: 512 Actor191: mtnk Location: 27,36 Owner: GDI - Facing: 128 + Facing: 512 Actor192: jeep Location: 8,38 Owner: GDI @@ -667,12 +667,12 @@ Location: 13,40 Owner: GDI Health: 83 - Facing: 224 + Facing: 896 SubCell: 4 Actor212: e3 Location: 13,42 Owner: GDI - Facing: 192 + Facing: 768 SubCell: 4 Actor213: e2 Location: 11,37 @@ -690,17 +690,17 @@ Actor222: c2 Location: 40,24 Owner: Civilians - Facing: 160 + Facing: 640 SubCell: 2 Actor223: c3 Location: 36,25 Owner: Civilians - Facing: 224 + Facing: 896 SubCell: 2 Actor224: c4 Location: 41,26 Owner: Civilians - Facing: 64 + Facing: 256 SubCell: 3 Actor225: c5 Location: 44,25 @@ -709,65 +709,65 @@ Actor226: c6 Location: 42,28 Owner: Civilians - Facing: 64 + Facing: 256 SubCell: 2 Actor227: c7 Location: 38,26 Owner: Civilians Health: 19 - Facing: 224 + Facing: 896 SubCell: 0 Actor228: c8 Location: 40,26 Owner: Civilians - Facing: 32 + Facing: 128 SubCell: 3 Actor229: c9 Location: 36,22 Owner: Civilians - Facing: 64 + Facing: 256 SubCell: 2 Actor230: c1 Location: 44,24 Owner: Civilians Health: 19 - Facing: 64 + Facing: 256 SubCell: 2 Actor231: c2 Location: 36,26 Owner: Civilians - Facing: 64 + Facing: 256 SubCell: 1 Actor232: c3 Location: 51,26 Owner: Civilians - Facing: 128 + Facing: 512 SubCell: 2 Actor233: c4 Location: 55,23 Owner: Civilians - Facing: 32 + Facing: 128 SubCell: 3 Actor234: c5 Location: 57,26 Owner: Civilians - Facing: 160 + Facing: 640 SubCell: 1 Actor235: c6 Location: 48,26 Owner: Civilians - Facing: 64 + Facing: 256 SubCell: 3 Actor236: c7 Location: 42,22 Owner: Civilians - Facing: 160 + Facing: 640 SubCell: 2 Actor237: c8 Location: 46,30 Owner: Civilians Health: 19 - Facing: 128 + Facing: 512 SubCell: 1 Actor238: c9 Location: 39,29 diff -Nru openra-20200503/mods/cnc/maps/nod07b/nod07b.lua openra-20210321/mods/cnc/maps/nod07b/nod07b.lua --- openra-20200503/mods/cnc/maps/nod07b/nod07b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod07b/nod07b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -83,7 +83,7 @@ local target = GetAirstrikeTarget(Nod) if target then - hq.SendAirstrike(target, false, Facing.NorthEast + 4) + hq.TargetAirstrike(target, Angle.NorthEast + Angle.New(16)) Trigger.AfterDelay(delay, function() SendGDIAirstrike(hq, delay) end) else Trigger.AfterDelay(delay/4, function() SendGDIAirstrike(hq, delay) end) diff -Nru openra-20200503/mods/cnc/maps/nod07c/map.yaml openra-20210321/mods/cnc/maps/nod07c/map.yaml --- openra-20200503/mods/cnc/maps/nod07c/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod07c/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -410,19 +410,19 @@ MediumTank3: mtnk Location: 44,45 Owner: GDI - Facing: 32 + Facing: 128 MediumTank2: mtnk Location: 34,34 Owner: GDI - Facing: 224 + Facing: 896 Jeep: jeep Location: 30,41 Owner: GDI - Facing: 224 + Facing: 896 Actor118: harv Location: 26,43 Owner: GDI - Facing: 224 + Facing: 896 Guard1: e2 Location: 46,57 Owner: GDI @@ -474,7 +474,7 @@ Actor141: e2 Location: 35,52 Owner: GDI - Facing: 192 + Facing: 768 SubCell: 1 Actor150: e1 Location: 25,37 @@ -527,12 +527,12 @@ Actor161: e2 Location: 17,20 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 1 Actor162: e2 Location: 17,19 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 1 Actor163: e1 Location: 24,37 @@ -541,7 +541,7 @@ Actor164: e1 Location: 34,51 Owner: GDI - Facing: 128 + Facing: 512 SubCell: 2 Actor165: e1 Location: 51,40 @@ -566,12 +566,12 @@ Actor170: e1 Location: 22,57 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 2 Actor171: e2 Location: 21,58 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 2 Actor172: e1 Location: 44,6 @@ -740,14 +740,14 @@ Owner: Target Location: 56,56 CenterPosition: 58450,58025,0 - Facing: 230 + Facing: 920 GunboatRight: waypoint Owner: Neutral Location: 58,16 Gunboat: boat Location: 32,16 Owner: GDI - Facing: 192 + Facing: 768 ReinforcementsTopSpawn: waypoint Owner: Neutral Location: 58,24 diff -Nru openra-20200503/mods/cnc/maps/nod07c/rules.yaml openra-20210321/mods/cnc/maps/nod07c/rules.yaml --- openra-20200503/mods/cnc/maps/nod07c/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod07c/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -117,7 +117,7 @@ Health: HP: 150000 RevealsShroud: - ValidStances: Ally, Neutral, Enemy + ValidRelationships: Ally, Neutral, Enemy Range: 4c0 TRAN.IN: Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/nod08a/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/nod08a/map.png differ diff -Nru openra-20200503/mods/cnc/maps/nod08a/map.yaml openra-20210321/mods/cnc/maps/nod08a/map.yaml --- openra-20200503/mods/cnc/maps/nod08a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod08a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -263,15 +263,15 @@ Actor88: mtnk Location: 45,20 Owner: GDI - Facing: 160 + Facing: 640 Actor89: mtnk Location: 50,58 Owner: GDI - Facing: 192 + Facing: 768 Actor90: mtnk Location: 57,28 Owner: GDI - Facing: 160 + Facing: 640 Actor91: e2 Location: 27,60 Owner: GDI @@ -375,62 +375,62 @@ Actor116: e3 Location: 55,23 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 1 Actor117: e1 Location: 56,23 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 1 Actor118: e1 Location: 54,28 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 1 Actor119: e2 Location: 53,28 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 0 Actor120: e2 Location: 56,24 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 2 Actor121: e1 Location: 35,25 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 0 Actor122: e2 Location: 36,50 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 4 Actor123: e1 Location: 44,58 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 4 Actor124: e1 Location: 47,55 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 0 Actor135: e1 Location: 46,58 Owner: GDI - Facing: 32 + Facing: 128 SubCell: 2 Actor136: e2 Location: 47,59 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 0 Actor137: e2 Location: 43,57 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 1 waypoint27: waypoint Location: 33,53 @@ -489,10 +489,10 @@ Actor145: waypoint Location: 49,22 Owner: Neutral - Actor156: split3 + Actor156: t13.transformable Owner: Neutral Location: 40,22 - Actor157: split3 + Actor157: t13.transformable Owner: Neutral Location: 57,42 AirstrikeTarget: waypoint @@ -534,14 +534,14 @@ GDIBuilding9: atwr Owner: GDI Location: 47,20 - TurretFacing: 92 + TurretFacing: 368 GDICYard: fact Location: 59,13 Owner: GDI GDIHarvester: harv Owner: GDI Location: 50,18 - Facing: 92 + Facing: 368 GDIHQ: hq Location: 51,13 Owner: GDI @@ -560,11 +560,11 @@ GDIOrca1: orca Owner: GDI Location: 41,12 - Facing: 92 + Facing: 368 GDIOrca2: orca Owner: GDI Location: 41,13 - Facing: 92 + Facing: 368 GDIProc: proc Owner: GDI Location: 50,16 diff -Nru openra-20200503/mods/cnc/maps/nod08a/nod08a.lua openra-20210321/mods/cnc/maps/nod08a/nod08a.lua --- openra-20200503/mods/cnc/maps/nod08a/nod08a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod08a/nod08a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -71,7 +71,7 @@ local target = GetAirstrikeTarget(Nod) if target then - hq.SendAirstrike(target, false, Facing.NorthEast + 4) + hq.TargetAirstrike(target, Angle.NorthEast + Angle.New(16)) Trigger.AfterDelay(delay, function() SendGDIAirstrike(hq, delay) end) else Trigger.AfterDelay(delay/4, function() SendGDIAirstrike(hq, delay) end) @@ -104,7 +104,7 @@ Trigger.AfterDelay(DateTime.Minutes(1), function() if not GDIHQ.IsDead and (not NodHand.IsDead or not NodNuke.IsDead) then local airstrikeproxy = Actor.Create("airstrike.proxy", false, { Owner = GDI }) - airstrikeproxy.SendAirstrike(AirstrikeTarget.CenterPosition, false, Facing.NorthEast + 4) + airstrikeproxy.TargetAirstrike(AirstrikeTarget.CenterPosition, Angle.NorthEast + Angle.New(16)) airstrikeproxy.Destroy() end end) Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/nod08b/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/nod08b/map.png differ diff -Nru openra-20200503/mods/cnc/maps/nod08b/map.yaml openra-20210321/mods/cnc/maps/nod08b/map.yaml --- openra-20200503/mods/cnc/maps/nod08b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod08b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -401,39 +401,39 @@ Actor111: t18 Location: 11,43 Owner: Neutral - Actor112: split3 + Actor112: t13.transformable Location: 5,31 Owner: Neutral - Actor113: split3 + Actor113: t13.transformable Location: 58,47 Owner: Neutral Actor142: mtnk Location: 8,9 Owner: GDI - Facing: 64 + Facing: 256 Actor143: mtnk Location: 27,34 Owner: GDI - Facing: 64 + Facing: 256 Actor144: mtnk Location: 14,25 Owner: GDI - Facing: 96 + Facing: 384 Actor145: mtnk Location: 47,3 Owner: GDI - Facing: 192 + Facing: 768 Actor148: jeep Location: 56,33 Owner: GDI Actor151: mtnk Location: 16,32 Owner: GDI - Facing: 224 + Facing: 896 Actor152: mtnk Location: 35,31 Owner: GDI - Facing: 224 + Facing: 896 Actor153: jeep Location: 18,55 Owner: GDI @@ -457,17 +457,17 @@ Actor159: e2 Location: 50,3 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 1 Actor160: e2 Location: 49,5 Owner: GDI - Facing: 192 + Facing: 768 SubCell: 2 Actor161: e1 Location: 48,6 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 4 Actor162: e2 Location: 41,16 @@ -476,37 +476,37 @@ Actor163: e2 Location: 35,17 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 2 Actor171: e1 Location: 45,5 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 1 Actor172: e1 Location: 44,4 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 1 Actor173: e1 Location: 45,4 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 1 Actor176: e1 Location: 58,27 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 4 Actor177: e1 Location: 52,22 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 4 Actor178: e1 Location: 50,23 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 3 Actor179: e2 Location: 59,30 @@ -515,12 +515,12 @@ Actor180: e2 Location: 49,24 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 3 Actor181: e1 Location: 31,33 Owner: GDI - Facing: 32 + Facing: 128 SubCell: 2 Actor182: e3 Location: 54,35 @@ -529,42 +529,42 @@ Actor183: e3 Location: 55,35 Owner: GDI - Facing: 32 + Facing: 128 SubCell: 4 Actor184: e3 Location: 55,35 Owner: GDI - Facing: 224 + Facing: 896 SubCell: 0 Actor185: e3 Location: 47,32 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 0 Actor186: e3 Location: 48,35 Owner: GDI - Facing: 32 + Facing: 128 SubCell: 1 Actor187: e3 Location: 43,26 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 0 Actor188: e3 Location: 46,22 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 3 Actor190: e2 Location: 31,33 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 3 Actor191: e2 Location: 32,33 Owner: GDI - Facing: 32 + Facing: 128 SubCell: 0 waypoint27: waypoint Location: 20,54 @@ -717,22 +717,22 @@ GDIOrca1: orca Owner: GDI Location: 17,52 - Facing: 92 + Facing: 368 GDIOrca2: orca Owner: GDI Location: 12,52 - Facing: 92 + Facing: 368 GDIWeap: weap Location: 8,48 Owner: GDI Gunboat1: boat Location: 31,59 Owner: GDI - Facing: 192 + Facing: 768 Gunboat2: boat Location: 25,60 Owner: GDI - Facing: 192 + Facing: 768 MoneyCrate: MoneyCrate Owner: Neutral Location: 24,54 @@ -754,7 +754,7 @@ OutpostHarv: harv Location: 55,27 Owner: Outpost - Facing: 192 + Facing: 768 OutpostNuke: nukeout.in Location: 59,27 Owner: Outpost diff -Nru openra-20200503/mods/cnc/maps/nod08b/nod08b.lua openra-20210321/mods/cnc/maps/nod08b/nod08b.lua --- openra-20200503/mods/cnc/maps/nod08b/nod08b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod08b/nod08b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -63,7 +63,7 @@ local target = GetAirstrikeTarget(Nod) if target then - hq.SendAirstrike(target, false, Facing.NorthEast + 4) + hq.TargetAirstrike(target, Angle.NorthEast + Angle.New(16)) Trigger.AfterDelay(delay, function() SendGDIAirstrike(hq, delay) end) else Trigger.AfterDelay(delay/4, function() SendGDIAirstrike(hq, delay) end) @@ -99,7 +99,7 @@ Trigger.AfterDelay(DateTime.Minutes(1), function() if not GDIHQ.IsDead and (not NodHand.IsDead or not NodNuke.IsDead) then local airstrikeproxy = Actor.Create("airstrike.proxy", false, { Owner = GDI }) - airstrikeproxy.SendAirstrike(AirstrikeTarget.CenterPosition, false, Facing.NorthEast + 4) + airstrikeproxy.TargetAirstrike(AirstrikeTarget.CenterPosition, Angle.NorthEast + Angle.New(16)) airstrikeproxy.Destroy() end end) diff -Nru openra-20200503/mods/cnc/maps/nod08b/rules.yaml openra-20210321/mods/cnc/maps/nod08b/rules.yaml --- openra-20200503/mods/cnc/maps/nod08b/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod08b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -169,7 +169,7 @@ Except: Attack RevealsShroud: Range: 4c0 - ValidStances: Enemy, Neutral, Ally + ValidRelationships: Enemy, Neutral, Ally FACT.IN: Inherits: FACT diff -Nru openra-20200503/mods/cnc/maps/nod09/map.yaml openra-20210321/mods/cnc/maps/nod09/map.yaml --- openra-20200503/mods/cnc/maps/nod09/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod09/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -348,10 +348,10 @@ Actor93: t08 Location: 50,55 Owner: Neutral - Actor94: split3 + Actor94: t13.transformable Location: 56,48 Owner: Neutral - Actor95: split3 + Actor95: t13.transformable Location: 6,24 Owner: Neutral Actor96: t18 @@ -405,10 +405,10 @@ Actor112: t08 Location: 29,15 Owner: Neutral - Actor113: split3 + Actor113: t13.transformable Location: 47,23 Owner: Neutral - Actor114: split3 + Actor114: t13.transformable Location: 38,20 Owner: Neutral Actor115: rock4 @@ -474,7 +474,7 @@ Actor154: jeep Location: 52,5 Owner: GDI - Facing: 96 + Facing: 384 Actor155: jeep Location: 47,13 Owner: GDI @@ -490,19 +490,19 @@ Actor159: mtnk Location: 52,12 Owner: GDI - Facing: 96 + Facing: 384 Actor162: jeep Location: 9,17 Owner: GDI - Facing: 64 + Facing: 256 Actor163: jeep Location: 23,4 Owner: GDI - Facing: 96 + Facing: 384 Actor164: jeep Location: 1,19 Owner: GDI - Facing: 64 + Facing: 256 Actor165: e2 Location: 57,15 Owner: GDI @@ -570,62 +570,62 @@ Actor181: e2 Location: 21,17 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 1 Actor182: e2 Location: 11,16 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 2 Actor183: e2 Location: 21,17 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 4 Actor184: e2 Location: 11,16 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 3 Actor185: c3 Location: 6,9 Owner: Civilians - Facing: 96 + Facing: 384 SubCell: 1 Actor186: c4 Location: 6,4 Owner: Civilians - Facing: 160 + Facing: 640 SubCell: 3 Actor187: c5 Location: 4,11 Owner: Civilians - Facing: 32 + Facing: 128 SubCell: 4 Actor189: e2 Location: 21,4 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 3 Actor190: e2 Location: 20,4 Owner: GDI - Facing: 160 + Facing: 640 SubCell: 1 Actor191: e2 Location: 27,6 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 4 Actor192: e2 Location: 27,5 Owner: GDI - Facing: 64 + Facing: 256 SubCell: 3 Actor193: e2 Location: 42,26 Owner: GDI - Facing: 96 + Facing: 384 SubCell: 1 Actor194: e2 Location: 40,25 @@ -694,8 +694,7 @@ Actor244: msam Owner: GDI Location: 54,6 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor245: moneycrate Location: 5,6 Owner: Neutral @@ -780,11 +779,11 @@ GDIBuilding4: atwr Owner: GDI Location: 45,7 - TurretFacing: 92 + TurretFacing: 368 GDIBuilding5: atwr Owner: GDI Location: 45,11 - TurretFacing: 92 + TurretFacing: 368 GDIBuilding6: silo Location: 59,13 Owner: GDI @@ -812,7 +811,7 @@ GDIHarvester: harv Owner: GDI Location: 54,12 - Facing: 92 + Facing: 368 GDIHQ: hq Location: 57,10 Owner: GDI @@ -831,11 +830,11 @@ GDIOrca1: orca Owner: GDI Location: 51,4 - Facing: 92 + Facing: 368 GDIOrca2: orca Owner: GDI Location: 53,4 - Facing: 92 + Facing: 368 GDIProc: proc Owner: GDI Location: 54,10 @@ -849,7 +848,7 @@ Gunboat: boat Location: 60,58 Owner: GDI - Facing: 192 + Facing: 768 HelicopterEntryEngineer: waypoint Owner: Neutral Location: 1,3 @@ -881,7 +880,7 @@ OutpostHarv: harv Location: 8,49 Owner: Outpost - Facing: 64 + Facing: 256 Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/cnc/maps/nod09/nod09.lua openra-20210321/mods/cnc/maps/nod09/nod09.lua --- openra-20200503/mods/cnc/maps/nod09/nod09.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod09/nod09.lua 2021-03-21 11:10:05.000000000 +0000 @@ -56,7 +56,7 @@ local target = GetAirstrikeTarget(Nod) if target then - hq.SendAirstrike(target, false, Facing.NorthEast + 4) + hq.TargetAirstrike(target, Angle.NorthEast + Angle.New(16)) Trigger.AfterDelay(delay, function() SendGDIAirstrike(hq, delay) end) else Trigger.AfterDelay(delay/4, function() SendGDIAirstrike(hq, delay) end) diff -Nru openra-20200503/mods/cnc/maps/nod09/rules.yaml openra-20210321/mods/cnc/maps/nod09/rules.yaml --- openra-20200503/mods/cnc/maps/nod09/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod09/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -137,7 +137,7 @@ RejectsOrders: Except: Attack RevealsShroud: - ValidStances: Ally, Neutral, Enemy + ValidRelationships: Ally, Neutral, Enemy Range: 4c0 TRAN.IN: @@ -176,10 +176,10 @@ Inherits: RMBO Health: HP: 30000 - SelfHealing: + ChangesHealth: Step: 500 Delay: 10 - HealIfBelow: 50 + StartIfBelow: 50 DamageCooldown: 200 RenderSprites: Image: RMBO diff -Nru openra-20200503/mods/cnc/maps/nod10a/map.yaml openra-20210321/mods/cnc/maps/nod10a/map.yaml --- openra-20200503/mods/cnc/maps/nod10a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod10a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -677,165 +677,165 @@ Actor187: mtnk Location: 15,6 Owner: GDI - Facing: 95 + Facing: 380 Actor188: jeep Location: 4,26 Owner: GDI - Facing: 159 + Facing: 636 Actor189: bggy Location: 7,46 Owner: Nod - Facing: 127 + Facing: 508 Actor190: bggy Location: 5,46 Owner: Nod - Facing: 127 + Facing: 508 Actor191: bggy Location: 3,46 Owner: Nod - Facing: 127 + Facing: 508 Actor192: ftnk Location: 5,43 Owner: Nod - Facing: 127 + Facing: 508 Actor193: ftnk Location: 5,42 Owner: Nod - Facing: 127 + Facing: 508 Actor194: ltnk Location: 3,42 Owner: Nod - Facing: 127 + Facing: 508 Actor195: ltnk Location: 3,43 Owner: Nod - Facing: 127 + Facing: 508 Actor196: ftnk Location: 7,42 Owner: Nod - Facing: 127 + Facing: 508 Actor197: ftnk Location: 7,43 Owner: Nod - Facing: 127 + Facing: 508 Actor198: apc Location: 54,21 Owner: GDI - Facing: 127 + Facing: 508 Actor199: apc Location: 57,43 Owner: GDI - Facing: 127 + Facing: 508 Actor200: apc Location: 28,60 Owner: GDI - Facing: 31 + Facing: 124 Actor201: apc Location: 17,57 Owner: GDI - Facing: 31 + Facing: 124 Actor202: jeep Location: 31,21 Owner: GDI - Facing: 191 + Facing: 764 Actor203: jeep Location: 6,34 Owner: GDI - Facing: 95 + Facing: 380 Actor204: mtnk Location: 47,58 Owner: GDI - Facing: 63 + Facing: 252 Actor205: apc Location: 53,6 Owner: GDI - Facing: 159 + Facing: 636 Actor206: mtnk Location: 42,5 Owner: GDI Actor207: jeep Location: 56,7 Owner: GDI - Facing: 31 + Facing: 124 Actor209: e1 Location: 33,31 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 1 Actor210: e1 Location: 4,27 Owner: GDI - Facing: 95 + Facing: 380 SubCell: 2 Actor211: e1 Location: 3,27 Owner: GDI - Facing: 95 + Facing: 380 SubCell: 4 Actor212: e1 Location: 3,27 Owner: GDI - Facing: 95 + Facing: 380 SubCell: 0 Actor214: e4 Location: 7,45 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 1 Actor215: e4 Location: 7,45 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 2 Actor216: e3 Location: 5,45 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 1 Actor217: e3 Location: 5,45 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 2 Actor218: e3 Location: 5,44 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 4 Actor219: e3 Location: 5,44 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 3 Actor220: e1 Location: 3,45 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 2 Actor221: e1 Location: 3,45 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 1 Actor222: e1 Location: 3,44 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 2 Actor223: e1 Location: 3,44 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 1 Actor224: e1 Location: 3,44 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 3 Actor225: e1 Location: 3,44 Owner: Nod - Facing: 127 + Facing: 508 SubCell: 4 Actor226: c4 Location: 4,5 @@ -844,102 +844,102 @@ Actor227: c3 Location: 9,7 Owner: Neutral - Facing: 159 + Facing: 636 SubCell: 4 Actor228: c3 Location: 6,5 Owner: Neutral - Facing: 31 + Facing: 124 SubCell: 3 Actor229: c2 Location: 5,5 Owner: Neutral - Facing: 223 + Facing: 892 SubCell: 4 Actor230: c1 Location: 10,5 Owner: Neutral - Facing: 95 + Facing: 380 SubCell: 3 Actor231: e2 Location: 6,7 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 2 Actor232: e2 Location: 8,6 Owner: GDI - Facing: 95 + Facing: 380 SubCell: 4 Actor233: e2 Location: 4,6 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 2 Actor234: e3 Location: 5,6 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 2 Actor235: e3 Location: 7,6 Owner: GDI - Facing: 95 + Facing: 380 SubCell: 4 Actor236: e1 Location: 5,16 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 4 Actor237: e1 Location: 4,24 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 2 Actor238: e3 Location: 52,7 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 1 Actor239: e3 Location: 54,7 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 3 Actor240: e3 Location: 61,22 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 3 Actor241: e3 Location: 61,23 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 1 Actor242: e3 Location: 60,22 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 4 Actor243: e3 Location: 60,22 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 3 Actor244: e3 Location: 56,44 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 1 Actor245: e3 Location: 55,44 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 4 Actor246: e3 Location: 55,44 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 1 Actor247: e3 Location: 25,4 @@ -952,7 +952,7 @@ Actor249: e3 Location: 41,37 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 1 Actor250: e3 Location: 42,37 @@ -965,32 +965,32 @@ Actor252: e1 Location: 9,51 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 4 Actor253: c9 Location: 39,25 Owner: Neutral - Facing: 31 + Facing: 124 SubCell: 4 Actor254: c9 Location: 38,28 Owner: Neutral - Facing: 95 + Facing: 380 SubCell: 2 Actor255: c8 Location: 37,24 Owner: Neutral - Facing: 223 + Facing: 892 SubCell: 3 Actor256: c8 Location: 38,26 Owner: Neutral - Facing: 191 + Facing: 764 SubCell: 2 Actor257: c7 Location: 40,26 Owner: Neutral - Facing: 31 + Facing: 124 SubCell: 0 Actor258: c7 Location: 37,25 @@ -999,27 +999,27 @@ Actor259: c6 Location: 37,27 Owner: Neutral - Facing: 31 + Facing: 124 SubCell: 3 Actor260: c6 Location: 40,32 Owner: Neutral - Facing: 31 + Facing: 124 SubCell: 1 Actor261: c5 Location: 38,26 Owner: Neutral - Facing: 31 + Facing: 124 SubCell: 1 Actor262: c5 Location: 38,27 Owner: Neutral - Facing: 31 + Facing: 124 SubCell: 3 Actor263: c4 Location: 42,17 Owner: Neutral - Facing: 159 + Facing: 636 SubCell: 2 Actor264: c4 Location: 35,33 @@ -1040,97 +1040,97 @@ Actor268: c2 Location: 37,27 Owner: Neutral - Facing: 127 + Facing: 508 SubCell: 1 Actor269: c1 Location: 39,25 Owner: Neutral - Facing: 223 + Facing: 892 SubCell: 3 Actor270: c1 Location: 37,27 Owner: Neutral - Facing: 63 + Facing: 252 SubCell: 2 Actor271: e2 Location: 7,12 Owner: GDI - Facing: 95 + Facing: 380 SubCell: 0 Actor272: e1 Location: 56,24 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 3 Actor273: e1 Location: 38,22 Owner: GDI - Facing: 95 + Facing: 380 SubCell: 1 Actor274: e1 Location: 38,22 Owner: GDI - Facing: 95 + Facing: 380 SubCell: 2 Actor275: e1 Location: 27,20 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 3 Actor276: e1 Location: 26,21 Owner: GDI - Facing: 63 + Facing: 252 SubCell: 0 Actor277: e2 Location: 17,58 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 0 Actor278: e2 Location: 25,57 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 3 Actor279: e2 Location: 15,59 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 2 Actor280: e2 Location: 22,56 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 0 Actor281: e1 Location: 26,55 Owner: GDI - Facing: 95 + Facing: 380 SubCell: 4 Actor282: e1 Location: 14,50 Owner: GDI - Facing: 95 + Facing: 380 SubCell: 4 Actor283: e1 Location: 21,58 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 1 Actor284: e1 Location: 22,57 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 4 Actor285: e1 Location: 47,52 Owner: GDI - Facing: 63 + Facing: 252 SubCell: 2 Actor286: e1 Location: 54,55 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 2 Actor287: c7 Location: 11,52 @@ -1151,18 +1151,18 @@ Actor291: c3 Location: 12,51 Owner: Neutral - Facing: 63 + Facing: 252 SubCell: 4 Actor292: c2 Location: 8,12 Owner: Neutral Health: 59 - Facing: 127 + Facing: 508 SubCell: 2 Actor293: c1 Location: 13,50 Owner: Neutral - Facing: 63 + Facing: 252 SubCell: 0 Actor294: e1 Location: 24,4 @@ -1171,27 +1171,27 @@ Actor295: e2 Location: 57,7 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 0 Actor296: e2 Location: 19,57 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 2 Actor297: e2 Location: 14,53 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 0 Actor298: e1 Location: 9,51 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 0 Actor299: e1 Location: 12,54 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 3 Actor300: e1 Location: 31,43 @@ -1216,32 +1216,32 @@ Actor305: e2 Location: 26,20 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 0 Actor306: e2 Location: 55,7 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 2 Actor307: e2 Location: 53,7 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 4 Actor308: e2 Location: 56,23 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 0 Actor309: e1 Location: 47,52 Owner: GDI - Facing: 63 + Facing: 252 SubCell: 3 Actor310: e1 Location: 48,52 Owner: GDI - Facing: 63 + Facing: 252 SubCell: 2 Actor311: c9 Location: 8,13 @@ -1250,7 +1250,7 @@ Actor312: c8 Location: 6,13 Owner: Neutral - Facing: 223 + Facing: 892 SubCell: 2 Actor313: c6 Location: 4,24 @@ -1259,37 +1259,37 @@ Actor314: c5 Location: 6,11 Owner: Neutral - Facing: 31 + Facing: 124 SubCell: 4 Actor315: c4 Location: 7,15 Owner: Neutral - Facing: 31 + Facing: 124 SubCell: 3 Actor316: e1 Location: 56,25 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 2 Actor317: c2 Location: 26,17 Owner: Neutral - Facing: 191 + Facing: 764 SubCell: 3 Actor318: c4 Location: 26,17 Owner: Neutral - Facing: 63 + Facing: 252 SubCell: 2 Actor319: c5 Location: 27,16 Owner: Neutral - Facing: 223 + Facing: 892 SubCell: 2 Actor320: c6 Location: 27,17 Owner: Neutral - Facing: 159 + Facing: 636 SubCell: 4 Actor321: e2 Location: 58,45 @@ -1314,12 +1314,12 @@ Actor326: e2 Location: 57,23 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 0 Actor327: e2 Location: 56,23 Owner: GDI - Facing: 127 + Facing: 508 SubCell: 0 DefaultChinookTarget: waypoint Location: 27,46 diff -Nru openra-20200503/mods/cnc/maps/nod10a/rules.yaml openra-20210321/mods/cnc/maps/nod10a/rules.yaml --- openra-20200503/mods/cnc/maps/nod10a/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod10a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -45,10 +45,10 @@ Inherits: RMBO Health: HP: 30000 - SelfHealing: + ChangesHealth: Step: 500 Delay: 10 - HealIfBelow: 50 + StartIfBelow: 50 DamageCooldown: 200 RenderSprites: Image: RMBO diff -Nru openra-20200503/mods/cnc/maps/nod10b/map.yaml openra-20210321/mods/cnc/maps/nod10b/map.yaml --- openra-20200503/mods/cnc/maps/nod10b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod10b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -495,7 +495,7 @@ Actor148: jeep Location: 56,17 Owner: GDI - Facing: 159 + Facing: 636 Mammoth1: htnk Location: 29,53 Owner: GDI @@ -508,18 +508,18 @@ PatrollingMammoth: htnk Location: 59,42 Owner: GDI - Facing: 31 + Facing: 124 Actor153: arty Location: 27,28 Owner: Nod MediumTank1: mtnk Location: 43,28 Owner: GDI - Facing: 191 + Facing: 764 MediumTank2: mtnk Location: 43,29 Owner: GDI - Facing: 191 + Facing: 764 Rifleman1: e1 Location: 16,54 Owner: GDI @@ -539,22 +539,22 @@ Actor160: e1 Location: 17,14 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 3 Actor161: e1 Location: 17,15 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 1 Actor162: e1 Location: 17,15 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 2 Actor163: e1 Location: 17,14 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 4 Actor164: e2 Location: 15,28 @@ -575,12 +575,12 @@ Actor168: e2 Location: 36,9 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 4 Actor169: e2 Location: 36,9 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 3 Actor170: e2 Location: 32,16 @@ -593,12 +593,12 @@ Actor172: e2 Location: 57,18 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 2 Actor173: e2 Location: 57,18 Owner: GDI - Facing: 159 + Facing: 636 SubCell: 0 Actor174: c8 Location: 57,54 @@ -607,12 +607,12 @@ Actor175: c3 Location: 56,49 Owner: Neutral - Facing: 95 + Facing: 380 SubCell: 2 Actor176: c4 Location: 56,49 Owner: Neutral - Facing: 223 + Facing: 892 SubCell: 3 Actor177: e3 Location: 26,27 @@ -661,22 +661,22 @@ Grenadier1: e2 Location: 40,19 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 2 Grenadier2: e2 Location: 40,18 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 4 Grenadier3: e2 Location: 41,19 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 1 Grenadier4: e2 Location: 41,18 Owner: GDI - Facing: 191 + Facing: 764 SubCell: 3 Actor192: e3 Location: 19,51 @@ -689,7 +689,7 @@ Actor194: e3 Location: 37,52 Owner: GDI - Facing: 31 + Facing: 124 SubCell: 4 Actor195: e3 Location: 33,54 diff -Nru openra-20200503/mods/cnc/maps/nod10b/rules.yaml openra-20210321/mods/cnc/maps/nod10b/rules.yaml --- openra-20200503/mods/cnc/maps/nod10b/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/maps/nod10b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -37,10 +37,10 @@ Inherits: RMBO Health: HP: 30000 - SelfHealing: + ChangesHealth: Step: 500 Delay: 10 - HealIfBelow: 50 + StartIfBelow: 50 DamageCooldown: 200 RenderSprites: Image: RMBO Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/order-of-battle.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/order-of-battle.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/plan-b.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/plan-b.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/reaching-out.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/reaching-out.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/thawed-front.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/thawed-front.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/the-new-mandarins.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/the-new-mandarins.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/tiberian-falls.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/tiberian-falls.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/tiberium-canopy.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/tiberium-canopy.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/tiberium-forest.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/tiberium-forest.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/tiberium-rift.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/tiberium-rift.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/too-hot.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/too-hot.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/tropic-expanse.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/tropic-expanse.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/twisted-peak.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/twisted-peak.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/understanding-power.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/understanding-power.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/valley-of-gold-6p.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/valley-of-gold-6p.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/valley-of-gold.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/valley-of-gold.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/warchild.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/warchild.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/maps/winters-end.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/maps/winters-end.oramap differ diff -Nru openra-20200503/mods/cnc/metrics.yaml openra-20210321/mods/cnc/metrics.yaml --- openra-20200503/mods/cnc/metrics.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/metrics.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,11 +7,3 @@ ColorPickerActorType: fact.colorpicker ColorPickerRemapIndices: 176, 178, 180, 182, 184, 186, 189, 191, 177, 179, 181, 183, 185, 187, 188, 190 TextfieldColorHighlight: 800000 - ChatLineSound: ChatLine - ClickDisabledSound: ClickDisabledSound - ClickSound: ClickSound - ChatMessageColor: FFFFFF - SystemMessageColor: FFFF00 - NormalSelectionColor: FFFFFF - AltSelectionColor: 00FFFF - CtrlSelectionColor: FFFF00 diff -Nru openra-20200503/mods/cnc/mod.yaml openra-20210321/mods/cnc/mod.yaml --- openra-20200503/mods/cnc/mod.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/mod.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,11 +7,11 @@ PackageFormats: Mix Packages: - ~^Content/cnc - ~^Content/cnc/movies - . + ~^SupportDir|Content/cnc + ~^SupportDir|Content/cnc/movies + ^EngineDir $cnc: cnc - ./mods/common: common + ^EngineDir|mods/common: common ~speech.mix ~conquer.mix ~sounds.mix @@ -34,7 +34,7 @@ MapFolders: cnc|maps: System - ~^maps/cnc/{DEV_VERSION}: User + ~^SupportDir|maps/cnc/{DEV_VERSION}: User Rules: cnc|rules/misc.yaml @@ -87,8 +87,8 @@ cnc|chrome.yaml Assemblies: - common|OpenRA.Mods.Common.dll - common|OpenRA.Mods.Cnc.dll + ^BinDir|OpenRA.Mods.Common.dll + ^BinDir|OpenRA.Mods.Cnc.dll ChromeLayout: cnc|chrome/mainmenu.yaml @@ -215,7 +215,7 @@ SpriteFormats: ShpTD, TmpTD, ShpTS, TmpRA -SpriteSequenceFormat: TilesetSpecificSpriteSequence +SpriteSequenceFormat: ClassicTilesetSpecificSpriteSequence TilesetExtensions: TEMPERAT: .tem WINTER: .win @@ -258,27 +258,26 @@ TeamColorPresets: f70606, ff7a22, f8d3b3, f8e947, 94b319, f335a0, a64d6c, ce08f9, f5b2db, 12b572, 502048, 1d06f7, 328dff, 78dbf8, cef6b1, 391d1d ModContent: - InstallPromptMessage: Tiberian Dawn requires artwork and audio from the original game.\n\nQuick Install will automatically download this content (without music\nor videos) from a mirror of the 2007 C&C Gold freeware release.\n\nAdvanced Install includes options for downloading the music and for\ncopying the videos and other content from an original game disc. + InstallPromptMessage: Tiberian Dawn requires artwork and audio from the original game.\n\nQuick Install will automatically download this content (without music\nor videos) from a mirror of the 2007 C&C Gold freeware release.\n\nAdvanced Install includes options for copying the music, videos, and\nother content from an original game disc or digital installation. QuickDownload: basefiles HeaderMessage: Game content may be extracted from the original game discs or an\nexisting digital install. OpenRA can also download the base game\nfiles from an online mirror of the 2007 freeware release of C&C. Packages: base: Base Game Files - TestFiles: ^Content/cnc/conquer.mix, ^Content/cnc/desert.mix, ^Content/cnc/sounds.mix, ^Content/cnc/speech.mix, ^Content/cnc/temperat.mix, ^Content/cnc/tempicnh.mix, ^Content/cnc/winter.mix + TestFiles: ^SupportDir|Content/cnc/conquer.mix, ^SupportDir|Content/cnc/desert.mix, ^SupportDir|Content/cnc/sounds.mix, ^SupportDir|Content/cnc/speech.mix, ^SupportDir|Content/cnc/temperat.mix, ^SupportDir|Content/cnc/tempicnh.mix, ^SupportDir|Content/cnc/winter.mix Sources: gdi95, gdi95-linux, nod95, nod95-linux, tfd, origin Required: true Download: basefiles music: Base Game Music - TestFiles: ^Content/cnc/scores.mix + TestFiles: ^SupportDir|Content/cnc/scores.mix Sources: gdi95, gdi95-linux, nod95, nod95-linux, tfd, origin - Download: music movies-gdi: GDI Campaign Briefings - TestFiles: ^Content/cnc/movies/visor.vqa, ^Content/cnc/movies/turtkill.vqa, ^Content/cnc/movies/trailer.vqa, ^Content/cnc/movies/tbrinfo3.vqa, ^Content/cnc/movies/tbrinfo2.vqa, ^Content/cnc/movies/tbrinfo1.vqa, ^Content/cnc/movies/seige.vqa, ^Content/cnc/movies/samsite.vqa, ^Content/cnc/movies/samdie.vqa, ^Content/cnc/movies/sabotage.vqa, ^Content/cnc/movies/retro.vqa, ^Content/cnc/movies/podium.vqa, ^Content/cnc/movies/planecra.vqa, ^Content/cnc/movies/pintle.vqa, ^Content/cnc/movies/paratrop.vqa, ^Content/cnc/movies/nodsweep.vqa, ^Content/cnc/movies/nodlose.vqa, ^Content/cnc/movies/nodflees.vqa, ^Content/cnc/movies/nod1.vqa, ^Content/cnc/movies/nitejump.vqa, ^Content/cnc/movies/napalm.vqa, ^Content/cnc/movies/logo.vqa, ^Content/cnc/movies/landing.vqa, ^Content/cnc/movies/intro2.vqa, ^Content/cnc/movies/hellvaly.vqa, ^Content/cnc/movies/gunboat.vqa, ^Content/cnc/movies/generic.vqa, ^Content/cnc/movies/gdilose.vqa, ^Content/cnc/movies/gdifinb.vqa, ^Content/cnc/movies/gdifina.vqa, ^Content/cnc/movies/gdiend2.vqa, ^Content/cnc/movies/gdiend1.vqa, ^Content/cnc/movies/gdi9.vqa, ^Content/cnc/movies/gdi8b.vqa, ^Content/cnc/movies/gdi8a.vqa, ^Content/cnc/movies/gdi7.vqa, ^Content/cnc/movies/gdi6.vqa, ^Content/cnc/movies/gdi5.vqa, ^Content/cnc/movies/gdi4b.vqa, ^Content/cnc/movies/gdi4a.vqa, ^Content/cnc/movies/gdi3lose.vqa, ^Content/cnc/movies/gdi3.vqa, ^Content/cnc/movies/gdi2.vqa, ^Content/cnc/movies/gdi15.vqa, ^Content/cnc/movies/gdi14.vqa, ^Content/cnc/movies/gdi13.vqa, ^Content/cnc/movies/gdi12.vqa, ^Content/cnc/movies/gdi11.vqa, ^Content/cnc/movies/gdi10.vqa, ^Content/cnc/movies/gdi1.vqa, ^Content/cnc/movies/gameover.vqa, ^Content/cnc/movies/forestkl.vqa, ^Content/cnc/movies/flyy.vqa, ^Content/cnc/movies/flag.vqa, ^Content/cnc/movies/dino.vqa, ^Content/cnc/movies/desolat.vqa, ^Content/cnc/movies/consyard.vqa, ^Content/cnc/movies/cc2tease.vqa, ^Content/cnc/movies/burdet2.vqa, ^Content/cnc/movies/burdet1.vqa, ^Content/cnc/movies/bombflee.vqa, ^Content/cnc/movies/bombaway.vqa, ^Content/cnc/movies/bkground.vqa, ^Content/cnc/movies/bcanyon.vqa, ^Content/cnc/movies/banner.vqa + TestFiles: ^SupportDir|Content/cnc/movies/visor.vqa, ^SupportDir|Content/cnc/movies/turtkill.vqa, ^SupportDir|Content/cnc/movies/trailer.vqa, ^SupportDir|Content/cnc/movies/tbrinfo3.vqa, ^SupportDir|Content/cnc/movies/tbrinfo2.vqa, ^SupportDir|Content/cnc/movies/tbrinfo1.vqa, ^SupportDir|Content/cnc/movies/seige.vqa, ^SupportDir|Content/cnc/movies/samsite.vqa, ^SupportDir|Content/cnc/movies/samdie.vqa, ^SupportDir|Content/cnc/movies/sabotage.vqa, ^SupportDir|Content/cnc/movies/retro.vqa, ^SupportDir|Content/cnc/movies/podium.vqa, ^SupportDir|Content/cnc/movies/planecra.vqa, ^SupportDir|Content/cnc/movies/pintle.vqa, ^SupportDir|Content/cnc/movies/paratrop.vqa, ^SupportDir|Content/cnc/movies/nodsweep.vqa, ^SupportDir|Content/cnc/movies/nodlose.vqa, ^SupportDir|Content/cnc/movies/nodflees.vqa, ^SupportDir|Content/cnc/movies/nod1.vqa, ^SupportDir|Content/cnc/movies/nitejump.vqa, ^SupportDir|Content/cnc/movies/napalm.vqa, ^SupportDir|Content/cnc/movies/logo.vqa, ^SupportDir|Content/cnc/movies/landing.vqa, ^SupportDir|Content/cnc/movies/intro2.vqa, ^SupportDir|Content/cnc/movies/hellvaly.vqa, ^SupportDir|Content/cnc/movies/gunboat.vqa, ^SupportDir|Content/cnc/movies/generic.vqa, ^SupportDir|Content/cnc/movies/gdilose.vqa, ^SupportDir|Content/cnc/movies/gdifinb.vqa, ^SupportDir|Content/cnc/movies/gdifina.vqa, ^SupportDir|Content/cnc/movies/gdiend2.vqa, ^SupportDir|Content/cnc/movies/gdiend1.vqa, ^SupportDir|Content/cnc/movies/gdi9.vqa, ^SupportDir|Content/cnc/movies/gdi8b.vqa, ^SupportDir|Content/cnc/movies/gdi8a.vqa, ^SupportDir|Content/cnc/movies/gdi7.vqa, ^SupportDir|Content/cnc/movies/gdi6.vqa, ^SupportDir|Content/cnc/movies/gdi5.vqa, ^SupportDir|Content/cnc/movies/gdi4b.vqa, ^SupportDir|Content/cnc/movies/gdi4a.vqa, ^SupportDir|Content/cnc/movies/gdi3lose.vqa, ^SupportDir|Content/cnc/movies/gdi3.vqa, ^SupportDir|Content/cnc/movies/gdi2.vqa, ^SupportDir|Content/cnc/movies/gdi15.vqa, ^SupportDir|Content/cnc/movies/gdi14.vqa, ^SupportDir|Content/cnc/movies/gdi13.vqa, ^SupportDir|Content/cnc/movies/gdi12.vqa, ^SupportDir|Content/cnc/movies/gdi11.vqa, ^SupportDir|Content/cnc/movies/gdi10.vqa, ^SupportDir|Content/cnc/movies/gdi1.vqa, ^SupportDir|Content/cnc/movies/gameover.vqa, ^SupportDir|Content/cnc/movies/forestkl.vqa, ^SupportDir|Content/cnc/movies/flyy.vqa, ^SupportDir|Content/cnc/movies/flag.vqa, ^SupportDir|Content/cnc/movies/dino.vqa, ^SupportDir|Content/cnc/movies/desolat.vqa, ^SupportDir|Content/cnc/movies/consyard.vqa, ^SupportDir|Content/cnc/movies/cc2tease.vqa, ^SupportDir|Content/cnc/movies/burdet2.vqa, ^SupportDir|Content/cnc/movies/burdet1.vqa, ^SupportDir|Content/cnc/movies/bombflee.vqa, ^SupportDir|Content/cnc/movies/bombaway.vqa, ^SupportDir|Content/cnc/movies/bkground.vqa, ^SupportDir|Content/cnc/movies/bcanyon.vqa, ^SupportDir|Content/cnc/movies/banner.vqa Sources: gdi95, gdi95-linux, tfd, origin movies-nod: Nod Campaign Briefings - TestFiles: ^Content/cnc/movies/visor.vqa, ^Content/cnc/movies/trtkil_d.vqa, ^Content/cnc/movies/trailer.vqa, ^Content/cnc/movies/tiberfx.vqa, ^Content/cnc/movies/tankkill.vqa, ^Content/cnc/movies/tankgo.vqa, ^Content/cnc/movies/sundial.vqa, ^Content/cnc/movies/stealth.vqa, ^Content/cnc/movies/spycrash.vqa, ^Content/cnc/movies/sethpre.vqa, ^Content/cnc/movies/seige.vqa, ^Content/cnc/movies/samsite.vqa, ^Content/cnc/movies/retro.vqa, ^Content/cnc/movies/refint.vqa, ^Content/cnc/movies/obel.vqa, ^Content/cnc/movies/nuke.vqa, ^Content/cnc/movies/nodlose.vqa, ^Content/cnc/movies/nodfinal.vqa, ^Content/cnc/movies/nodend4.vqa, ^Content/cnc/movies/nodend3.vqa, ^Content/cnc/movies/nodend2.vqa, ^Content/cnc/movies/nodend1.vqa, ^Content/cnc/movies/nod9.vqa, ^Content/cnc/movies/nod8.vqa, ^Content/cnc/movies/nod7b.vqa, ^Content/cnc/movies/nod7a.vqa, ^Content/cnc/movies/nod6.vqa, ^Content/cnc/movies/nod5.vqa, ^Content/cnc/movies/nod4b.vqa, ^Content/cnc/movies/nod4a.vqa, ^Content/cnc/movies/nod3.vqa, ^Content/cnc/movies/nod2.vqa, ^Content/cnc/movies/nod1pre.vqa, ^Content/cnc/movies/nod13.vqa, ^Content/cnc/movies/nod12.vqa, ^Content/cnc/movies/nod11.vqa, ^Content/cnc/movies/nod10b.vqa, ^Content/cnc/movies/nod10a.vqa, ^Content/cnc/movies/nod1.vqa, ^Content/cnc/movies/logo.vqa, ^Content/cnc/movies/landing.vqa, ^Content/cnc/movies/kanepre.vqa, ^Content/cnc/movies/intro2.vqa, ^Content/cnc/movies/insites.vqa, ^Content/cnc/movies/generic.vqa, ^Content/cnc/movies/gdi1.vqa, ^Content/cnc/movies/gameover.vqa, ^Content/cnc/movies/forestkl.vqa, ^Content/cnc/movies/flag.vqa, ^Content/cnc/movies/dino.vqa, ^Content/cnc/movies/dessweep.vqa, ^Content/cnc/movies/deskill.vqa, ^Content/cnc/movies/desflees.vqa, ^Content/cnc/movies/consyard.vqa, ^Content/cnc/movies/cc2tease.vqa, ^Content/cnc/movies/bombflee.vqa, ^Content/cnc/movies/bombaway.vqa, ^Content/cnc/movies/bcanyon.vqa, ^Content/cnc/movies/banner.vqa, ^Content/cnc/movies/akira.vqa, ^Content/cnc/movies/airstrk.vqa + TestFiles: ^SupportDir|Content/cnc/movies/visor.vqa, ^SupportDir|Content/cnc/movies/trtkil_d.vqa, ^SupportDir|Content/cnc/movies/trailer.vqa, ^SupportDir|Content/cnc/movies/tiberfx.vqa, ^SupportDir|Content/cnc/movies/tankkill.vqa, ^SupportDir|Content/cnc/movies/tankgo.vqa, ^SupportDir|Content/cnc/movies/sundial.vqa, ^SupportDir|Content/cnc/movies/stealth.vqa, ^SupportDir|Content/cnc/movies/spycrash.vqa, ^SupportDir|Content/cnc/movies/sethpre.vqa, ^SupportDir|Content/cnc/movies/seige.vqa, ^SupportDir|Content/cnc/movies/samsite.vqa, ^SupportDir|Content/cnc/movies/retro.vqa, ^SupportDir|Content/cnc/movies/refint.vqa, ^SupportDir|Content/cnc/movies/obel.vqa, ^SupportDir|Content/cnc/movies/nuke.vqa, ^SupportDir|Content/cnc/movies/nodlose.vqa, ^SupportDir|Content/cnc/movies/nodfinal.vqa, ^SupportDir|Content/cnc/movies/nodend4.vqa, ^SupportDir|Content/cnc/movies/nodend3.vqa, ^SupportDir|Content/cnc/movies/nodend2.vqa, ^SupportDir|Content/cnc/movies/nodend1.vqa, ^SupportDir|Content/cnc/movies/nod9.vqa, ^SupportDir|Content/cnc/movies/nod8.vqa, ^SupportDir|Content/cnc/movies/nod7b.vqa, ^SupportDir|Content/cnc/movies/nod7a.vqa, ^SupportDir|Content/cnc/movies/nod6.vqa, ^SupportDir|Content/cnc/movies/nod5.vqa, ^SupportDir|Content/cnc/movies/nod4b.vqa, ^SupportDir|Content/cnc/movies/nod4a.vqa, ^SupportDir|Content/cnc/movies/nod3.vqa, ^SupportDir|Content/cnc/movies/nod2.vqa, ^SupportDir|Content/cnc/movies/nod1pre.vqa, ^SupportDir|Content/cnc/movies/nod13.vqa, ^SupportDir|Content/cnc/movies/nod12.vqa, ^SupportDir|Content/cnc/movies/nod11.vqa, ^SupportDir|Content/cnc/movies/nod10b.vqa, ^SupportDir|Content/cnc/movies/nod10a.vqa, ^SupportDir|Content/cnc/movies/nod1.vqa, ^SupportDir|Content/cnc/movies/logo.vqa, ^SupportDir|Content/cnc/movies/landing.vqa, ^SupportDir|Content/cnc/movies/kanepre.vqa, ^SupportDir|Content/cnc/movies/intro2.vqa, ^SupportDir|Content/cnc/movies/insites.vqa, ^SupportDir|Content/cnc/movies/generic.vqa, ^SupportDir|Content/cnc/movies/gdi1.vqa, ^SupportDir|Content/cnc/movies/gameover.vqa, ^SupportDir|Content/cnc/movies/forestkl.vqa, ^SupportDir|Content/cnc/movies/flag.vqa, ^SupportDir|Content/cnc/movies/dino.vqa, ^SupportDir|Content/cnc/movies/dessweep.vqa, ^SupportDir|Content/cnc/movies/deskill.vqa, ^SupportDir|Content/cnc/movies/desflees.vqa, ^SupportDir|Content/cnc/movies/consyard.vqa, ^SupportDir|Content/cnc/movies/cc2tease.vqa, ^SupportDir|Content/cnc/movies/bombflee.vqa, ^SupportDir|Content/cnc/movies/bombaway.vqa, ^SupportDir|Content/cnc/movies/bcanyon.vqa, ^SupportDir|Content/cnc/movies/banner.vqa, ^SupportDir|Content/cnc/movies/akira.vqa, ^SupportDir|Content/cnc/movies/airstrk.vqa Sources: nod95, nod95-linux, tfd, origin music-covertops: Covert Operations Music - TestFiles: ^Content/cnc/scores-covertops.mix + TestFiles: ^SupportDir|Content/cnc/scores-covertops.mix Sources: covertops, covertops-linux, tfd, origin Downloads: cnc|installer/downloads.yaml @@ -288,3 +287,6 @@ cnc|installer/gdi95.yaml cnc|installer/nod95.yaml cnc|installer/origin.yaml + +DiscordService: + ApplicationId: 699223250181292033 diff -Nru openra-20200503/mods/cnc/rules/aircraft.yaml openra-20210321/mods/cnc/rules/aircraft.yaml --- openra-20200503/mods/cnc/rules/aircraft.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/aircraft.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,5 +1,6 @@ TRAN: Inherits: ^Helicopter + Inherits@TRANSPORT: ^Transport Valued: Cost: 750 Tooltip: @@ -12,7 +13,7 @@ Queue: Aircraft.GDI, Aircraft.Nod Description: Fast Infantry Transport Helicopter.\n Unarmed Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 150 AltitudeVelocity: 0c100 Health: @@ -41,11 +42,9 @@ Cargo: Types: Infantry MaxWeight: 10 - PipCount: 10 AfterUnloadDelay: 40 SpawnActorOnDeath: Actor: TRAN.Husk - SelectionDecorations: Selectable: DecorationBounds: 41,41 @@ -65,7 +64,7 @@ Queue: Aircraft.Nod Description: Helicopter Gunship with Chainguns.\n Strong vs Infantry, Light Vehicles and\n Aircraft\n Weak vs Tanks Aircraft: - TurnSpeed: 7 + TurnSpeed: 28 Speed: 180 Health: HP: 12500 @@ -88,13 +87,12 @@ AutoTarget: ScanRadius: 4 AttackAircraft: - FacingTolerance: 20 + FacingTolerance: 80 OpportunityFire: false PersistentTargeting: false AttackType: Hover AmmoPool: Ammo: 10 - PipCount: 5 AmmoCondition: ammo WithIdleOverlay@ROTORAIR: Offset: 0,0,85 @@ -107,12 +105,16 @@ WithMuzzleOverlay: SpawnActorOnDeath: Actor: HELI.Husk - SelectionDecorations: ReloadAmmoPool: Delay: 40 Count: 1 Selectable: DecorationBounds: 30,24 + WithAmmoPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + PipCount: 5 ORCA: Inherits: ^Helicopter @@ -130,7 +132,7 @@ Queue: Aircraft.GDI Description: Helicopter Gunship with AG Missiles.\n Strong vs Buildings, Tanks\n Weak vs Infantry Aircraft: - TurnSpeed: 7 + TurnSpeed: 28 Speed: 186 Health: HP: 9000 @@ -150,45 +152,57 @@ AutoTarget: ScanRadius: 5 AttackAircraft: - FacingTolerance: 20 + FacingTolerance: 80 OpportunityFire: false PersistentTargeting: false AttackType: Hover AmmoPool: Ammo: 6 - PipCount: 6 AmmoCondition: ammo SpawnActorOnDeath: Actor: ORCA.Husk WithMoveAnimation: MoveSequence: move - SelectionDecorations: ReloadAmmoPool: Delay: 100 Count: 2 Selectable: DecorationBounds: 30,24 + WithAmmoPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true C17: Inherits: ^Plane + Inherits@TRANSPORT: ^Transport Interactable: Tooltip: Name: Supply Aircraft Valued: Cost: 2000 + UpdatesPlayerStatistics: + AddToAssetsValue: false Aircraft: - TurnSpeed: 5 - Speed: 326 + TurnSpeed: 20 + Speed: 700 Repulsable: False MaximumPitch: 36 HiddenUnderFog: - AlwaysVisibleStances: None + AlwaysVisibleRelationships: None Type: CenterPosition Cargo: MaxWeight: 10 - PipCount: 10 DamageMultiplier@INVULNERABLE: Modifier: 0 + GrantConditionOnPrerequisite@GLOBALC17STEALTH: + Condition: global-C17-stealth + Prerequisites: global-C17-stealth + Cloak: + InitialDelay: 0 + CloakDelay: 0 + CloakTypes: C17 + RequiresCondition: global-C17-stealth Contrail@1: Offset: -261,-650,0 TrailLength: 15 @@ -210,8 +224,10 @@ Name: A10 Bomber Valued: Cost: 2000 + UpdatesPlayerStatistics: + AddToAssetsValue: false Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 373 Repulsable: False AttackBomber: @@ -238,7 +254,7 @@ Tooltip: Name: Chinook Transport Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 140 RevealsShroud: Range: 10c0 @@ -257,7 +273,7 @@ Tooltip: Name: Apache Longbow Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 186 RevealsShroud: Range: 10c0 @@ -273,7 +289,7 @@ Tooltip: Name: Orca Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 186 RevealsShroud: Range: 10c0 diff -Nru openra-20200503/mods/cnc/rules/campaign-maprules.yaml openra-20210321/mods/cnc/rules/campaign-maprules.yaml --- openra-20200503/mods/cnc/rules/campaign-maprules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/campaign-maprules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -27,6 +27,7 @@ -ConquestVictoryConditions: MissionObjectives: EarlyGameOver: true + GameOverDelay: 3000 Shroud: FogCheckboxLocked: True FogCheckboxEnabled: True diff -Nru openra-20200503/mods/cnc/rules/defaults.yaml openra-20210321/mods/cnc/rules/defaults.yaml --- openra-20200503/mods/cnc/rules/defaults.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/defaults.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -5,7 +5,6 @@ GivesExperience: PlayerExperienceModifier: 1 ScriptTriggers: - ConditionManager: RenderDebugState: ^SpriteActor: @@ -13,6 +12,11 @@ QuantizeFacingsFromSequence: RenderSprites: +^ClassicFacingSpriteActor: + ClassicFacingBodyOrientation: + QuantizeFacingsFromSequence: + RenderSprites: + ^1x1Shape: HitShape: UseTargetableCellsOffsets: true @@ -45,108 +49,68 @@ GainsExperience: LevelUpNotification: LevelUp Conditions: - 200: rank-veteran - 400: rank-veteran - 800: rank-veteran - 1600: rank-veteran + 250: rank-veteran + 500: rank-veteran + 750: rank-veteran LevelUpImage: crate-effects GrantCondition@RANK-ELITE: - RequiresCondition: rank-veteran >= 4 + RequiresCondition: rank-veteran >= 3 Condition: rank-elite - DamageMultiplier@RANK-1: - RequiresCondition: rank-veteran == 1 - Modifier: 95 - DamageMultiplier@RANK-2: - RequiresCondition: rank-veteran == 2 - Modifier: 90 - DamageMultiplier@RANK-3: - RequiresCondition: rank-veteran == 3 - Modifier: 85 - DamageMultiplier@RANK-ELITE: - RequiresCondition: rank-elite - Modifier: 75 FirepowerMultiplier@RANK-1: RequiresCondition: rank-veteran == 1 - Modifier: 105 + Modifier: 125 FirepowerMultiplier@RANK-2: RequiresCondition: rank-veteran == 2 - Modifier: 110 - FirepowerMultiplier@RANK-3: - RequiresCondition: rank-veteran == 3 - Modifier: 120 + Modifier: 125 FirepowerMultiplier@RANK-ELITE: RequiresCondition: rank-elite - Modifier: 130 - SpeedMultiplier@RANK-1: - RequiresCondition: rank-veteran == 1 - Modifier: 105 - SpeedMultiplier@RANK-2: + Modifier: 125 + DamageMultiplier@RANK-2: RequiresCondition: rank-veteran == 2 - Modifier: 110 - SpeedMultiplier@RANK-3: - RequiresCondition: rank-veteran == 3 - Modifier: 120 + Modifier: 80 + DamageMultiplier@RANK-ELITE: + RequiresCondition: rank-elite + Modifier: 80 SpeedMultiplier@RANK-ELITE: RequiresCondition: rank-elite - Modifier: 140 - ReloadDelayMultiplier@RANK-1: - RequiresCondition: rank-veteran == 1 - Modifier: 95 - ReloadDelayMultiplier@RANK-2: - RequiresCondition: rank-veteran == 2 - Modifier: 90 - ReloadDelayMultiplier@RANK-3: - RequiresCondition: rank-veteran == 3 - Modifier: 85 - ReloadDelayMultiplier@RANK-ELITE: + Modifier: 125 + RangeMultiplier@RANK-ELITE: RequiresCondition: rank-elite - Modifier: 75 - InaccuracyMultiplier@RANK-1: - RequiresCondition: rank-veteran == 1 - Modifier: 90 - InaccuracyMultiplier@RANK-2: - RequiresCondition: rank-veteran == 2 - Modifier: 80 - InaccuracyMultiplier@RANK-3: - RequiresCondition: rank-veteran == 3 - Modifier: 70 - InaccuracyMultiplier@RANK-ELITE: + Modifier: 125 + RevealsShroudMultiplier@RANK-ELITE: RequiresCondition: rank-elite - Modifier: 50 - SelfHealing@ELITE: - Step: 200 - Delay: 100 - HealIfBelow: 100 + Modifier: 125 + ChangesHealth@ELITE: + Step: 0 + PercentageStep: 5 + Delay: 75 + StartIfBelow: 100 DamageCooldown: 125 RequiresCondition: rank-elite WithDecoration@RANK-1: Image: rank Sequence: rank-veteran-1 Palette: effect - ReferencePoint: Bottom, Right + Position: BottomRight + Margin: 5, 6 + ValidRelationships: Ally, Enemy, Neutral RequiresCondition: rank-veteran == 1 - ZOffset: 256 WithDecoration@RANK-2: Image: rank Sequence: rank-veteran-2 Palette: effect - ReferencePoint: Bottom, Right + Position: BottomRight + Margin: 5, 6 + ValidRelationships: Ally, Enemy, Neutral RequiresCondition: rank-veteran == 2 - ZOffset: 256 - WithDecoration@RANK-3: - Image: rank - Sequence: rank-veteran-3 - Palette: effect - ReferencePoint: Bottom, Right - RequiresCondition: rank-veteran == 3 - ZOffset: 256 WithDecoration@RANK-ELITE: Image: rank Sequence: rank-elite Palette: effect - ReferencePoint: Bottom, Right + Position: BottomRight + Margin: 5, 6 + ValidRelationships: Ally, Enemy, Neutral RequiresCondition: rank-elite - ZOffset: 256 ^InfantryExperienceHospitalHazmatOverrides: WithDecoration@RANK-1: @@ -159,11 +123,6 @@ BlinkPatterns: hospitalheal && hazmatsuits: On, Off, Off hospitalheal || hazmatsuits: On, Off - WithDecoration@RANK-3: - BlinkInterval: 32 - BlinkPatterns: - hospitalheal && hazmatsuits: On, Off, Off - hospitalheal || hazmatsuits: On, Off WithDecoration@RANK-ELITE: BlinkInterval: 32 BlinkPatterns: @@ -228,6 +187,11 @@ AttackMove: AssaultMoveCondition: assault-move +^PlayerHandicaps: + HandicapFirepowerMultiplier: + HandicapDamageMultiplier: + HandicapProductionTimeMultiplier: + ^AcceptsCloakCrate: Cloak: InitialDelay: 15 @@ -242,18 +206,36 @@ Condition: cloak-force-disabled ValidDamageStates: Critical +^Transport: + Cargo: + WithCargoPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + CustomPipSequences: + gray: pip-gray + yellow: pip-yellow + red: pip-red + +^StoresResources: + StoresResources: + WithResourceStoragePipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + PipCount: 10 + ^Vehicle: Inherits@1: ^ExistsInWorld - Inherits@3: ^SpriteActor + Inherits@3: ^ClassicFacingSpriteActor Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill Mobile: Locomotor: wheeled - TurnSpeed: 5 - SelectionDecorations: - WithSpriteControlGroupDecoration: + TurnSpeed: 20 Selectable: Bounds: 24,24 Targetable: @@ -265,7 +247,6 @@ ActorLostNotification: HiddenUnderFog: AttackMove: - DrawLineToTarget: WithDamageOverlay: WithFacingSpriteBody: Explodes: @@ -278,8 +259,6 @@ MustBeDestroyed: Voiced: VoiceSet: VehicleVoice - BodyOrientation: - UseClassicFacingFudge: True HitShape: MapEditorData: Categories: Vehicle @@ -288,14 +267,15 @@ Inherits: ^Vehicle Mobile: Locomotor: tracked - TurnSpeed: 5 + TurnSpeed: 20 Tooltip: GenericName: Tank ^Helicopter: Inherits@1: ^ExistsInWorld - Inherits@3: ^SpriteActor + Inherits@3: ^ClassicFacingSpriteActor Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill @@ -307,8 +287,6 @@ Targetable@AIRBORNE: TargetTypes: Air RequiresCondition: airborne - SelectionDecorations: - WithSpriteControlGroupDecoration: Selectable: Bounds: 24,24 Repairable: @@ -321,7 +299,6 @@ VTOL: true LandableTerrainTypes: Clear, Rough, Road, Beach, Tiberium, BlueTiberium Crushes: crate, infantry - InitialFacing: 224 CanSlide: True HiddenUnderFog: Type: GroundPosition @@ -330,7 +307,6 @@ Weapon: HeliExplode EmptyWeapon: HeliExplode AttackMove: - DrawLineToTarget: Guard: Guardable: Tooltip: @@ -344,8 +320,6 @@ MustBeDestroyed: Voiced: VoiceSet: VehicleVoice - BodyOrientation: - UseClassicFacingFudge: True HitShape: MapEditorData: Categories: Aircraft @@ -356,6 +330,7 @@ Inherits@1: ^ExistsInWorld Inherits@3: ^SpriteActor Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill @@ -366,9 +341,8 @@ RevealsShroud: Range: 5c0 Mobile: + AlwaysTurnInPlace: true Locomotor: foot - SelectionDecorations: - WithSpriteControlGroupDecoration: Selectable: Bounds: 18,18,0,-6 DecorationBounds: 12,17,0,-6 @@ -388,7 +362,6 @@ TiberiumDeath: 6 CrushedSequence: die-crushed AttackMove: - DrawLineToTarget: Passenger: CargoType: Infantry HiddenUnderFog: @@ -410,7 +383,8 @@ WithDecoration@HAZMAT: Image: pips Sequence: pip-hazmat - ReferencePoint: Bottom, Right + Position: BottomRight + Margin: 5, 6 RequiresCondition: hazmatsuits ActorLostNotification: SpawnActorOnDeath: @@ -424,10 +398,10 @@ WarnProbability: 75 CrushSound: squish2.aud Guardable: - SelfHealing@HOSPITAL: + ChangesHealth@HOSPITAL: Step: 500 Delay: 100 - HealIfBelow: 100 + StartIfBelow: 100 DamageCooldown: 125 RequiresCondition: hospitalheal GrantConditionOnPrerequisite@HOSPITAL: @@ -442,7 +416,8 @@ WithDecoration@REDCROSS: Image: pips Sequence: pip-heal - ReferencePoint: Bottom, Right + Position: BottomRight + Margin: 5, 6 RequiresCondition: hospitalheal BlinkInterval: 32 BlinkPattern: On, Off @@ -496,11 +471,12 @@ RevealsShroud: Range: 2c0 Passenger: - PipType: Gray + CustomPipType: gray ActorLostNotification: Notification: CivilianKilled NotifyAll: true ScaredyCat: + AvoidTerrainTypes: Tiberium, BlueTiberium Crushable: CrushSound: squish2.aud Voiced: @@ -508,6 +484,7 @@ Wanders: MinMoveDelay: 150 MaxMoveDelay: 750 + AvoidTerrainTypes: Tiberium, BlueTiberium MapEditorData: Categories: Civilian infantry @@ -523,6 +500,7 @@ Inherits@2: ^SpriteActor Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill @@ -544,8 +522,6 @@ Locomotor: critter Speed: 113 Voice: Move - SelectionDecorations: - WithSpriteControlGroupDecoration: Selectable: Bounds: 24,24 Targetable: @@ -565,7 +541,6 @@ Voice: Attack AttackFrontal: Voice: Attack - DrawLineToTarget: DeathSounds: Voiced: VoiceSet: DinoVoice @@ -580,19 +555,18 @@ Inherits@2: ^SpriteActor Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: Health: - HP: 30000 + HP: 40000 Armor: - Type: Wood + Type: Light RevealsShroud: Range: 6c0 Mobile: Voice: Move Speed: 71 Locomotor: critter - SelectionDecorations: - WithSpriteControlGroupDecoration: Selectable: Bounds: 24,24 Targetable: @@ -601,7 +575,6 @@ ScanRadius: 5 AttackMove: Voice: Attack - DrawLineToTarget: HiddenUnderFog: Valued: Cost: 1000 @@ -632,10 +605,13 @@ Radius: 427 MapEditorData: Categories: Critter + WithDeathAnimation: + UseDeathTypeSuffix: false ^Plane: Inherits@1: ^ExistsInWorld - Inherits@2: ^SpriteActor + Inherits@2: ^ClassicFacingSpriteActor + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill @@ -643,7 +619,7 @@ UseLocation: true HiddenUnderFog: Type: GroundPosition - AlwaysVisibleStances: None + AlwaysVisibleRelationships: None ActorLostNotification: AttackMove: WithShadow: @@ -661,18 +637,15 @@ Inherits@1: ^ExistsInWorld Inherits@3: ^SpriteActor Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill - SelectionDecorations: - WithSpriteControlGroupDecoration: - Selectable: Targetable: TargetTypes: Ground, Water HiddenUnderFog: ActorLostNotification: AttackMove: - DrawLineToTarget: WithDamageOverlay: Explodes: Weapon: UnitExplodeShip @@ -692,11 +665,10 @@ Inherits@2: ^SpriteActor Inherits@shape: ^1x1Shape Inherits@selection: ^SelectableBuilding + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill - SelectionDecorations: - WithSpriteControlGroupDecoration: Targetable: TargetTypes: Ground, C4, Structure Armor: @@ -709,8 +681,8 @@ ActorPreviewPlaceBuildingPreview: OverridePalette: placebuilding SoundOnDamageTransition: - DamagedSounds: xplos.aud - DestroyedSounds: crumble.aud + DamagedSounds: xplobig4.aud + DestroyedSounds: crumble.aud, xplobig4.aud WithSpriteBody: Explodes: Type: Footprint @@ -772,13 +744,12 @@ WithBuildingRepairDecoration: Image: allyrepair Sequence: repair - ReferencePoint: Center + Position: Center Palette: player IsPlayerPalette: True ^CivBuilding: Inherits: ^Building - -ConditionManager: Tooltip: GenericName: Civilian Building GenericStancePrefix: false @@ -829,14 +800,13 @@ WithBuildingRepairDecoration: Image: allyrepair Sequence: repair - ReferencePoint: Center + Position: Center Palette: player IsPlayerPalette: True ^CivField: Inherits: ^CivBuilding -Selectable: - -SelectionDecorations: Interactable: Tooltip: GenericName: Field @@ -898,7 +868,6 @@ RenderSprites: Palette: staticterrain WithWallSpriteBody: - GivesExperience: Sellable: SellSounds: cashturn.aud Guardable: @@ -912,6 +881,8 @@ Terrain: Wall MapEditorData: Categories: Wall + UpdatesPlayerStatistics: + AddToAssetsValue: false ^Tree: Inherits@1: ^SpriteActor @@ -1031,15 +1002,15 @@ ValidOwnerNames: Neutral ^CommonHuskDefaults: - Inherits@1: ^SpriteActor + Inherits@1: ^ClassicFacingSpriteActor Interactable: Health: - HP: 14000 + HP: 28000 Armor: - Type: Light + Type: Heavy HiddenUnderFog: Type: CenterPosition - AlwaysVisibleStances: None + AlwaysVisibleRelationships: None WithFacingSpriteBody: HitShape: MapEditorData: @@ -1049,16 +1020,13 @@ Inherits: ^CommonHuskDefaults Husk: AllowedTerrain: Clear, Rough, Road, Tiberium, BlueTiberium, Beach - Burns: - Damage: 100 - Interval: 6 Targetable: RequiresForceFire: true TargetTypes: Ground, Husk CaptureManager: Capturable: Types: husk - ValidStances: Enemy, Neutral, Ally + ValidRelationships: Enemy, Neutral, Ally TransformOnCapture: ForceHealthPercentage: 25 Tooltip: @@ -1069,13 +1037,19 @@ Explodes: Weapon: UnitExplodeSmall EmptyWeapon: UnitExplodeSmall - BodyOrientation: - UseClassicFacingFudge: True + WithIdleOverlay@Burns: + Image: fire + Sequence: 1 + IsDecoration: True + ChangesHealth: + Step: -200 + StartIfBelow: 101 + Delay: 6 ^LightHusk: Inherits: ^Husk Health: - HP: 2000 + HP: 4000 ^HelicopterHusk: Inherits: ^CommonHuskDefaults @@ -1091,8 +1065,6 @@ Explosion: HeliCrash Tooltip: GenericName: Destroyed Helicopter - BodyOrientation: - UseClassicFacingFudge: True -MapEditorData: ^Bridge: @@ -1161,25 +1133,37 @@ RequiresCondition: lowpower Palette: disabled +^Selectable: + Selectable: + SelectionDecorations: + WithSpriteControlGroupDecoration: + Margin: -2, 0 + DrawLineToTarget: + ^SelectableCombatUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 10 PriorityModifiers: Ctrl ^SelectableSupportUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 8 PriorityModifiers: Ctrl, Alt ^SelectableEconomicUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 6 PriorityModifiers: Ctrl, Alt ^SelectableCombatBuilding: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 4 ^SelectableBuilding: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 2 diff -Nru openra-20200503/mods/cnc/rules/husks.yaml openra-20210321/mods/cnc/rules/husks.yaml --- openra-20200503/mods/cnc/rules/husks.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/husks.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ Image: harv.destroyed APC.Husk: - Inherits: ^LightHusk + Inherits: ^Husk Tooltip: Name: APC (Destroyed) TransformOnCapture: @@ -35,7 +35,7 @@ Image: ftnk.destroyed ARTY.Husk: - Inherits: ^Husk + Inherits: ^LightHusk Tooltip: Name: Artillery (Destroyed) TransformOnCapture: @@ -104,7 +104,7 @@ Image: htnk.destroyed MSAM.Husk: - Inherits: ^Husk + Inherits: ^LightHusk Tooltip: Name: Rocket Launcher (Destroyed) ThrowsParticle@turret: @@ -115,7 +115,7 @@ Image: msam.destroyed MLRS.Husk: - Inherits: ^Husk + Inherits: ^LightHusk Tooltip: Name: Mobile S.A.M. (Destroyed) ThrowsParticle@turret: @@ -133,9 +133,12 @@ IntoActor: stnk RenderSprites: Image: stnk.destroyed + Explodes: + Weapon: UnitExplodeStealthTank + EmptyWeapon: UnitExplodeStealthTank TRUCK.Husk: - Inherits: ^Husk + Inherits: ^LightHusk Tooltip: Name: Supply Truck (Destroyed) TransformOnCapture: diff -Nru openra-20200503/mods/cnc/rules/infantry.yaml openra-20210321/mods/cnc/rules/infantry.yaml --- openra-20200503/mods/cnc/rules/infantry.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/infantry.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -179,7 +179,7 @@ Health: HP: 3000 Passenger: - PipType: Yellow + CustomPipType: yellow EngineerRepair: RepairsBridges: CaptureManager: @@ -198,7 +198,7 @@ Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove Inherits@DECORATIONS: ^InfantryExperienceHospitalHazmatOverrides Valued: - Cost: 2000 + Cost: 1800 Tooltip: Name: Commando UpdatesPlayerStatistics: @@ -207,8 +207,6 @@ BuildPaletteOrder: 50 Prerequisites: eye, ~techlevel.high Queue: Infantry.GDI - BuildDuration: 2000 - BuildDurationModifier: 40 Description: Elite sniper infantry unit.\n Strong vs Infantry, Buildings\n Weak vs Vehicles Mobile: Speed: 71 @@ -218,7 +216,7 @@ Health: HP: 15000 Passenger: - PipType: Red + CustomPipType: red Voice: Move RevealsShroud: Range: 6c0 @@ -277,7 +275,6 @@ Selectable: Bounds: 48,36,2,1 DecorationBounds: 52,38 - SelectionDecorations: Buildable: Description: Bipedal carnivore with a massive skull @@ -287,7 +284,6 @@ Name: Triceratops Armament: Weapon: horn - SelectionDecorations: Buildable: Description: Quadruped with large bony frill and three horns Selectable: diff -Nru openra-20200503/mods/cnc/rules/player.yaml openra-20210321/mods/cnc/rules/player.yaml --- openra-20200503/mods/cnc/rules/player.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/player.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -24,8 +24,10 @@ PlayerResources: CashTickUpNotification: CashTickUp CashTickDownNotification: CashTickDown + SelectableCash: 2500, 5000, 7500, 10000, 20000 + DefaultCash: 7500 DeveloperMode: - CheckboxDisplayOrder: 8 + CheckboxDisplayOrder: 9 BaseAttackNotifier: Shroud: FogCheckboxDisplayOrder: 3 @@ -36,6 +38,13 @@ Enabled: True DisplayOrder: 7 Prerequisites: global-factundeploy + LobbyPrerequisiteCheckbox@GLOBALC17STEALTH: + ID: C17-Stealth + Label: Stealth Deliveries + Description: Nod's delivery plane is cloaked + Enabled: False + DisplayOrder: 8 + Prerequisites: global-C17-stealth PlayerStatistics: FrozenActorLayer: PlaceBeacon: @@ -58,6 +67,5 @@ GrantConditionOnPrerequisiteManager: ResourceStorageWarning: PlayerExperience: - ConditionManager: GameSaveViewportManager: PlayerRadarTerrain: diff -Nru openra-20200503/mods/cnc/rules/ships.yaml openra-20210321/mods/cnc/rules/ships.yaml --- openra-20200503/mods/cnc/rules/ships.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/ships.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ Range: 7c0 Type: CenterPosition Turreted: - TurnSpeed: 5 + TurnSpeed: 20 Offset: 0,896,171 Armament: Weapon: BoatMissile @@ -35,7 +35,6 @@ AutoTarget: AllowMovement: false RejectsOrders: - SelectionDecorations: GrantConditionOnDamageState@HEAVY: Condition: heavy-damage ValidDamageStates: Heavy @@ -51,6 +50,7 @@ LST: Inherits: ^Ship + Inherits@TRANSPORT: ^Transport Valued: Cost: 300 Tooltip: @@ -62,7 +62,7 @@ Mobile: Locomotor: lcraft InitialFacing: 0 - TurnSpeed: 4 + TurnSpeed: 16 Speed: 142 PauseOnCondition: notmobile Health: @@ -71,6 +71,8 @@ Type: Heavy RevealsShroud: Range: 7c0 + -BodyOrientation: + ClassicFacingBodyOrientation: WithFacingSpriteBody: Selectable: Bounds: 48,48 @@ -81,6 +83,5 @@ Cargo: Types: Infantry, Vehicle MaxWeight: 5 - PipCount: 5 PassengerFacing: 0 LoadingCondition: notmobile diff -Nru openra-20200503/mods/cnc/rules/structures.yaml openra-20210321/mods/cnc/rules/structures.yaml --- openra-20200503/mods/cnc/rules/structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,7 +4,7 @@ Selectable: Bounds: 72,48 Valued: - Cost: 3500 + Cost: 3000 Tooltip: Name: Construction Yard Building: @@ -24,7 +24,7 @@ PauseOnCondition: being-demolished || build-incomplete IntoActor: mcv Offset: 1,1 - Facing: 108 + Facing: 432 TransformsIntoMobile: RequiresCondition: factundeploy Locomotor: heavywheeled @@ -47,7 +47,7 @@ DisplayOrder: 0 Factions: gdi Group: Building - LowPowerModifier: 200 + LowPowerModifier: 150 ReadyAudio: ConstructionComplete BlockedAudio: NoBuild LimitedAudio: BuildingInProgress @@ -59,7 +59,7 @@ DisplayOrder: 0 Factions: nod Group: Building - LowPowerModifier: 200 + LowPowerModifier: 150 ReadyAudio: ConstructionComplete BlockedAudio: NoBuild LimitedAudio: BuildingInProgress @@ -71,7 +71,7 @@ DisplayOrder: 1 Factions: gdi Group: Defence - LowPowerModifier: 300 + LowPowerModifier: 150 ReadyAudio: ConstructionComplete BlockedAudio: NoBuild LimitedAudio: BuildingInProgress @@ -83,7 +83,7 @@ DisplayOrder: 1 Factions: nod Group: Defence - LowPowerModifier: 300 + LowPowerModifier: 150 ReadyAudio: ConstructionComplete BlockedAudio: NoBuild LimitedAudio: BuildingInProgress @@ -97,10 +97,11 @@ ProductionType: Building.Nod ProductionBar@DefenceGDI: ProductionType: Defence.GDI + Color: 8A8A8A ProductionBar@DefenceNod: ProductionType: Defence.Nod + Color: 8A8A8A BaseProvider: - Cooldown: 75 Range: 14c0 WithBuildingBib: WithBuildingPlacedAnimation: @@ -152,7 +153,6 @@ BuildPaletteOrder: 10 Prerequisites: fact Queue: Building.GDI, Building.Nod - BuildDuration: 330 Description: Generates power Building: Footprint: xX xx == @@ -200,6 +200,7 @@ PROC: Inherits: ^BaseBuilding + Inherits@RESOURCES: ^StoresResources HitShape: Type: Rectangle TopLeft: -1536, -512 @@ -218,7 +219,7 @@ Queue: Building.GDI, Building.Nod Description: Processes raw Tiberium\ninto useable resources Building: - Footprint: _x_ xxx === === + Footprint: _x_ xxx +++ === Dimensions: 3,4 LocalCenterOffset: 0,-512,0 Health: @@ -226,36 +227,34 @@ RevealsShroud: Range: 6c0 Refinery: - DockAngle: 112 + DockAngle: 448 DockOffset: 0,2 IsDragRequired: True DragOffset: -554,512,0 DragLength: 12 TickRate: 15 StoresResources: - PipColor: Green - PipCount: 10 Capacity: 1000 Selectable: Bounds: 72,56 DecorationBounds: 73,72 CustomSellValue: - Value: 500 + Value: 400 FreeActor: Actor: HARV SpawnOffset: 1,2 - Facing: 64 + Facing: 256 WithBuildingBib: WithResourceLevelOverlay: RequiresCondition: !build-incomplete Power: Amount: -40 ProvidesPrerequisite@buildingname: - SelectionDecorations: SILO: Inherits: ^BaseBuilding Inherits@shape: ^2x1Shape + Inherits@RESOURCES: ^StoresResources Valued: Cost: 100 Tooltip: @@ -279,15 +278,12 @@ WithResourceLevelSpriteBody: Sequence: stages StoresResources: - PipCount: 10 - PipColor: Green Capacity: 3000 -SpawnActorsOnSell: Power: Amount: -10 MustBeDestroyed: RequiredForShortGame: false - SelectionDecorations: -AcceptsDeliveredCash: Selectable: Bounds: 48,24 @@ -336,7 +332,7 @@ Type: Infantry.GDI DisplayOrder: 2 Group: Infantry - LowPowerModifier: 300 + LowPowerModifier: 150 ReadyAudio: UnitReady BlockedAudio: NoBuild LimitedAudio: BuildingInProgress @@ -346,7 +342,7 @@ ProductionBar: ProductionType: Infantry.GDI Power: - Amount: -20 + Amount: -15 ProvidesPrerequisite@buildingname: Selectable: Bounds: 48,42,0,-5 @@ -387,7 +383,7 @@ Type: Infantry.Nod DisplayOrder: 2 Group: Infantry - LowPowerModifier: 300 + LowPowerModifier: 150 ReadyAudio: UnitReady BlockedAudio: NoBuild LimitedAudio: BuildingInProgress @@ -397,12 +393,11 @@ ProductionBar: ProductionType: Infantry.Nod Power: - Amount: -20 + Amount: -15 ProvidesPrerequisite@buildingname: Selectable: Bounds: 48,48 DecorationBounds: 48,68,0,-10 - SelectionDecorations: AFLD: Inherits: ^BaseBuilding @@ -449,7 +444,7 @@ Type: Vehicle.Nod DisplayOrder: 3 Group: Vehicle - LowPowerModifier: 300 + LowPowerModifier: 150 BlockedAudio: NoBuild LimitedAudio: BuildingInProgress QueuedAudio: Training @@ -481,13 +476,12 @@ Queue: Building.GDI Description: Produces vehicles Building: - Footprint: xxx === === + Footprint: xxx +++ === Dimensions: 3,3 LocalCenterOffset: 0,-512,0 Selectable: Bounds: 72,48 DecorationBounds: 72,64,0,-16 - SelectionDecorations: Health: HP: 110000 RevealsShroud: @@ -507,7 +501,7 @@ Type: Vehicle.GDI DisplayOrder: 3 Group: Vehicle - LowPowerModifier: 300 + LowPowerModifier: 150 ReadyAudio: UnitReady BlockedAudio: NoBuild LimitedAudio: BuildingInProgress @@ -540,7 +534,7 @@ BuildPaletteOrder: 50 Prerequisites: proc Queue: Building.GDI, Building.Nod - Description: Produces, rearms and\nrepairs helicopters + Description: Produces and repairs helicopters Building: Footprint: xx xx Dimensions: 2,2 @@ -550,6 +544,7 @@ Range: 5c0 Exit@1: SpawnOffset: 0,-256,0 + Facing: 896 Production: Produces: Aircraft.GDI, Aircraft.Nod Reservable: @@ -565,7 +560,7 @@ DisplayOrder: 4 Factions: gdi Group: Aircraft - LowPowerModifier: 300 + LowPowerModifier: 150 ReadyAudio: UnitReady BlockedAudio: NoBuild LimitedAudio: BuildingInProgress @@ -577,7 +572,7 @@ DisplayOrder: 4 Factions: nod Group: Aircraft - LowPowerModifier: 300 + LowPowerModifier: 150 ReadyAudio: UnitReady BlockedAudio: NoBuild LimitedAudio: BuildingInProgress @@ -589,7 +584,7 @@ ProductionBar@Nod: ProductionType: Aircraft.Nod Power: - Amount: -10 + Amount: -20 ProvidesPrerequisite@buildingname: HQ: @@ -618,7 +613,6 @@ Selectable: Bounds: 48,40,0,9 DecorationBounds: 48,53,0,-4 - SelectionDecorations: WithSpriteBody: PauseOnCondition: lowpower Health: @@ -636,7 +630,7 @@ PauseOnCondition: lowpower Prerequisites: ~techlevel.superweapons Icon: airstrike - ChargeInterval: 6000 + ChargeInterval: 7500 SquadSize: 3 QuantizedFacings: 8 Description: Air Strike @@ -682,7 +676,6 @@ Selectable: Bounds: 64,34,0,3 DecorationBounds: 72,48 - SelectionDecorations: Health: HP: 80000 RevealsShroud: @@ -728,7 +721,6 @@ Selectable: Bounds: 48,40,0,9 DecorationBounds: 48,53,0,-4 - SelectionDecorations: WithSpriteBody: PauseOnCondition: lowpower Health: @@ -747,7 +739,7 @@ Prerequisites: ~techlevel.superweapons Icon: ioncannon Cursor: ioncannon - ChargeInterval: 6750 + ChargeInterval: 9000 Description: Ion Cannon LongDesc: Initiate an Ion Cannon strike.\nApplies instant damage to a small area. BeginChargeSpeechNotification: IonCannonCharging @@ -788,7 +780,6 @@ Selectable: Bounds: 72,48 DecorationBounds: 72,68,0,-12 - SelectionDecorations: Health: HP: 210000 RevealsShroud: @@ -802,7 +793,7 @@ Prerequisites: ~techlevel.superweapons Icon: abomb Cursor: nuke - ChargeInterval: 9000 + ChargeInterval: 11250 Description: Nuclear Strike LongDesc: Launch a tactical nuclear warhead.\nApplies heavy damage over a large area. EndChargeSpeechNotification: NuclearWeaponAvailable @@ -823,9 +814,9 @@ CircleSequence: circles SupportPowerPaletteOrder: 30 WithBuildingBib: - WithNukeLaunchAnimation: + WithSupportPowerActivationAnimation: RequiresCondition: !build-incomplete - WithNukeLaunchOverlay: + WithSupportPowerActivationOverlay: RequiresCondition: !build-incomplete Sequence: smoke SupportPowerChargeBar: @@ -846,8 +837,7 @@ BuildPaletteOrder: 45 Prerequisites: barracks Queue: Defence.GDI, Defence.Nod - BuildDuration: 1440 - BuildDurationModifier: 40 + BuildDuration: 960 Description: Basic Anti-Tank base defense.\n Strong vs Tanks, vehicles\n Weak vs Infantry Building: Health: @@ -859,10 +849,15 @@ WithBuildingBib: HasMinibib: true Turreted: - TurnSpeed: 12 - InitialFacing: 56 - -WithSpriteBody: - WithEmbeddedTurretSpriteBody: + TurnSpeed: 48 + InitialFacing: 192 + RealignDelay: -1 + RequiresCondition: !build-incomplete + WithSpriteTurret: + RequiresCondition: !build-incomplete + Recoils: false + WithTurretAttackAnimation: + Sequence: recoil Armament: Weapon: TurretGun LocalOffset: 512,0,112 @@ -875,8 +870,8 @@ Range: 3c0 Power: Amount: -20 - BodyOrientation: - UseClassicFacingFudge: True + -BodyOrientation: + ClassicFacingBodyOrientation: SAM: Inherits: ^Defense @@ -897,8 +892,7 @@ BuildPaletteOrder: 50 Prerequisites: hand Queue: Defence.Nod - BuildDuration: 1700 - BuildDurationModifier: 40 + BuildDuration: 1130 Description: Anti-Aircraft base defense.\n Strong vs Aircraft\n Cannot target Ground units. Building: Footprint: xx @@ -908,13 +902,14 @@ Armor: Type: Heavy RevealsShroud: - Range: 6c0 + Range: 8c0 Turreted: - TurnSpeed: 10 + TurnSpeed: 40 InitialFacing: 0 RealignDelay: -1 -WithSpriteBody: WithEmbeddedTurretSpriteBody: + QuantizedFacings: 32 Armament: Weapon: Dragon MuzzleSequence: muzzle @@ -925,8 +920,8 @@ -RenderDetectionCircle: Power: Amount: -20 - BodyOrientation: - UseClassicFacingFudge: True + -BodyOrientation: + ClassicFacingBodyOrientation: -ActorPreviewPlaceBuildingPreview: SequencePlaceBuildingPreview: Sequence: place @@ -944,13 +939,11 @@ BuildPaletteOrder: 60 Prerequisites: tmpl, ~techlevel.high Queue: Defence.Nod - BuildDuration: 3120 - BuildDurationModifier: 40 + BuildDuration: 2080 Description: Advanced base defense.\nRequires power to operate.\n Strong vs all Ground units\n Cannot target Aircraft Selectable: Bounds: 24,24 DecorationBounds: 22,44,0,-10 - SelectionDecorations: Health: HP: 75000 Armor: @@ -994,8 +987,7 @@ BuildPaletteOrder: 40 Prerequisites: barracks Queue: Defence.GDI, Defence.Nod - BuildDuration: 1440 - BuildDurationModifier: 40 + BuildDuration: 960 Description: Basic defensive structure.\n Strong vs Infantry\n Weak vs Tanks Building: Health: @@ -1016,7 +1008,7 @@ Range: 3c0 WithMuzzleOverlay: Turreted: - TurnSpeed: 255 + TurnSpeed: 512 Power: Amount: -10 @@ -1032,23 +1024,25 @@ BuildPaletteOrder: 60 Prerequisites: anyhq, ~techlevel.medium Queue: Defence.GDI - BuildDuration: 2880 - BuildDurationModifier: 40 - Description: All-purpose defensive structure.\n Strong vs Aircraft, Tanks\n Weak vs Infantry + BuildDuration: 1920 + Description: All-purpose defensive structure.\n Strong vs Aircraft, Infantry\n Weak vs Tanks Selectable: Bounds: 24,24 DecorationBounds: 22,48,0,-12 - SelectionDecorations: Health: HP: 55000 Armor: Type: Heavy RevealsShroud: Range: 8c0 + -RenderRangeCircle: + WithRangeCircle: + Range: 7c0 + Color: FFFF0080 WithBuildingBib: HasMinibib: true Turreted: - TurnSpeed: 255 + TurnSpeed: 512 Offset: 128,128,384 Armament@PRIMARY: Weapon: TowerMissile @@ -1125,8 +1119,7 @@ BuildPaletteOrder: 30 Prerequisites: vehicleproduction Queue: Defence.GDI, Defence.Nod - BuildDuration: 500 - BuildDurationModifier: 40 + BuildDuration: 330 Description: Stops infantry and most tanks.\nBlocks some projectiles. Health: HP: 25000 @@ -1136,8 +1129,6 @@ Crushable: CrushClasses: heavywall -CrushSound: - SoundOnDamageTransition: - DestroyedSounds: crumble.aud LineBuild: NodeTypes: concrete LineBuildNode: diff -Nru openra-20200503/mods/cnc/rules/tech.yaml openra-20210321/mods/cnc/rules/tech.yaml --- openra-20200503/mods/cnc/rules/tech.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/tech.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -3,6 +3,8 @@ Selectable: Bounds: 24,24 CashTrickler: + Amount: 10 + RequiresCondition: enabled Building: Footprint: x Dimensions: 1,1 @@ -12,13 +14,15 @@ Name: Oil Derrick TooltipDescription@ally: Description: Provides additional funds. - ValidStances: Ally + ValidRelationships: Ally TooltipDescription@other: Description: Capture to receive additional funds. - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy SpawnActorOnDeath: Actor: V19.Husk UpdatesDerrickCount: + GrantConditionOnCombatantOwner: + Condition: enabled V19.Husk: Inherits: ^CivBuildingHusk @@ -48,10 +52,10 @@ Name: Hospital TooltipDescription@ally: Description: Provides infantry with self-healing. - ValidStances: Ally + ValidRelationships: Ally TooltipDescription@other: Description: Capture to enable self-healing for infantry. - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy SpawnActorOnDeath: Actor: HOSP.Husk WithBuildingBib: @@ -83,11 +87,11 @@ Tooltip: Name: Biological Lab TooltipDescription@ally: - Description: Produces Bio-Lab units. - ValidStances: Ally + Description: Provides infantry with Tiberium immunity. Produces Visceroids. + ValidRelationships: Ally TooltipDescription@other: - Description: Capture to produce Bio-Lab units. - ValidStances: Neutral, Enemy + Description: Capture to enable Tiberium immunity for infantry. Produces Visceroids. + ValidRelationships: Neutral, Enemy Exit@1: SpawnOffset: 0,-426,0 ExitCell: 0,-1 diff -Nru openra-20200503/mods/cnc/rules/trees.yaml openra-20210321/mods/cnc/rules/trees.yaml --- openra-20200503/mods/cnc/rules/trees.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/trees.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,6 +4,7 @@ ResourceType: Tiberium Interval: 55 WithIdleAnimation: + Interval: 500, 1000 SPLIT3: Inherits: ^TibTree @@ -13,6 +14,7 @@ ResourceType: Tiberium Interval: 55 WithIdleAnimation: + Interval: 500, 1000 SPLITBLUE: Inherits: ^TibTree @@ -22,6 +24,7 @@ ResourceType: BlueTiberium Interval: 110 WithIdleAnimation: + Interval: 500, 1000 Tooltip: Name: Blossom Tree (blue) RadarColorFromTerrain: @@ -98,6 +101,21 @@ SpawnActorOnDeath: Actor: T03.Husk +T03.Transformable: + Inherits: ^Tree + RenderSprites: + Image: t03 + MapEditorData: + ExcludeTilesets: DESERT + SpawnActorOnDeath: + Actor: T03.Husk + TransformsNearResources: + Type: Tiberium + IntoActor: split2 + Offset: 0,1 + EditorOnlyTooltip: + Name: (Tree that can transform into a Blossom Tree) + T03.Husk: Inherits: ^TreeHusk MapEditorData: @@ -235,6 +253,21 @@ SpawnActorOnDeath: Actor: T13.Husk +T13.Transformable: + Inherits: ^Tree + RenderSprites: + Image: t13 + MapEditorData: + ExcludeTilesets: DESERT + SpawnActorOnDeath: + Actor: T13.Husk + TransformsNearResources: + Type: Tiberium + IntoActor: split3 + Offset: 0,1 + EditorOnlyTooltip: + Name: (Tree that can transform into a Blossom Tree) + T13.Husk: Inherits: ^TreeHusk Building: diff -Nru openra-20200503/mods/cnc/rules/vehicles.yaml openra-20210321/mods/cnc/rules/vehicles.yaml --- openra-20200503/mods/cnc/rules/vehicles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/vehicles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,15 +2,13 @@ Inherits: ^Vehicle Inherits@selection: ^SelectableSupportUnit Valued: - Cost: 3500 + Cost: 3000 Tooltip: Name: Mobile Construction Vehicle Buildable: BuildPaletteOrder: 100 Prerequisites: anyhq, ~techlevel.medium, fix Queue: Vehicle.GDI, Vehicle.Nod - BuildDuration: 3750 - BuildDurationModifier: 40 Description: Deploys into another Construction Yard.\n Unarmed Selectable: DecorationBounds: 36,36 @@ -20,7 +18,7 @@ Health: HP: 120000 Repairable: - HpPerStep: 2182 + HpPerStep: 1819 Armor: Type: Heavy RevealsShroud: @@ -28,7 +26,7 @@ Transforms: IntoActor: fact Offset: -1,-1 - Facing: 108 + Facing: 432 TransformSounds: constru2.aud, hvydoor1.aud NoTransformNotification: BuildingCannotPlaceAudio MustBeDestroyed: @@ -38,14 +36,13 @@ Actor: MCV.Husk OwnerType: InternalName EffectiveOwnerFromOwner: true - SelectionDecorations: HARV: Inherits: ^Tank Inherits@CLOAK: ^AcceptsCloakCrate Inherits@selection: ^SelectableEconomicUnit Valued: - Cost: 1000 + Cost: 1100 Tooltip: Name: Harvester GenericName: Harvester @@ -53,46 +50,57 @@ BuildPaletteOrder: 10 Prerequisites: proc Queue: Vehicle.GDI, Vehicle.Nod - BuildDuration: 1680 - BuildDurationModifier: 40 Description: Collects Tiberium for processing.\n Unarmed Selectable: DecorationBounds: 36,36 Harvester: Resources: Tiberium, BlueTiberium - PipCount: 7 Capacity: 20 BaleLoadDelay: 12 BaleUnloadDelay: 6 SearchFromProcRadius: 15 SearchFromHarvesterRadius: 8 + HarvestFacings: 8 EmptyCondition: no-tiberium Mobile: Speed: 85 Health: HP: 62500 Repairable: - HpPerStep: 2537 + HpPerStep: 2584 Armor: Type: Heavy RevealsShroud: Range: 4c0 + ActorLostNotification: + Notification: HarvesterLost SpawnActorOnDeath: Actor: HARV.Husk OwnerType: InternalName EffectiveOwnerFromOwner: true WithHarvestAnimation: WithDockingAnimation: + Explodes@EMPTY: + Weapon: UnitExplodeHarvEmpty + EmptyWeapon: UnitExplodeHarvEmpty Explodes: RequiresCondition: !no-tiberium Weapon: TiberiumExplosion - SelectionDecorations: + WithHarvesterPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + PipCount: 7 + ResourceSequences: + Tiberium: pip-green + BlueTiberium: pip-blue APC: Inherits: ^Tank Inherits@EXPERIENCE: ^GainsExperience Inherits@CLOAK: ^AcceptsCloakCrate Inherits@AUTOTARGET: ^AutoTargetAllAssaultMove + Inherits@TRANSPORT: ^Transport Valued: Cost: 600 Tooltip: @@ -103,11 +111,9 @@ BuildPaletteOrder: 30 Prerequisites: pyle Queue: Vehicle.GDI - BuildDuration: 938 - BuildDurationModifier: 40 Description: Armed infantry transport.\nCan attack Aircraft.\n Strong vs Vehicles\n Weak vs Infantry Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 132 PauseOnCondition: notmobile Health: @@ -117,30 +123,49 @@ Armor: Type: Heavy RevealsShroud: - Range: 6c0 + Range: 7c0 Turreted: - TurnSpeed: 10 + TurnSpeed: 40 + AutoTargetPriority@Air: + ValidTargets: Air + Priority: 2 Armament@PRIMARY: Weapon: APCGun - Recoil: 96 + Recoil: 48 RecoilRecovery: 18 - LocalOffset: 85,85,299, 85,-85,299 + LocalOffset: 255,100,189, 255,-100,189 MuzzleSequence: muzzle + PauseOnCondition: reload-air + ReloadingCondition: reload-ground Armament@SECONDARY: Name: secondary Weapon: APCGun.AA - Recoil: 96 + Recoil: 48 RecoilRecovery: 18 - LocalOffset: 85,85,299, 85,-85,299 - MuzzleSequence: muzzle + LocalOffset: 175,100,299, 175,-100,299 + MuzzleSequence: muzzle-air + PauseOnCondition: reload-ground + ReloadingCondition: reload-air + GrantConditionOnAttack: + Condition: attack-air + ArmamentNames: secondary + RevokeDelay: 18 + RevokeOnNewTarget: False + RevokeAll: True AttackTurreted: WithMuzzleOverlay: WithSpriteTurret: + RequiresCondition: !attack-air + WithSpriteTurret@AIR: + Sequence: turret-air + RequiresCondition: attack-air Cargo: Types: Infantry MaxWeight: 5 - PipCount: 5 LoadingCondition: notmobile + Explodes: + Weapon: UnitExplodeBig + EmptyWeapon: UnitExplodeBig SpawnActorOnDeath: Actor: APC.Husk OwnerType: InternalName @@ -163,12 +188,12 @@ Queue: Vehicle.Nod Description: Long-range artillery.\n Strong vs Infantry, Vehicles and Buildings Mobile: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 85 Health: HP: 7500 Repairable: - HpPerStep: 569 + HpPerStep: 568 Armor: Type: Light RevealsShroud: @@ -209,7 +234,7 @@ Queue: Vehicle.Nod Description: Heavily armored flame-throwing vehicle.\n Strong vs Infantry, Buildings and Vehicles\n Weak vs Tanks Mobile: - TurnSpeed: 7 + TurnSpeed: 28 Speed: 99 Health: HP: 27000 @@ -218,7 +243,7 @@ Armor: Type: Heavy RevealsShroud: - Range: 5c0 + Range: 6c0 Armament: Weapon: BigFlamer LocalOffset: 512,128,42, 512,-128,42 @@ -250,7 +275,7 @@ Queue: Vehicle.Nod Description: Fast scout and anti-infantry vehicle.\n Strong vs Infantry\n Weak vs Tanks Mobile: - TurnSpeed: 10 + TurnSpeed: 40 Speed: 170 Health: HP: 12000 @@ -261,7 +286,7 @@ RevealsShroud: Range: 8c0 Turreted: - TurnSpeed: 10 + TurnSpeed: 40 Offset: -43,0,128 Armament: Weapon: MachineGun @@ -292,9 +317,9 @@ Queue: Vehicle.Nod Description: Fast scout vehicle, armed with\nrockets.\nCan attack Aircraft.\n Strong vs Vehicles, Tanks\n Weak vs Infantry Mobile: - TurnSpeed: 10 - Speed: 213 - Locomotor: bike + TurnSpeed: 40 + Speed: 184 + Locomotor: wheeled Health: HP: 11000 Repairable: @@ -330,7 +355,7 @@ Queue: Vehicle.GDI Description: Fast scout and anti-infantry vehicle.\n Strong vs Infantry\n Weak vs Tanks Mobile: - TurnSpeed: 10 + TurnSpeed: 40 Speed: 156 Health: HP: 16000 @@ -341,7 +366,7 @@ RevealsShroud: Range: 8c0 Turreted: - TurnSpeed: 10 + TurnSpeed: 40 Offset: -85,0,128 Armament: Weapon: MachineGunH @@ -361,7 +386,7 @@ Inherits@CLOAK: ^AcceptsCloakCrate Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove Valued: - Cost: 650 + Cost: 750 Tooltip: Name: Light Tank UpdatesPlayerStatistics: @@ -370,22 +395,20 @@ BuildPaletteOrder: 40 Prerequisites: anyhq, ~techlevel.medium Queue: Vehicle.Nod - BuildDuration: 1020 - BuildDurationModifier: 40 Description: Fast, light tank.\n Strong vs Vehicles, Tanks\n Weak vs Infantry Mobile: - TurnSpeed: 7 + TurnSpeed: 28 Speed: 110 Health: HP: 34000 Repairable: - HpPerStep: 2273 + HpPerStep: 2062 Armor: Type: Heavy RevealsShroud: Range: 6c0 Turreted: - TurnSpeed: 7 + TurnSpeed: 28 Armament: Weapon: 70mm Recoil: 85 @@ -406,7 +429,7 @@ Inherits@CLOAK: ^AcceptsCloakCrate Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove Valued: - Cost: 800 + Cost: 900 Tooltip: Name: Medium Tank UpdatesPlayerStatistics: @@ -421,13 +444,13 @@ Health: HP: 45000 Repairable: - HpPerStep: 2557 + HpPerStep: 2274 Armor: Type: Heavy RevealsShroud: Range: 6c0 Turreted: - TurnSpeed: 5 + TurnSpeed: 20 Armament: Weapon: 120mm Recoil: 128 @@ -437,11 +460,13 @@ AttackTurreted: WithMuzzleOverlay: WithSpriteTurret: + Explodes: + Weapon: UnitExplodeBig + EmptyWeapon: UnitExplodeBig SpawnActorOnDeath: Actor: MTNK.Husk OwnerType: InternalName EffectiveOwnerFromOwner: true - SelectionDecorations: Selectable: DecorationBounds: 28,28 @@ -451,7 +476,7 @@ Inherits@CLOAK: ^AcceptsCloakCrate Inherits@AUTOTARGET: ^AutoTargetAllAssaultMove Valued: - Cost: 1500 + Cost: 1800 Tooltip: Name: Mammoth Tank UpdatesPlayerStatistics: @@ -464,18 +489,18 @@ Mobile: Locomotor: heavytracked Speed: 56 - TurnSpeed: 3 + TurnSpeed: 12 Health: HP: 87000 Repairable: - HpPerStep: 2637 + HpPerStep: 2198 Armor: Type: Heavy RevealsShroud: Range: 6c0 WithSpriteTurret: Turreted: - TurnSpeed: 3 + TurnSpeed: 12 Armament@PRIMARY: Weapon: 120mmDual LocalOffset: 900,180,340, 900,-180,340 @@ -491,16 +516,18 @@ MuzzleSequence: muzzle AttackTurreted: WithMuzzleOverlay: - SelfHealing: + ChangesHealth: Step: 500 Delay: 10 - HealIfBelow: 50 + StartIfBelow: 50 DamageCooldown: 200 + Explodes: + Weapon: UnitExplodeMech + EmptyWeapon: UnitExplodeMech SpawnActorOnDeath: Actor: HTNK.Husk OwnerType: InternalName EffectiveOwnerFromOwner: true - SelectionDecorations: Selectable: DecorationBounds: 34,34,0,-3 @@ -522,17 +549,17 @@ Description: Long range rocket artillery.\n Strong vs all Ground units. Mobile: Speed: 85 - TurnSpeed: 4 + TurnSpeed: 16 Health: HP: 12000 Repairable: - HpPerStep: 546 + HpPerStep: 606 Armor: Type: Light RevealsShroud: Range: 5c0 Turreted: - TurnSpeed: 255 + TurnSpeed: 512 Offset: -256,0,128 Armament@PRIMARY: Weapon: 227mm @@ -545,6 +572,9 @@ TargetFrozenActors: True ForceFireIgnoresActors: True WithSpriteTurret: + Explodes: + Weapon: UnitExplodeMech + EmptyWeapon: UnitExplodeMech SpawnActorOnDeath: Actor: MSAM.Husk OwnerType: InternalName @@ -570,7 +600,7 @@ Description: Powerful anti-air unit.\nCannot attack Ground units. Mobile: Speed: 99 - TurnSpeed: 7 + TurnSpeed: 28 Health: HP: 18000 Repairable: @@ -580,7 +610,7 @@ RevealsShroud: Range: 8c0 Turreted: - TurnSpeed: 8 + TurnSpeed: 32 Offset: -128,0,128 RealignDelay: 0 Armament: @@ -588,7 +618,6 @@ LocalOffset: 0,-171,0, 0,171,0 AmmoPool: Ammo: 2 - PipCount: 0 AmmoCondition: ammo AttackTurreted: WithSpriteTurret: @@ -627,8 +656,10 @@ Description: Long-range missile tank that can cloak.\nCan attack Aircraft.\nHas weak armor. Can be spotted by infantry and defense structures.\n Strong vs Vehicles, Tanks\n Weak vs Infantry. Mobile: Locomotor: heavywheeled - TurnSpeed: 10 + TurnSpeed: 40 Speed: 142 + Targetable: + TargetTypes: Ground, Vehicle, StealthTank Health: HP: 15000 Repairable: @@ -642,17 +673,24 @@ CloakDelay: 90 CloakSound: trans1.aud UncloakSound: trans1.aud + UncloakOn: Attack, Unload, Dock, Damage, Heal PauseOnCondition: cloak-force-disabled GrantConditionOnDamageState@UNCLOAK: Condition: cloak-force-disabled ValidDamageStates: Critical - Armament: + Armament@PRIMARY: Weapon: 227mm.stnk LocalOffset: 213,43,128, 213,-43,128 + Armament@SECONDARY: + Weapon: 227mm.stnkAA + LocalOffset: 213,43,128, 213,-43,128 AttackFrontal: AutoTarget: InitialStance: HoldFire InitialStanceAI: ReturnFire + Explodes: + Weapon: UnitExplodeStealthTank + EmptyWeapon: UnitExplodeStealthTank SpawnActorOnDeath: Actor: STNK.Husk OwnerType: InternalName @@ -686,9 +724,10 @@ Queue: Vehicle.GDI, Vehicle.Nod BuildPaletteOrder: 35 Prerequisites: vehicleproduction - Description: Transports cash to other players.\n Unarmed + BuildDuration: 500 + Description: Transports cash to other players.\n Builds fast\n Unarmed Valued: - Cost: 500 + Cost: 1000 Tooltip: Name: Supply Truck Health: @@ -700,8 +739,8 @@ RevealsShroud: Range: 4c0 DeliversCash: - Payload: 500 - PlayerExperience: 50 + Payload: 1000 + PlayerExperience: 100 SpawnActorOnDeath: Actor: TRUCK.Husk OwnerType: InternalName diff -Nru openra-20200503/mods/cnc/rules/world.yaml openra-20210321/mods/cnc/rules/world.yaml --- openra-20200503/mods/cnc/rules/world.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/rules/world.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -52,17 +52,6 @@ Tiberium: 50 BlueTiberium: 50 Beach: 50 - Locomotor@BIKE: - Name: bike - Crushes: crate - TerrainSpeeds: - Clear: 70 - Rough: 35 - Road: 100 - Bridge: 100 - Tiberium: 35 - BlueTiberium: 35 - Beach: 35 Locomotor@HEAVYWHEELED: Name: heavywheeled Crushes: crate, infantry @@ -140,7 +129,6 @@ ResourceType@green-tib: Type: Tiberium Name: Tiberium - PipColor: Green ResourceType: 1 Palette: staticterrain TerrainType: Tiberium @@ -152,7 +140,6 @@ ResourceType@blue-tib: Type: BlueTiberium Name: Tiberium - PipColor: Blue ResourceType: 2 Palette: bluetiberium TerrainType: BlueTiberium @@ -161,6 +148,8 @@ ValuePerUnit: 60 AllowedTerrainTypes: Clear,Road AllowUnderActors: true + ResourceRenderer: + RenderTypes: Tiberium, BlueTiberium World: Inherits: ^BaseWorld @@ -179,18 +168,23 @@ SmudgeLayer@SCORCH: Type: Scorch Sequence: scorches - SmokePercentage: 50 + SmokeChance: 50 + SmokeImage: smoke_m + SmokeSequences: idle SmudgeLayer@CRATER: Type: Crater Sequence: craters + SmokeChance: 25 + SmokeImage: smoke_m + SmokeSequences: idle ResourceLayer: - ResourceRenderer: - RenderTypes: Tiberium, BlueTiberium ResourceClaimLayer: WarheadDebugOverlay: CustomTerrainDebugOverlay: MapCreeps: CheckboxVisible: False + CheckboxEnabled: True + CheckboxLocked: True SpawnMapActors: MapBuildRadius: AllyBuildRadiusCheckboxDisplayOrder: 4 @@ -244,7 +238,6 @@ BaseActor: mcv SupportActors: e1,e1,e1,e1,e1,e2,e2,e2,e3,e3,apc,mtnk SpawnMPUnits: - StartingUnitsClass: light DropdownDisplayOrder: 0 CrateSpawner: Minimum: 1 diff -Nru openra-20200503/mods/cnc/sequences/aircraft.yaml openra-20210321/mods/cnc/sequences/aircraft.yaml --- openra-20200503/mods/cnc/sequences/aircraft.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/sequences/aircraft.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,13 +1,13 @@ c17: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: c17icnh tran: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True rotor: lrotor Length: 4 rotor2: rrotor @@ -29,7 +29,7 @@ heli: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True rotor: lrotor Length: 4 slow-rotor: lrotor @@ -44,7 +44,7 @@ orca: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True move: Start: 32 Facings: 32 @@ -54,7 +54,7 @@ a10: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: minigun Length: 6 Facings: 8 diff -Nru openra-20200503/mods/cnc/sequences/campaign.yaml openra-20210321/mods/cnc/sequences/campaign.yaml --- openra-20200503/mods/cnc/sequences/campaign.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/sequences/campaign.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,9 +1,9 @@ lst: idle: lstnew - UseClassicFacingFudge: True + UseClassicFacings: True Facings: 32 roof: lstnew2 - UseClassicFacingFudge: True + UseClassicFacings: True Facings: 32 icon: lsticnh.tem AddExtension: False diff -Nru openra-20200503/mods/cnc/sequences/decorations.yaml openra-20210321/mods/cnc/sequences/decorations.yaml --- openra-20200503/mods/cnc/sequences/decorations.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/sequences/decorations.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -6,6 +6,7 @@ DESERT: TEMPERAT make: Length: 30 + Tick: 120 active: Start: 30 Length: 24 @@ -18,6 +19,7 @@ UseTilesetExtension: true make: Length: 30 + Tick: 120 active: Start: 30 Length: 24 diff -Nru openra-20200503/mods/cnc/sequences/infantry.yaml openra-20210321/mods/cnc/sequences/infantry.yaml --- openra-20200503/mods/cnc/sequences/infantry.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/sequences/infantry.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -29,6 +29,9 @@ Offset: -3,2 Facings: 8 Length: 13 + die: chemball + Length: * + ZOffset: 2047 icon: viceicnh pvice: @@ -283,7 +286,7 @@ Start: 476 Length: 3 Facings: 8 - Tick: 120 + Tick: 120 # Shot die1: Start: 397 @@ -376,7 +379,7 @@ Start: 588 Length: 3 Facings: 8 - Tick: 120 + Tick: 120 # Shot die1: Start: 509 @@ -497,7 +500,7 @@ Start: 588 Length: 3 Facings: 8 - Tick: 120 + Tick: 120 # Shot die1: Start: 509 diff -Nru openra-20200503/mods/cnc/sequences/structures.yaml openra-20210321/mods/cnc/sequences/structures.yaml --- openra-20200503/mods/cnc/sequences/structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/sequences/structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -435,21 +435,22 @@ Length: 16 gun: - idle: + idle: gunmake # Empty first frame. We need WithSpriteBody for the make anim, and WSB needs at least a placeholder default sequence to work + turret: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True recoil: Start: 32 Facings: 32 - UseClassicFacingFudge: True - damaged-idle: + UseClassicFacings: True + damaged-turret: Start: 64 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True damaged-recoil: Start: 96 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True make: gunmake Length: * Tick: 80 @@ -476,7 +477,7 @@ idle: Start: 17 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True closing: Start: 50 Length: 14 @@ -490,7 +491,7 @@ damaged-idle: Start: 81 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True damaged-closing: Start: 114 Length: 14 @@ -502,7 +503,7 @@ Start: 0 make: sammake Length: 20 - Tick: 30 + Tick: 50 muzzle: samfire Length: 18 Facings: 8 diff -Nru openra-20200503/mods/cnc/sequences/vehicles.yaml openra-20210321/mods/cnc/sequences/vehicles.yaml --- openra-20200503/mods/cnc/sequences/vehicles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/sequences/vehicles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,20 +1,20 @@ mcv: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: mcvicnh.tem AddExtension: False mcv.destroyed: idle: mcv Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 harv: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True harvest: Start: 32 Length: 4 @@ -30,17 +30,17 @@ harv.destroyed: idle: harv Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 bggy: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: minigun Length: 6 Facings: 8 @@ -50,22 +50,22 @@ bggy.destroyed: idle: bggy Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: bggy Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 mtnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: * icon: mtnkicnh.tem @@ -74,22 +74,22 @@ mtnk.destroyed: idle: mtnk Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: mtnk Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 ltnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: * icon: ltnkicnh.tem @@ -98,22 +98,22 @@ ltnk.destroyed: idle: ltnk Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: ltnk Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 htnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: * icon: htnkicnh.tem @@ -122,22 +122,22 @@ htnk.destroyed: idle: htnk Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: htnk Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 jeep: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: minigun Length: 6 Facings: 8 @@ -147,31 +147,31 @@ jeep.destroyed: idle: jeep Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: jeep Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 bike: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: bikeicnh.tem AddExtension: False bike.destroyed: idle: bike Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 ftnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: Combine: flame-n: @@ -206,13 +206,13 @@ ftnk.destroyed: idle: ftnk Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 mhq: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True spinner: Start: 32 Length: 32 @@ -221,80 +221,80 @@ msam: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True empty-aim: Start: 64 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True aim: Start: 64 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: msamicnh.tem AddExtension: False msam.destroyed: idle: msam Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: msam Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 mlrs: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret1: Start: 64 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret0: Start: 96 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: mlrsicnh.tem AddExtension: False mlrs.destroyed: idle: mlrs Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: mlrs Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 stnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: stnkicnh.tem AddExtension: False stnk.destroyed: idle: stnk Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 arty: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: * icon: artyicnh.tem @@ -303,16 +303,22 @@ arty.destroyed: idle: arty Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 apc: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: apctur Facings: 32 - muzzle: apcmuz + turret-air: apctur + Start: 32 + Facings: 32 + muzzle: minigun + Length: 6 + Facings: 8 + muzzle-air: apcmuz Length: 3 Stride: 6 Facings: 8 @@ -327,7 +333,7 @@ apc.destroyed: idle: apc Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: apctur Facings: 32 @@ -336,11 +342,11 @@ truck: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: truckicon truck.destroyed: idle: truck Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/uibits/chrome-2x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/uibits/chrome-2x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/uibits/chrome-3x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/uibits/chrome-3x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/cnc/uibits/chrome.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/cnc/uibits/chrome.png differ diff -Nru openra-20200503/mods/cnc/weapons/ballistics.yaml openra-20210321/mods/cnc/weapons/ballistics.yaml --- openra-20200503/mods/cnc/weapons/ballistics.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/weapons/ballistics.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -34,12 +34,13 @@ Damage: 2500 Versus: None: 24 - Wood: 72 + Wood: 88 Light: 100 Heavy: 88 120mm: Inherits: ^BallisticWeapon + Report: tnkfire4.aud 120mmDual: Inherits: ^BallisticWeapon diff -Nru openra-20200503/mods/cnc/weapons/explosions.yaml openra-20210321/mods/cnc/weapons/explosions.yaml --- openra-20200503/mods/cnc/weapons/explosions.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/weapons/explosions.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -33,7 +33,7 @@ DamageTypes: Prone50Percent, TriggerProne, FireDeath Warhead@2Eff: CreateEffect Explosions: big_napalm - ImpactSounds: xplobig6.aud + ImpactSounds: flamer2.aud Warhead@3Smu: LeaveSmudge SmudgeType: Scorch @@ -74,6 +74,29 @@ Explosions: big_frag ImpactSounds: xplobig4.aud +UnitExplodeBig: + Inherits: ^DamagingExplosionHE + Warhead@2Eff: CreateEffect + Explosions: big_frag + ImpactSounds: xplobig6.aud + +UnitExplodeMech: + Inherits: ^DamagingExplosionHE + Warhead@2Eff: CreateEffect + Explosions: poof + ImpactSounds: xplosml2.aud + +UnitExplodeHarvEmpty: + Inherits: ^DamagingExplosionHE + Warhead@2Eff: CreateEffect + Explosions: building + ImpactSounds: xplos.aud + +UnitExplodeStealthTank: + Inherits: UnitExplodeBig + Warhead@1Dam: SpreadDamage + InvalidTargets: StealthTank + GrenadierExplode: Inherits: ^DamagingExplosionHE Warhead@1Dam: SpreadDamage diff -Nru openra-20200503/mods/cnc/weapons/missiles.yaml openra-20210321/mods/cnc/weapons/missiles.yaml --- openra-20200503/mods/cnc/weapons/missiles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/weapons/missiles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -3,14 +3,14 @@ Range: 6c0 MinRange: 0c512 Report: bazook1.aud - ValidTargets: Ground, Air + ValidTargets: Ground, Water, Air Projectile: Missile Arm: 0 Blockable: false Inaccuracy: 128 Image: DRAGON Shadow: true - HorizontalRateOfTurn: 15 + HorizontalRateOfTurn: 60 TrailImage: smokey ContrailLength: 8 Speed: 298 @@ -49,7 +49,7 @@ BurstDelays: 5 Projectile: Missile Speed: 426 - HorizontalRateOfTurn: 20 + HorizontalRateOfTurn: 80 RangeLimit: 12c0 Warhead@1Dam: SpreadDamage ValidTargets: Air @@ -65,10 +65,11 @@ BikeRockets: Inherits: ^MissileWeapon + ReloadDelay: 60 Burst: 2 BurstDelays: 10 Projectile: Missile - HorizontalRateOfTurn: 10 + HorizontalRateOfTurn: 40 Speed: 213 Warhead@1Dam: SpreadDamage Versus: @@ -80,12 +81,12 @@ OrcaAGMissiles: Inherits: ^MissileWeapon ReloadDelay: 12 - Range: 5c0 + Range: 4c768 MinRange: 1c256 - ValidTargets: Ground + ValidTargets: Ground, Water Projectile: Missile Arm: 1 - HorizontalRateOfTurn: 20 + HorizontalRateOfTurn: 80 Speed: 256 RangeLimit: 6c0 Warhead@1Dam: SpreadDamage @@ -106,18 +107,17 @@ ValidTargets: Air Versus: Light: 84 - Heavy: 56 -Warhead@2Smu: MammothMissiles: Inherits: ^MissileWeapon ReloadDelay: 45 - Range: 5c0 + Range: 4c768 Report: rocket1.aud Burst: 2 BurstDelays: 15 Projectile: Missile - HorizontalRateOfTurn: 20 + HorizontalRateOfTurn: 80 Speed: 341 RangeLimit: 6c0 Warhead@1Dam: SpreadDamage @@ -130,6 +130,7 @@ Heavy: 44 Warhead@3Eff: CreateEffect Explosions: small_poof + ImpactSounds: xplobig4.aud Warhead@4EffAir: CreateEffect Explosions: small_building @@ -141,7 +142,7 @@ Burst: 4 BurstDelays: 4 Report: rocket1.aud - ValidTargets: Ground + ValidTargets: Ground, Water TargetActorCenter: true # Remove default Missile properties -Projectile: @@ -164,17 +165,19 @@ Heavy: 48 Warhead@3Eff: CreateEffect Explosions: med_frag + ImpactSounds: xplobig4.aud 227mm.stnk: Inherits: ^MissileWeapon ReloadDelay: 70 Range: 7c0 Report: rocket1.aud + ValidTargets: Ground, Water Burst: 2 BurstDelays: 10 Projectile: Missile Inaccuracy: 213 - HorizontalRateOfTurn: 10 + HorizontalRateOfTurn: 40 Speed: 213 RangeLimit: 8c409 Warhead@1Dam: SpreadDamage @@ -185,6 +188,11 @@ Light: 100 Heavy: 90 +227mm.stnkAA: + Inherits: 227mm.stnk + MinRange: 2c512 + ValidTargets: Air + BoatMissile: Inherits: ^MissileWeapon ReloadDelay: 35 @@ -194,7 +202,7 @@ Report: rocket2.aud Projectile: Missile Inaccuracy: 426 - HorizontalRateOfTurn: 5 + HorizontalRateOfTurn: 20 Speed: 170 RangeLimit: 9c614 Warhead@1Dam: SpreadDamage @@ -208,6 +216,7 @@ DamageTypes: Prone50Percent, TriggerProne, SmallExplosionDeath Warhead@3Eff: CreateEffect Explosions: small_poof + ImpactSounds: xplobig4.aud Warhead@4EffAir: CreateEffect Explosions: small_building @@ -216,9 +225,9 @@ ReloadDelay: 15 Range: 7c0 Report: rocket2.aud - ValidTargets: Ground + ValidTargets: Ground, Water Projectile: Missile - HorizontalRateOfTurn: 20 + HorizontalRateOfTurn: 80 Speed: 298 RangeLimit: 8c409 Warhead@1Dam: SpreadDamage @@ -241,7 +250,7 @@ ValidTargets: Air Projectile: Missile Image: MISSILE - HorizontalRateOfTurn: 20 + HorizontalRateOfTurn: 80 Speed: 426 RangeLimit: 9c614 Inaccuracy: 0 @@ -249,10 +258,7 @@ Spread: 682 ValidTargets: Air Versus: - None: 140 - Wood: 140 Light: 140 - Heavy: 104 -Warhead@2Smu: Warhead@4EffAir: CreateEffect Explosions: small_building @@ -266,7 +272,7 @@ ValidTargets: Air Projectile: Missile Image: MISSILE - HorizontalRateOfTurn: 20 + HorizontalRateOfTurn: 80 Speed: 300 RangeLimit: 10c819 Inaccuracy: 0 diff -Nru openra-20200503/mods/cnc/weapons/other.yaml openra-20210321/mods/cnc/weapons/other.yaml --- openra-20200503/mods/cnc/weapons/other.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/weapons/other.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,13 +1,13 @@ ^FlameWeapon: ValidTargets: Ground, Water, Trees ReloadDelay: 55 - Range: 2c512 + Range: 3c0 InvalidTargets: Wall Report: flamer2.aud Projectile: Bullet Speed: 1c682 Warhead@1Dam: SpreadDamage - Spread: 468 + Spread: 256 Damage: 4000 ValidTargets: Ground, Water, Trees InvalidTargets: Wall @@ -22,7 +22,6 @@ InvalidTargets: Vehicle, Structure, Wall Warhead@3Eff: CreateEffect Explosions: small_napalm - ImpactSounds: flamer2.aud ImpactActors: false Flamethrower: @@ -30,12 +29,12 @@ BigFlamer: Inherits: ^FlameWeapon - ReloadDelay: 50 + ReloadDelay: 65 Range: 3c512 Projectile: Bullet Speed: 341 Burst: 2 - BurstDelays: 25 + BurstDelays: 10 Warhead@1Dam: SpreadDamage Spread: 400 Damage: 10000 @@ -50,12 +49,10 @@ Chemspray: Inherits: ^FlameWeapon ReloadDelay: 65 - Range: 3c0 - InvalidTargets: + -InvalidTargets: Warhead@1Dam: SpreadDamage - Spread: 256 Damage: 8000 - InvalidTargets: + -InvalidTargets: Versus: None: 70 Wood: 35 diff -Nru openra-20200503/mods/cnc/weapons/smallcaliber.yaml openra-20210321/mods/cnc/weapons/smallcaliber.yaml --- openra-20200503/mods/cnc/weapons/smallcaliber.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/weapons/smallcaliber.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,7 +1,7 @@ Sniper: Report: ramgun2.aud ValidTargets: Ground, Infantry - InvalidTargets: Vehicle, Water, Structure, Wall, Husk + InvalidTargets: Vehicle, Water, Structure, Wall, Husk, Creep ReloadDelay: 40 Range: 8c0 Projectile: Bullet @@ -11,6 +11,10 @@ Damage: 10000 ValidTargets: Infantry DamageTypes: Prone50Percent, TriggerProne, BulletDeath + Warhead@2Eff: CreateEffect + Explosions: piff + ImpactActors: false + ValidTargets: Ground, Water, Air ^HeavyMG: ReloadDelay: 25 @@ -48,8 +52,9 @@ Spread: 426 Damage: 10000 Versus: + None: 90 Wood: 15 - Light: 100 + Light: 35 Heavy: 35 HeliAGGun: @@ -63,11 +68,11 @@ Projectile: Bullet Blockable: false Warhead@1Dam: SpreadDamage - Spread: 256 + Spread: 128 Damage: 2000 Versus: None: 100 - Wood: 50 + Wood: 75 Light: 75 Heavy: 25 DamageTypes: Prone80Percent, TriggerProne, RippedApartDeath @@ -76,21 +81,10 @@ Inherits: HeliAGGun ValidTargets: Air Warhead@1Dam: SpreadDamage - Spread: 128 ValidTargets: Air Versus: Light: 50 -Pistol: - Inherits: ^LightMG - ReloadDelay: 7 - Range: 3c0 - Report: gun18.aud - Warhead@1Dam: SpreadDamage - Damage: 100 - Versus: - None: 100 - ^LightMG: Inherits: ^HeavyMG ReloadDelay: 20 @@ -109,9 +103,30 @@ DamageTypes: Prone50Percent, TriggerProne, BulletDeath Warhead@2Eff: CreateEffect Explosions: piff + Inaccuracy: 171 + +Pistol: + Inherits: ^LightMG + ReloadDelay: 7 + Range: 3c0 + Report: gun18.aud + Warhead@1Dam: SpreadDamage + Damage: 100 + Versus: + None: 100 + Warhead@2Eff: CreateEffect + Inaccuracy: 128 M16: Inherits: ^LightMG + Warhead@2Eff2: CreateEffect + Delay: 2 + Explosions: piff + Inaccuracy: 171 + Warhead@2Eff3: CreateEffect + Delay: 4 + Explosions: piff + Inaccuracy: 171 MachineGun: Inherits: ^LightMG @@ -122,7 +137,7 @@ Wood: 10 Light: 70 Warhead@2Eff: CreateEffect - Explosions: piffs + Inaccuracy: 213 MachineGunH: Inherits: MachineGun @@ -131,14 +146,14 @@ Light: 80 APCGun: - ReloadDelay: 18 + ReloadDelay: 9 Range: 5c0 Report: gun20.aud Projectile: Bullet Speed: 900 Warhead@1Dam: SpreadDamage Spread: 128 - Damage: 2000 + Damage: 1000 Versus: None: 30 Wood: 25 @@ -148,10 +163,11 @@ Warhead@2Eff: CreateEffect Explosions: small_frag ValidTargets: Ground, Water, Air + ImpactActors: false APCGun.AA: Inherits: APCGun - Range: 6c0 + Range: 7c0 ValidTargets: Air Projectile: Bullet Speed: 2c0 @@ -159,9 +175,6 @@ Warhead@1Dam: SpreadDamage ValidTargets: Air Versus: - None: 60 - Wood: 60 Light: 125 - Heavy: 60 Warhead@2Eff: CreateEffect Explosions: small_poof diff -Nru openra-20200503/mods/cnc/weapons/superweapons.yaml openra-20210321/mods/cnc/weapons/superweapons.yaml --- openra-20200503/mods/cnc/weapons/superweapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/cnc/weapons/superweapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,5 +1,5 @@ Atomic: - ValidTargets: Ground, Air, Trees + ValidTargets: Ground, Water, Air, Trees Report: nukemisl.aud Warhead@1Dam_impact: SpreadDamage Spread: 1c0 @@ -88,9 +88,11 @@ Duration: 20 Intensity: 5 Multiplier: 1,1 + Warhead@14FlashEffect: FlashPaletteEffect + Duration: 20 IonCannon: - ValidTargets: Ground, Air, Trees + ValidTargets: Ground, Water, Air, Trees Warhead@1Dam_impact: SpreadDamage Range: 0, 1c1, 2c1, 2c512 Damage: 10000 diff -Nru openra-20200503/mods/common/chrome/dropdowns.yaml openra-20210321/mods/common/chrome/dropdowns.yaml --- openra-20200503/mods/common/chrome/dropdowns.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/dropdowns.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -108,7 +108,7 @@ Height: 16 Label@LABEL: X: 40 - Width: 60 + Width: PARENT_RIGHT Height: 25 Shadow: True Label@NOFLAG_LABEL: diff -Nru openra-20200503/mods/common/chrome/editor.yaml openra-20210321/mods/common/chrome/editor.yaml --- openra-20200503/mods/common/chrome/editor.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/editor.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -271,8 +271,14 @@ Slider@OPTION: X: 75 Y: 1 - Width: 210 + Width: 149 Height: 20 + TextField@VALUE: + X: 226 + Y: 1 + Width: 50 + Height: 20 + Type: Integer Container@DROPDOWN_OPTION_TEMPLATE: Width: PARENT_RIGHT Height: 27 diff -Nru openra-20200503/mods/common/chrome/ingame-observer.yaml openra-20210321/mods/common/chrome/ingame-observer.yaml --- openra-20200503/mods/common/chrome/ingame-observer.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/ingame-observer.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -74,7 +74,7 @@ Y: 2 Label@LABEL: X: 34 - Width: 60 + Width: PARENT_RIGHT Height: 25 Shadow: True Label@NOFLAG_LABEL: @@ -841,7 +841,7 @@ X: PARENT_RIGHT - 200 Y: 0 Width: 200 - Height: PARENT_BOTTOM + Height: PARENT_BOTTOM Image@FLAG: X: 5 Y: 4 diff -Nru openra-20200503/mods/common/chrome/lobby-music.yaml openra-20210321/mods/common/chrome/lobby-music.yaml --- openra-20200503/mods/common/chrome/lobby-music.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/lobby-music.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -20,12 +20,13 @@ Height: 25 Text: Track Font: Bold - Label@TYPE: - X: PARENT_RIGHT - 63 + Label@LENGTH: + X: PARENT_RIGHT - 80 Height: 25 Width: 50 Text: Length Font: Bold + Align: Right Background@CONTROLS: Background: dialog3 Width: 268 diff -Nru openra-20200503/mods/common/chrome/lobby-options.yaml openra-20210321/mods/common/chrome/lobby-options.yaml --- openra-20200503/mods/common/chrome/lobby-options.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/lobby-options.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -23,19 +23,19 @@ Height: 30 Children: Checkbox@A: - Width: 175 + Width: 220 Height: 20 Visible: False TooltipContainer: TOOLTIP_CONTAINER Checkbox@B: - X: 190 - Width: 175 + X: 225 + Width: 220 Height: 20 Visible: False TooltipContainer: TOOLTIP_CONTAINER Checkbox@C: - X: 375 - Width: 175 + X: 450 + Width: 190 Height: 20 Visible: False TooltipContainer: TOOLTIP_CONTAINER @@ -44,25 +44,25 @@ Width: PARENT_RIGHT Children: Label@A_DESC: - Width: 90 + Width: 140 Height: 25 Align: Right Visible: False DropDownButton@A: - X: 95 - Width: 160 + X: 145 + Width: 180 Height: 25 Visible: False TooltipContainer: TOOLTIP_CONTAINER Label@B_DESC: - X: PARENT_RIGHT - WIDTH - 183 - Width: 160 + X: PARENT_RIGHT - WIDTH - 203 + Width: 140 Height: 25 Align: Right Visible: False DropDownButton@B: X: PARENT_RIGHT - WIDTH - 18 - Width: 160 + Width: 180 Height: 25 Font: Regular Visible: False diff -Nru openra-20200503/mods/common/chrome/lobby-players.yaml openra-20210321/mods/common/chrome/lobby-players.yaml --- openra-20200503/mods/common/chrome/lobby-players.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/lobby-players.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -23,27 +23,34 @@ Font: Bold Label@LABEL_LOBBY_FACTION: X: 270 - Width: 130 + Width: 140 Height: 25 Text: Faction Align: Center Font: Bold Label@LABEL_LOBBY_TEAM: - X: 410 + X: 420 Width: 48 Height: 25 Text: Team Align: Center Font: Bold + Label@LABEL_LOBBY_HANDICAP: + X: 478 + Width: 72 + Height: 25 + Text: Handicap + Align: Center + Font: Bold Label@LABEL_LOBBY_SPAWN: - X: 468 + X: 560 Width: 48 Height: 25 Text: Spawn Align: Center Font: Bold Label@LABEL_LOBBY_STATUS: - X: 525 + X: 617 Width: 20 Height: 25 Text: Ready @@ -118,7 +125,7 @@ Height: PARENT_BOTTOM - 12 DropDownButton@FACTION: X: 270 - Width: 130 + Width: 140 Height: 25 IgnoreChildMouseOver: true TooltipContainer: TOOLTIP_CONTAINER @@ -135,23 +142,29 @@ Height: 25 Text: Faction DropDownButton@TEAM_DROPDOWN: - X: 410 + X: 420 Width: 48 Height: 25 Text: Team + DropDownButton@HANDICAP_DROPDOWN: + X: 478 + Width: 72 + Height: 25 + TooltipContainer: TOOLTIP_CONTAINER + TooltipText: A handicap decreases the combat effectiveness of the player's forces DropDownButton@SPAWN_DROPDOWN: - X: 468 + X: 560 Width: 48 Height: 25 Text: Spawn Checkbox@STATUS_CHECKBOX: - X: 525 + X: 617 Y: 2 Width: 20 Height: 20 Visible: false Image@STATUS_IMAGE: - X: 527 + X: 619 Y: 4 Width: 20 Height: 20 @@ -225,7 +238,7 @@ Height: 13 Container@FACTION: X: 270 - Width: 150 + Width: 160 Height: 25 Children: Image@FACTIONFLAG: @@ -239,28 +252,39 @@ Height: 25 Text: Faction Label@TEAM: - X: 410 + X: 420 Width: 23 Height: 25 Text: Team Align: Center - Label@SPAWN: - X: 468 - Width: 23 - Height: 25 - Align: Center DropDownButton@TEAM_DROPDOWN: - X: 410 + X: 420 Width: 48 Height: 25 Visible: false + Label@HANDICAP: + X: 478 + Width: 47 + Height: 25 + Align: Center + DropDownButton@HANDICAP_DROPDOWN: + X: 478 + Width: 72 + Height: 25 + TooltipContainer: TOOLTIP_CONTAINER + TooltipText: A handicap decreases the combat effectiveness of the player's forces + Label@SPAWN: + X: 560 + Width: 23 + Height: 25 + Align: Center DropDownButton@SPAWN_DROPDOWN: - X: 468 + X: 560 Width: 48 Height: 25 Visible: false Image@STATUS_IMAGE: - X: 527 + X: 619 Y: 4 Width: 20 Height: 20 @@ -287,7 +311,7 @@ Button@JOIN: X: 190 Text: Play in this slot - Width: 326 + Width: 418 Height: 25 Container@TEMPLATE_EDITABLE_SPECTATOR: X: 5 @@ -333,19 +357,19 @@ Template: ANONYMOUS_PLAYER_TOOLTIP Label@SPECTATOR: X: 190 - Width: 326 + Width: 418 Height: 25 Text: Spectator Align: Center Font: Bold Checkbox@STATUS_CHECKBOX: - X: 525 + X: 617 Y: 2 Width: 20 Height: 20 Visible: false Image@STATUS_IMAGE: - X: 527 + X: 619 Y: 4 Width: 20 Height: 20 @@ -414,13 +438,13 @@ Template: ANONYMOUS_PLAYER_TOOLTIP Label@SPECTATOR: X: 190 - Width: 326 + Width: 418 Height: 25 Text: Spectator Align: Center Font: Bold Image@STATUS_IMAGE: - X: 527 + X: 619 Y: 4 Width: 20 Height: 20 @@ -441,7 +465,7 @@ Text: Allow Spectators? Button@SPECTATE: X: 190 - Width: 326 + Width: 418 Height: 25 Text: Spectate Font: Regular diff -Nru openra-20200503/mods/common/chrome/lobby-servers.yaml openra-20210321/mods/common/chrome/lobby-servers.yaml --- openra-20200503/mods/common/chrome/lobby-servers.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/lobby-servers.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -9,32 +9,32 @@ Children: Label@NAME: X: 5 - Width: 255 + Width: 347 Height: 25 Text: Server Align: Center Font: Bold Label@PLAYERS: - X: 290 + X: 382 Width: 85 Height: 25 Text: Players Font: Bold Label@LOCATION: - X: 380 + X: 472 Width: 110 Height: 25 Text: Location Font: Bold Label@STATUS: - X: 495 + X: 587 Width: 50 Height: 25 Text: Status Font: Bold LogicTicker@NOTICE_WATCHER: Background@NOTICE_CONTAINER: - Width: 583 + Width: PARENT_RIGHT Height: 20 Background: dialog2 Children: @@ -83,12 +83,12 @@ Children: LabelWithTooltip@TITLE: X: 5 - Width: 245 + Width: 337 Height: 25 TooltipContainer: TOOLTIP_CONTAINER TooltipTemplate: SIMPLE_TOOLTIP Image@PASSWORD_PROTECTED: - X: 272 + X: 364 Y: 6 Width: 12 Height: 13 @@ -97,7 +97,7 @@ TooltipTemplate: SIMPLE_TOOLTIP TooltipText: Requires Password Image@REQUIRES_AUTHENTICATION: - X: 272 + X: 364 Y: 6 Width: 12 Height: 13 @@ -106,17 +106,17 @@ TooltipTemplate: SIMPLE_TOOLTIP TooltipText: Requires OpenRA forum account LabelWithTooltip@PLAYERS: - X: 290 + X: 382 Width: 85 Height: 25 TooltipContainer: TOOLTIP_CONTAINER TooltipTemplate: SIMPLE_TOOLTIP Label@LOCATION: - X: 380 + X: 472 Width: 110 Height: 25 Label@STATUS: - X: 495 + X: 587 Width: 50 Height: 25 Label@PROGRESS_LABEL: @@ -128,12 +128,12 @@ Visible: false DropDownButton@FILTERS_DROPDOWNBUTTON: Y: PARENT_BOTTOM + 5 - Width: 147 + Width: 154 Height: 25 Text: Filter Games Font: Bold Button@RELOAD_BUTTON: - X: 152 + X: 159 Y: PARENT_BOTTOM + 5 Width: 26 Height: 25 diff -Nru openra-20200503/mods/common/chrome/lobby.yaml openra-20210321/mods/common/chrome/lobby.yaml --- openra-20200503/mods/common/chrome/lobby.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/lobby.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,7 +2,7 @@ Logic: LobbyLogic X: (WINDOW_RIGHT - WIDTH) / 2 Y: (WINDOW_BOTTOM - HEIGHT) / 2 - Width: 808 + Width: 900 Height: 600 Children: ColorPreviewManager@COLOR_MANAGER: @@ -20,69 +20,71 @@ DropDownButton@SLOTS_DROPDOWNBUTTON: X: 20 Y: 291 - Width: 178 + Width: 185 Height: 25 Font: Bold Text: Slot Admin Container@SKIRMISH_TABS: + X: 695 - WIDTH + Width: 486 Visible: False Children: Button@PLAYERS_TAB: - X: 203 Y: 285 - Width: 134 + Width: 162 Height: 31 Font: Bold Text: Players Button@OPTIONS_TAB: - X: 337 + X: 162 Y: 285 - Width: 133 + Width: 162 Height: 31 Font: Bold Text: Options Button@MUSIC_TAB: - X: 470 + X: 2*162 Y: 285 - Width: 133 + Width: 162 Height: 31 Font: Bold Text: Music Container@MULTIPLAYER_TABS: + X: 695 - WIDTH + Width: 486 Visible: False Children: Button@PLAYERS_TAB: - X: 203 Y: 285 - Width: 100 + Width: 121 Height: 31 Font: Bold Text: Players Button@OPTIONS_TAB: - X: 303 + X: 121 Y: 285 - Width: 100 + Width: 122 Height: 31 Font: Bold Text: Options Button@MUSIC_TAB: - X: 403 + X: 243 Y: 285 - Width: 100 + Width: 121 Height: 31 Font: Bold Text: Music Button@SERVERS_TAB: - X: 503 + X: 364 Y: 285 - Width: 100 + Width: 122 Height: 31 Font: Bold Text: Servers Container@TOP_PANELS_ROOT: X: 20 Y: 67 - Width: 583 + Width: 675 Height: 219 Button@CHANGEMAP_BUTTON: X: PARENT_RIGHT - WIDTH - 20 diff -Nru openra-20200503/mods/common/chrome/mainmenu-prompts.yaml openra-20210321/mods/common/chrome/mainmenu-prompts.yaml --- openra-20200503/mods/common/chrome/mainmenu-prompts.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/mainmenu-prompts.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -245,7 +245,7 @@ Text: Increase Cursor Size Button@CONTINUE_BUTTON: X: PARENT_RIGHT - 180 - Y: PARENT_BOTTOM - 45 + Y: PARENT_BOTTOM - 45 Width: 160 Height: 25 Text: Continue diff -Nru openra-20200503/mods/common/chrome/map-chooser.yaml openra-20210321/mods/common/chrome/map-chooser.yaml --- openra-20200503/mods/common/chrome/map-chooser.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/map-chooser.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,7 +2,7 @@ X: (WINDOW_RIGHT - WIDTH) / 2 Y: (WINDOW_BOTTOM - HEIGHT) / 2 Logic: MapChooserLogic - Width: 808 + Width: 900 Height: 600 Children: Label@MAPCHOOSER_TITLE: @@ -47,16 +47,16 @@ Height: PARENT_BOTTOM Children: ScrollItem@MAP_TEMPLATE: - Width: 185 - Height: 243 + Width: 208 + Height: 266 X: 2 Visible: false Children: MapPreview@PREVIEW: X: (PARENT_RIGHT - WIDTH) / 2 Y: 3 - Width: 179 - Height: 179 + Width: 202 + Height: 202 IgnoreMouseOver: true IgnoreMouseInput: true Label@TITLE: diff -Nru openra-20200503/mods/common/chrome/multiplayer-browser.yaml openra-20210321/mods/common/chrome/multiplayer-browser.yaml --- openra-20200503/mods/common/chrome/multiplayer-browser.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/multiplayer-browser.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,7 +2,7 @@ Logic: MultiplayerLogic X: (WINDOW_RIGHT - WIDTH) / 2 Y: (WINDOW_BOTTOM - HEIGHT) / 2 - Width: 808 + Width: 900 Height: 600 Children: Label@TITLE: @@ -20,25 +20,25 @@ Children: Label@NAME: X: 5 - Width: 255 + Width: 347 Height: 25 Text: Server Align: Center Font: Bold Label@PLAYERS: - X: 290 + X: 382 Width: 85 Height: 25 Text: Players Font: Bold Label@LOCATION: - X: 380 + X: 472 Width: 110 Height: 25 Text: Location Font: Bold Label@STATUS: - X: 495 + X: 587 Width: 50 Height: 25 Text: Status @@ -47,7 +47,7 @@ Background@NOTICE_CONTAINER: X: 20 Y: 67 - Width: 583 + Width: 675 Height: 20 Background: dialog2 Children: @@ -75,7 +75,7 @@ ScrollPanel@SERVER_LIST: X: 20 Y: 67 - Width: 583 + Width: 675 Height: PARENT_BOTTOM - 119 TopBottomSpacing: 2 Children: @@ -99,12 +99,12 @@ Children: LabelWithTooltip@TITLE: X: 5 - Width: 245 + Width: 337 Height: 25 TooltipContainer: TOOLTIP_CONTAINER TooltipTemplate: SIMPLE_TOOLTIP Image@PASSWORD_PROTECTED: - X: 272 + X: 364 Y: 6 Width: 12 Height: 13 @@ -113,7 +113,7 @@ TooltipTemplate: SIMPLE_TOOLTIP TooltipText: Requires Password Image@REQUIRES_AUTHENTICATION: - X: 272 + X: 364 Y: 6 Width: 12 Height: 13 @@ -122,23 +122,23 @@ TooltipTemplate: SIMPLE_TOOLTIP TooltipText: Requires OpenRA forum account LabelWithTooltip@PLAYERS: - X: 290 + X: 382 Width: 85 Height: 25 TooltipContainer: TOOLTIP_CONTAINER TooltipTemplate: SIMPLE_TOOLTIP Label@LOCATION: - X: 380 + X: 472 Width: 110 Height: 25 Label@STATUS: - X: 495 + X: 587 Width: 50 Height: 25 Label@PROGRESS_LABEL: X: 20 Y: 67 + (PARENT_BOTTOM - 119 - HEIGHT) / 2 - Width: 582 + Width: 675 Height: 25 Font: Bold Align: Center @@ -225,21 +225,21 @@ Children: LogicTicker@ANIMATION: Label@PLAYER_COUNT: - X: 208 + X: 254 Y: PARENT_BOTTOM - HEIGHT - 20 Width: 190 Height: 25 Align: Center Font: Bold Button@DIRECTCONNECT_BUTTON: - X: 398 + X: 490 Y: PARENT_BOTTOM - HEIGHT - 20 Width: 100 Height: 25 Text: Direct IP Font: Bold Button@CREATE_BUTTON: - X: 503 + X: 595 Y: PARENT_BOTTOM - HEIGHT - 20 Width: 100 Height: 25 diff -Nru openra-20200503/mods/common/chrome/settings.yaml openra-20210321/mods/common/chrome/settings.yaml --- openra-20200503/mods/common/chrome/settings.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/chrome/settings.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -47,7 +47,7 @@ Button@BACK_BUTTON: Key: escape X: PARENT_RIGHT - 180 - Y: PARENT_BOTTOM - 45 + Y: PARENT_BOTTOM - 45 Width: 160 Height: 25 Text: Back @@ -188,12 +188,19 @@ Font: Regular Text: Increase Cursor Size Checkbox@PLAYER_STANCE_COLORS_CHECKBOX: - X: 310 + X: 195 Y: 133 Width: 200 Height: 20 Font: Regular Text: Player Stance Colors + Checkbox@PAUSE_SHELLMAP_CHECKBOX: + X: 375 + Y: 133 + Width: 200 + Height: 20 + Font: Regular + Text: Pause Menu Background Label@VIDEO_TITLE: Y: 190 Width: PARENT_RIGHT @@ -719,6 +726,13 @@ Font: Tiny Align: Left Text: This is already used for "{0}" + Button@OVERRIDE_HOTKEY_BUTTON: + X: PARENT_RIGHT - 3 * WIDTH - 30 + Y: 20 + Width: 70 + Height: 25 + Text: Override + Font: Bold Button@CLEAR_HOTKEY_BUTTON: X: PARENT_RIGHT - 2 * WIDTH - 30 Y: 20 diff -Nru openra-20200503/mods/common/metrics.yaml openra-20210321/mods/common/metrics.yaml --- openra-20200503/mods/common/metrics.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/common/metrics.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -46,3 +46,11 @@ NoticeWarningColor: FFA500 NoticeSuccessColor: 00FF00 NoticeErrorColor: FF0000 + ChatLineSound: ChatLine + ClickDisabledSound: ClickDisabledSound + ClickSound: ClickSound + ChatMessageColor: FFFFFF + SystemMessageColor: FFFF00 + NormalSelectionColor: FFFFFF + AltSelectionColor: 00FFFF + CtrlSelectionColor: FFFF00 diff -Nru openra-20200503/mods/d2k/audio/notifications.yaml openra-20210321/mods/d2k/audio/notifications.yaml --- openra-20200503/mods/d2k/audio/notifications.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/audio/notifications.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -62,10 +62,10 @@ Sounds: DefaultVariant: .WAV Notifications: - RadarUp: MULTI1 + RadarUp: RADRON1 RadarDown: - DisablePower: POWRUP1 - EnablePower: POWRDN1 + DisablePower: POWRDN1 + EnablePower: POWRUP1 CashTickUp: CASHTIK1 CashTickDown: CASHTIK1 LevelUp: SCORTIK1 diff -Nru openra-20200503/mods/d2k/chrome/dropdowns.yaml openra-20210321/mods/d2k/chrome/dropdowns.yaml --- openra-20200503/mods/d2k/chrome/dropdowns.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/chrome/dropdowns.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -104,7 +104,7 @@ Y: 2 Label@LABEL: X: 34 - Width: 60 + Width: PARENT_RIGHT Height: 25 Shadow: True Label@NOFLAG_LABEL: diff -Nru openra-20200503/mods/d2k/chrome/ingame-observer.yaml openra-20210321/mods/d2k/chrome/ingame-observer.yaml --- openra-20200503/mods/d2k/chrome/ingame-observer.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/chrome/ingame-observer.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -94,7 +94,7 @@ Y: 2 Label@LABEL: X: 34 - Width: 60 + Width: PARENT_RIGHT Height: 25 Shadow: True Label@NOFLAG_LABEL: @@ -863,7 +863,7 @@ X: PARENT_RIGHT - 200 Y: 0 Width: 200 - Height: PARENT_BOTTOM + Height: PARENT_BOTTOM Image@FLAG: X: 2 Y: 2 diff -Nru openra-20200503/mods/d2k/chrome/ingame-player.yaml openra-20210321/mods/d2k/chrome/ingame-player.yaml --- openra-20200503/mods/d2k/chrome/ingame-player.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/chrome/ingame-player.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -616,8 +616,8 @@ Image@ICON: X: 5 Y: 5 - ImageCollection: scrollbar - ImageName: up_arrow + ImageCollection: scrollpanel-decorations + ImageName: up Button@SCROLL_DOWN_BUTTON: Y: 248 Width: 25 @@ -630,5 +630,5 @@ Image@ICON: X: 5 Y: 5 - ImageCollection: scrollbar - ImageName: down_arrow + ImageCollection: scrollpanel-decorations + ImageName: down diff -Nru openra-20200503/mods/d2k/chrome/lobby-players.yaml openra-20210321/mods/d2k/chrome/lobby-players.yaml --- openra-20200503/mods/d2k/chrome/lobby-players.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/chrome/lobby-players.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -23,27 +23,34 @@ Font: Bold Label@LABEL_LOBBY_FACTION: X: 270 - Width: 130 + Width: 140 Height: 25 Text: Faction Align: Center Font: Bold Label@LABEL_LOBBY_TEAM: - X: 410 + X: 420 Width: 48 Height: 25 Text: Team Align: Center Font: Bold + Label@LABEL_LOBBY_HANDICAP: + X: 478 + Width: 72 + Height: 25 + Text: Handicap + Align: Center + Font: Bold Label@LABEL_LOBBY_SPAWN: - X: 468 + X: 560 Width: 48 Height: 25 Text: Spawn Align: Center Font: Bold Label@LABEL_LOBBY_STATUS: - X: 525 + X: 617 Width: 20 Height: 25 Text: Ready @@ -118,7 +125,7 @@ Height: PARENT_BOTTOM - 12 DropDownButton@FACTION: X: 270 - Width: 130 + Width: 140 Height: 25 IgnoreChildMouseOver: true TooltipContainer: TOOLTIP_CONTAINER @@ -135,23 +142,29 @@ Height: 25 Text: Faction DropDownButton@TEAM_DROPDOWN: - X: 410 + X: 420 Width: 48 Height: 25 Text: Team + DropDownButton@HANDICAP_DROPDOWN: + X: 478 + Width: 72 + Height: 25 + TooltipContainer: TOOLTIP_CONTAINER + TooltipText: A handicap decreases the combat effectiveness of the player's forces DropDownButton@SPAWN_DROPDOWN: - X: 468 + X: 560 Width: 48 Height: 25 Text: Spawn Checkbox@STATUS_CHECKBOX: - X: 525 + X: 617 Y: 2 Width: 20 Height: 20 Visible: false Image@STATUS_IMAGE: - X: 527 + X: 619 Y: 4 Width: 20 Height: 20 @@ -225,7 +238,7 @@ Height: 13 Container@FACTION: X: 270 - Width: 160 + Width: 170 Height: 25 Children: Image@FACTIONFLAG: @@ -235,32 +248,43 @@ Height: 23 Label@FACTIONNAME: X: 34 - Width: 60 + Width: 70 Height: 25 Text: Faction Label@TEAM: - X: 410 + X: 420 Width: 23 Height: 25 Align: Center Text: Team - Label@SPAWN: - X: 468 - Width: 23 - Height: 25 - Align: Center DropDownButton@TEAM_DROPDOWN: - X: 410 + X: 420 Width: 48 Height: 25 Visible: false + Label@HANDICAP: + X: 478 + Width: 47 + Height: 25 + Align: Center + DropDownButton@HANDICAP_DROPDOWN: + X: 478 + Width: 72 + Height: 25 + TooltipContainer: TOOLTIP_CONTAINER + TooltipText: A handicap decreases the combat effectiveness of the player's forces + Label@SPAWN: + X: 560 + Width: 23 + Height: 25 + Align: Center DropDownButton@SPAWN_DROPDOWN: - X: 468 + X: 560 Width: 48 Height: 25 Visible: false Image@STATUS_IMAGE: - X: 527 + X: 619 Y: 4 Width: 20 Height: 20 @@ -286,7 +310,7 @@ Visible: false Button@JOIN: X: 190 - Width: 326 + Width: 418 Height: 25 Text: Play in this slot Container@TEMPLATE_EDITABLE_SPECTATOR: @@ -333,19 +357,19 @@ Template: ANONYMOUS_PLAYER_TOOLTIP Label@SPECTATOR: X: 190 - Width: 326 + Width: 418 Height: 25 Text: Spectator Align: Center Font: Bold Checkbox@STATUS_CHECKBOX: - X: 525 + X: 617 Y: 2 Width: 20 Height: 20 Visible: false Image@STATUS_IMAGE: - X: 527 + X: 619 Y: 4 Width: 20 Height: 20 @@ -414,13 +438,13 @@ Template: ANONYMOUS_PLAYER_TOOLTIP Label@SPECTATOR: X: 190 - Width: 326 + Width: 418 Height: 25 Text: Spectator Align: Center Font: Bold Image@STATUS_IMAGE: - X: 527 + X: 619 Y: 4 Width: 20 Height: 20 @@ -441,7 +465,7 @@ Font: Regular Button@SPECTATE: X: 190 - Width: 326 + Width: 418 Height: 25 Text: Spectate Font: Regular diff -Nru openra-20200503/mods/d2k/chrome.yaml openra-20210321/mods/d2k/chrome.yaml --- openra-20200503/mods/d2k/chrome.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/chrome.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -241,10 +241,11 @@ lobby-bits: Inherits: ^Glyphs Regions: - spawn-unclaimed: 91, 119, 22, 22 - spawn-claimed: 68, 119, 22, 22 + spawn-claimed: 27, 119, 22, 22 + spawn-unclaimed: 50, 119, 22, 22 + spawn-disabled: 73, 119, 22, 22 admin: 170, 0, 6, 5 - colorpicker: 68, 119, 22, 22 + colorpicker: 27, 119, 22, 22 huepicker: 136, 0, 7, 15 kick: 153, 0, 11, 11 protected: 0, 17, 12, 13 @@ -283,14 +284,6 @@ prev: 68, 0, 16, 16 fastforward: 85, 0, 16, 16 -scrollbar: - Inherits: ^Glyphs - Regions: - down_arrow: 119, 0, 16, 16 - down_pressed: 119, 0, 16, 16 - up_arrow: 102, 0, 16, 16 - up_pressed: 102, 0, 16, 16 - progressbar-bg: Inherits: button-pressed @@ -400,6 +393,12 @@ checkbox-highlighted: Inherits: button-highlighted-pressed +checkbox-highlighted-hover: + Inherits: checkbox-highlighted + +checkbox-highlighted-disabled: + Inherits: checkbox-disabled + scrollitem-selected: Inherits: button-pressed @@ -412,10 +411,24 @@ scrollitem-nohover: Inherits: ^Dialog -dropdown: +scrollpanel-decorations: + Inherits: ^Glyphs + Regions: + down: 119, 0, 16, 16 + up: 102, 0, 16, 16 + +dropdown-decorations: + Inherits: ^Glyphs + Regions: + marker: 119, 0, 16, 16 + +dropdown-separators: Inherits: ^Dialog Regions: - separator: 513, 1, 1, 19 + separator: 513, 2, 1, 19 + separator-hover: 513, 130, 1, 19 + separator-pressed: 641, 2, 1, 19 + separator-disabled: 513, 258, 1, 19 logos: Inherits: ^LoadScreen diff -Nru openra-20200503/mods/d2k/installer/d2k-a.yaml openra-20210321/mods/d2k/installer/d2k-a.yaml --- openra-20200503/mods/d2k/installer/d2k-a.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/installer/d2k-a.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,854 +4,854 @@ SETUP/SETUP.Z: 937f5ceb1236bf3f3d4e43929305ffe5004078e7 Install: copy: MOVIES - ^Content/d2k/v2/Movies/A_BR01_E.VQA: A_BR01_E.VQA - ^Content/d2k/v2/Movies/A_BR02_E.VQA: A_BR02_E.VQA - ^Content/d2k/v2/Movies/A_BR03_E.VQA: A_BR03_E.VQA - ^Content/d2k/v2/Movies/A_BR04_E.VQA: A_BR04_E.VQA - ^Content/d2k/v2/Movies/A_BR05_E.VQA: A_BR05_E.VQA - ^Content/d2k/v2/Movies/A_BR06_E.VQA: A_BR06_E.VQA - ^Content/d2k/v2/Movies/A_BR07_E.VQA: A_BR07_E.VQA - ^Content/d2k/v2/Movies/A_BR08_E.VQA: A_BR08_E.VQA - ^Content/d2k/v2/Movies/A_BR09_E.VQA: A_BR09_E.VQA - ^Content/d2k/v2/Movies/A_FINL_E.VQA: A_FINL_E.VQA - ^Content/d2k/v2/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA - ^Content/d2k/v2/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA - ^Content/d2k/v2/Movies/H_BR01_E.VQA: H_BR01_E.VQA - ^Content/d2k/v2/Movies/H_BR02_E.VQA: H_BR02_E.VQA - ^Content/d2k/v2/Movies/H_BR03_E.VQA: H_BR03_E.VQA - ^Content/d2k/v2/Movies/H_BR04_E.VQA: H_BR04_E.VQA - ^Content/d2k/v2/Movies/H_BR05_E.VQA: H_BR05_E.VQA - ^Content/d2k/v2/Movies/H_BR06_E.VQA: H_BR06_E.VQA - ^Content/d2k/v2/Movies/H_BR07_E.VQA: H_BR07_E.VQA - ^Content/d2k/v2/Movies/H_BR08_E.VQA: H_BR08_E.VQA - ^Content/d2k/v2/Movies/H_BR09_E.VQA: H_BR09_E.VQA - ^Content/d2k/v2/Movies/H_FINL_E.VQA: H_FINL_E.VQA - ^Content/d2k/v2/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA - ^Content/d2k/v2/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA - ^Content/d2k/v2/Movies/O_BR01_E.VQA: O_BR01_E.VQA - ^Content/d2k/v2/Movies/O_BR02_E.VQA: O_BR02_E.VQA - ^Content/d2k/v2/Movies/O_BR03_E.VQA: O_BR03_E.VQA - ^Content/d2k/v2/Movies/O_BR04_E.VQA: O_BR04_E.VQA - ^Content/d2k/v2/Movies/O_BR05_E.VQA: O_BR05_E.VQA - ^Content/d2k/v2/Movies/O_BR06_E.VQA: O_BR06_E.VQA - ^Content/d2k/v2/Movies/O_BR07_E.VQA: O_BR07_E.VQA - ^Content/d2k/v2/Movies/O_BR08_E.VQA: O_BR08_E.VQA - ^Content/d2k/v2/Movies/O_BR09_E.VQA: O_BR09_E.VQA - ^Content/d2k/v2/Movies/O_FINL_E.VQA: O_FINL_E.VQA - ^Content/d2k/v2/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA - ^Content/d2k/v2/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA - ^Content/d2k/v2/Movies/G_INT1_E.VQA: G_INT1_E.VQA - ^Content/d2k/v2/Movies/G_INT2_E.VQA: G_INT2_E.VQA - ^Content/d2k/v2/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA - ^Content/d2k/v2/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA - ^Content/d2k/v2/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA - ^Content/d2k/v2/Movies/T_TITL_E.VQA: T_TITL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA: A_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR02_E.VQA: A_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR03_E.VQA: A_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR04_E.VQA: A_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR05_E.VQA: A_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR06_E.VQA: A_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR07_E.VQA: A_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR08_E.VQA: A_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR09_E.VQA: A_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_FINL_E.VQA: A_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR01_E.VQA: H_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR02_E.VQA: H_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR03_E.VQA: H_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR04_E.VQA: H_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR05_E.VQA: H_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR06_E.VQA: H_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR07_E.VQA: H_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR08_E.VQA: H_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR09_E.VQA: H_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_FINL_E.VQA: H_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR01_E.VQA: O_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR02_E.VQA: O_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR03_E.VQA: O_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR04_E.VQA: O_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR05_E.VQA: O_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR06_E.VQA: O_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR07_E.VQA: O_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR08_E.VQA: O_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR09_E.VQA: O_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_FINL_E.VQA: O_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_INT1_E.VQA: G_INT1_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_INT2_E.VQA: G_INT2_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA + ^SupportDir|Content/d2k/v2/Movies/T_TITL_E.VQA: T_TITL_E.VQA copy: MUSIC - ^Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD - ^Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD - ^Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD - ^Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD - ^Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD - ^Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD - ^Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD - ^Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD - ^Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD - ^Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD - ^Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD - ^Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD - ^Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD - ^Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD - ^Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD - ^Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD - ^Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD extract-blast: SETUP/SETUP.Z - ^Content/d2k/v2/BLOXBAT.R8: + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: Offset: 1156652 Length: 512750 - ^Content/d2k/v2/BLOXBASE.R8: + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: Offset: 1669402 Length: 497092 - ^Content/d2k/v2/BLOXBGBS.R8: + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: Offset: 4055223 Length: 499135 - ^Content/d2k/v2/BLOXICE.R8: + ^SupportDir|Content/d2k/v2/BLOXICE.R8: Offset: 5524509 Length: 514963 - ^Content/d2k/v2/BLOXTREE.R8: + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: Offset: 6994370 Length: 509867 - ^Content/d2k/v2/BLOXWAST.R8: + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: Offset: 8455018 Length: 508567 - ^Content/d2k/v2/MOUSE.R8: + ^SupportDir|Content/d2k/v2/MOUSE.R8: Offset: 14012491 Length: 16996 - ^Content/d2k/v2/PALETTE.BIN: + ^SupportDir|Content/d2k/v2/PALETTE.BIN: Offset: 22938401 Length: 815 - ^Content/d2k/v2/FONT.BIN: + ^SupportDir|Content/d2k/v2/FONT.BIN: Offset: 22927461 Length: 199 - ^Content/d2k/v2/FONTCOL.FNT: + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: Offset: 13985176 Length: 3011 - ^Content/d2k/v2/FONTCOL.FPL: + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: Offset: 13988187 Length: 238 - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: Offset: 15560305 Length: 9647 - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: Offset: 15569952 Length: 8676 - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: Offset: 15578628 Length: 9641 - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: Offset: 15588269 Length: 7371 - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: Offset: 15595640 Length: 11326 - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: Offset: 15606966 Length: 11329 - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: Offset: 15618295 Length: 8964 - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: Offset: 15627259 Length: 11336 - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: Offset: 15638595 Length: 14606 - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: Offset: 15653201 Length: 27230 - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: Offset: 15680431 Length: 19621 - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: Offset: 15700052 Length: 28781 - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: Offset: 15728833 Length: 29703 - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: Offset: 15758536 Length: 29555 - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: Offset: 15788091 Length: 27961 - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: Offset: 15816052 Length: 20925 - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: Offset: 15836977 Length: 10925 - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: Offset: 15847902 Length: 8125 - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: Offset: 15856027 Length: 26212 - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: Offset: 15882239 Length: 27166 - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: Offset: 15909405 Length: 31126 - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: Offset: 15940531 Length: 33481 - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: Offset: 15974012 Length: 17265 - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: Offset: 15991277 Length: 14523 - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: Offset: 16005800 Length: 18266 - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: Offset: 16024066 Length: 8467 - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: Offset: 16032533 Length: 9748 - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: Offset: 16042281 Length: 14264 - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: Offset: 16056545 Length: 12087 - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: Offset: 16068632 Length: 14428 - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: Offset: 16083060 Length: 16985 - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: Offset: 16100045 Length: 12638 - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: Offset: 16112683 Length: 13229 - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: Offset: 16125912 Length: 26572 - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: Offset: 16152484 Length: 12085 - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: Offset: 16164569 Length: 18232 - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: Offset: 16182801 Length: 8328 - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: Offset: 16191129 Length: 12497 - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: Offset: 16203626 Length: 9546 - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: Offset: 16213172 Length: 17135 - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: Offset: 16230307 Length: 26937 - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: Offset: 16257244 Length: 17940 - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: Offset: 16275184 Length: 14985 - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: Offset: 16290169 Length: 9089 - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: Offset: 16299258 Length: 28401 - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: Offset: 16327659 Length: 23949 - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: Offset: 16351608 Length: 29489 - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: Offset: 16381097 Length: 11016 - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: Offset: 16392113 Length: 27566 - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: Offset: 16419679 Length: 26539 - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: Offset: 16446218 Length: 30821 - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: Offset: 16477039 Length: 7978 - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: Offset: 16485017 Length: 11880 - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: Offset: 16496897 Length: 8995 - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: Offset: 16505892 Length: 10120 - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: Offset: 16516012 Length: 8999 - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: Offset: 16525011 Length: 6593 - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: Offset: 16531604 Length: 34790 - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: Offset: 16566394 Length: 35606 - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: Offset: 16602000 Length: 10303 - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: Offset: 16612303 Length: 22969 - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: Offset: 16635272 Length: 31816 - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: Offset: 16667088 Length: 19585 - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: Offset: 16686673 Length: 14563 - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: Offset: 16701236 Length: 13353 - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: Offset: 16714589 Length: 9671 - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: Offset: 16724260 Length: 15031 - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: Offset: 16739291 Length: 28368 - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: Offset: 16767659 Length: 9649 - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: Offset: 16777308 Length: 17157 - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: Offset: 16794465 Length: 13407 - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: Offset: 16807872 Length: 29910 - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: Offset: 16837782 Length: 22890 - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: Offset: 16860672 Length: 22923 - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: Offset: 16883595 Length: 34017 - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: Offset: 16917612 Length: 56714 - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: Offset: 16974326 Length: 27200 - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: Offset: 17001526 Length: 19828 - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: Offset: 17021354 Length: 13869 - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: Offset: 17035223 Length: 14197 - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: Offset: 17049420 Length: 29136 - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: Offset: 17078556 Length: 26204 - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: Offset: 17104760 Length: 24264 - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: Offset: 17129024 Length: 43921 - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: Offset: 17172945 Length: 22151 - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: Offset: 17195096 Length: 12300 - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: Offset: 17207396 Length: 21971 - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: Offset: 17229367 Length: 22041 - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: Offset: 17251408 Length: 21545 - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: Offset: 17272953 Length: 14344 - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: Offset: 17287297 Length: 28156 - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: Offset: 17315453 Length: 16983 - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: Offset: 17332436 Length: 19583 - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: Offset: 17352019 Length: 12875 - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: Offset: 17364894 Length: 20974 - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: Offset: 17385868 Length: 14699 - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: Offset: 17400567 Length: 20919 - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: Offset: 17421486 Length: 18984 - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: Offset: 17440470 Length: 11779 - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: Offset: 17452249 Length: 13980 - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: Offset: 17466229 Length: 33483 - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: Offset: 17499712 Length: 26566 - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: Offset: 17526278 Length: 25237 - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: Offset: 17551515 Length: 16072 - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: Offset: 17567587 Length: 12037 - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: Offset: 17579624 Length: 30243 - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: Offset: 17609867 Length: 31710 - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: Offset: 17641577 Length: 27450 - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: Offset: 17669027 Length: 30854 - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: Offset: 17699881 Length: 10860 - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: Offset: 17710741 Length: 19337 - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: Offset: 17730078 Length: 15004 - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: Offset: 17745082 Length: 23023 - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: Offset: 17768105 Length: 22321 - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: Offset: 17790426 Length: 21698 - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: Offset: 17812124 Length: 10282 - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: Offset: 17822406 Length: 28615 - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: Offset: 17851021 Length: 12771 - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: Offset: 17863792 Length: 9917 - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: Offset: 17873709 Length: 18502 - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: Offset: 17892211 Length: 12832 - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: Offset: 17905043 Length: 22413 - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: Offset: 17927456 Length: 29577 - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: Offset: 17957033 Length: 24798 - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: Offset: 17981831 Length: 14784 - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: Offset: 17996615 Length: 18526 - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: Offset: 18015141 Length: 12390 - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: Offset: 18027531 Length: 11851 - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: Offset: 18039382 Length: 9867 - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: Offset: 18049249 Length: 16907 - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: Offset: 18066156 Length: 17659 - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: Offset: 18083815 Length: 20337 - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: Offset: 18104152 Length: 18877 - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: Offset: 18123029 Length: 30788 - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: Offset: 18153817 Length: 18322 - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: Offset: 18172139 Length: 22178 - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: Offset: 18194317 Length: 24878 - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: Offset: 18219195 Length: 15741 - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: Offset: 18234936 Length: 14892 - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: Offset: 18249828 Length: 23026 - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: Offset: 18272854 Length: 43938 - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: Offset: 18316792 Length: 10992 - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: Offset: 18327784 Length: 19514 - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: Offset: 18347298 Length: 23895 - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: Offset: 18371193 Length: 18626 - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: Offset: 18389819 Length: 22564 - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: Offset: 18412383 Length: 18445 - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: Offset: 18430828 Length: 19492 - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: Offset: 18450320 Length: 14194 - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: Offset: 18464514 Length: 8310 - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: Offset: 18472824 Length: 8332 - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: Offset: 18481156 Length: 15789 - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: Offset: 18496945 Length: 9791 - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: Offset: 18506736 Length: 15099 - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: Offset: 18521835 Length: 14863 - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: Offset: 18536698 Length: 9753 - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: Offset: 18546451 Length: 9329 - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: Offset: 18555780 Length: 9449 - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: Offset: 18565229 Length: 15600 - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: Offset: 18580829 Length: 16157 - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: Offset: 18596986 Length: 13149 - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: Offset: 18610135 Length: 13928 - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: Offset: 18624063 Length: 16430 - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: Offset: 18640493 Length: 41640 - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: Offset: 18682133 Length: 41809 - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: Offset: 18723942 Length: 29117 - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: Offset: 18753059 Length: 36982 - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: Offset: 18790041 Length: 60681 - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: Offset: 18850722 Length: 21396 - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: Offset: 18872118 Length: 37995 - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: Offset: 18910113 Length: 32674 - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: Offset: 18942787 Length: 18399 - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: Offset: 18961186 Length: 26359 - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: Offset: 18987545 Length: 21335 - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: Offset: 19008880 Length: 28418 - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: Offset: 19037298 Length: 9269 - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: Offset: 19046567 Length: 19854 - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: Offset: 19066421 Length: 20038 - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: Offset: 19086459 Length: 16073 - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: Offset: 19102532 Length: 14873 - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: Offset: 19117405 Length: 41683 - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: Offset: 19159088 Length: 34475 - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: Offset: 19193563 Length: 34903 - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: Offset: 19228466 Length: 59613 - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: Offset: 19288079 Length: 22150 - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: Offset: 19310229 Length: 9090 - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: Offset: 19319319 Length: 21350 - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: Offset: 19340669 Length: 31478 - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: Offset: 19372147 Length: 19876 - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: Offset: 19392023 Length: 22359 - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: Offset: 19414382 Length: 28902 - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: Offset: 19443284 Length: 26855 - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: Offset: 19470139 Length: 19104 - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: Offset: 19489243 Length: 24655 - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: Offset: 19513898 Length: 23032 - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: Offset: 19536930 Length: 35588 - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: Offset: 19572518 Length: 8945 - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: Offset: 19581463 Length: 9005 - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: Offset: 19590468 Length: 9606 - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: Offset: 19600074 Length: 11671 - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: Offset: 19611745 Length: 10644 - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: Offset: 19622389 Length: 10387 - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: Offset: 19632776 Length: 17225 - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: Offset: 19650001 Length: 10077 - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: Offset: 19660078 Length: 13616 - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: Offset: 19673694 Length: 11251 - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: Offset: 19684945 Length: 8144 - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: Offset: 19693089 Length: 14865 - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: Offset: 19707954 Length: 11912 - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: Offset: 19719866 Length: 19540 - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: Offset: 19739406 Length: 10246 - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: Offset: 19749652 Length: 31148 - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: Offset: 19780800 Length: 8307 - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: Offset: 19789107 Length: 14331 - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: Offset: 19803438 Length: 11295 - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: Offset: 19814733 Length: 20437 - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: Offset: 19835170 Length: 27739 - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: Offset: 19862909 Length: 22200 - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: Offset: 19885109 Length: 9620 - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: Offset: 19894729 Length: 13368 - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: Offset: 19908097 Length: 15612 - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: Offset: 19923709 Length: 8279 - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: Offset: 19931988 Length: 11383 - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: Offset: 19943371 Length: 18511 - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: Offset: 19961882 Length: 14244 - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: Offset: 19976126 Length: 24075 - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: Offset: 20000201 Length: 26716 - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: Offset: 20026917 Length: 21716 - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: Offset: 20048633 Length: 32417 - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: Offset: 20081050 Length: 33724 - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: Offset: 20114774 Length: 21828 - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: Offset: 20136602 Length: 30404 - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: Offset: 20167006 Length: 9862 - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: Offset: 20176868 Length: 18149 - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: Offset: 20195017 Length: 14697 - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: Offset: 20209714 Length: 17316 - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: Offset: 20227030 Length: 14869 - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: Offset: 20241899 Length: 29873 - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: Offset: 20271772 Length: 16335 - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: Offset: 20288107 Length: 20565 - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: Offset: 20308672 Length: 25497 - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: Offset: 20334169 Length: 17142 - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: Offset: 20351311 Length: 20120 - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: Offset: 20371431 Length: 29921 - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: Offset: 20401352 Length: 14467 - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: Offset: 20415819 Length: 10906 - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: Offset: 20426725 Length: 25959 - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: Offset: 20452684 Length: 34175 - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: Offset: 20486859 Length: 30124 - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: Offset: 20516983 Length: 21881 - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: Offset: 20538864 Length: 20567 - ^Content/d2k/v2/SOUND.RS: + ^SupportDir|Content/d2k/v2/SOUND.RS: Offset: 20559431 Length: 1929247 d2k-a-linux: Dune 2000 (English) @@ -860,853 +860,853 @@ setup/setup.z: 937f5ceb1236bf3f3d4e43929305ffe5004078e7 Install: copy: movies - ^Content/d2k/v2/Movies/A_BR01_E.VQA: a_br01_e.vqa - ^Content/d2k/v2/Movies/A_BR02_E.VQA: a_br02_e.vqa - ^Content/d2k/v2/Movies/A_BR03_E.VQA: a_br03_e.vqa - ^Content/d2k/v2/Movies/A_BR04_E.VQA: a_br04_e.vqa - ^Content/d2k/v2/Movies/A_BR05_E.VQA: a_br05_e.vqa - ^Content/d2k/v2/Movies/A_BR06_E.VQA: a_br06_e.vqa - ^Content/d2k/v2/Movies/A_BR07_E.VQA: a_br07_e.vqa - ^Content/d2k/v2/Movies/A_BR08_E.VQA: a_br08_e.vqa - ^Content/d2k/v2/Movies/A_BR09_E.VQA: a_br09_e.vqa - ^Content/d2k/v2/Movies/A_FINL_E.VQA: a_finl_e.vqa - ^Content/d2k/v2/Movies/A_LOSE_E.VQA: a_lose_e.vqa - ^Content/d2k/v2/Movies/A_MNTG_E.VQA: a_mntg_e.vqa - ^Content/d2k/v2/Movies/H_BR01_E.VQA: h_br01_e.vqa - ^Content/d2k/v2/Movies/H_BR02_E.VQA: h_br02_e.vqa - ^Content/d2k/v2/Movies/H_BR03_E.VQA: h_br03_e.vqa - ^Content/d2k/v2/Movies/H_BR04_E.VQA: h_br04_e.vqa - ^Content/d2k/v2/Movies/H_BR05_E.VQA: h_br05_e.vqa - ^Content/d2k/v2/Movies/H_BR06_E.VQA: h_br06_e.vqa - ^Content/d2k/v2/Movies/H_BR07_E.VQA: h_br07_e.vqa - ^Content/d2k/v2/Movies/H_BR08_E.VQA: h_br08_e.vqa - ^Content/d2k/v2/Movies/H_BR09_E.VQA: h_br09_e.vqa - ^Content/d2k/v2/Movies/H_FINL_E.VQA: h_finl_e.vqa - ^Content/d2k/v2/Movies/H_LOSE_E.VQA: h_lose_e.vqa - ^Content/d2k/v2/Movies/H_MNTG_E.VQA: h_mntg_e.vqa - ^Content/d2k/v2/Movies/O_BR01_E.VQA: o_br01_e.vqa - ^Content/d2k/v2/Movies/O_BR02_E.VQA: o_br02_e.vqa - ^Content/d2k/v2/Movies/O_BR03_E.VQA: o_br03_e.vqa - ^Content/d2k/v2/Movies/O_BR04_E.VQA: o_br04_e.vqa - ^Content/d2k/v2/Movies/O_BR05_E.VQA: o_br05_e.vqa - ^Content/d2k/v2/Movies/O_BR06_E.VQA: o_br06_e.vqa - ^Content/d2k/v2/Movies/O_BR07_E.VQA: o_br07_e.vqa - ^Content/d2k/v2/Movies/O_BR08_E.VQA: o_br08_e.vqa - ^Content/d2k/v2/Movies/O_BR09_E.VQA: o_br09_e.vqa - ^Content/d2k/v2/Movies/O_FINL_E.VQA: o_finl_e.vqa - ^Content/d2k/v2/Movies/O_LOSE_E.VQA: o_lose_e.vqa - ^Content/d2k/v2/Movies/O_MNTG_E.VQA: o_mntg_e.vqa - ^Content/d2k/v2/Movies/G_INT1_E.VQA: g_int1_e.vqa - ^Content/d2k/v2/Movies/G_INT2_E.VQA: g_int2_e.vqa - ^Content/d2k/v2/Movies/G_MAPS_E.VQA: g_maps_e.vqa - ^Content/d2k/v2/Movies/G_PLN2_E.VQA: g_pln2_e.vqa - ^Content/d2k/v2/Movies/G_PLNT_E.VQA: g_plnt_e.vqa - ^Content/d2k/v2/Movies/T_TITL_E.VQA: t_titl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA: a_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR02_E.VQA: a_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR03_E.VQA: a_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR04_E.VQA: a_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR05_E.VQA: a_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR06_E.VQA: a_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR07_E.VQA: a_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR08_E.VQA: a_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR09_E.VQA: a_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_FINL_E.VQA: a_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_LOSE_E.VQA: a_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_MNTG_E.VQA: a_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR01_E.VQA: h_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR02_E.VQA: h_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR03_E.VQA: h_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR04_E.VQA: h_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR05_E.VQA: h_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR06_E.VQA: h_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR07_E.VQA: h_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR08_E.VQA: h_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR09_E.VQA: h_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_FINL_E.VQA: h_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_LOSE_E.VQA: h_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_MNTG_E.VQA: h_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR01_E.VQA: o_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR02_E.VQA: o_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR03_E.VQA: o_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR04_E.VQA: o_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR05_E.VQA: o_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR06_E.VQA: o_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR07_E.VQA: o_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR08_E.VQA: o_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR09_E.VQA: o_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_FINL_E.VQA: o_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_LOSE_E.VQA: o_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_MNTG_E.VQA: o_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_INT1_E.VQA: g_int1_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_INT2_E.VQA: g_int2_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_MAPS_E.VQA: g_maps_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_PLN2_E.VQA: g_pln2_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_PLNT_E.VQA: g_plnt_e.vqa + ^SupportDir|Content/d2k/v2/Movies/T_TITL_E.VQA: t_titl_e.vqa copy: music - ^Content/d2k/v2/Music/AMBUSH.AUD: ambush.aud - ^Content/d2k/v2/Music/ARAKATAK.AUD: arakatak.aud - ^Content/d2k/v2/Music/ATREGAIN.AUD: atregain.aud - ^Content/d2k/v2/Music/ENTORDOS.AUD: entordos.aud - ^Content/d2k/v2/Music/FIGHTPWR.AUD: fightpwr.aud - ^Content/d2k/v2/Music/FREMEN.AUD: fremen.aud - ^Content/d2k/v2/Music/HARK_BAT.AUD: hark_bat.aud - ^Content/d2k/v2/Music/LANDSAND.AUD: landsand.aud - ^Content/d2k/v2/Music/OPTIONS.AUD: options.aud - ^Content/d2k/v2/Music/PLOTTING.AUD: plotting.aud - ^Content/d2k/v2/Music/RISEHARK.AUD: risehark.aud - ^Content/d2k/v2/Music/ROBOTIX.AUD: robotix.aud - ^Content/d2k/v2/Music/SCORE.AUD: score.aud - ^Content/d2k/v2/Music/SOLDAPPR.AUD: soldappr.aud - ^Content/d2k/v2/Music/SPICESCT.AUD: spicesct.aud - ^Content/d2k/v2/Music/UNDERCON.AUD: undercon.aud - ^Content/d2k/v2/Music/WAITGAME.A: waitgame.aud + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: ambush.aud + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: arakatak.aud + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: atregain.aud + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: entordos.aud + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: fightpwr.aud + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: fremen.aud + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: hark_bat.aud + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: landsand.aud + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: options.aud + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: plotting.aud + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: risehark.aud + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: robotix.aud + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: score.aud + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: soldappr.aud + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: spicesct.aud + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: undercon.aud + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: waitgame.aud extract-blast: setup/setup.z - ^Content/d2k/v2/BLOXBAT.R8: + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: Offset: 1156652 Length: 512750 - ^Content/d2k/v2/BLOXBASE.R8: + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: Offset: 1669402 Length: 497092 - ^Content/d2k/v2/BLOXBGBS.R8: + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: Offset: 4055223 Length: 499135 - ^Content/d2k/v2/BLOXICE.R8: + ^SupportDir|Content/d2k/v2/BLOXICE.R8: Offset: 5524509 Length: 514963 - ^Content/d2k/v2/BLOXTREE.R8: + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: Offset: 6994370 Length: 509867 - ^Content/d2k/v2/BLOXWAST.R8: + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: Offset: 8455018 Length: 508567 - ^Content/d2k/v2/MOUSE.R8: + ^SupportDir|Content/d2k/v2/MOUSE.R8: Offset: 14012491 Length: 16996 - ^Content/d2k/v2/PALETTE.BIN: + ^SupportDir|Content/d2k/v2/PALETTE.BIN: Offset: 22938401 Length: 815 - ^Content/d2k/v2/FONT.BIN: + ^SupportDir|Content/d2k/v2/FONT.BIN: Offset: 22927461 Length: 199 - ^Content/d2k/v2/FONTCOL.FNT: + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: Offset: 13985176 Length: 3011 - ^Content/d2k/v2/FONTCOL.FPL: + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: Offset: 13988187 Length: 238 - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: Offset: 15560305 Length: 9647 - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: Offset: 15569952 Length: 8676 - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: Offset: 15578628 Length: 9641 - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: Offset: 15588269 Length: 7371 - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: Offset: 15595640 Length: 11326 - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: Offset: 15606966 Length: 11329 - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: Offset: 15618295 Length: 8964 - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: Offset: 15627259 Length: 11336 - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: Offset: 15638595 Length: 14606 - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: Offset: 15653201 Length: 27230 - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: Offset: 15680431 Length: 19621 - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: Offset: 15700052 Length: 28781 - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: Offset: 15728833 Length: 29703 - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: Offset: 15758536 Length: 29555 - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: Offset: 15788091 Length: 27961 - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: Offset: 15816052 Length: 20925 - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: Offset: 15836977 Length: 10925 - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: Offset: 15847902 Length: 8125 - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: Offset: 15856027 Length: 26212 - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: Offset: 15882239 Length: 27166 - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: Offset: 15909405 Length: 31126 - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: Offset: 15940531 Length: 33481 - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: Offset: 15974012 Length: 17265 - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: Offset: 15991277 Length: 14523 - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: Offset: 16005800 Length: 18266 - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: Offset: 16024066 Length: 8467 - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: Offset: 16032533 Length: 9748 - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: Offset: 16042281 Length: 14264 - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: Offset: 16056545 Length: 12087 - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: Offset: 16068632 Length: 14428 - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: Offset: 16083060 Length: 16985 - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: Offset: 16100045 Length: 12638 - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: Offset: 16112683 Length: 13229 - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: Offset: 16125912 Length: 26572 - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: Offset: 16152484 Length: 12085 - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: Offset: 16164569 Length: 18232 - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: Offset: 16182801 Length: 8328 - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: Offset: 16191129 Length: 12497 - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: Offset: 16203626 Length: 9546 - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: Offset: 16213172 Length: 17135 - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: Offset: 16230307 Length: 26937 - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: Offset: 16257244 Length: 17940 - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: Offset: 16275184 Length: 14985 - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: Offset: 16290169 Length: 9089 - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: Offset: 16299258 Length: 28401 - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: Offset: 16327659 Length: 23949 - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: Offset: 16351608 Length: 29489 - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: Offset: 16381097 Length: 11016 - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: Offset: 16392113 Length: 27566 - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: Offset: 16419679 Length: 26539 - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: Offset: 16446218 Length: 30821 - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: Offset: 16477039 Length: 7978 - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: Offset: 16485017 Length: 11880 - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: Offset: 16496897 Length: 8995 - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: Offset: 16505892 Length: 10120 - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: Offset: 16516012 Length: 8999 - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: Offset: 16525011 Length: 6593 - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: Offset: 16531604 Length: 34790 - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: Offset: 16566394 Length: 35606 - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: Offset: 16602000 Length: 10303 - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: Offset: 16612303 Length: 22969 - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: Offset: 16635272 Length: 31816 - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: Offset: 16667088 Length: 19585 - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: Offset: 16686673 Length: 14563 - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: Offset: 16701236 Length: 13353 - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: Offset: 16714589 Length: 9671 - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: Offset: 16724260 Length: 15031 - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: Offset: 16739291 Length: 28368 - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: Offset: 16767659 Length: 9649 - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: Offset: 16777308 Length: 17157 - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: Offset: 16794465 Length: 13407 - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: Offset: 16807872 Length: 29910 - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: Offset: 16837782 Length: 22890 - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: Offset: 16860672 Length: 22923 - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: Offset: 16883595 Length: 34017 - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: Offset: 16917612 Length: 56714 - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: Offset: 16974326 Length: 27200 - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: Offset: 17001526 Length: 19828 - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: Offset: 17021354 Length: 13869 - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: Offset: 17035223 Length: 14197 - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: Offset: 17049420 Length: 29136 - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: Offset: 17078556 Length: 26204 - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: Offset: 17104760 Length: 24264 - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: Offset: 17129024 Length: 43921 - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: Offset: 17172945 Length: 22151 - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: Offset: 17195096 Length: 12300 - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: Offset: 17207396 Length: 21971 - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: Offset: 17229367 Length: 22041 - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: Offset: 17251408 Length: 21545 - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: Offset: 17272953 Length: 14344 - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: Offset: 17287297 Length: 28156 - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: Offset: 17315453 Length: 16983 - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: Offset: 17332436 Length: 19583 - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: Offset: 17352019 Length: 12875 - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: Offset: 17364894 Length: 20974 - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: Offset: 17385868 Length: 14699 - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: Offset: 17400567 Length: 20919 - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: Offset: 17421486 Length: 18984 - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: Offset: 17440470 Length: 11779 - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: Offset: 17452249 Length: 13980 - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: Offset: 17466229 Length: 33483 - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: Offset: 17499712 Length: 26566 - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: Offset: 17526278 Length: 25237 - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: Offset: 17551515 Length: 16072 - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: Offset: 17567587 Length: 12037 - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: Offset: 17579624 Length: 30243 - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: Offset: 17609867 Length: 31710 - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: Offset: 17641577 Length: 27450 - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: Offset: 17669027 Length: 30854 - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: Offset: 17699881 Length: 10860 - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: Offset: 17710741 Length: 19337 - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: Offset: 17730078 Length: 15004 - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: Offset: 17745082 Length: 23023 - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: Offset: 17768105 Length: 22321 - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: Offset: 17790426 Length: 21698 - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: Offset: 17812124 Length: 10282 - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: Offset: 17822406 Length: 28615 - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: Offset: 17851021 Length: 12771 - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: Offset: 17863792 Length: 9917 - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: Offset: 17873709 Length: 18502 - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: Offset: 17892211 Length: 12832 - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: Offset: 17905043 Length: 22413 - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: Offset: 17927456 Length: 29577 - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: Offset: 17957033 Length: 24798 - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: Offset: 17981831 Length: 14784 - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: Offset: 17996615 Length: 18526 - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: Offset: 18015141 Length: 12390 - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: Offset: 18027531 Length: 11851 - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: Offset: 18039382 Length: 9867 - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: Offset: 18049249 Length: 16907 - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: Offset: 18066156 Length: 17659 - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: Offset: 18083815 Length: 20337 - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: Offset: 18104152 Length: 18877 - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: Offset: 18123029 Length: 30788 - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: Offset: 18153817 Length: 18322 - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: Offset: 18172139 Length: 22178 - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: Offset: 18194317 Length: 24878 - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: Offset: 18219195 Length: 15741 - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: Offset: 18234936 Length: 14892 - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: Offset: 18249828 Length: 23026 - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: Offset: 18272854 Length: 43938 - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: Offset: 18316792 Length: 10992 - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: Offset: 18327784 Length: 19514 - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: Offset: 18347298 Length: 23895 - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: Offset: 18371193 Length: 18626 - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: Offset: 18389819 Length: 22564 - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: Offset: 18412383 Length: 18445 - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: Offset: 18430828 Length: 19492 - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: Offset: 18450320 Length: 14194 - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: Offset: 18464514 Length: 8310 - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: Offset: 18472824 Length: 8332 - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: Offset: 18481156 Length: 15789 - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: Offset: 18496945 Length: 9791 - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: Offset: 18506736 Length: 15099 - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: Offset: 18521835 Length: 14863 - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: Offset: 18536698 Length: 9753 - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: Offset: 18546451 Length: 9329 - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: Offset: 18555780 Length: 9449 - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: Offset: 18565229 Length: 15600 - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: Offset: 18580829 Length: 16157 - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: Offset: 18596986 Length: 13149 - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: Offset: 18610135 Length: 13928 - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: Offset: 18624063 Length: 16430 - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: Offset: 18640493 Length: 41640 - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: Offset: 18682133 Length: 41809 - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: Offset: 18723942 Length: 29117 - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: Offset: 18753059 Length: 36982 - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: Offset: 18790041 Length: 60681 - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: Offset: 18850722 Length: 21396 - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: Offset: 18872118 Length: 37995 - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: Offset: 18910113 Length: 32674 - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: Offset: 18942787 Length: 18399 - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: Offset: 18961186 Length: 26359 - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: Offset: 18987545 Length: 21335 - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: Offset: 19008880 Length: 28418 - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: Offset: 19037298 Length: 9269 - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: Offset: 19046567 Length: 19854 - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: Offset: 19066421 Length: 20038 - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: Offset: 19086459 Length: 16073 - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: Offset: 19102532 Length: 14873 - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: Offset: 19117405 Length: 41683 - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: Offset: 19159088 Length: 34475 - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: Offset: 19193563 Length: 34903 - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: Offset: 19228466 Length: 59613 - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: Offset: 19288079 Length: 22150 - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: Offset: 19310229 Length: 9090 - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: Offset: 19319319 Length: 21350 - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: Offset: 19340669 Length: 31478 - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: Offset: 19372147 Length: 19876 - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: Offset: 19392023 Length: 22359 - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: Offset: 19414382 Length: 28902 - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: Offset: 19443284 Length: 26855 - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: Offset: 19470139 Length: 19104 - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: Offset: 19489243 Length: 24655 - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: Offset: 19513898 Length: 23032 - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: Offset: 19536930 Length: 35588 - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: Offset: 19572518 Length: 8945 - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: Offset: 19581463 Length: 9005 - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: Offset: 19590468 Length: 9606 - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: Offset: 19600074 Length: 11671 - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: Offset: 19611745 Length: 10644 - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: Offset: 19622389 Length: 10387 - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: Offset: 19632776 Length: 17225 - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: Offset: 19650001 Length: 10077 - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: Offset: 19660078 Length: 13616 - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: Offset: 19673694 Length: 11251 - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: Offset: 19684945 Length: 8144 - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: Offset: 19693089 Length: 14865 - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: Offset: 19707954 Length: 11912 - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: Offset: 19719866 Length: 19540 - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: Offset: 19739406 Length: 10246 - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: Offset: 19749652 Length: 31148 - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: Offset: 19780800 Length: 8307 - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: Offset: 19789107 Length: 14331 - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: Offset: 19803438 Length: 11295 - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: Offset: 19814733 Length: 20437 - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: Offset: 19835170 Length: 27739 - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: Offset: 19862909 Length: 22200 - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: Offset: 19885109 Length: 9620 - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: Offset: 19894729 Length: 13368 - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: Offset: 19908097 Length: 15612 - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: Offset: 19923709 Length: 8279 - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: Offset: 19931988 Length: 11383 - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: Offset: 19943371 Length: 18511 - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: Offset: 19961882 Length: 14244 - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: Offset: 19976126 Length: 24075 - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: Offset: 20000201 Length: 26716 - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: Offset: 20026917 Length: 21716 - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: Offset: 20048633 Length: 32417 - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: Offset: 20081050 Length: 33724 - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: Offset: 20114774 Length: 21828 - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: Offset: 20136602 Length: 30404 - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: Offset: 20167006 Length: 9862 - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: Offset: 20176868 Length: 18149 - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: Offset: 20195017 Length: 14697 - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: Offset: 20209714 Length: 17316 - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: Offset: 20227030 Length: 14869 - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: Offset: 20241899 Length: 29873 - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: Offset: 20271772 Length: 16335 - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: Offset: 20288107 Length: 20565 - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: Offset: 20308672 Length: 25497 - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: Offset: 20334169 Length: 17142 - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: Offset: 20351311 Length: 20120 - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: Offset: 20371431 Length: 29921 - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: Offset: 20401352 Length: 14467 - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: Offset: 20415819 Length: 10906 - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: Offset: 20426725 Length: 25959 - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: Offset: 20452684 Length: 34175 - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: Offset: 20486859 Length: 30124 - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: Offset: 20516983 Length: 21881 - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: Offset: 20538864 Length: 20567 - ^Content/d2k/v2/SOUND.RS: + ^SupportDir|Content/d2k/v2/SOUND.RS: Offset: 20559431 Length: 1929247 \ No newline at end of file diff -Nru openra-20200503/mods/d2k/installer/d2k-b.yaml openra-20210321/mods/d2k/installer/d2k-b.yaml --- openra-20200503/mods/d2k/installer/d2k-b.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/installer/d2k-b.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,854 +4,854 @@ SETUP/SETUP.Z: 029722e70fb7636f8120028f5c9b6ce81627ff90 Install: copy: MOVIES - ^Content/d2k/v2/Movies/A_BR01_E.VQA: A_BR01_E.VQA - ^Content/d2k/v2/Movies/A_BR02_E.VQA: A_BR02_E.VQA - ^Content/d2k/v2/Movies/A_BR03_E.VQA: A_BR03_E.VQA - ^Content/d2k/v2/Movies/A_BR04_E.VQA: A_BR04_E.VQA - ^Content/d2k/v2/Movies/A_BR05_E.VQA: A_BR05_E.VQA - ^Content/d2k/v2/Movies/A_BR06_E.VQA: A_BR06_E.VQA - ^Content/d2k/v2/Movies/A_BR07_E.VQA: A_BR07_E.VQA - ^Content/d2k/v2/Movies/A_BR08_E.VQA: A_BR08_E.VQA - ^Content/d2k/v2/Movies/A_BR09_E.VQA: A_BR09_E.VQA - ^Content/d2k/v2/Movies/A_FINL_E.VQA: A_FINL_E.VQA - ^Content/d2k/v2/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA - ^Content/d2k/v2/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA - ^Content/d2k/v2/Movies/H_BR01_E.VQA: H_BR01_E.VQA - ^Content/d2k/v2/Movies/H_BR02_E.VQA: H_BR02_E.VQA - ^Content/d2k/v2/Movies/H_BR03_E.VQA: H_BR03_E.VQA - ^Content/d2k/v2/Movies/H_BR04_E.VQA: H_BR04_E.VQA - ^Content/d2k/v2/Movies/H_BR05_E.VQA: H_BR05_E.VQA - ^Content/d2k/v2/Movies/H_BR06_E.VQA: H_BR06_E.VQA - ^Content/d2k/v2/Movies/H_BR07_E.VQA: H_BR07_E.VQA - ^Content/d2k/v2/Movies/H_BR08_E.VQA: H_BR08_E.VQA - ^Content/d2k/v2/Movies/H_BR09_E.VQA: H_BR09_E.VQA - ^Content/d2k/v2/Movies/H_FINL_E.VQA: H_FINL_E.VQA - ^Content/d2k/v2/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA - ^Content/d2k/v2/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA - ^Content/d2k/v2/Movies/O_BR01_E.VQA: O_BR01_E.VQA - ^Content/d2k/v2/Movies/O_BR02_E.VQA: O_BR02_E.VQA - ^Content/d2k/v2/Movies/O_BR03_E.VQA: O_BR03_E.VQA - ^Content/d2k/v2/Movies/O_BR04_E.VQA: O_BR04_E.VQA - ^Content/d2k/v2/Movies/O_BR05_E.VQA: O_BR05_E.VQA - ^Content/d2k/v2/Movies/O_BR06_E.VQA: O_BR06_E.VQA - ^Content/d2k/v2/Movies/O_BR07_E.VQA: O_BR07_E.VQA - ^Content/d2k/v2/Movies/O_BR08_E.VQA: O_BR08_E.VQA - ^Content/d2k/v2/Movies/O_BR09_E.VQA: O_BR09_E.VQA - ^Content/d2k/v2/Movies/O_FINL_E.VQA: O_FINL_E.VQA - ^Content/d2k/v2/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA - ^Content/d2k/v2/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA - ^Content/d2k/v2/Movies/G_INT1_E.VQA: G_INT1_E.VQA - ^Content/d2k/v2/Movies/G_INT2_E.VQA: G_INT2_E.VQA - ^Content/d2k/v2/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA - ^Content/d2k/v2/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA - ^Content/d2k/v2/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA - ^Content/d2k/v2/Movies/T_TITL_E.VQA: T_TITL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA: A_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR02_E.VQA: A_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR03_E.VQA: A_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR04_E.VQA: A_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR05_E.VQA: A_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR06_E.VQA: A_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR07_E.VQA: A_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR08_E.VQA: A_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR09_E.VQA: A_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_FINL_E.VQA: A_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR01_E.VQA: H_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR02_E.VQA: H_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR03_E.VQA: H_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR04_E.VQA: H_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR05_E.VQA: H_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR06_E.VQA: H_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR07_E.VQA: H_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR08_E.VQA: H_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR09_E.VQA: H_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_FINL_E.VQA: H_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR01_E.VQA: O_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR02_E.VQA: O_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR03_E.VQA: O_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR04_E.VQA: O_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR05_E.VQA: O_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR06_E.VQA: O_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR07_E.VQA: O_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR08_E.VQA: O_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR09_E.VQA: O_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_FINL_E.VQA: O_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_INT1_E.VQA: G_INT1_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_INT2_E.VQA: G_INT2_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA + ^SupportDir|Content/d2k/v2/Movies/T_TITL_E.VQA: T_TITL_E.VQA copy: MUSIC - ^Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD - ^Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD - ^Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD - ^Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD - ^Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD - ^Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD - ^Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD - ^Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD - ^Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD - ^Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD - ^Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD - ^Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD - ^Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD - ^Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD - ^Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD - ^Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD - ^Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD extract-blast: SETUP/SETUP.Z - ^Content/d2k/v2/BLOXBAT.R8: + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: Offset: 1156877 Length: 512750 - ^Content/d2k/v2/BLOXBASE.R8: + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: Offset: 1669627 Length: 497092 - ^Content/d2k/v2/BLOXBGBS.R8: + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: Offset: 4055448 Length: 499135 - ^Content/d2k/v2/BLOXICE.R8: + ^SupportDir|Content/d2k/v2/BLOXICE.R8: Offset: 5524734 Length: 514963 - ^Content/d2k/v2/BLOXTREE.R8: + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: Offset: 6994595 Length: 509867 - ^Content/d2k/v2/BLOXWAST.R8: + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: Offset: 8455243 Length: 508567 - ^Content/d2k/v2/MOUSE.R8: + ^SupportDir|Content/d2k/v2/MOUSE.R8: Offset: 14012716 Length: 16996 - ^Content/d2k/v2/PALETTE.BIN: + ^SupportDir|Content/d2k/v2/PALETTE.BIN: Offset: 22938626 Length: 815 - ^Content/d2k/v2/FONT.BIN: + ^SupportDir|Content/d2k/v2/FONT.BIN: Offset: 22927686 Length: 199 - ^Content/d2k/v2/FONTCOL.FNT: + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: Offset: 13985401 Length: 3011 - ^Content/d2k/v2/FONTCOL.FPL: + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: Offset: 13988412 Length: 238 - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: Offset: 15560530 Length: 9647 - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: Offset: 15570177 Length: 8676 - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: Offset: 15578853 Length: 9641 - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: Offset: 15588494 Length: 7371 - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: Offset: 15595865 Length: 11326 - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: Offset: 15607191 Length: 11329 - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: Offset: 15618520 Length: 8964 - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: Offset: 15627484 Length: 11336 - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: Offset: 15638820 Length: 14606 - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: Offset: 15653426 Length: 27230 - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: Offset: 15680656 Length: 19621 - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: Offset: 15700277 Length: 28781 - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: Offset: 15729058 Length: 29703 - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: Offset: 15758761 Length: 29555 - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: Offset: 15788316 Length: 27961 - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: Offset: 15816277 Length: 20925 - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: Offset: 15837202 Length: 10925 - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: Offset: 15848127 Length: 8125 - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: Offset: 15856252 Length: 26212 - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: Offset: 15882464 Length: 27166 - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: Offset: 15909630 Length: 31126 - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: Offset: 15940756 Length: 33481 - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: Offset: 15974237 Length: 17265 - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: Offset: 15991502 Length: 14523 - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: Offset: 16006025 Length: 18266 - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: Offset: 16024291 Length: 8467 - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: Offset: 16032758 Length: 9748 - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: Offset: 16042506 Length: 14264 - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: Offset: 16056770 Length: 12087 - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: Offset: 16068857 Length: 14428 - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: Offset: 16083285 Length: 16985 - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: Offset: 16100270 Length: 12638 - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: Offset: 16112908 Length: 13229 - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: Offset: 16126137 Length: 26572 - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: Offset: 16152709 Length: 12085 - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: Offset: 16164794 Length: 18232 - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: Offset: 16183026 Length: 8328 - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: Offset: 16191354 Length: 12497 - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: Offset: 16203851 Length: 9546 - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: Offset: 16213397 Length: 17135 - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: Offset: 16230532 Length: 26937 - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: Offset: 16257469 Length: 17940 - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: Offset: 16275409 Length: 14985 - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: Offset: 16290394 Length: 9089 - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: Offset: 16299483 Length: 28401 - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: Offset: 16327884 Length: 23949 - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: Offset: 16351833 Length: 29489 - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: Offset: 16381322 Length: 11016 - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: Offset: 16392338 Length: 27566 - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: Offset: 16419904 Length: 26539 - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: Offset: 16446443 Length: 30821 - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: Offset: 16477264 Length: 7978 - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: Offset: 16485242 Length: 11880 - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: Offset: 16497122 Length: 8995 - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: Offset: 16506117 Length: 10120 - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: Offset: 16516237 Length: 8999 - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: Offset: 16525236 Length: 6593 - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: Offset: 16531829 Length: 34790 - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: Offset: 16566619 Length: 35606 - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: Offset: 16602225 Length: 10303 - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: Offset: 16612528 Length: 22969 - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: Offset: 16635497 Length: 31816 - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: Offset: 16667313 Length: 19585 - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: Offset: 16686898 Length: 14563 - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: Offset: 16701461 Length: 13353 - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: Offset: 16714814 Length: 9671 - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: Offset: 16724485 Length: 15031 - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: Offset: 16739516 Length: 28368 - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: Offset: 16767884 Length: 9649 - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: Offset: 16777533 Length: 17157 - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: Offset: 16794690 Length: 13407 - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: Offset: 16808097 Length: 29910 - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: Offset: 16838007 Length: 22890 - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: Offset: 16860897 Length: 22923 - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: Offset: 16883820 Length: 34017 - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: Offset: 16917837 Length: 56714 - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: Offset: 16974551 Length: 27200 - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: Offset: 17001751 Length: 19828 - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: Offset: 17021579 Length: 13869 - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: Offset: 17035448 Length: 14197 - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: Offset: 17049645 Length: 29136 - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: Offset: 17078781 Length: 26204 - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: Offset: 17104985 Length: 24264 - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: Offset: 17129249 Length: 43921 - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: Offset: 17173170 Length: 22151 - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: Offset: 17195321 Length: 12300 - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: Offset: 17207621 Length: 21971 - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: Offset: 17229592 Length: 22041 - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: Offset: 17251633 Length: 21545 - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: Offset: 17273178 Length: 14344 - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: Offset: 17287522 Length: 28156 - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: Offset: 17315678 Length: 16983 - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: Offset: 17332661 Length: 19583 - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: Offset: 17352244 Length: 12875 - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: Offset: 17365119 Length: 20974 - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: Offset: 17386093 Length: 14699 - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: Offset: 17400792 Length: 20919 - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: Offset: 17421711 Length: 18984 - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: Offset: 17440695 Length: 11779 - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: Offset: 17452474 Length: 13980 - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: Offset: 17466454 Length: 33483 - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: Offset: 17499937 Length: 26566 - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: Offset: 17526503 Length: 25237 - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: Offset: 17551740 Length: 16072 - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: Offset: 17567812 Length: 12037 - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: Offset: 17579849 Length: 30243 - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: Offset: 17610092 Length: 31710 - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: Offset: 17641802 Length: 27450 - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: Offset: 17669252 Length: 30854 - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: Offset: 17700106 Length: 10860 - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: Offset: 17710966 Length: 19337 - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: Offset: 17730303 Length: 15004 - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: Offset: 17745307 Length: 23023 - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: Offset: 17768330 Length: 22321 - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: Offset: 17790651 Length: 21698 - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: Offset: 17812349 Length: 10282 - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: Offset: 17822631 Length: 28615 - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: Offset: 17851246 Length: 12771 - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: Offset: 17864017 Length: 9917 - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: Offset: 17873934 Length: 18502 - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: Offset: 17892436 Length: 12832 - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: Offset: 17905268 Length: 22413 - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: Offset: 17927681 Length: 29577 - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: Offset: 17957258 Length: 24798 - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: Offset: 17982056 Length: 14784 - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: Offset: 17996840 Length: 18526 - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: Offset: 18015366 Length: 12390 - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: Offset: 18027756 Length: 11851 - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: Offset: 18039607 Length: 9867 - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: Offset: 18049474 Length: 16907 - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: Offset: 18066381 Length: 17659 - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: Offset: 18084040 Length: 20337 - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: Offset: 18104377 Length: 18877 - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: Offset: 18123254 Length: 30788 - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: Offset: 18154042 Length: 18322 - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: Offset: 18172364 Length: 22178 - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: Offset: 18194542 Length: 24878 - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: Offset: 18219420 Length: 15741 - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: Offset: 18235161 Length: 14892 - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: Offset: 18250053 Length: 23026 - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: Offset: 18273079 Length: 43938 - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: Offset: 18317017 Length: 10992 - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: Offset: 18328009 Length: 19514 - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: Offset: 18347523 Length: 23895 - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: Offset: 18371418 Length: 18626 - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: Offset: 18390044 Length: 22564 - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: Offset: 18412608 Length: 18445 - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: Offset: 18431053 Length: 19492 - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: Offset: 18450545 Length: 14194 - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: Offset: 18464739 Length: 8310 - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: Offset: 18473049 Length: 8332 - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: Offset: 18481381 Length: 15789 - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: Offset: 18497170 Length: 9791 - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: Offset: 18506961 Length: 15099 - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: Offset: 18522060 Length: 14863 - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: Offset: 18536923 Length: 9753 - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: Offset: 18546676 Length: 9329 - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: Offset: 18556005 Length: 9449 - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: Offset: 18565454 Length: 15600 - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: Offset: 18581054 Length: 16157 - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: Offset: 18597211 Length: 13149 - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: Offset: 18610360 Length: 13928 - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: Offset: 18624288 Length: 16430 - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: Offset: 18640718 Length: 41640 - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: Offset: 18682358 Length: 41809 - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: Offset: 18724167 Length: 29117 - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: Offset: 18753284 Length: 36982 - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: Offset: 18790266 Length: 60681 - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: Offset: 18850947 Length: 21396 - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: Offset: 18872343 Length: 37995 - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: Offset: 18910338 Length: 32674 - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: Offset: 18943012 Length: 18399 - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: Offset: 18961411 Length: 26359 - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: Offset: 18987770 Length: 21335 - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: Offset: 19009105 Length: 28418 - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: Offset: 19037523 Length: 9269 - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: Offset: 19046792 Length: 19854 - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: Offset: 19066646 Length: 20038 - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: Offset: 19086684 Length: 16073 - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: Offset: 19102757 Length: 14873 - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: Offset: 19117630 Length: 41683 - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: Offset: 19159313 Length: 34475 - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: Offset: 19193788 Length: 34903 - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: Offset: 19228691 Length: 59613 - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: Offset: 19288304 Length: 22150 - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: Offset: 19310454 Length: 9090 - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: Offset: 19319544 Length: 21350 - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: Offset: 19340894 Length: 31478 - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: Offset: 19372372 Length: 19876 - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: Offset: 19392248 Length: 22359 - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: Offset: 19414607 Length: 28902 - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: Offset: 19443509 Length: 26855 - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: Offset: 19470364 Length: 19104 - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: Offset: 19489468 Length: 24655 - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: Offset: 19514123 Length: 23032 - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: Offset: 19537155 Length: 35588 - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: Offset: 19572743 Length: 8945 - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: Offset: 19581688 Length: 9005 - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: Offset: 19590693 Length: 9606 - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: Offset: 19600299 Length: 11671 - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: Offset: 19611970 Length: 10644 - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: Offset: 19622614 Length: 10387 - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: Offset: 19633001 Length: 17225 - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: Offset: 19650226 Length: 10077 - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: Offset: 19660303 Length: 13616 - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: Offset: 19673919 Length: 11251 - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: Offset: 19685170 Length: 8144 - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: Offset: 19693314 Length: 14865 - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: Offset: 19708179 Length: 11912 - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: Offset: 19720091 Length: 19540 - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: Offset: 19739631 Length: 10246 - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: Offset: 19749877 Length: 31148 - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: Offset: 19781025 Length: 8307 - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: Offset: 19789332 Length: 14331 - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: Offset: 19803663 Length: 11295 - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: Offset: 19814958 Length: 20437 - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: Offset: 19835395 Length: 27739 - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: Offset: 19863134 Length: 22200 - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: Offset: 19885334 Length: 9620 - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: Offset: 19894954 Length: 13368 - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: Offset: 19908322 Length: 15612 - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: Offset: 19923934 Length: 8279 - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: Offset: 19932213 Length: 11383 - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: Offset: 19943596 Length: 18511 - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: Offset: 19962107 Length: 14244 - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: Offset: 19976351 Length: 24075 - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: Offset: 20000426 Length: 26716 - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: Offset: 20027142 Length: 21716 - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: Offset: 20048858 Length: 32417 - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: Offset: 20081275 Length: 33724 - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: Offset: 20114999 Length: 21828 - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: Offset: 20136827 Length: 30404 - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: Offset: 20167231 Length: 9862 - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: Offset: 20177093 Length: 18149 - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: Offset: 20195242 Length: 14697 - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: Offset: 20209939 Length: 17316 - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: Offset: 20227255 Length: 14869 - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: Offset: 20242124 Length: 29873 - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: Offset: 20271997 Length: 16335 - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: Offset: 20288332 Length: 20565 - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: Offset: 20308897 Length: 25497 - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: Offset: 20334394 Length: 17142 - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: Offset: 20351536 Length: 20120 - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: Offset: 20371656 Length: 29921 - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: Offset: 20401577 Length: 14467 - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: Offset: 20416044 Length: 10906 - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: Offset: 20426950 Length: 25959 - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: Offset: 20452909 Length: 34175 - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: Offset: 20487084 Length: 30124 - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: Offset: 20517208 Length: 21881 - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: Offset: 20539089 Length: 20567 - ^Content/d2k/v2/SOUND.RS: + ^SupportDir|Content/d2k/v2/SOUND.RS: Offset: 20559656 Length: 1929247 d2k-b-linux: Dune 2000 (English) @@ -860,853 +860,853 @@ setup/setup.z: 029722e70fb7636f8120028f5c9b6ce81627ff90 Install: copy: movies - ^Content/d2k/v2/Movies/A_BR01_E.VQA: a_br01_e.vqa - ^Content/d2k/v2/Movies/A_BR02_E.VQA: a_br02_e.vqa - ^Content/d2k/v2/Movies/A_BR03_E.VQA: a_br03_e.vqa - ^Content/d2k/v2/Movies/A_BR04_E.VQA: a_br04_e.vqa - ^Content/d2k/v2/Movies/A_BR05_E.VQA: a_br05_e.vqa - ^Content/d2k/v2/Movies/A_BR06_E.VQA: a_br06_e.vqa - ^Content/d2k/v2/Movies/A_BR07_E.VQA: a_br07_e.vqa - ^Content/d2k/v2/Movies/A_BR08_E.VQA: a_br08_e.vqa - ^Content/d2k/v2/Movies/A_BR09_E.VQA: a_br09_e.vqa - ^Content/d2k/v2/Movies/A_FINL_E.VQA: a_finl_e.vqa - ^Content/d2k/v2/Movies/A_LOSE_E.VQA: a_lose_e.vqa - ^Content/d2k/v2/Movies/A_MNTG_E.VQA: a_mntg_e.vqa - ^Content/d2k/v2/Movies/H_BR01_E.VQA: h_br01_e.vqa - ^Content/d2k/v2/Movies/H_BR02_E.VQA: h_br02_e.vqa - ^Content/d2k/v2/Movies/H_BR03_E.VQA: h_br03_e.vqa - ^Content/d2k/v2/Movies/H_BR04_E.VQA: h_br04_e.vqa - ^Content/d2k/v2/Movies/H_BR05_E.VQA: h_br05_e.vqa - ^Content/d2k/v2/Movies/H_BR06_E.VQA: h_br06_e.vqa - ^Content/d2k/v2/Movies/H_BR07_E.VQA: h_br07_e.vqa - ^Content/d2k/v2/Movies/H_BR08_E.VQA: h_br08_e.vqa - ^Content/d2k/v2/Movies/H_BR09_E.VQA: h_br09_e.vqa - ^Content/d2k/v2/Movies/H_FINL_E.VQA: h_finl_e.vqa - ^Content/d2k/v2/Movies/H_LOSE_E.VQA: h_lose_e.vqa - ^Content/d2k/v2/Movies/H_MNTG_E.VQA: h_mntg_e.vqa - ^Content/d2k/v2/Movies/O_BR01_E.VQA: o_br01_e.vqa - ^Content/d2k/v2/Movies/O_BR02_E.VQA: o_br02_e.vqa - ^Content/d2k/v2/Movies/O_BR03_E.VQA: o_br03_e.vqa - ^Content/d2k/v2/Movies/O_BR04_E.VQA: o_br04_e.vqa - ^Content/d2k/v2/Movies/O_BR05_E.VQA: o_br05_e.vqa - ^Content/d2k/v2/Movies/O_BR06_E.VQA: o_br06_e.vqa - ^Content/d2k/v2/Movies/O_BR07_E.VQA: o_br07_e.vqa - ^Content/d2k/v2/Movies/O_BR08_E.VQA: o_br08_e.vqa - ^Content/d2k/v2/Movies/O_BR09_E.VQA: o_br09_e.vqa - ^Content/d2k/v2/Movies/O_FINL_E.VQA: o_finl_e.vqa - ^Content/d2k/v2/Movies/O_LOSE_E.VQA: o_lose_e.vqa - ^Content/d2k/v2/Movies/O_MNTG_E.VQA: o_mntg_e.vqa - ^Content/d2k/v2/Movies/G_INT1_E.VQA: g_int1_e.vqa - ^Content/d2k/v2/Movies/G_INT2_E.VQA: g_int2_e.vqa - ^Content/d2k/v2/Movies/G_MAPS_E.VQA: g_maps_e.vqa - ^Content/d2k/v2/Movies/G_PLN2_E.VQA: g_pln2_e.vqa - ^Content/d2k/v2/Movies/G_PLNT_E.VQA: g_plnt_e.vqa - ^Content/d2k/v2/Movies/T_TITL_E.VQA: t_titl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA: a_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR02_E.VQA: a_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR03_E.VQA: a_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR04_E.VQA: a_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR05_E.VQA: a_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR06_E.VQA: a_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR07_E.VQA: a_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR08_E.VQA: a_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR09_E.VQA: a_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_FINL_E.VQA: a_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_LOSE_E.VQA: a_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_MNTG_E.VQA: a_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR01_E.VQA: h_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR02_E.VQA: h_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR03_E.VQA: h_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR04_E.VQA: h_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR05_E.VQA: h_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR06_E.VQA: h_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR07_E.VQA: h_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR08_E.VQA: h_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR09_E.VQA: h_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_FINL_E.VQA: h_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_LOSE_E.VQA: h_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_MNTG_E.VQA: h_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR01_E.VQA: o_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR02_E.VQA: o_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR03_E.VQA: o_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR04_E.VQA: o_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR05_E.VQA: o_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR06_E.VQA: o_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR07_E.VQA: o_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR08_E.VQA: o_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR09_E.VQA: o_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_FINL_E.VQA: o_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_LOSE_E.VQA: o_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_MNTG_E.VQA: o_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_INT1_E.VQA: g_int1_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_INT2_E.VQA: g_int2_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_MAPS_E.VQA: g_maps_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_PLN2_E.VQA: g_pln2_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_PLNT_E.VQA: g_plnt_e.vqa + ^SupportDir|Content/d2k/v2/Movies/T_TITL_E.VQA: t_titl_e.vqa copy: music - ^Content/d2k/v2/Music/AMBUSH.AUD: ambush.aud - ^Content/d2k/v2/Music/ARAKATAK.AUD: arakatak.aud - ^Content/d2k/v2/Music/ATREGAIN.AUD: atregain.aud - ^Content/d2k/v2/Music/ENTORDOS.AUD: entordos.aud - ^Content/d2k/v2/Music/FIGHTPWR.AUD: fightpwr.aud - ^Content/d2k/v2/Music/FREMEN.AUD: fremen.aud - ^Content/d2k/v2/Music/HARK_BAT.AUD: hark_bat.aud - ^Content/d2k/v2/Music/LANDSAND.AUD: landsand.aud - ^Content/d2k/v2/Music/OPTIONS.AUD: options.aud - ^Content/d2k/v2/Music/PLOTTING.AUD: plotting.aud - ^Content/d2k/v2/Music/RISEHARK.AUD: risehark.aud - ^Content/d2k/v2/Music/ROBOTIX.AUD: robotix.aud - ^Content/d2k/v2/Music/SCORE.AUD: score.aud - ^Content/d2k/v2/Music/SOLDAPPR.AUD: soldappr.aud - ^Content/d2k/v2/Music/SPICESCT.AUD: spicesct.aud - ^Content/d2k/v2/Music/UNDERCON.AUD: undercon.aud - ^Content/d2k/v2/Music/WAITGAME.A: waitgame.aud + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: ambush.aud + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: arakatak.aud + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: atregain.aud + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: entordos.aud + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: fightpwr.aud + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: fremen.aud + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: hark_bat.aud + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: landsand.aud + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: options.aud + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: plotting.aud + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: risehark.aud + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: robotix.aud + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: score.aud + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: soldappr.aud + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: spicesct.aud + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: undercon.aud + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: waitgame.aud extract-blast: setup/setup.z - ^Content/d2k/v2/BLOXBAT.R8: + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: Offset: 1156877 Length: 512750 - ^Content/d2k/v2/BLOXBASE.R8: + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: Offset: 1669627 Length: 497092 - ^Content/d2k/v2/BLOXBGBS.R8: + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: Offset: 4055448 Length: 499135 - ^Content/d2k/v2/BLOXICE.R8: + ^SupportDir|Content/d2k/v2/BLOXICE.R8: Offset: 5524734 Length: 514963 - ^Content/d2k/v2/BLOXTREE.R8: + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: Offset: 6994595 Length: 509867 - ^Content/d2k/v2/BLOXWAST.R8: + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: Offset: 8455243 Length: 508567 - ^Content/d2k/v2/MOUSE.R8: + ^SupportDir|Content/d2k/v2/MOUSE.R8: Offset: 14012716 Length: 16996 - ^Content/d2k/v2/PALETTE.BIN: + ^SupportDir|Content/d2k/v2/PALETTE.BIN: Offset: 22938626 Length: 815 - ^Content/d2k/v2/FONT.BIN: + ^SupportDir|Content/d2k/v2/FONT.BIN: Offset: 22927686 Length: 199 - ^Content/d2k/v2/FONTCOL.FNT: + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: Offset: 13985401 Length: 3011 - ^Content/d2k/v2/FONTCOL.FPL: + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: Offset: 13988412 Length: 238 - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: Offset: 15560530 Length: 9647 - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: Offset: 15570177 Length: 8676 - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: Offset: 15578853 Length: 9641 - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: Offset: 15588494 Length: 7371 - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: Offset: 15595865 Length: 11326 - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: Offset: 15607191 Length: 11329 - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: Offset: 15618520 Length: 8964 - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: Offset: 15627484 Length: 11336 - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: Offset: 15638820 Length: 14606 - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: Offset: 15653426 Length: 27230 - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: Offset: 15680656 Length: 19621 - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: Offset: 15700277 Length: 28781 - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: Offset: 15729058 Length: 29703 - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: Offset: 15758761 Length: 29555 - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: Offset: 15788316 Length: 27961 - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: Offset: 15816277 Length: 20925 - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: Offset: 15837202 Length: 10925 - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: Offset: 15848127 Length: 8125 - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: Offset: 15856252 Length: 26212 - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: Offset: 15882464 Length: 27166 - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: Offset: 15909630 Length: 31126 - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: Offset: 15940756 Length: 33481 - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: Offset: 15974237 Length: 17265 - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: Offset: 15991502 Length: 14523 - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: Offset: 16006025 Length: 18266 - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: Offset: 16024291 Length: 8467 - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: Offset: 16032758 Length: 9748 - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: Offset: 16042506 Length: 14264 - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: Offset: 16056770 Length: 12087 - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: Offset: 16068857 Length: 14428 - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: Offset: 16083285 Length: 16985 - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: Offset: 16100270 Length: 12638 - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: Offset: 16112908 Length: 13229 - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: Offset: 16126137 Length: 26572 - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: Offset: 16152709 Length: 12085 - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: Offset: 16164794 Length: 18232 - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: Offset: 16183026 Length: 8328 - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: Offset: 16191354 Length: 12497 - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: Offset: 16203851 Length: 9546 - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: Offset: 16213397 Length: 17135 - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: Offset: 16230532 Length: 26937 - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: Offset: 16257469 Length: 17940 - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: Offset: 16275409 Length: 14985 - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: Offset: 16290394 Length: 9089 - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: Offset: 16299483 Length: 28401 - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: Offset: 16327884 Length: 23949 - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: Offset: 16351833 Length: 29489 - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: Offset: 16381322 Length: 11016 - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: Offset: 16392338 Length: 27566 - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: Offset: 16419904 Length: 26539 - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: Offset: 16446443 Length: 30821 - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: Offset: 16477264 Length: 7978 - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: Offset: 16485242 Length: 11880 - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: Offset: 16497122 Length: 8995 - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: Offset: 16506117 Length: 10120 - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: Offset: 16516237 Length: 8999 - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: Offset: 16525236 Length: 6593 - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: Offset: 16531829 Length: 34790 - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: Offset: 16566619 Length: 35606 - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: Offset: 16602225 Length: 10303 - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: Offset: 16612528 Length: 22969 - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: Offset: 16635497 Length: 31816 - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: Offset: 16667313 Length: 19585 - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: Offset: 16686898 Length: 14563 - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: Offset: 16701461 Length: 13353 - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: Offset: 16714814 Length: 9671 - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: Offset: 16724485 Length: 15031 - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: Offset: 16739516 Length: 28368 - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: Offset: 16767884 Length: 9649 - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: Offset: 16777533 Length: 17157 - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: Offset: 16794690 Length: 13407 - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: Offset: 16808097 Length: 29910 - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: Offset: 16838007 Length: 22890 - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: Offset: 16860897 Length: 22923 - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: Offset: 16883820 Length: 34017 - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: Offset: 16917837 Length: 56714 - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: Offset: 16974551 Length: 27200 - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: Offset: 17001751 Length: 19828 - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: Offset: 17021579 Length: 13869 - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: Offset: 17035448 Length: 14197 - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: Offset: 17049645 Length: 29136 - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: Offset: 17078781 Length: 26204 - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: Offset: 17104985 Length: 24264 - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: Offset: 17129249 Length: 43921 - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: Offset: 17173170 Length: 22151 - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: Offset: 17195321 Length: 12300 - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: Offset: 17207621 Length: 21971 - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: Offset: 17229592 Length: 22041 - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: Offset: 17251633 Length: 21545 - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: Offset: 17273178 Length: 14344 - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: Offset: 17287522 Length: 28156 - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: Offset: 17315678 Length: 16983 - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: Offset: 17332661 Length: 19583 - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: Offset: 17352244 Length: 12875 - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: Offset: 17365119 Length: 20974 - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: Offset: 17386093 Length: 14699 - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: Offset: 17400792 Length: 20919 - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: Offset: 17421711 Length: 18984 - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: Offset: 17440695 Length: 11779 - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: Offset: 17452474 Length: 13980 - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: Offset: 17466454 Length: 33483 - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: Offset: 17499937 Length: 26566 - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: Offset: 17526503 Length: 25237 - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: Offset: 17551740 Length: 16072 - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: Offset: 17567812 Length: 12037 - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: Offset: 17579849 Length: 30243 - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: Offset: 17610092 Length: 31710 - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: Offset: 17641802 Length: 27450 - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: Offset: 17669252 Length: 30854 - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: Offset: 17700106 Length: 10860 - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: Offset: 17710966 Length: 19337 - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: Offset: 17730303 Length: 15004 - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: Offset: 17745307 Length: 23023 - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: Offset: 17768330 Length: 22321 - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: Offset: 17790651 Length: 21698 - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: Offset: 17812349 Length: 10282 - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: Offset: 17822631 Length: 28615 - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: Offset: 17851246 Length: 12771 - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: Offset: 17864017 Length: 9917 - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: Offset: 17873934 Length: 18502 - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: Offset: 17892436 Length: 12832 - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: Offset: 17905268 Length: 22413 - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: Offset: 17927681 Length: 29577 - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: Offset: 17957258 Length: 24798 - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: Offset: 17982056 Length: 14784 - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: Offset: 17996840 Length: 18526 - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: Offset: 18015366 Length: 12390 - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: Offset: 18027756 Length: 11851 - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: Offset: 18039607 Length: 9867 - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: Offset: 18049474 Length: 16907 - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: Offset: 18066381 Length: 17659 - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: Offset: 18084040 Length: 20337 - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: Offset: 18104377 Length: 18877 - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: Offset: 18123254 Length: 30788 - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: Offset: 18154042 Length: 18322 - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: Offset: 18172364 Length: 22178 - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: Offset: 18194542 Length: 24878 - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: Offset: 18219420 Length: 15741 - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: Offset: 18235161 Length: 14892 - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: Offset: 18250053 Length: 23026 - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: Offset: 18273079 Length: 43938 - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: Offset: 18317017 Length: 10992 - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: Offset: 18328009 Length: 19514 - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: Offset: 18347523 Length: 23895 - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: Offset: 18371418 Length: 18626 - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: Offset: 18390044 Length: 22564 - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: Offset: 18412608 Length: 18445 - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: Offset: 18431053 Length: 19492 - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: Offset: 18450545 Length: 14194 - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: Offset: 18464739 Length: 8310 - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: Offset: 18473049 Length: 8332 - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: Offset: 18481381 Length: 15789 - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: Offset: 18497170 Length: 9791 - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: Offset: 18506961 Length: 15099 - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: Offset: 18522060 Length: 14863 - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: Offset: 18536923 Length: 9753 - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: Offset: 18546676 Length: 9329 - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: Offset: 18556005 Length: 9449 - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: Offset: 18565454 Length: 15600 - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: Offset: 18581054 Length: 16157 - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: Offset: 18597211 Length: 13149 - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: Offset: 18610360 Length: 13928 - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: Offset: 18624288 Length: 16430 - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: Offset: 18640718 Length: 41640 - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: Offset: 18682358 Length: 41809 - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: Offset: 18724167 Length: 29117 - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: Offset: 18753284 Length: 36982 - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: Offset: 18790266 Length: 60681 - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: Offset: 18850947 Length: 21396 - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: Offset: 18872343 Length: 37995 - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: Offset: 18910338 Length: 32674 - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: Offset: 18943012 Length: 18399 - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: Offset: 18961411 Length: 26359 - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: Offset: 18987770 Length: 21335 - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: Offset: 19009105 Length: 28418 - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: Offset: 19037523 Length: 9269 - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: Offset: 19046792 Length: 19854 - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: Offset: 19066646 Length: 20038 - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: Offset: 19086684 Length: 16073 - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: Offset: 19102757 Length: 14873 - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: Offset: 19117630 Length: 41683 - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: Offset: 19159313 Length: 34475 - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: Offset: 19193788 Length: 34903 - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: Offset: 19228691 Length: 59613 - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: Offset: 19288304 Length: 22150 - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: Offset: 19310454 Length: 9090 - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: Offset: 19319544 Length: 21350 - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: Offset: 19340894 Length: 31478 - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: Offset: 19372372 Length: 19876 - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: Offset: 19392248 Length: 22359 - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: Offset: 19414607 Length: 28902 - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: Offset: 19443509 Length: 26855 - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: Offset: 19470364 Length: 19104 - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: Offset: 19489468 Length: 24655 - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: Offset: 19514123 Length: 23032 - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: Offset: 19537155 Length: 35588 - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: Offset: 19572743 Length: 8945 - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: Offset: 19581688 Length: 9005 - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: Offset: 19590693 Length: 9606 - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: Offset: 19600299 Length: 11671 - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: Offset: 19611970 Length: 10644 - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: Offset: 19622614 Length: 10387 - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: Offset: 19633001 Length: 17225 - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: Offset: 19650226 Length: 10077 - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: Offset: 19660303 Length: 13616 - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: Offset: 19673919 Length: 11251 - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: Offset: 19685170 Length: 8144 - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: Offset: 19693314 Length: 14865 - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: Offset: 19708179 Length: 11912 - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: Offset: 19720091 Length: 19540 - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: Offset: 19739631 Length: 10246 - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: Offset: 19749877 Length: 31148 - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: Offset: 19781025 Length: 8307 - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: Offset: 19789332 Length: 14331 - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: Offset: 19803663 Length: 11295 - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: Offset: 19814958 Length: 20437 - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: Offset: 19835395 Length: 27739 - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: Offset: 19863134 Length: 22200 - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: Offset: 19885334 Length: 9620 - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: Offset: 19894954 Length: 13368 - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: Offset: 19908322 Length: 15612 - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: Offset: 19923934 Length: 8279 - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: Offset: 19932213 Length: 11383 - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: Offset: 19943596 Length: 18511 - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: Offset: 19962107 Length: 14244 - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: Offset: 19976351 Length: 24075 - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: Offset: 20000426 Length: 26716 - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: Offset: 20027142 Length: 21716 - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: Offset: 20048858 Length: 32417 - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: Offset: 20081275 Length: 33724 - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: Offset: 20114999 Length: 21828 - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: Offset: 20136827 Length: 30404 - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: Offset: 20167231 Length: 9862 - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: Offset: 20177093 Length: 18149 - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: Offset: 20195242 Length: 14697 - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: Offset: 20209939 Length: 17316 - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: Offset: 20227255 Length: 14869 - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: Offset: 20242124 Length: 29873 - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: Offset: 20271997 Length: 16335 - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: Offset: 20288332 Length: 20565 - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: Offset: 20308897 Length: 25497 - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: Offset: 20334394 Length: 17142 - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: Offset: 20351536 Length: 20120 - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: Offset: 20371656 Length: 29921 - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: Offset: 20401577 Length: 14467 - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: Offset: 20416044 Length: 10906 - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: Offset: 20426950 Length: 25959 - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: Offset: 20452909 Length: 34175 - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: Offset: 20487084 Length: 30124 - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: Offset: 20517208 Length: 21881 - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: Offset: 20539089 Length: 20567 - ^Content/d2k/v2/SOUND.RS: + ^SupportDir|Content/d2k/v2/SOUND.RS: Offset: 20559656 Length: 1929247 \ No newline at end of file diff -Nru openra-20200503/mods/d2k/installer/d2k-c.yaml openra-20210321/mods/d2k/installer/d2k-c.yaml --- openra-20200503/mods/d2k/installer/d2k-c.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/installer/d2k-c.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,854 +4,854 @@ SETUP/SETUP.Z: d939b39bdbc952b259ce2b45c0bbedefa534b7f2 Install: copy: MOVIES - ^Content/d2k/v2/Movies/A_BR01_E.VQA: A_BR01_E.VQA - ^Content/d2k/v2/Movies/A_BR02_E.VQA: A_BR02_E.VQA - ^Content/d2k/v2/Movies/A_BR03_E.VQA: A_BR03_E.VQA - ^Content/d2k/v2/Movies/A_BR04_E.VQA: A_BR04_E.VQA - ^Content/d2k/v2/Movies/A_BR05_E.VQA: A_BR05_E.VQA - ^Content/d2k/v2/Movies/A_BR06_E.VQA: A_BR06_E.VQA - ^Content/d2k/v2/Movies/A_BR07_E.VQA: A_BR07_E.VQA - ^Content/d2k/v2/Movies/A_BR08_E.VQA: A_BR08_E.VQA - ^Content/d2k/v2/Movies/A_BR09_E.VQA: A_BR09_E.VQA - ^Content/d2k/v2/Movies/A_FINL_E.VQA: A_FINL_E.VQA - ^Content/d2k/v2/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA - ^Content/d2k/v2/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA - ^Content/d2k/v2/Movies/H_BR01_E.VQA: H_BR01_E.VQA - ^Content/d2k/v2/Movies/H_BR02_E.VQA: H_BR02_E.VQA - ^Content/d2k/v2/Movies/H_BR03_E.VQA: H_BR03_E.VQA - ^Content/d2k/v2/Movies/H_BR04_E.VQA: H_BR04_E.VQA - ^Content/d2k/v2/Movies/H_BR05_E.VQA: H_BR05_E.VQA - ^Content/d2k/v2/Movies/H_BR06_E.VQA: H_BR06_E.VQA - ^Content/d2k/v2/Movies/H_BR07_E.VQA: H_BR07_E.VQA - ^Content/d2k/v2/Movies/H_BR08_E.VQA: H_BR08_E.VQA - ^Content/d2k/v2/Movies/H_BR09_E.VQA: H_BR09_E.VQA - ^Content/d2k/v2/Movies/H_FINL_E.VQA: H_FINL_E.VQA - ^Content/d2k/v2/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA - ^Content/d2k/v2/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA - ^Content/d2k/v2/Movies/O_BR01_E.VQA: O_BR01_E.VQA - ^Content/d2k/v2/Movies/O_BR02_E.VQA: O_BR02_E.VQA - ^Content/d2k/v2/Movies/O_BR03_E.VQA: O_BR03_E.VQA - ^Content/d2k/v2/Movies/O_BR04_E.VQA: O_BR04_E.VQA - ^Content/d2k/v2/Movies/O_BR05_E.VQA: O_BR05_E.VQA - ^Content/d2k/v2/Movies/O_BR06_E.VQA: O_BR06_E.VQA - ^Content/d2k/v2/Movies/O_BR07_E.VQA: O_BR07_E.VQA - ^Content/d2k/v2/Movies/O_BR08_E.VQA: O_BR08_E.VQA - ^Content/d2k/v2/Movies/O_BR09_E.VQA: O_BR09_E.VQA - ^Content/d2k/v2/Movies/O_FINL_E.VQA: O_FINL_E.VQA - ^Content/d2k/v2/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA - ^Content/d2k/v2/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA - ^Content/d2k/v2/Movies/G_INT1_E.VQA: G_INT1_E.VQA - ^Content/d2k/v2/Movies/G_INT2_E.VQA: G_INT2_E.VQA - ^Content/d2k/v2/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA - ^Content/d2k/v2/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA - ^Content/d2k/v2/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA - ^Content/d2k/v2/Movies/T_TITL_E.VQA: T_TITL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA: A_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR02_E.VQA: A_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR03_E.VQA: A_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR04_E.VQA: A_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR05_E.VQA: A_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR06_E.VQA: A_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR07_E.VQA: A_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR08_E.VQA: A_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR09_E.VQA: A_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_FINL_E.VQA: A_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR01_E.VQA: H_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR02_E.VQA: H_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR03_E.VQA: H_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR04_E.VQA: H_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR05_E.VQA: H_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR06_E.VQA: H_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR07_E.VQA: H_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR08_E.VQA: H_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR09_E.VQA: H_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_FINL_E.VQA: H_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR01_E.VQA: O_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR02_E.VQA: O_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR03_E.VQA: O_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR04_E.VQA: O_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR05_E.VQA: O_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR06_E.VQA: O_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR07_E.VQA: O_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR08_E.VQA: O_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR09_E.VQA: O_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_FINL_E.VQA: O_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_INT1_E.VQA: G_INT1_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_INT2_E.VQA: G_INT2_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA + ^SupportDir|Content/d2k/v2/Movies/T_TITL_E.VQA: T_TITL_E.VQA copy: MUSIC - ^Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD - ^Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD - ^Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD - ^Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD - ^Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD - ^Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD - ^Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD - ^Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD - ^Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD - ^Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD - ^Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD - ^Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD - ^Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD - ^Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD - ^Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD - ^Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD - ^Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD extract-blast: SETUP/SETUP.Z - ^Content/d2k/v2/BLOXBAT.R8: + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: Offset: 704502 Length: 512750 - ^Content/d2k/v2/BLOXBASE.R8: + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: Offset: 1217252 Length: 497092 - ^Content/d2k/v2/BLOXBGBS.R8: + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: Offset: 3603073 Length: 499135 - ^Content/d2k/v2/BLOXICE.R8: + ^SupportDir|Content/d2k/v2/BLOXICE.R8: Offset: 5072359 Length: 514963 - ^Content/d2k/v2/BLOXTREE.R8: + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: Offset: 6542220 Length: 509867 - ^Content/d2k/v2/BLOXWAST.R8: + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: Offset: 8002868 Length: 508567 - ^Content/d2k/v2/FONTCOL.FNT: + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: Offset: 13533026 Length: 3011 - ^Content/d2k/v2/FONTCOL.FPL: + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: Offset: 13536037 Length: 238 - ^Content/d2k/v2/MOUSE.R8: + ^SupportDir|Content/d2k/v2/MOUSE.R8: Offset: 13560341 Length: 16996 - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: Offset: 15108155 Length: 9647 - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: Offset: 15117802 Length: 8676 - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: Offset: 15126478 Length: 9641 - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: Offset: 15136119 Length: 7371 - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: Offset: 15143490 Length: 11326 - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: Offset: 15154816 Length: 11329 - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: Offset: 15166145 Length: 8964 - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: Offset: 15175109 Length: 11336 - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: Offset: 15186445 Length: 14606 - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: Offset: 15201051 Length: 27230 - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: Offset: 15228281 Length: 19621 - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: Offset: 15247902 Length: 28781 - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: Offset: 15276683 Length: 29703 - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: Offset: 15306386 Length: 29555 - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: Offset: 15335941 Length: 27961 - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: Offset: 15363902 Length: 20925 - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: Offset: 15384827 Length: 10925 - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: Offset: 15395752 Length: 8125 - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: Offset: 15403877 Length: 26212 - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: Offset: 15430089 Length: 27166 - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: Offset: 15457255 Length: 31126 - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: Offset: 15488381 Length: 33481 - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: Offset: 15521862 Length: 17265 - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: Offset: 15539127 Length: 14523 - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: Offset: 15553650 Length: 18266 - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: Offset: 15571916 Length: 8467 - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: Offset: 15580383 Length: 9748 - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: Offset: 15590131 Length: 14264 - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: Offset: 15604395 Length: 12087 - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: Offset: 15616482 Length: 14428 - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: Offset: 15630910 Length: 16985 - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: Offset: 15647895 Length: 12638 - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: Offset: 15660533 Length: 13229 - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: Offset: 15673762 Length: 26572 - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: Offset: 15700334 Length: 12085 - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: Offset: 15712419 Length: 18232 - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: Offset: 15730651 Length: 8328 - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: Offset: 15738979 Length: 12497 - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: Offset: 15751476 Length: 9546 - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: Offset: 15761022 Length: 17135 - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: Offset: 15778157 Length: 26937 - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: Offset: 15805094 Length: 17940 - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: Offset: 15823034 Length: 14985 - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: Offset: 15838019 Length: 9089 - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: Offset: 15847108 Length: 28401 - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: Offset: 15875509 Length: 23949 - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: Offset: 15899458 Length: 29489 - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: Offset: 15928947 Length: 11016 - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: Offset: 15939963 Length: 27566 - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: Offset: 15967529 Length: 26539 - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: Offset: 15994068 Length: 30821 - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: Offset: 16024889 Length: 7978 - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: Offset: 16032867 Length: 11880 - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: Offset: 16044747 Length: 8995 - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: Offset: 16053742 Length: 10120 - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: Offset: 16063862 Length: 8999 - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: Offset: 16072861 Length: 6593 - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: Offset: 16079454 Length: 34790 - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: Offset: 16114244 Length: 35606 - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: Offset: 16149850 Length: 10303 - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: Offset: 16160153 Length: 22969 - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: Offset: 16183122 Length: 31816 - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: Offset: 16214938 Length: 19585 - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: Offset: 16234523 Length: 14563 - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: Offset: 16249086 Length: 13353 - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: Offset: 16262439 Length: 9671 - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: Offset: 16272110 Length: 15031 - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: Offset: 16287141 Length: 28368 - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: Offset: 16315509 Length: 9649 - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: Offset: 16325158 Length: 17157 - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: Offset: 16342315 Length: 13407 - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: Offset: 16355722 Length: 29910 - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: Offset: 16385632 Length: 22890 - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: Offset: 16408522 Length: 22923 - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: Offset: 16431445 Length: 34017 - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: Offset: 16465462 Length: 56714 - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: Offset: 16522176 Length: 27200 - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: Offset: 16549376 Length: 19828 - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: Offset: 16569204 Length: 13869 - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: Offset: 16583073 Length: 14197 - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: Offset: 16597270 Length: 29136 - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: Offset: 16626406 Length: 26204 - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: Offset: 16652610 Length: 24264 - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: Offset: 16676874 Length: 43921 - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: Offset: 16720795 Length: 22151 - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: Offset: 16742946 Length: 12300 - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: Offset: 16755246 Length: 21971 - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: Offset: 16777217 Length: 22041 - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: Offset: 16799258 Length: 21545 - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: Offset: 16820803 Length: 14344 - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: Offset: 16835147 Length: 28156 - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: Offset: 16863303 Length: 16983 - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: Offset: 16880286 Length: 19583 - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: Offset: 16899869 Length: 12875 - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: Offset: 16912744 Length: 20974 - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: Offset: 16933718 Length: 14699 - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: Offset: 16948417 Length: 20919 - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: Offset: 16969336 Length: 18984 - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: Offset: 16988320 Length: 11779 - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: Offset: 17000099 Length: 13980 - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: Offset: 17014079 Length: 33483 - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: Offset: 17047562 Length: 26566 - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: Offset: 17074128 Length: 25237 - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: Offset: 17099365 Length: 16072 - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: Offset: 17115437 Length: 12037 - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: Offset: 17127474 Length: 30243 - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: Offset: 17157717 Length: 31710 - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: Offset: 17189427 Length: 27450 - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: Offset: 17216877 Length: 30854 - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: Offset: 17247731 Length: 10860 - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: Offset: 17258591 Length: 19337 - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: Offset: 17277928 Length: 15004 - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: Offset: 17292932 Length: 23023 - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: Offset: 17315955 Length: 22321 - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: Offset: 17338276 Length: 21698 - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: Offset: 17359974 Length: 10282 - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: Offset: 17370256 Length: 28615 - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: Offset: 17398871 Length: 12771 - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: Offset: 17411642 Length: 9917 - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: Offset: 17421559 Length: 18502 - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: Offset: 17440061 Length: 12832 - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: Offset: 17452893 Length: 22413 - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: Offset: 17475306 Length: 29577 - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: Offset: 17504883 Length: 24798 - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: Offset: 17529681 Length: 14784 - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: Offset: 17544465 Length: 18526 - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: Offset: 17562991 Length: 12390 - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: Offset: 17575381 Length: 11851 - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: Offset: 17587232 Length: 9867 - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: Offset: 17597099 Length: 16907 - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: Offset: 17614006 Length: 17659 - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: Offset: 17631665 Length: 20337 - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: Offset: 17652002 Length: 18877 - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: Offset: 17670879 Length: 30788 - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: Offset: 17701667 Length: 18322 - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: Offset: 17719989 Length: 22178 - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: Offset: 17742167 Length: 24878 - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: Offset: 17767045 Length: 15741 - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: Offset: 17782786 Length: 14892 - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: Offset: 17797678 Length: 23026 - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: Offset: 17820704 Length: 43938 - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: Offset: 17864642 Length: 10992 - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: Offset: 17875634 Length: 19514 - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: Offset: 17895148 Length: 23895 - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: Offset: 17919043 Length: 18626 - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: Offset: 17937669 Length: 22564 - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: Offset: 17960233 Length: 18445 - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: Offset: 17978678 Length: 19492 - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: Offset: 17998170 Length: 14194 - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: Offset: 18012364 Length: 8310 - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: Offset: 18020674 Length: 8332 - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: Offset: 18029006 Length: 15789 - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: Offset: 18044795 Length: 9791 - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: Offset: 18054586 Length: 15099 - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: Offset: 18069685 Length: 14863 - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: Offset: 18084548 Length: 9753 - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: Offset: 18094301 Length: 9329 - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: Offset: 18103630 Length: 9449 - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: Offset: 18113079 Length: 15600 - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: Offset: 18128679 Length: 16157 - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: Offset: 18144836 Length: 13149 - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: Offset: 18157985 Length: 13928 - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: Offset: 18171913 Length: 16430 - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: Offset: 18188343 Length: 41640 - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: Offset: 18229983 Length: 41809 - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: Offset: 18271792 Length: 29117 - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: Offset: 18300909 Length: 36982 - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: Offset: 18337891 Length: 60681 - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: Offset: 18398572 Length: 21396 - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: Offset: 18419968 Length: 37995 - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: Offset: 18457963 Length: 32674 - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: Offset: 18490637 Length: 18399 - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: Offset: 18509036 Length: 26359 - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: Offset: 18535395 Length: 21335 - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: Offset: 18556730 Length: 28418 - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: Offset: 18585148 Length: 9269 - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: Offset: 18594417 Length: 19854 - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: Offset: 18614271 Length: 20038 - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: Offset: 18634309 Length: 16073 - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: Offset: 18650382 Length: 14873 - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: Offset: 18665255 Length: 41683 - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: Offset: 18706938 Length: 34475 - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: Offset: 18741413 Length: 34903 - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: Offset: 18776316 Length: 59613 - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: Offset: 18835929 Length: 22150 - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: Offset: 18858079 Length: 9090 - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: Offset: 18867169 Length: 21350 - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: Offset: 18888519 Length: 31478 - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: Offset: 18919997 Length: 19876 - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: Offset: 18939873 Length: 22359 - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: Offset: 18962232 Length: 28902 - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: Offset: 18991134 Length: 26855 - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: Offset: 19017989 Length: 19104 - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: Offset: 19037093 Length: 24655 - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: Offset: 19061748 Length: 23032 - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: Offset: 19084780 Length: 35588 - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: Offset: 19120368 Length: 8945 - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: Offset: 19129313 Length: 9005 - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: Offset: 19138318 Length: 9606 - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: Offset: 19147924 Length: 11671 - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: Offset: 19159595 Length: 10644 - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: Offset: 19170239 Length: 10387 - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: Offset: 19180626 Length: 17225 - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: Offset: 19197851 Length: 10077 - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: Offset: 19207928 Length: 13616 - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: Offset: 19221544 Length: 11251 - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: Offset: 19232795 Length: 8144 - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: Offset: 19240939 Length: 14865 - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: Offset: 19255804 Length: 11912 - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: Offset: 19267716 Length: 19540 - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: Offset: 19287256 Length: 10246 - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: Offset: 19297502 Length: 31148 - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: Offset: 19328650 Length: 8307 - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: Offset: 19336957 Length: 14331 - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: Offset: 19351288 Length: 11295 - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: Offset: 19362583 Length: 20437 - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: Offset: 19383020 Length: 27739 - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: Offset: 19410759 Length: 22200 - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: Offset: 19432959 Length: 9620 - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: Offset: 19442579 Length: 13368 - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: Offset: 19455947 Length: 15612 - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: Offset: 19471559 Length: 8279 - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: Offset: 19479838 Length: 11383 - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: Offset: 19491221 Length: 18511 - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: Offset: 19509732 Length: 14244 - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: Offset: 19523976 Length: 24075 - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: Offset: 19548051 Length: 26716 - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: Offset: 19574767 Length: 21716 - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: Offset: 19596483 Length: 32417 - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: Offset: 19628900 Length: 33724 - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: Offset: 19662624 Length: 21828 - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: Offset: 19684452 Length: 30404 - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: Offset: 19714856 Length: 9862 - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: Offset: 19724718 Length: 18149 - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: Offset: 19742867 Length: 14697 - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: Offset: 19757564 Length: 17316 - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: Offset: 19774880 Length: 14869 - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: Offset: 19789749 Length: 29873 - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: Offset: 19819622 Length: 16335 - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: Offset: 19835957 Length: 20565 - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: Offset: 19856522 Length: 25497 - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: Offset: 19882019 Length: 17142 - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: Offset: 19899161 Length: 20120 - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: Offset: 19919281 Length: 29921 - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: Offset: 19949202 Length: 14467 - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: Offset: 19963669 Length: 10906 - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: Offset: 19974575 Length: 25959 - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: Offset: 20000534 Length: 34175 - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: Offset: 20034709 Length: 30124 - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: Offset: 20064833 Length: 21881 - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: Offset: 20086714 Length: 20567 - ^Content/d2k/v2/SOUND.RS: + ^SupportDir|Content/d2k/v2/SOUND.RS: Offset: 20107281 Length: 1929247 - ^Content/d2k/v2/FONT.BIN: + ^SupportDir|Content/d2k/v2/FONT.BIN: Offset: 22475311 Length: 199 - ^Content/d2k/v2/PALETTE.BIN: + ^SupportDir|Content/d2k/v2/PALETTE.BIN: Offset: 22486251 Length: 815 d2k-c-linux: Dune 2000 (English) @@ -860,853 +860,853 @@ setup/setup.z: d939b39bdbc952b259ce2b45c0bbedefa534b7f2 Install: copy: movies - ^Content/d2k/v2/Movies/A_BR01_E.VQA: a_br01_e.vqa - ^Content/d2k/v2/Movies/A_BR02_E.VQA: a_br02_e.vqa - ^Content/d2k/v2/Movies/A_BR03_E.VQA: a_br03_e.vqa - ^Content/d2k/v2/Movies/A_BR04_E.VQA: a_br04_e.vqa - ^Content/d2k/v2/Movies/A_BR05_E.VQA: a_br05_e.vqa - ^Content/d2k/v2/Movies/A_BR06_E.VQA: a_br06_e.vqa - ^Content/d2k/v2/Movies/A_BR07_E.VQA: a_br07_e.vqa - ^Content/d2k/v2/Movies/A_BR08_E.VQA: a_br08_e.vqa - ^Content/d2k/v2/Movies/A_BR09_E.VQA: a_br09_e.vqa - ^Content/d2k/v2/Movies/A_FINL_E.VQA: a_finl_e.vqa - ^Content/d2k/v2/Movies/A_LOSE_E.VQA: a_lose_e.vqa - ^Content/d2k/v2/Movies/A_MNTG_E.VQA: a_mntg_e.vqa - ^Content/d2k/v2/Movies/H_BR01_E.VQA: h_br01_e.vqa - ^Content/d2k/v2/Movies/H_BR02_E.VQA: h_br02_e.vqa - ^Content/d2k/v2/Movies/H_BR03_E.VQA: h_br03_e.vqa - ^Content/d2k/v2/Movies/H_BR04_E.VQA: h_br04_e.vqa - ^Content/d2k/v2/Movies/H_BR05_E.VQA: h_br05_e.vqa - ^Content/d2k/v2/Movies/H_BR06_E.VQA: h_br06_e.vqa - ^Content/d2k/v2/Movies/H_BR07_E.VQA: h_br07_e.vqa - ^Content/d2k/v2/Movies/H_BR08_E.VQA: h_br08_e.vqa - ^Content/d2k/v2/Movies/H_BR09_E.VQA: h_br09_e.vqa - ^Content/d2k/v2/Movies/H_FINL_E.VQA: h_finl_e.vqa - ^Content/d2k/v2/Movies/H_LOSE_E.VQA: h_lose_e.vqa - ^Content/d2k/v2/Movies/H_MNTG_E.VQA: h_mntg_e.vqa - ^Content/d2k/v2/Movies/O_BR01_E.VQA: o_br01_e.vqa - ^Content/d2k/v2/Movies/O_BR02_E.VQA: o_br02_e.vqa - ^Content/d2k/v2/Movies/O_BR03_E.VQA: o_br03_e.vqa - ^Content/d2k/v2/Movies/O_BR04_E.VQA: o_br04_e.vqa - ^Content/d2k/v2/Movies/O_BR05_E.VQA: o_br05_e.vqa - ^Content/d2k/v2/Movies/O_BR06_E.VQA: o_br06_e.vqa - ^Content/d2k/v2/Movies/O_BR07_E.VQA: o_br07_e.vqa - ^Content/d2k/v2/Movies/O_BR08_E.VQA: o_br08_e.vqa - ^Content/d2k/v2/Movies/O_BR09_E.VQA: o_br09_e.vqa - ^Content/d2k/v2/Movies/O_FINL_E.VQA: o_finl_e.vqa - ^Content/d2k/v2/Movies/O_LOSE_E.VQA: o_lose_e.vqa - ^Content/d2k/v2/Movies/O_MNTG_E.VQA: o_mntg_e.vqa - ^Content/d2k/v2/Movies/G_INT1_E.VQA: g_int1_e.vqa - ^Content/d2k/v2/Movies/G_INT2_E.VQA: g_int2_e.vqa - ^Content/d2k/v2/Movies/G_MAPS_E.VQA: g_maps_e.vqa - ^Content/d2k/v2/Movies/G_PLN2_E.VQA: g_pln2_e.vqa - ^Content/d2k/v2/Movies/G_PLNT_E.VQA: g_plnt_e.vqa - ^Content/d2k/v2/Movies/T_TITL_E.VQA: t_titl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA: a_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR02_E.VQA: a_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR03_E.VQA: a_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR04_E.VQA: a_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR05_E.VQA: a_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR06_E.VQA: a_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR07_E.VQA: a_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR08_E.VQA: a_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR09_E.VQA: a_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_FINL_E.VQA: a_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_LOSE_E.VQA: a_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_MNTG_E.VQA: a_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR01_E.VQA: h_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR02_E.VQA: h_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR03_E.VQA: h_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR04_E.VQA: h_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR05_E.VQA: h_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR06_E.VQA: h_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR07_E.VQA: h_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR08_E.VQA: h_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR09_E.VQA: h_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_FINL_E.VQA: h_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_LOSE_E.VQA: h_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_MNTG_E.VQA: h_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR01_E.VQA: o_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR02_E.VQA: o_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR03_E.VQA: o_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR04_E.VQA: o_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR05_E.VQA: o_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR06_E.VQA: o_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR07_E.VQA: o_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR08_E.VQA: o_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR09_E.VQA: o_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_FINL_E.VQA: o_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_LOSE_E.VQA: o_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_MNTG_E.VQA: o_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_INT1_E.VQA: g_int1_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_INT2_E.VQA: g_int2_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_MAPS_E.VQA: g_maps_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_PLN2_E.VQA: g_pln2_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_PLNT_E.VQA: g_plnt_e.vqa + ^SupportDir|Content/d2k/v2/Movies/T_TITL_E.VQA: t_titl_e.vqa copy: music - ^Content/d2k/v2/Music/AMBUSH.AUD: ambush.aud - ^Content/d2k/v2/Music/ARAKATAK.AUD: arakatak.aud - ^Content/d2k/v2/Music/ATREGAIN.AUD: atregain.aud - ^Content/d2k/v2/Music/ENTORDOS.AUD: entordos.aud - ^Content/d2k/v2/Music/FIGHTPWR.AUD: fightpwr.aud - ^Content/d2k/v2/Music/FREMEN.AUD: fremen.aud - ^Content/d2k/v2/Music/HARK_BAT.AUD: hark_bat.aud - ^Content/d2k/v2/Music/LANDSAND.AUD: landsand.aud - ^Content/d2k/v2/Music/OPTIONS.AUD: options.aud - ^Content/d2k/v2/Music/PLOTTING.AUD: plotting.aud - ^Content/d2k/v2/Music/RISEHARK.AUD: risehark.aud - ^Content/d2k/v2/Music/ROBOTIX.AUD: robotix.aud - ^Content/d2k/v2/Music/SCORE.AUD: score.aud - ^Content/d2k/v2/Music/SOLDAPPR.AUD: soldappr.aud - ^Content/d2k/v2/Music/SPICESCT.AUD: spicesct.aud - ^Content/d2k/v2/Music/UNDERCON.AUD: undercon.aud - ^Content/d2k/v2/Music/WAITGAME.A: waitgame.aud + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: ambush.aud + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: arakatak.aud + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: atregain.aud + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: entordos.aud + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: fightpwr.aud + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: fremen.aud + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: hark_bat.aud + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: landsand.aud + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: options.aud + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: plotting.aud + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: risehark.aud + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: robotix.aud + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: score.aud + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: soldappr.aud + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: spicesct.aud + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: undercon.aud + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: waitgame.aud extract-blast: setup/setup.z - ^Content/d2k/v2/BLOXBAT.R8: + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: Offset: 704502 Length: 512750 - ^Content/d2k/v2/BLOXBASE.R8: + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: Offset: 1217252 Length: 497092 - ^Content/d2k/v2/BLOXBGBS.R8: + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: Offset: 3603073 Length: 499135 - ^Content/d2k/v2/BLOXICE.R8: + ^SupportDir|Content/d2k/v2/BLOXICE.R8: Offset: 5072359 Length: 514963 - ^Content/d2k/v2/BLOXTREE.R8: + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: Offset: 6542220 Length: 509867 - ^Content/d2k/v2/BLOXWAST.R8: + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: Offset: 8002868 Length: 508567 - ^Content/d2k/v2/FONTCOL.FNT: + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: Offset: 13533026 Length: 3011 - ^Content/d2k/v2/FONTCOL.FPL: + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: Offset: 13536037 Length: 238 - ^Content/d2k/v2/MOUSE.R8: + ^SupportDir|Content/d2k/v2/MOUSE.R8: Offset: 13560341 Length: 16996 - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: Offset: 15108155 Length: 9647 - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: Offset: 15117802 Length: 8676 - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: Offset: 15126478 Length: 9641 - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: Offset: 15136119 Length: 7371 - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: Offset: 15143490 Length: 11326 - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: Offset: 15154816 Length: 11329 - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: Offset: 15166145 Length: 8964 - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: Offset: 15175109 Length: 11336 - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: Offset: 15186445 Length: 14606 - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: Offset: 15201051 Length: 27230 - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: Offset: 15228281 Length: 19621 - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: Offset: 15247902 Length: 28781 - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: Offset: 15276683 Length: 29703 - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: Offset: 15306386 Length: 29555 - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: Offset: 15335941 Length: 27961 - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: Offset: 15363902 Length: 20925 - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: Offset: 15384827 Length: 10925 - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: Offset: 15395752 Length: 8125 - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: Offset: 15403877 Length: 26212 - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: Offset: 15430089 Length: 27166 - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: Offset: 15457255 Length: 31126 - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: Offset: 15488381 Length: 33481 - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: Offset: 15521862 Length: 17265 - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: Offset: 15539127 Length: 14523 - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: Offset: 15553650 Length: 18266 - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: Offset: 15571916 Length: 8467 - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: Offset: 15580383 Length: 9748 - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: Offset: 15590131 Length: 14264 - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: Offset: 15604395 Length: 12087 - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: Offset: 15616482 Length: 14428 - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: Offset: 15630910 Length: 16985 - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: Offset: 15647895 Length: 12638 - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: Offset: 15660533 Length: 13229 - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: Offset: 15673762 Length: 26572 - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: Offset: 15700334 Length: 12085 - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: Offset: 15712419 Length: 18232 - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: Offset: 15730651 Length: 8328 - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: Offset: 15738979 Length: 12497 - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: Offset: 15751476 Length: 9546 - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: Offset: 15761022 Length: 17135 - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: Offset: 15778157 Length: 26937 - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: Offset: 15805094 Length: 17940 - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: Offset: 15823034 Length: 14985 - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: Offset: 15838019 Length: 9089 - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: Offset: 15847108 Length: 28401 - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: Offset: 15875509 Length: 23949 - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: Offset: 15899458 Length: 29489 - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: Offset: 15928947 Length: 11016 - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: Offset: 15939963 Length: 27566 - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: Offset: 15967529 Length: 26539 - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: Offset: 15994068 Length: 30821 - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: Offset: 16024889 Length: 7978 - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: Offset: 16032867 Length: 11880 - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: Offset: 16044747 Length: 8995 - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: Offset: 16053742 Length: 10120 - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: Offset: 16063862 Length: 8999 - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: Offset: 16072861 Length: 6593 - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: Offset: 16079454 Length: 34790 - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: Offset: 16114244 Length: 35606 - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: Offset: 16149850 Length: 10303 - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: Offset: 16160153 Length: 22969 - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: Offset: 16183122 Length: 31816 - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: Offset: 16214938 Length: 19585 - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: Offset: 16234523 Length: 14563 - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: Offset: 16249086 Length: 13353 - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: Offset: 16262439 Length: 9671 - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: Offset: 16272110 Length: 15031 - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: Offset: 16287141 Length: 28368 - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: Offset: 16315509 Length: 9649 - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: Offset: 16325158 Length: 17157 - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: Offset: 16342315 Length: 13407 - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: Offset: 16355722 Length: 29910 - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: Offset: 16385632 Length: 22890 - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: Offset: 16408522 Length: 22923 - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: Offset: 16431445 Length: 34017 - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: Offset: 16465462 Length: 56714 - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: Offset: 16522176 Length: 27200 - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: Offset: 16549376 Length: 19828 - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: Offset: 16569204 Length: 13869 - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: Offset: 16583073 Length: 14197 - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: Offset: 16597270 Length: 29136 - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: Offset: 16626406 Length: 26204 - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: Offset: 16652610 Length: 24264 - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: Offset: 16676874 Length: 43921 - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: Offset: 16720795 Length: 22151 - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: Offset: 16742946 Length: 12300 - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: Offset: 16755246 Length: 21971 - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: Offset: 16777217 Length: 22041 - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: Offset: 16799258 Length: 21545 - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: Offset: 16820803 Length: 14344 - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: Offset: 16835147 Length: 28156 - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: Offset: 16863303 Length: 16983 - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: Offset: 16880286 Length: 19583 - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: Offset: 16899869 Length: 12875 - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: Offset: 16912744 Length: 20974 - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: Offset: 16933718 Length: 14699 - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: Offset: 16948417 Length: 20919 - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: Offset: 16969336 Length: 18984 - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: Offset: 16988320 Length: 11779 - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: Offset: 17000099 Length: 13980 - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: Offset: 17014079 Length: 33483 - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: Offset: 17047562 Length: 26566 - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: Offset: 17074128 Length: 25237 - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: Offset: 17099365 Length: 16072 - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: Offset: 17115437 Length: 12037 - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: Offset: 17127474 Length: 30243 - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: Offset: 17157717 Length: 31710 - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: Offset: 17189427 Length: 27450 - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: Offset: 17216877 Length: 30854 - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: Offset: 17247731 Length: 10860 - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: Offset: 17258591 Length: 19337 - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: Offset: 17277928 Length: 15004 - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: Offset: 17292932 Length: 23023 - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: Offset: 17315955 Length: 22321 - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: Offset: 17338276 Length: 21698 - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: Offset: 17359974 Length: 10282 - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: Offset: 17370256 Length: 28615 - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: Offset: 17398871 Length: 12771 - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: Offset: 17411642 Length: 9917 - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: Offset: 17421559 Length: 18502 - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: Offset: 17440061 Length: 12832 - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: Offset: 17452893 Length: 22413 - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: Offset: 17475306 Length: 29577 - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: Offset: 17504883 Length: 24798 - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: Offset: 17529681 Length: 14784 - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: Offset: 17544465 Length: 18526 - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: Offset: 17562991 Length: 12390 - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: Offset: 17575381 Length: 11851 - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: Offset: 17587232 Length: 9867 - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: Offset: 17597099 Length: 16907 - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: Offset: 17614006 Length: 17659 - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: Offset: 17631665 Length: 20337 - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: Offset: 17652002 Length: 18877 - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: Offset: 17670879 Length: 30788 - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: Offset: 17701667 Length: 18322 - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: Offset: 17719989 Length: 22178 - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: Offset: 17742167 Length: 24878 - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: Offset: 17767045 Length: 15741 - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: Offset: 17782786 Length: 14892 - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: Offset: 17797678 Length: 23026 - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: Offset: 17820704 Length: 43938 - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: Offset: 17864642 Length: 10992 - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: Offset: 17875634 Length: 19514 - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: Offset: 17895148 Length: 23895 - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: Offset: 17919043 Length: 18626 - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: Offset: 17937669 Length: 22564 - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: Offset: 17960233 Length: 18445 - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: Offset: 17978678 Length: 19492 - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: Offset: 17998170 Length: 14194 - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: Offset: 18012364 Length: 8310 - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: Offset: 18020674 Length: 8332 - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: Offset: 18029006 Length: 15789 - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: Offset: 18044795 Length: 9791 - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: Offset: 18054586 Length: 15099 - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: Offset: 18069685 Length: 14863 - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: Offset: 18084548 Length: 9753 - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: Offset: 18094301 Length: 9329 - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: Offset: 18103630 Length: 9449 - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: Offset: 18113079 Length: 15600 - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: Offset: 18128679 Length: 16157 - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: Offset: 18144836 Length: 13149 - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: Offset: 18157985 Length: 13928 - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: Offset: 18171913 Length: 16430 - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: Offset: 18188343 Length: 41640 - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: Offset: 18229983 Length: 41809 - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: Offset: 18271792 Length: 29117 - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: Offset: 18300909 Length: 36982 - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: Offset: 18337891 Length: 60681 - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: Offset: 18398572 Length: 21396 - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: Offset: 18419968 Length: 37995 - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: Offset: 18457963 Length: 32674 - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: Offset: 18490637 Length: 18399 - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: Offset: 18509036 Length: 26359 - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: Offset: 18535395 Length: 21335 - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: Offset: 18556730 Length: 28418 - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: Offset: 18585148 Length: 9269 - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: Offset: 18594417 Length: 19854 - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: Offset: 18614271 Length: 20038 - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: Offset: 18634309 Length: 16073 - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: Offset: 18650382 Length: 14873 - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: Offset: 18665255 Length: 41683 - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: Offset: 18706938 Length: 34475 - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: Offset: 18741413 Length: 34903 - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: Offset: 18776316 Length: 59613 - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: Offset: 18835929 Length: 22150 - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: Offset: 18858079 Length: 9090 - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: Offset: 18867169 Length: 21350 - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: Offset: 18888519 Length: 31478 - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: Offset: 18919997 Length: 19876 - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: Offset: 18939873 Length: 22359 - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: Offset: 18962232 Length: 28902 - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: Offset: 18991134 Length: 26855 - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: Offset: 19017989 Length: 19104 - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: Offset: 19037093 Length: 24655 - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: Offset: 19061748 Length: 23032 - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: Offset: 19084780 Length: 35588 - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: Offset: 19120368 Length: 8945 - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: Offset: 19129313 Length: 9005 - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: Offset: 19138318 Length: 9606 - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: Offset: 19147924 Length: 11671 - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: Offset: 19159595 Length: 10644 - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: Offset: 19170239 Length: 10387 - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: Offset: 19180626 Length: 17225 - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: Offset: 19197851 Length: 10077 - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: Offset: 19207928 Length: 13616 - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: Offset: 19221544 Length: 11251 - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: Offset: 19232795 Length: 8144 - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: Offset: 19240939 Length: 14865 - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: Offset: 19255804 Length: 11912 - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: Offset: 19267716 Length: 19540 - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: Offset: 19287256 Length: 10246 - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: Offset: 19297502 Length: 31148 - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: Offset: 19328650 Length: 8307 - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: Offset: 19336957 Length: 14331 - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: Offset: 19351288 Length: 11295 - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: Offset: 19362583 Length: 20437 - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: Offset: 19383020 Length: 27739 - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: Offset: 19410759 Length: 22200 - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: Offset: 19432959 Length: 9620 - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: Offset: 19442579 Length: 13368 - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: Offset: 19455947 Length: 15612 - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: Offset: 19471559 Length: 8279 - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: Offset: 19479838 Length: 11383 - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: Offset: 19491221 Length: 18511 - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: Offset: 19509732 Length: 14244 - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: Offset: 19523976 Length: 24075 - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: Offset: 19548051 Length: 26716 - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: Offset: 19574767 Length: 21716 - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: Offset: 19596483 Length: 32417 - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: Offset: 19628900 Length: 33724 - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: Offset: 19662624 Length: 21828 - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: Offset: 19684452 Length: 30404 - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: Offset: 19714856 Length: 9862 - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: Offset: 19724718 Length: 18149 - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: Offset: 19742867 Length: 14697 - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: Offset: 19757564 Length: 17316 - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: Offset: 19774880 Length: 14869 - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: Offset: 19789749 Length: 29873 - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: Offset: 19819622 Length: 16335 - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: Offset: 19835957 Length: 20565 - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: Offset: 19856522 Length: 25497 - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: Offset: 19882019 Length: 17142 - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: Offset: 19899161 Length: 20120 - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: Offset: 19919281 Length: 29921 - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: Offset: 19949202 Length: 14467 - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: Offset: 19963669 Length: 10906 - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: Offset: 19974575 Length: 25959 - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: Offset: 20000534 Length: 34175 - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: Offset: 20034709 Length: 30124 - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: Offset: 20064833 Length: 21881 - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: Offset: 20086714 Length: 20567 - ^Content/d2k/v2/SOUND.RS: + ^SupportDir|Content/d2k/v2/SOUND.RS: Offset: 20107281 Length: 1929247 - ^Content/d2k/v2/FONT.BIN: + ^SupportDir|Content/d2k/v2/FONT.BIN: Offset: 22475311 Length: 199 - ^Content/d2k/v2/PALETTE.BIN: + ^SupportDir|Content/d2k/v2/PALETTE.BIN: Offset: 22486251 Length: 815 \ No newline at end of file diff -Nru openra-20200503/mods/d2k/installer/d2k-d.yaml openra-20210321/mods/d2k/installer/d2k-d.yaml --- openra-20200503/mods/d2k/installer/d2k-d.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/installer/d2k-d.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,854 +4,854 @@ SETUP/SETUP.Z: 2411cc5df36954ebd534ceafa3007c8aa9232909 Install: copy: MOVIES - ^Content/d2k/v2/Movies/A_BR01_E.VQA: A_BR01_E.VQA - ^Content/d2k/v2/Movies/A_BR02_E.VQA: A_BR02_E.VQA - ^Content/d2k/v2/Movies/A_BR03_E.VQA: A_BR03_E.VQA - ^Content/d2k/v2/Movies/A_BR04_E.VQA: A_BR04_E.VQA - ^Content/d2k/v2/Movies/A_BR05_E.VQA: A_BR05_E.VQA - ^Content/d2k/v2/Movies/A_BR06_E.VQA: A_BR06_E.VQA - ^Content/d2k/v2/Movies/A_BR07_E.VQA: A_BR07_E.VQA - ^Content/d2k/v2/Movies/A_BR08_E.VQA: A_BR08_E.VQA - ^Content/d2k/v2/Movies/A_BR09_E.VQA: A_BR09_E.VQA - ^Content/d2k/v2/Movies/A_FINL_E.VQA: A_FINL_E.VQA - ^Content/d2k/v2/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA - ^Content/d2k/v2/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA - ^Content/d2k/v2/Movies/H_BR01_E.VQA: H_BR01_E.VQA - ^Content/d2k/v2/Movies/H_BR02_E.VQA: H_BR02_E.VQA - ^Content/d2k/v2/Movies/H_BR03_E.VQA: H_BR03_E.VQA - ^Content/d2k/v2/Movies/H_BR04_E.VQA: H_BR04_E.VQA - ^Content/d2k/v2/Movies/H_BR05_E.VQA: H_BR05_E.VQA - ^Content/d2k/v2/Movies/H_BR06_E.VQA: H_BR06_E.VQA - ^Content/d2k/v2/Movies/H_BR07_E.VQA: H_BR07_E.VQA - ^Content/d2k/v2/Movies/H_BR08_E.VQA: H_BR08_E.VQA - ^Content/d2k/v2/Movies/H_BR09_E.VQA: H_BR09_E.VQA - ^Content/d2k/v2/Movies/H_FINL_E.VQA: H_FINL_E.VQA - ^Content/d2k/v2/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA - ^Content/d2k/v2/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA - ^Content/d2k/v2/Movies/O_BR01_E.VQA: O_BR01_E.VQA - ^Content/d2k/v2/Movies/O_BR02_E.VQA: O_BR02_E.VQA - ^Content/d2k/v2/Movies/O_BR03_E.VQA: O_BR03_E.VQA - ^Content/d2k/v2/Movies/O_BR04_E.VQA: O_BR04_E.VQA - ^Content/d2k/v2/Movies/O_BR05_E.VQA: O_BR05_E.VQA - ^Content/d2k/v2/Movies/O_BR06_E.VQA: O_BR06_E.VQA - ^Content/d2k/v2/Movies/O_BR07_E.VQA: O_BR07_E.VQA - ^Content/d2k/v2/Movies/O_BR08_E.VQA: O_BR08_E.VQA - ^Content/d2k/v2/Movies/O_BR09_E.VQA: O_BR09_E.VQA - ^Content/d2k/v2/Movies/O_FINL_E.VQA: O_FINL_E.VQA - ^Content/d2k/v2/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA - ^Content/d2k/v2/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA - ^Content/d2k/v2/Movies/G_INT1_E.VQA: G_INT1_E.VQA - ^Content/d2k/v2/Movies/G_INT2_E.VQA: G_INT2_E.VQA - ^Content/d2k/v2/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA - ^Content/d2k/v2/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA - ^Content/d2k/v2/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA - ^Content/d2k/v2/Movies/T_TITL_E.VQA: T_TITL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA: A_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR02_E.VQA: A_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR03_E.VQA: A_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR04_E.VQA: A_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR05_E.VQA: A_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR06_E.VQA: A_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR07_E.VQA: A_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR08_E.VQA: A_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR09_E.VQA: A_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_FINL_E.VQA: A_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR01_E.VQA: H_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR02_E.VQA: H_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR03_E.VQA: H_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR04_E.VQA: H_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR05_E.VQA: H_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR06_E.VQA: H_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR07_E.VQA: H_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR08_E.VQA: H_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR09_E.VQA: H_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_FINL_E.VQA: H_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR01_E.VQA: O_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR02_E.VQA: O_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR03_E.VQA: O_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR04_E.VQA: O_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR05_E.VQA: O_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR06_E.VQA: O_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR07_E.VQA: O_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR08_E.VQA: O_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR09_E.VQA: O_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_FINL_E.VQA: O_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_INT1_E.VQA: G_INT1_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_INT2_E.VQA: G_INT2_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA + ^SupportDir|Content/d2k/v2/Movies/T_TITL_E.VQA: T_TITL_E.VQA copy: MUSIC - ^Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD - ^Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD - ^Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD - ^Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD - ^Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD - ^Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD - ^Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD - ^Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD - ^Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD - ^Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD - ^Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD - ^Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD - ^Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD - ^Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD - ^Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD - ^Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD - ^Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD extract-blast: SETUP/SETUP.Z - ^Content/d2k/v2/BLOXBAT.R8: + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: Offset: 702406 Length: 512750 - ^Content/d2k/v2/BLOXBASE.R8: + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: Offset: 1215156 Length: 497092 - ^Content/d2k/v2/BLOXBGBS.R8: + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: Offset: 3600977 Length: 499135 - ^Content/d2k/v2/BLOXICE.R8: + ^SupportDir|Content/d2k/v2/BLOXICE.R8: Offset: 5070263 Length: 514963 - ^Content/d2k/v2/BLOXTREE.R8: + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: Offset: 6540124 Length: 509867 - ^Content/d2k/v2/BLOXWAST.R8: + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: Offset: 8000772 Length: 508567 - ^Content/d2k/v2/FONTCOL.FNT: + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: Offset: 13530930 Length: 3011 - ^Content/d2k/v2/FONTCOL.FPL: + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: Offset: 13533941 Length: 238 - ^Content/d2k/v2/MOUSE.R8: + ^SupportDir|Content/d2k/v2/MOUSE.R8: Offset: 13558245 Length: 16996 - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: Offset: 15106059 Length: 9647 - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: Offset: 15115706 Length: 8676 - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: Offset: 15124382 Length: 9641 - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: Offset: 15134023 Length: 7371 - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: Offset: 15141394 Length: 11326 - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: Offset: 15152720 Length: 11329 - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: Offset: 15164049 Length: 8964 - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: Offset: 15173013 Length: 11336 - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: Offset: 15184349 Length: 14606 - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: Offset: 15198955 Length: 27230 - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: Offset: 15226185 Length: 19621 - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: Offset: 15245806 Length: 28781 - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: Offset: 15274587 Length: 29703 - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: Offset: 15304290 Length: 29555 - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: Offset: 15333845 Length: 27961 - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: Offset: 15361806 Length: 20925 - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: Offset: 15382731 Length: 10925 - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: Offset: 15393656 Length: 8125 - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: Offset: 15401781 Length: 26212 - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: Offset: 15427993 Length: 27166 - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: Offset: 15455159 Length: 31126 - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: Offset: 15486285 Length: 33481 - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: Offset: 15519766 Length: 17265 - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: Offset: 15537031 Length: 14523 - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: Offset: 15551554 Length: 18266 - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: Offset: 15569820 Length: 8467 - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: Offset: 15578287 Length: 9748 - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: Offset: 15588035 Length: 14264 - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: Offset: 15602299 Length: 12087 - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: Offset: 15614386 Length: 14428 - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: Offset: 15628814 Length: 16985 - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: Offset: 15645799 Length: 12638 - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: Offset: 15658437 Length: 13229 - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: Offset: 15671666 Length: 26572 - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: Offset: 15698238 Length: 12085 - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: Offset: 15710323 Length: 18232 - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: Offset: 15728555 Length: 8328 - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: Offset: 15736883 Length: 12497 - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: Offset: 15749380 Length: 9546 - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: Offset: 15758926 Length: 17135 - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: Offset: 15776061 Length: 26937 - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: Offset: 15802998 Length: 17940 - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: Offset: 15820938 Length: 14985 - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: Offset: 15835923 Length: 9089 - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: Offset: 15845012 Length: 28401 - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: Offset: 15873413 Length: 23949 - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: Offset: 15897362 Length: 29489 - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: Offset: 15926851 Length: 11016 - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: Offset: 15937867 Length: 27566 - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: Offset: 15965433 Length: 26539 - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: Offset: 15991972 Length: 30821 - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: Offset: 16022793 Length: 7978 - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: Offset: 16030771 Length: 11880 - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: Offset: 16042651 Length: 8995 - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: Offset: 16051646 Length: 10120 - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: Offset: 16061766 Length: 8999 - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: Offset: 16070765 Length: 6593 - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: Offset: 16077358 Length: 34790 - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: Offset: 16112148 Length: 35606 - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: Offset: 16147754 Length: 10303 - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: Offset: 16158057 Length: 22969 - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: Offset: 16181026 Length: 31816 - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: Offset: 16212842 Length: 19585 - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: Offset: 16232427 Length: 14563 - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: Offset: 16246990 Length: 13353 - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: Offset: 16260343 Length: 9671 - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: Offset: 16270014 Length: 15031 - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: Offset: 16285045 Length: 28368 - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: Offset: 16313413 Length: 9649 - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: Offset: 16323062 Length: 17157 - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: Offset: 16340219 Length: 13407 - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: Offset: 16353626 Length: 29910 - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: Offset: 16383536 Length: 22890 - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: Offset: 16406426 Length: 22923 - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: Offset: 16429349 Length: 34017 - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: Offset: 16463366 Length: 56714 - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: Offset: 16520080 Length: 27200 - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: Offset: 16547280 Length: 19828 - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: Offset: 16567108 Length: 13869 - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: Offset: 16580977 Length: 14197 - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: Offset: 16595174 Length: 29136 - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: Offset: 16624310 Length: 26204 - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: Offset: 16650514 Length: 24264 - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: Offset: 16674778 Length: 43921 - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: Offset: 16718699 Length: 22151 - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: Offset: 16740850 Length: 12300 - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: Offset: 16753150 Length: 21971 - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: Offset: 16775121 Length: 22041 - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: Offset: 16797162 Length: 21545 - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: Offset: 16818707 Length: 14344 - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: Offset: 16833051 Length: 28156 - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: Offset: 16861207 Length: 16983 - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: Offset: 16878190 Length: 19583 - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: Offset: 16897773 Length: 12875 - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: Offset: 16910648 Length: 20974 - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: Offset: 16931622 Length: 14699 - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: Offset: 16946321 Length: 20919 - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: Offset: 16967240 Length: 18984 - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: Offset: 16986224 Length: 11779 - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: Offset: 16998003 Length: 13980 - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: Offset: 17011983 Length: 33483 - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: Offset: 17045466 Length: 26566 - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: Offset: 17072032 Length: 25237 - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: Offset: 17097269 Length: 16072 - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: Offset: 17113341 Length: 12037 - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: Offset: 17125378 Length: 30243 - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: Offset: 17155621 Length: 31710 - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: Offset: 17187331 Length: 27450 - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: Offset: 17214781 Length: 30854 - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: Offset: 17245635 Length: 10860 - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: Offset: 17256495 Length: 19337 - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: Offset: 17275832 Length: 15004 - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: Offset: 17290836 Length: 23023 - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: Offset: 17313859 Length: 22321 - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: Offset: 17336180 Length: 21698 - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: Offset: 17357878 Length: 10282 - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: Offset: 17368160 Length: 28615 - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: Offset: 17396775 Length: 12771 - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: Offset: 17409546 Length: 9917 - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: Offset: 17419463 Length: 18502 - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: Offset: 17437965 Length: 12832 - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: Offset: 17450797 Length: 22413 - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: Offset: 17473210 Length: 29577 - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: Offset: 17502787 Length: 24798 - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: Offset: 17527585 Length: 14784 - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: Offset: 17542369 Length: 18526 - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: Offset: 17560895 Length: 12390 - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: Offset: 17573285 Length: 11851 - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: Offset: 17585136 Length: 9867 - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: Offset: 17595003 Length: 16907 - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: Offset: 17611910 Length: 17659 - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: Offset: 17629569 Length: 20337 - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: Offset: 17649906 Length: 18877 - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: Offset: 17668783 Length: 30788 - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: Offset: 17699571 Length: 18322 - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: Offset: 17717893 Length: 22178 - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: Offset: 17740071 Length: 24878 - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: Offset: 17764949 Length: 15741 - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: Offset: 17780690 Length: 14892 - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: Offset: 17795582 Length: 23026 - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: Offset: 17818608 Length: 43938 - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: Offset: 17862546 Length: 10992 - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: Offset: 17873538 Length: 19514 - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: Offset: 17893052 Length: 23895 - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: Offset: 17916947 Length: 18626 - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: Offset: 17935573 Length: 22564 - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: Offset: 17958137 Length: 18445 - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: Offset: 17976582 Length: 19492 - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: Offset: 17996074 Length: 14194 - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: Offset: 18010268 Length: 8310 - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: Offset: 18018578 Length: 8332 - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: Offset: 18026910 Length: 15789 - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: Offset: 18042699 Length: 9791 - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: Offset: 18052490 Length: 15099 - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: Offset: 18067589 Length: 14863 - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: Offset: 18082452 Length: 9753 - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: Offset: 18092205 Length: 9329 - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: Offset: 18101534 Length: 9449 - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: Offset: 18110983 Length: 15600 - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: Offset: 18126583 Length: 16157 - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: Offset: 18142740 Length: 13149 - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: Offset: 18155889 Length: 13928 - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: Offset: 18169817 Length: 16430 - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: Offset: 18186247 Length: 41640 - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: Offset: 18227887 Length: 41809 - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: Offset: 18269696 Length: 29117 - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: Offset: 18298813 Length: 36982 - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: Offset: 18335795 Length: 60681 - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: Offset: 18396476 Length: 21396 - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: Offset: 18417872 Length: 37995 - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: Offset: 18455867 Length: 32674 - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: Offset: 18488541 Length: 18399 - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: Offset: 18506940 Length: 26359 - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: Offset: 18533299 Length: 21335 - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: Offset: 18554634 Length: 28418 - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: Offset: 18583052 Length: 9269 - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: Offset: 18592321 Length: 19854 - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: Offset: 18612175 Length: 20038 - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: Offset: 18632213 Length: 16073 - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: Offset: 18648286 Length: 14873 - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: Offset: 18663159 Length: 41683 - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: Offset: 18704842 Length: 34475 - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: Offset: 18739317 Length: 34903 - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: Offset: 18774220 Length: 59613 - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: Offset: 18833833 Length: 22150 - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: Offset: 18855983 Length: 9090 - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: Offset: 18865073 Length: 21350 - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: Offset: 18886423 Length: 31478 - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: Offset: 18917901 Length: 19876 - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: Offset: 18937777 Length: 22359 - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: Offset: 18960136 Length: 28902 - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: Offset: 18989038 Length: 26855 - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: Offset: 19015893 Length: 19104 - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: Offset: 19034997 Length: 24655 - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: Offset: 19059652 Length: 23032 - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: Offset: 19082684 Length: 35588 - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: Offset: 19118272 Length: 8945 - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: Offset: 19127217 Length: 9005 - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: Offset: 19136222 Length: 9606 - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: Offset: 19145828 Length: 11671 - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: Offset: 19157499 Length: 10644 - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: Offset: 19168143 Length: 10387 - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: Offset: 19178530 Length: 17225 - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: Offset: 19195755 Length: 10077 - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: Offset: 19205832 Length: 13616 - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: Offset: 19219448 Length: 11251 - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: Offset: 19230699 Length: 8144 - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: Offset: 19238843 Length: 14865 - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: Offset: 19253708 Length: 11912 - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: Offset: 19265620 Length: 19540 - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: Offset: 19285160 Length: 10246 - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: Offset: 19295406 Length: 31148 - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: Offset: 19326554 Length: 8307 - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: Offset: 19334861 Length: 14331 - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: Offset: 19349192 Length: 11295 - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: Offset: 19360487 Length: 20437 - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: Offset: 19380924 Length: 27739 - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: Offset: 19408663 Length: 22200 - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: Offset: 19430863 Length: 9620 - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: Offset: 19440483 Length: 13368 - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: Offset: 19453851 Length: 15612 - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: Offset: 19469463 Length: 8279 - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: Offset: 19477742 Length: 11383 - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: Offset: 19489125 Length: 18511 - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: Offset: 19507636 Length: 14244 - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: Offset: 19521880 Length: 24075 - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: Offset: 19545955 Length: 26716 - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: Offset: 19572671 Length: 21716 - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: Offset: 19594387 Length: 32417 - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: Offset: 19626804 Length: 33724 - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: Offset: 19660528 Length: 21828 - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: Offset: 19682356 Length: 30404 - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: Offset: 19712760 Length: 9862 - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: Offset: 19722622 Length: 18149 - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: Offset: 19740771 Length: 14697 - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: Offset: 19755468 Length: 17316 - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: Offset: 19772784 Length: 14869 - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: Offset: 19787653 Length: 29873 - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: Offset: 19817526 Length: 16335 - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: Offset: 19833861 Length: 20565 - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: Offset: 19854426 Length: 25497 - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: Offset: 19879923 Length: 17142 - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: Offset: 19897065 Length: 20120 - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: Offset: 19917185 Length: 29921 - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: Offset: 19947106 Length: 14467 - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: Offset: 19961573 Length: 10906 - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: Offset: 19972479 Length: 25959 - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: Offset: 19998438 Length: 34175 - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: Offset: 20032613 Length: 30124 - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: Offset: 20062737 Length: 21881 - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: Offset: 20084618 Length: 20567 - ^Content/d2k/v2/SOUND.RS: + ^SupportDir|Content/d2k/v2/SOUND.RS: Offset: 20105185 Length: 1929247 - ^Content/d2k/v2/FONT.BIN: + ^SupportDir|Content/d2k/v2/FONT.BIN: Offset: 22473215 Length: 199 - ^Content/d2k/v2/PALETTE.BIN: + ^SupportDir|Content/d2k/v2/PALETTE.BIN: Offset: 22484155 Length: 815 d2k-d-linux: Dune 2000 (English) @@ -860,853 +860,853 @@ setup/setup.z: 2411cc5df36954ebd534ceafa3007c8aa9232909 Install: copy: movies - ^Content/d2k/v2/Movies/A_BR01_E.VQA: a_br01_e.vqa - ^Content/d2k/v2/Movies/A_BR02_E.VQA: a_br02_e.vqa - ^Content/d2k/v2/Movies/A_BR03_E.VQA: a_br03_e.vqa - ^Content/d2k/v2/Movies/A_BR04_E.VQA: a_br04_e.vqa - ^Content/d2k/v2/Movies/A_BR05_E.VQA: a_br05_e.vqa - ^Content/d2k/v2/Movies/A_BR06_E.VQA: a_br06_e.vqa - ^Content/d2k/v2/Movies/A_BR07_E.VQA: a_br07_e.vqa - ^Content/d2k/v2/Movies/A_BR08_E.VQA: a_br08_e.vqa - ^Content/d2k/v2/Movies/A_BR09_E.VQA: a_br09_e.vqa - ^Content/d2k/v2/Movies/A_FINL_E.VQA: a_finl_e.vqa - ^Content/d2k/v2/Movies/A_LOSE_E.VQA: a_lose_e.vqa - ^Content/d2k/v2/Movies/A_MNTG_E.VQA: a_mntg_e.vqa - ^Content/d2k/v2/Movies/H_BR01_E.VQA: h_br01_e.vqa - ^Content/d2k/v2/Movies/H_BR02_E.VQA: h_br02_e.vqa - ^Content/d2k/v2/Movies/H_BR03_E.VQA: h_br03_e.vqa - ^Content/d2k/v2/Movies/H_BR04_E.VQA: h_br04_e.vqa - ^Content/d2k/v2/Movies/H_BR05_E.VQA: h_br05_e.vqa - ^Content/d2k/v2/Movies/H_BR06_E.VQA: h_br06_e.vqa - ^Content/d2k/v2/Movies/H_BR07_E.VQA: h_br07_e.vqa - ^Content/d2k/v2/Movies/H_BR08_E.VQA: h_br08_e.vqa - ^Content/d2k/v2/Movies/H_BR09_E.VQA: h_br09_e.vqa - ^Content/d2k/v2/Movies/H_FINL_E.VQA: h_finl_e.vqa - ^Content/d2k/v2/Movies/H_LOSE_E.VQA: h_lose_e.vqa - ^Content/d2k/v2/Movies/H_MNTG_E.VQA: h_mntg_e.vqa - ^Content/d2k/v2/Movies/O_BR01_E.VQA: o_br01_e.vqa - ^Content/d2k/v2/Movies/O_BR02_E.VQA: o_br02_e.vqa - ^Content/d2k/v2/Movies/O_BR03_E.VQA: o_br03_e.vqa - ^Content/d2k/v2/Movies/O_BR04_E.VQA: o_br04_e.vqa - ^Content/d2k/v2/Movies/O_BR05_E.VQA: o_br05_e.vqa - ^Content/d2k/v2/Movies/O_BR06_E.VQA: o_br06_e.vqa - ^Content/d2k/v2/Movies/O_BR07_E.VQA: o_br07_e.vqa - ^Content/d2k/v2/Movies/O_BR08_E.VQA: o_br08_e.vqa - ^Content/d2k/v2/Movies/O_BR09_E.VQA: o_br09_e.vqa - ^Content/d2k/v2/Movies/O_FINL_E.VQA: o_finl_e.vqa - ^Content/d2k/v2/Movies/O_LOSE_E.VQA: o_lose_e.vqa - ^Content/d2k/v2/Movies/O_MNTG_E.VQA: o_mntg_e.vqa - ^Content/d2k/v2/Movies/G_INT1_E.VQA: g_int1_e.vqa - ^Content/d2k/v2/Movies/G_INT2_E.VQA: g_int2_e.vqa - ^Content/d2k/v2/Movies/G_MAPS_E.VQA: g_maps_e.vqa - ^Content/d2k/v2/Movies/G_PLN2_E.VQA: g_pln2_e.vqa - ^Content/d2k/v2/Movies/G_PLNT_E.VQA: g_plnt_e.vqa - ^Content/d2k/v2/Movies/T_TITL_E.VQA: t_titl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA: a_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR02_E.VQA: a_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR03_E.VQA: a_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR04_E.VQA: a_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR05_E.VQA: a_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR06_E.VQA: a_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR07_E.VQA: a_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR08_E.VQA: a_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR09_E.VQA: a_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_FINL_E.VQA: a_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_LOSE_E.VQA: a_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_MNTG_E.VQA: a_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR01_E.VQA: h_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR02_E.VQA: h_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR03_E.VQA: h_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR04_E.VQA: h_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR05_E.VQA: h_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR06_E.VQA: h_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR07_E.VQA: h_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR08_E.VQA: h_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR09_E.VQA: h_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_FINL_E.VQA: h_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_LOSE_E.VQA: h_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_MNTG_E.VQA: h_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR01_E.VQA: o_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR02_E.VQA: o_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR03_E.VQA: o_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR04_E.VQA: o_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR05_E.VQA: o_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR06_E.VQA: o_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR07_E.VQA: o_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR08_E.VQA: o_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR09_E.VQA: o_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_FINL_E.VQA: o_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_LOSE_E.VQA: o_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_MNTG_E.VQA: o_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_INT1_E.VQA: g_int1_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_INT2_E.VQA: g_int2_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_MAPS_E.VQA: g_maps_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_PLN2_E.VQA: g_pln2_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_PLNT_E.VQA: g_plnt_e.vqa + ^SupportDir|Content/d2k/v2/Movies/T_TITL_E.VQA: t_titl_e.vqa copy: music - ^Content/d2k/v2/Music/AMBUSH.AUD: ambush.aud - ^Content/d2k/v2/Music/ARAKATAK.AUD: arakatak.aud - ^Content/d2k/v2/Music/ATREGAIN.AUD: atregain.aud - ^Content/d2k/v2/Music/ENTORDOS.AUD: entordos.aud - ^Content/d2k/v2/Music/FIGHTPWR.AUD: fightpwr.aud - ^Content/d2k/v2/Music/FREMEN.AUD: fremen.aud - ^Content/d2k/v2/Music/HARK_BAT.AUD: hark_bat.aud - ^Content/d2k/v2/Music/LANDSAND.AUD: landsand.aud - ^Content/d2k/v2/Music/OPTIONS.AUD: options.aud - ^Content/d2k/v2/Music/PLOTTING.AUD: plotting.aud - ^Content/d2k/v2/Music/RISEHARK.AUD: risehark.aud - ^Content/d2k/v2/Music/ROBOTIX.AUD: robotix.aud - ^Content/d2k/v2/Music/SCORE.AUD: score.aud - ^Content/d2k/v2/Music/SOLDAPPR.AUD: soldappr.aud - ^Content/d2k/v2/Music/SPICESCT.AUD: spicesct.aud - ^Content/d2k/v2/Music/UNDERCON.AUD: undercon.aud - ^Content/d2k/v2/Music/WAITGAME.A: waitgame.aud + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: ambush.aud + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: arakatak.aud + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: atregain.aud + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: entordos.aud + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: fightpwr.aud + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: fremen.aud + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: hark_bat.aud + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: landsand.aud + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: options.aud + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: plotting.aud + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: risehark.aud + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: robotix.aud + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: score.aud + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: soldappr.aud + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: spicesct.aud + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: undercon.aud + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: waitgame.aud extract-blast: setup/setup.z - ^Content/d2k/v2/BLOXBAT.R8: + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: Offset: 702406 Length: 512750 - ^Content/d2k/v2/BLOXBASE.R8: + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: Offset: 1215156 Length: 497092 - ^Content/d2k/v2/BLOXBGBS.R8: + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: Offset: 3600977 Length: 499135 - ^Content/d2k/v2/BLOXICE.R8: + ^SupportDir|Content/d2k/v2/BLOXICE.R8: Offset: 5070263 Length: 514963 - ^Content/d2k/v2/BLOXTREE.R8: + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: Offset: 6540124 Length: 509867 - ^Content/d2k/v2/BLOXWAST.R8: + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: Offset: 8000772 Length: 508567 - ^Content/d2k/v2/FONTCOL.FNT: + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: Offset: 13530930 Length: 3011 - ^Content/d2k/v2/FONTCOL.FPL: + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: Offset: 13533941 Length: 238 - ^Content/d2k/v2/MOUSE.R8: + ^SupportDir|Content/d2k/v2/MOUSE.R8: Offset: 13558245 Length: 16996 - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: Offset: 15106059 Length: 9647 - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: Offset: 15115706 Length: 8676 - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: Offset: 15124382 Length: 9641 - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: Offset: 15134023 Length: 7371 - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: Offset: 15141394 Length: 11326 - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: Offset: 15152720 Length: 11329 - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: Offset: 15164049 Length: 8964 - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: Offset: 15173013 Length: 11336 - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: Offset: 15184349 Length: 14606 - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: Offset: 15198955 Length: 27230 - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: Offset: 15226185 Length: 19621 - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: Offset: 15245806 Length: 28781 - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: Offset: 15274587 Length: 29703 - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: Offset: 15304290 Length: 29555 - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: Offset: 15333845 Length: 27961 - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: Offset: 15361806 Length: 20925 - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: Offset: 15382731 Length: 10925 - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: Offset: 15393656 Length: 8125 - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: Offset: 15401781 Length: 26212 - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: Offset: 15427993 Length: 27166 - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: Offset: 15455159 Length: 31126 - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: Offset: 15486285 Length: 33481 - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: Offset: 15519766 Length: 17265 - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: Offset: 15537031 Length: 14523 - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: Offset: 15551554 Length: 18266 - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: Offset: 15569820 Length: 8467 - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: Offset: 15578287 Length: 9748 - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: Offset: 15588035 Length: 14264 - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: Offset: 15602299 Length: 12087 - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: Offset: 15614386 Length: 14428 - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: Offset: 15628814 Length: 16985 - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: Offset: 15645799 Length: 12638 - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: Offset: 15658437 Length: 13229 - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: Offset: 15671666 Length: 26572 - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: Offset: 15698238 Length: 12085 - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: Offset: 15710323 Length: 18232 - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: Offset: 15728555 Length: 8328 - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: Offset: 15736883 Length: 12497 - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: Offset: 15749380 Length: 9546 - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: Offset: 15758926 Length: 17135 - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: Offset: 15776061 Length: 26937 - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: Offset: 15802998 Length: 17940 - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: Offset: 15820938 Length: 14985 - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: Offset: 15835923 Length: 9089 - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: Offset: 15845012 Length: 28401 - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: Offset: 15873413 Length: 23949 - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: Offset: 15897362 Length: 29489 - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: Offset: 15926851 Length: 11016 - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: Offset: 15937867 Length: 27566 - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: Offset: 15965433 Length: 26539 - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: Offset: 15991972 Length: 30821 - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: Offset: 16022793 Length: 7978 - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: Offset: 16030771 Length: 11880 - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: Offset: 16042651 Length: 8995 - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: Offset: 16051646 Length: 10120 - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: Offset: 16061766 Length: 8999 - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: Offset: 16070765 Length: 6593 - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: Offset: 16077358 Length: 34790 - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: Offset: 16112148 Length: 35606 - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: Offset: 16147754 Length: 10303 - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: Offset: 16158057 Length: 22969 - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: Offset: 16181026 Length: 31816 - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: Offset: 16212842 Length: 19585 - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: Offset: 16232427 Length: 14563 - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: Offset: 16246990 Length: 13353 - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: Offset: 16260343 Length: 9671 - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: Offset: 16270014 Length: 15031 - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: Offset: 16285045 Length: 28368 - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: Offset: 16313413 Length: 9649 - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: Offset: 16323062 Length: 17157 - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: Offset: 16340219 Length: 13407 - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: Offset: 16353626 Length: 29910 - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: Offset: 16383536 Length: 22890 - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: Offset: 16406426 Length: 22923 - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: Offset: 16429349 Length: 34017 - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: Offset: 16463366 Length: 56714 - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: Offset: 16520080 Length: 27200 - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: Offset: 16547280 Length: 19828 - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: Offset: 16567108 Length: 13869 - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: Offset: 16580977 Length: 14197 - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: Offset: 16595174 Length: 29136 - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: Offset: 16624310 Length: 26204 - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: Offset: 16650514 Length: 24264 - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: Offset: 16674778 Length: 43921 - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: Offset: 16718699 Length: 22151 - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: Offset: 16740850 Length: 12300 - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: Offset: 16753150 Length: 21971 - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: Offset: 16775121 Length: 22041 - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: Offset: 16797162 Length: 21545 - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: Offset: 16818707 Length: 14344 - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: Offset: 16833051 Length: 28156 - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: Offset: 16861207 Length: 16983 - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: Offset: 16878190 Length: 19583 - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: Offset: 16897773 Length: 12875 - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: Offset: 16910648 Length: 20974 - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: Offset: 16931622 Length: 14699 - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: Offset: 16946321 Length: 20919 - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: Offset: 16967240 Length: 18984 - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: Offset: 16986224 Length: 11779 - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: Offset: 16998003 Length: 13980 - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: Offset: 17011983 Length: 33483 - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: Offset: 17045466 Length: 26566 - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: Offset: 17072032 Length: 25237 - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: Offset: 17097269 Length: 16072 - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: Offset: 17113341 Length: 12037 - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: Offset: 17125378 Length: 30243 - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: Offset: 17155621 Length: 31710 - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: Offset: 17187331 Length: 27450 - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: Offset: 17214781 Length: 30854 - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: Offset: 17245635 Length: 10860 - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: Offset: 17256495 Length: 19337 - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: Offset: 17275832 Length: 15004 - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: Offset: 17290836 Length: 23023 - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: Offset: 17313859 Length: 22321 - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: Offset: 17336180 Length: 21698 - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: Offset: 17357878 Length: 10282 - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: Offset: 17368160 Length: 28615 - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: Offset: 17396775 Length: 12771 - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: Offset: 17409546 Length: 9917 - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: Offset: 17419463 Length: 18502 - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: Offset: 17437965 Length: 12832 - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: Offset: 17450797 Length: 22413 - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: Offset: 17473210 Length: 29577 - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: Offset: 17502787 Length: 24798 - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: Offset: 17527585 Length: 14784 - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: Offset: 17542369 Length: 18526 - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: Offset: 17560895 Length: 12390 - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: Offset: 17573285 Length: 11851 - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: Offset: 17585136 Length: 9867 - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: Offset: 17595003 Length: 16907 - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: Offset: 17611910 Length: 17659 - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: Offset: 17629569 Length: 20337 - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: Offset: 17649906 Length: 18877 - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: Offset: 17668783 Length: 30788 - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: Offset: 17699571 Length: 18322 - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: Offset: 17717893 Length: 22178 - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: Offset: 17740071 Length: 24878 - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: Offset: 17764949 Length: 15741 - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: Offset: 17780690 Length: 14892 - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: Offset: 17795582 Length: 23026 - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: Offset: 17818608 Length: 43938 - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: Offset: 17862546 Length: 10992 - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: Offset: 17873538 Length: 19514 - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: Offset: 17893052 Length: 23895 - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: Offset: 17916947 Length: 18626 - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: Offset: 17935573 Length: 22564 - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: Offset: 17958137 Length: 18445 - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: Offset: 17976582 Length: 19492 - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: Offset: 17996074 Length: 14194 - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: Offset: 18010268 Length: 8310 - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: Offset: 18018578 Length: 8332 - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: Offset: 18026910 Length: 15789 - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: Offset: 18042699 Length: 9791 - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: Offset: 18052490 Length: 15099 - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: Offset: 18067589 Length: 14863 - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: Offset: 18082452 Length: 9753 - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: Offset: 18092205 Length: 9329 - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: Offset: 18101534 Length: 9449 - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: Offset: 18110983 Length: 15600 - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: Offset: 18126583 Length: 16157 - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: Offset: 18142740 Length: 13149 - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: Offset: 18155889 Length: 13928 - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: Offset: 18169817 Length: 16430 - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: Offset: 18186247 Length: 41640 - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: Offset: 18227887 Length: 41809 - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: Offset: 18269696 Length: 29117 - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: Offset: 18298813 Length: 36982 - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: Offset: 18335795 Length: 60681 - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: Offset: 18396476 Length: 21396 - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: Offset: 18417872 Length: 37995 - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: Offset: 18455867 Length: 32674 - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: Offset: 18488541 Length: 18399 - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: Offset: 18506940 Length: 26359 - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: Offset: 18533299 Length: 21335 - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: Offset: 18554634 Length: 28418 - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: Offset: 18583052 Length: 9269 - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: Offset: 18592321 Length: 19854 - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: Offset: 18612175 Length: 20038 - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: Offset: 18632213 Length: 16073 - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: Offset: 18648286 Length: 14873 - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: Offset: 18663159 Length: 41683 - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: Offset: 18704842 Length: 34475 - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: Offset: 18739317 Length: 34903 - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: Offset: 18774220 Length: 59613 - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: Offset: 18833833 Length: 22150 - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: Offset: 18855983 Length: 9090 - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: Offset: 18865073 Length: 21350 - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: Offset: 18886423 Length: 31478 - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: Offset: 18917901 Length: 19876 - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: Offset: 18937777 Length: 22359 - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: Offset: 18960136 Length: 28902 - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: Offset: 18989038 Length: 26855 - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: Offset: 19015893 Length: 19104 - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: Offset: 19034997 Length: 24655 - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: Offset: 19059652 Length: 23032 - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: Offset: 19082684 Length: 35588 - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: Offset: 19118272 Length: 8945 - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: Offset: 19127217 Length: 9005 - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: Offset: 19136222 Length: 9606 - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: Offset: 19145828 Length: 11671 - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: Offset: 19157499 Length: 10644 - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: Offset: 19168143 Length: 10387 - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: Offset: 19178530 Length: 17225 - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: Offset: 19195755 Length: 10077 - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: Offset: 19205832 Length: 13616 - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: Offset: 19219448 Length: 11251 - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: Offset: 19230699 Length: 8144 - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: Offset: 19238843 Length: 14865 - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: Offset: 19253708 Length: 11912 - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: Offset: 19265620 Length: 19540 - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: Offset: 19285160 Length: 10246 - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: Offset: 19295406 Length: 31148 - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: Offset: 19326554 Length: 8307 - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: Offset: 19334861 Length: 14331 - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: Offset: 19349192 Length: 11295 - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: Offset: 19360487 Length: 20437 - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: Offset: 19380924 Length: 27739 - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: Offset: 19408663 Length: 22200 - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: Offset: 19430863 Length: 9620 - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: Offset: 19440483 Length: 13368 - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: Offset: 19453851 Length: 15612 - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: Offset: 19469463 Length: 8279 - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: Offset: 19477742 Length: 11383 - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: Offset: 19489125 Length: 18511 - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: Offset: 19507636 Length: 14244 - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: Offset: 19521880 Length: 24075 - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: Offset: 19545955 Length: 26716 - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: Offset: 19572671 Length: 21716 - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: Offset: 19594387 Length: 32417 - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: Offset: 19626804 Length: 33724 - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: Offset: 19660528 Length: 21828 - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: Offset: 19682356 Length: 30404 - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: Offset: 19712760 Length: 9862 - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: Offset: 19722622 Length: 18149 - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: Offset: 19740771 Length: 14697 - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: Offset: 19755468 Length: 17316 - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: Offset: 19772784 Length: 14869 - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: Offset: 19787653 Length: 29873 - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: Offset: 19817526 Length: 16335 - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: Offset: 19833861 Length: 20565 - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: Offset: 19854426 Length: 25497 - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: Offset: 19879923 Length: 17142 - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: Offset: 19897065 Length: 20120 - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: Offset: 19917185 Length: 29921 - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: Offset: 19947106 Length: 14467 - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: Offset: 19961573 Length: 10906 - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: Offset: 19972479 Length: 25959 - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: Offset: 19998438 Length: 34175 - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: Offset: 20032613 Length: 30124 - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: Offset: 20062737 Length: 21881 - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: Offset: 20084618 Length: 20567 - ^Content/d2k/v2/SOUND.RS: + ^SupportDir|Content/d2k/v2/SOUND.RS: Offset: 20105185 Length: 1929247 - ^Content/d2k/v2/FONT.BIN: + ^SupportDir|Content/d2k/v2/FONT.BIN: Offset: 22473215 Length: 199 - ^Content/d2k/v2/PALETTE.BIN: + ^SupportDir|Content/d2k/v2/PALETTE.BIN: Offset: 22484155 Length: 815 \ No newline at end of file diff -Nru openra-20200503/mods/d2k/installer/d2k-e.yaml openra-20210321/mods/d2k/installer/d2k-e.yaml --- openra-20200503/mods/d2k/installer/d2k-e.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/installer/d2k-e.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,854 +4,854 @@ SETUP/SETUP.Z: b476661e82eeb05949e97fa1f75fed2343174be5 Install: copy: MOVIES - ^Content/d2k/v2/Movies/A_BR01_E.VQA: A_BR01_E.VQA - ^Content/d2k/v2/Movies/A_BR02_E.VQA: A_BR02_E.VQA - ^Content/d2k/v2/Movies/A_BR03_E.VQA: A_BR03_E.VQA - ^Content/d2k/v2/Movies/A_BR04_E.VQA: A_BR04_E.VQA - ^Content/d2k/v2/Movies/A_BR05_E.VQA: A_BR05_E.VQA - ^Content/d2k/v2/Movies/A_BR06_E.VQA: A_BR06_E.VQA - ^Content/d2k/v2/Movies/A_BR07_E.VQA: A_BR07_E.VQA - ^Content/d2k/v2/Movies/A_BR08_E.VQA: A_BR08_E.VQA - ^Content/d2k/v2/Movies/A_BR09_E.VQA: A_BR09_E.VQA - ^Content/d2k/v2/Movies/A_FINL_E.VQA: A_FINL_E.VQA - ^Content/d2k/v2/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA - ^Content/d2k/v2/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA - ^Content/d2k/v2/Movies/H_BR01_E.VQA: H_BR01_E.VQA - ^Content/d2k/v2/Movies/H_BR02_E.VQA: H_BR02_E.VQA - ^Content/d2k/v2/Movies/H_BR03_E.VQA: H_BR03_E.VQA - ^Content/d2k/v2/Movies/H_BR04_E.VQA: H_BR04_E.VQA - ^Content/d2k/v2/Movies/H_BR05_E.VQA: H_BR05_E.VQA - ^Content/d2k/v2/Movies/H_BR06_E.VQA: H_BR06_E.VQA - ^Content/d2k/v2/Movies/H_BR07_E.VQA: H_BR07_E.VQA - ^Content/d2k/v2/Movies/H_BR08_E.VQA: H_BR08_E.VQA - ^Content/d2k/v2/Movies/H_BR09_E.VQA: H_BR09_E.VQA - ^Content/d2k/v2/Movies/H_FINL_E.VQA: H_FINL_E.VQA - ^Content/d2k/v2/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA - ^Content/d2k/v2/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA - ^Content/d2k/v2/Movies/O_BR01_E.VQA: O_BR01_E.VQA - ^Content/d2k/v2/Movies/O_BR02_E.VQA: O_BR02_E.VQA - ^Content/d2k/v2/Movies/O_BR03_E.VQA: O_BR03_E.VQA - ^Content/d2k/v2/Movies/O_BR04_E.VQA: O_BR04_E.VQA - ^Content/d2k/v2/Movies/O_BR05_E.VQA: O_BR05_E.VQA - ^Content/d2k/v2/Movies/O_BR06_E.VQA: O_BR06_E.VQA - ^Content/d2k/v2/Movies/O_BR07_E.VQA: O_BR07_E.VQA - ^Content/d2k/v2/Movies/O_BR08_E.VQA: O_BR08_E.VQA - ^Content/d2k/v2/Movies/O_BR09_E.VQA: O_BR09_E.VQA - ^Content/d2k/v2/Movies/O_FINL_E.VQA: O_FINL_E.VQA - ^Content/d2k/v2/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA - ^Content/d2k/v2/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA - ^Content/d2k/v2/Movies/G_INT1_E.VQA: G_INT1_E.VQA - ^Content/d2k/v2/Movies/G_INT2_E.VQA: G_INT2_E.VQA - ^Content/d2k/v2/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA - ^Content/d2k/v2/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA - ^Content/d2k/v2/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA - ^Content/d2k/v2/Movies/T_TITL_E.VQA: T_TITL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA: A_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR02_E.VQA: A_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR03_E.VQA: A_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR04_E.VQA: A_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR05_E.VQA: A_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR06_E.VQA: A_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR07_E.VQA: A_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR08_E.VQA: A_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_BR09_E.VQA: A_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_FINL_E.VQA: A_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR01_E.VQA: H_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR02_E.VQA: H_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR03_E.VQA: H_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR04_E.VQA: H_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR05_E.VQA: H_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR06_E.VQA: H_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR07_E.VQA: H_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR08_E.VQA: H_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_BR09_E.VQA: H_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_FINL_E.VQA: H_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR01_E.VQA: O_BR01_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR02_E.VQA: O_BR02_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR03_E.VQA: O_BR03_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR04_E.VQA: O_BR04_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR05_E.VQA: O_BR05_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR06_E.VQA: O_BR06_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR07_E.VQA: O_BR07_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR08_E.VQA: O_BR08_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_BR09_E.VQA: O_BR09_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_FINL_E.VQA: O_FINL_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA + ^SupportDir|Content/d2k/v2/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_INT1_E.VQA: G_INT1_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_INT2_E.VQA: G_INT2_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA + ^SupportDir|Content/d2k/v2/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA + ^SupportDir|Content/d2k/v2/Movies/T_TITL_E.VQA: T_TITL_E.VQA copy: MUSIC - ^Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD - ^Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD - ^Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD - ^Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD - ^Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD - ^Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD - ^Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD - ^Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD - ^Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD - ^Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD - ^Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD - ^Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD - ^Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD - ^Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD - ^Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD - ^Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD - ^Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD extract-blast: SETUP/SETUP.Z - ^Content/d2k/v2/BLOXBAT.R8: + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: Offset: 702405 Length: 512750 - ^Content/d2k/v2/BLOXBASE.R8: + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: Offset: 1215155 Length: 497092 - ^Content/d2k/v2/BLOXBGBS.R8: + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: Offset: 3600976 Length: 499135 - ^Content/d2k/v2/BLOXICE.R8: + ^SupportDir|Content/d2k/v2/BLOXICE.R8: Offset: 5070262 Length: 514963 - ^Content/d2k/v2/BLOXTREE.R8: + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: Offset: 6540123 Length: 509867 - ^Content/d2k/v2/BLOXWAST.R8: + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: Offset: 8000771 Length: 508567 - ^Content/d2k/v2/FONTCOL.FNT: + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: Offset: 13530929 Length: 3011 - ^Content/d2k/v2/FONTCOL.FPL: + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: Offset: 13533940 Length: 238 - ^Content/d2k/v2/MOUSE.R8: + ^SupportDir|Content/d2k/v2/MOUSE.R8: Offset: 13558244 Length: 16996 - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: Offset: 15106058 Length: 9647 - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: Offset: 15115705 Length: 8676 - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: Offset: 15124381 Length: 9641 - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: Offset: 15134022 Length: 7371 - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: Offset: 15141393 Length: 11326 - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: Offset: 15152719 Length: 11329 - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: Offset: 15164048 Length: 8964 - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: Offset: 15173012 Length: 11336 - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: Offset: 15184348 Length: 14606 - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: Offset: 15198954 Length: 27230 - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: Offset: 15226184 Length: 19621 - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: Offset: 15245805 Length: 28781 - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: Offset: 15274586 Length: 29703 - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: Offset: 15304289 Length: 29555 - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: Offset: 15333844 Length: 27961 - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: Offset: 15361805 Length: 20925 - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: Offset: 15382730 Length: 10925 - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: Offset: 15393655 Length: 8125 - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: Offset: 15401780 Length: 26212 - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: Offset: 15427992 Length: 27166 - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: Offset: 15455158 Length: 31126 - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: Offset: 15486284 Length: 33481 - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: Offset: 15519765 Length: 17265 - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: Offset: 15537030 Length: 14523 - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: Offset: 15551553 Length: 18266 - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: Offset: 15569819 Length: 8467 - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: Offset: 15578286 Length: 9748 - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: Offset: 15588034 Length: 14264 - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: Offset: 15602298 Length: 12087 - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: Offset: 15614385 Length: 14428 - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: Offset: 15628813 Length: 16985 - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: Offset: 15645798 Length: 12638 - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: Offset: 15658436 Length: 13229 - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: Offset: 15671665 Length: 26572 - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: Offset: 15698237 Length: 12085 - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: Offset: 15710322 Length: 18232 - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: Offset: 15728554 Length: 8328 - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: Offset: 15736882 Length: 12497 - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: Offset: 15749379 Length: 9546 - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: Offset: 15758925 Length: 17135 - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: Offset: 15776060 Length: 26937 - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: Offset: 15802997 Length: 17940 - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: Offset: 15820937 Length: 14985 - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: Offset: 15835922 Length: 9089 - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: Offset: 15845011 Length: 28401 - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: Offset: 15873412 Length: 23949 - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: Offset: 15897361 Length: 29489 - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: Offset: 15926850 Length: 11016 - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: Offset: 15937866 Length: 27566 - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: Offset: 15965432 Length: 26539 - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: Offset: 15991971 Length: 30821 - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: Offset: 16022792 Length: 7978 - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: Offset: 16030770 Length: 11880 - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: Offset: 16042650 Length: 8995 - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: Offset: 16051645 Length: 10120 - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: Offset: 16061765 Length: 8999 - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: Offset: 16070764 Length: 6593 - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: Offset: 16077357 Length: 34790 - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: Offset: 16112147 Length: 35606 - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: Offset: 16147753 Length: 10303 - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: Offset: 16158056 Length: 22969 - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: Offset: 16181025 Length: 31816 - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: Offset: 16212841 Length: 19585 - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: Offset: 16232426 Length: 14563 - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: Offset: 16246989 Length: 13353 - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: Offset: 16260342 Length: 9671 - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: Offset: 16270013 Length: 15031 - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: Offset: 16285044 Length: 28368 - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: Offset: 16313412 Length: 9649 - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: Offset: 16323061 Length: 17157 - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: Offset: 16340218 Length: 13407 - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: Offset: 16353625 Length: 29910 - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: Offset: 16383535 Length: 22890 - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: Offset: 16406425 Length: 22923 - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: Offset: 16429348 Length: 34017 - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: Offset: 16463365 Length: 56714 - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: Offset: 16520079 Length: 27200 - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: Offset: 16547279 Length: 19828 - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: Offset: 16567107 Length: 13869 - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: Offset: 16580976 Length: 14197 - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: Offset: 16595173 Length: 29136 - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: Offset: 16624309 Length: 26204 - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: Offset: 16650513 Length: 24264 - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: Offset: 16674777 Length: 43921 - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: Offset: 16718698 Length: 22151 - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: Offset: 16740849 Length: 12300 - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: Offset: 16753149 Length: 21971 - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: Offset: 16775120 Length: 22041 - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: Offset: 16797161 Length: 21545 - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: Offset: 16818706 Length: 14344 - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: Offset: 16833050 Length: 28156 - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: Offset: 16861206 Length: 16983 - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: Offset: 16878189 Length: 19583 - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: Offset: 16897772 Length: 12875 - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: Offset: 16910647 Length: 20974 - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: Offset: 16931621 Length: 14699 - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: Offset: 16946320 Length: 20919 - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: Offset: 16967239 Length: 18984 - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: Offset: 16986223 Length: 11779 - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: Offset: 16998002 Length: 13980 - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: Offset: 17011982 Length: 33483 - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: Offset: 17045465 Length: 26566 - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: Offset: 17072031 Length: 25237 - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: Offset: 17097268 Length: 16072 - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: Offset: 17113340 Length: 12037 - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: Offset: 17125377 Length: 30243 - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: Offset: 17155620 Length: 31710 - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: Offset: 17187330 Length: 27450 - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: Offset: 17214780 Length: 30854 - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: Offset: 17245634 Length: 10860 - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: Offset: 17256494 Length: 19337 - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: Offset: 17275831 Length: 15004 - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: Offset: 17290835 Length: 23023 - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: Offset: 17313858 Length: 22321 - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: Offset: 17336179 Length: 21698 - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: Offset: 17357877 Length: 10282 - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: Offset: 17368159 Length: 28615 - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: Offset: 17396774 Length: 12771 - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: Offset: 17409545 Length: 9917 - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: Offset: 17419462 Length: 18502 - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: Offset: 17437964 Length: 12832 - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: Offset: 17450796 Length: 22413 - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: Offset: 17473209 Length: 29577 - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: Offset: 17502786 Length: 24798 - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: Offset: 17527584 Length: 14784 - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: Offset: 17542368 Length: 18526 - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: Offset: 17560894 Length: 12390 - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: Offset: 17573284 Length: 11851 - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: Offset: 17585135 Length: 9867 - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: Offset: 17595002 Length: 16907 - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: Offset: 17611909 Length: 17659 - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: Offset: 17629568 Length: 20337 - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: Offset: 17649905 Length: 18877 - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: Offset: 17668782 Length: 30788 - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: Offset: 17699570 Length: 18322 - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: Offset: 17717892 Length: 22178 - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: Offset: 17740070 Length: 24878 - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: Offset: 17764948 Length: 15741 - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: Offset: 17780689 Length: 14892 - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: Offset: 17795581 Length: 23026 - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: Offset: 17818607 Length: 43938 - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: Offset: 17862545 Length: 10992 - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: Offset: 17873537 Length: 19514 - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: Offset: 17893051 Length: 23895 - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: Offset: 17916946 Length: 18626 - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: Offset: 17935572 Length: 22564 - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: Offset: 17958136 Length: 18445 - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: Offset: 17976581 Length: 19492 - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: Offset: 17996073 Length: 14194 - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: Offset: 18010267 Length: 8310 - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: Offset: 18018577 Length: 8332 - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: Offset: 18026909 Length: 15789 - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: Offset: 18042698 Length: 9791 - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: Offset: 18052489 Length: 15099 - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: Offset: 18067588 Length: 14863 - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: Offset: 18082451 Length: 9753 - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: Offset: 18092204 Length: 9329 - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: Offset: 18101533 Length: 9449 - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: Offset: 18110982 Length: 15600 - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: Offset: 18126582 Length: 16157 - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: Offset: 18142739 Length: 13149 - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: Offset: 18155888 Length: 13928 - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: Offset: 18169816 Length: 16430 - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: Offset: 18186246 Length: 41640 - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: Offset: 18227886 Length: 41809 - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: Offset: 18269695 Length: 29117 - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: Offset: 18298812 Length: 36982 - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: Offset: 18335794 Length: 60681 - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: Offset: 18396475 Length: 21396 - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: Offset: 18417871 Length: 37995 - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: Offset: 18455866 Length: 32674 - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: Offset: 18488540 Length: 18399 - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: Offset: 18506939 Length: 26359 - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: Offset: 18533298 Length: 21335 - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: Offset: 18554633 Length: 28418 - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: Offset: 18583051 Length: 9269 - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: Offset: 18592320 Length: 19854 - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: Offset: 18612174 Length: 20038 - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: Offset: 18632212 Length: 16073 - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: Offset: 18648285 Length: 14873 - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: Offset: 18663158 Length: 41683 - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: Offset: 18704841 Length: 34475 - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: Offset: 18739316 Length: 34903 - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: Offset: 18774219 Length: 59613 - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: Offset: 18833832 Length: 22150 - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: Offset: 18855982 Length: 9090 - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: Offset: 18865072 Length: 21350 - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: Offset: 18886422 Length: 31478 - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: Offset: 18917900 Length: 19876 - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: Offset: 18937776 Length: 22359 - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: Offset: 18960135 Length: 28902 - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: Offset: 18989037 Length: 26855 - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: Offset: 19015892 Length: 19104 - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: Offset: 19034996 Length: 24655 - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: Offset: 19059651 Length: 23032 - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: Offset: 19082683 Length: 35588 - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: Offset: 19118271 Length: 8945 - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: Offset: 19127216 Length: 9005 - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: Offset: 19136221 Length: 9606 - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: Offset: 19145827 Length: 11671 - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: Offset: 19157498 Length: 10644 - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: Offset: 19168142 Length: 10387 - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: Offset: 19178529 Length: 17225 - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: Offset: 19195754 Length: 10077 - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: Offset: 19205831 Length: 13616 - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: Offset: 19219447 Length: 11251 - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: Offset: 19230698 Length: 8144 - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: Offset: 19238842 Length: 14865 - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: Offset: 19253707 Length: 11912 - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: Offset: 19265619 Length: 19540 - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: Offset: 19285159 Length: 10246 - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: Offset: 19295405 Length: 31148 - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: Offset: 19326553 Length: 8307 - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: Offset: 19334860 Length: 14331 - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: Offset: 19349191 Length: 11295 - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: Offset: 19360486 Length: 20437 - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: Offset: 19380923 Length: 27739 - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: Offset: 19408662 Length: 22200 - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: Offset: 19430862 Length: 9620 - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: Offset: 19440482 Length: 13368 - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: Offset: 19453850 Length: 15612 - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: Offset: 19469462 Length: 8279 - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: Offset: 19477741 Length: 11383 - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: Offset: 19489124 Length: 18511 - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: Offset: 19507635 Length: 14244 - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: Offset: 19521879 Length: 24075 - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: Offset: 19545954 Length: 26716 - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: Offset: 19572670 Length: 21716 - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: Offset: 19594386 Length: 32417 - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: Offset: 19626803 Length: 33724 - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: Offset: 19660527 Length: 21828 - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: Offset: 19682355 Length: 30404 - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: Offset: 19712759 Length: 9862 - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: Offset: 19722621 Length: 18149 - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: Offset: 19740770 Length: 14697 - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: Offset: 19755467 Length: 17316 - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: Offset: 19772783 Length: 14869 - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: Offset: 19787652 Length: 29873 - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: Offset: 19817525 Length: 16335 - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: Offset: 19833860 Length: 20565 - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: Offset: 19854425 Length: 25497 - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: Offset: 19879922 Length: 17142 - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: Offset: 19897064 Length: 20120 - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: Offset: 19917184 Length: 29921 - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: Offset: 19947105 Length: 14467 - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: Offset: 19961572 Length: 10906 - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: Offset: 19972478 Length: 25959 - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: Offset: 19998437 Length: 34175 - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: Offset: 20032612 Length: 30124 - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: Offset: 20062736 Length: 21881 - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: Offset: 20084617 Length: 20567 - ^Content/d2k/v2/SOUND.RS: + ^SupportDir|Content/d2k/v2/SOUND.RS: Offset: 20105184 Length: 1929247 - ^Content/d2k/v2/FONT.BIN: + ^SupportDir|Content/d2k/v2/FONT.BIN: Offset: 22473214 Length: 199 - ^Content/d2k/v2/PALETTE.BIN: + ^SupportDir|Content/d2k/v2/PALETTE.BIN: Offset: 22484154 Length: 815 d2k-e-linux: Dune 2000 (English) @@ -860,853 +860,853 @@ setup/setup.z: b476661e82eeb05949e97fa1f75fed2343174be5 Install: copy: movies - ^Content/d2k/v2/Movies/A_BR01_E.VQA: a_br01_e.vqa - ^Content/d2k/v2/Movies/A_BR02_E.VQA: a_br02_e.vqa - ^Content/d2k/v2/Movies/A_BR03_E.VQA: a_br03_e.vqa - ^Content/d2k/v2/Movies/A_BR04_E.VQA: a_br04_e.vqa - ^Content/d2k/v2/Movies/A_BR05_E.VQA: a_br05_e.vqa - ^Content/d2k/v2/Movies/A_BR06_E.VQA: a_br06_e.vqa - ^Content/d2k/v2/Movies/A_BR07_E.VQA: a_br07_e.vqa - ^Content/d2k/v2/Movies/A_BR08_E.VQA: a_br08_e.vqa - ^Content/d2k/v2/Movies/A_BR09_E.VQA: a_br09_e.vqa - ^Content/d2k/v2/Movies/A_FINL_E.VQA: a_finl_e.vqa - ^Content/d2k/v2/Movies/A_LOSE_E.VQA: a_lose_e.vqa - ^Content/d2k/v2/Movies/A_MNTG_E.VQA: a_mntg_e.vqa - ^Content/d2k/v2/Movies/H_BR01_E.VQA: h_br01_e.vqa - ^Content/d2k/v2/Movies/H_BR02_E.VQA: h_br02_e.vqa - ^Content/d2k/v2/Movies/H_BR03_E.VQA: h_br03_e.vqa - ^Content/d2k/v2/Movies/H_BR04_E.VQA: h_br04_e.vqa - ^Content/d2k/v2/Movies/H_BR05_E.VQA: h_br05_e.vqa - ^Content/d2k/v2/Movies/H_BR06_E.VQA: h_br06_e.vqa - ^Content/d2k/v2/Movies/H_BR07_E.VQA: h_br07_e.vqa - ^Content/d2k/v2/Movies/H_BR08_E.VQA: h_br08_e.vqa - ^Content/d2k/v2/Movies/H_BR09_E.VQA: h_br09_e.vqa - ^Content/d2k/v2/Movies/H_FINL_E.VQA: h_finl_e.vqa - ^Content/d2k/v2/Movies/H_LOSE_E.VQA: h_lose_e.vqa - ^Content/d2k/v2/Movies/H_MNTG_E.VQA: h_mntg_e.vqa - ^Content/d2k/v2/Movies/O_BR01_E.VQA: o_br01_e.vqa - ^Content/d2k/v2/Movies/O_BR02_E.VQA: o_br02_e.vqa - ^Content/d2k/v2/Movies/O_BR03_E.VQA: o_br03_e.vqa - ^Content/d2k/v2/Movies/O_BR04_E.VQA: o_br04_e.vqa - ^Content/d2k/v2/Movies/O_BR05_E.VQA: o_br05_e.vqa - ^Content/d2k/v2/Movies/O_BR06_E.VQA: o_br06_e.vqa - ^Content/d2k/v2/Movies/O_BR07_E.VQA: o_br07_e.vqa - ^Content/d2k/v2/Movies/O_BR08_E.VQA: o_br08_e.vqa - ^Content/d2k/v2/Movies/O_BR09_E.VQA: o_br09_e.vqa - ^Content/d2k/v2/Movies/O_FINL_E.VQA: o_finl_e.vqa - ^Content/d2k/v2/Movies/O_LOSE_E.VQA: o_lose_e.vqa - ^Content/d2k/v2/Movies/O_MNTG_E.VQA: o_mntg_e.vqa - ^Content/d2k/v2/Movies/G_INT1_E.VQA: g_int1_e.vqa - ^Content/d2k/v2/Movies/G_INT2_E.VQA: g_int2_e.vqa - ^Content/d2k/v2/Movies/G_MAPS_E.VQA: g_maps_e.vqa - ^Content/d2k/v2/Movies/G_PLN2_E.VQA: g_pln2_e.vqa - ^Content/d2k/v2/Movies/G_PLNT_E.VQA: g_plnt_e.vqa - ^Content/d2k/v2/Movies/T_TITL_E.VQA: t_titl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA: a_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR02_E.VQA: a_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR03_E.VQA: a_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR04_E.VQA: a_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR05_E.VQA: a_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR06_E.VQA: a_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR07_E.VQA: a_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR08_E.VQA: a_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_BR09_E.VQA: a_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_FINL_E.VQA: a_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_LOSE_E.VQA: a_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/A_MNTG_E.VQA: a_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR01_E.VQA: h_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR02_E.VQA: h_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR03_E.VQA: h_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR04_E.VQA: h_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR05_E.VQA: h_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR06_E.VQA: h_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR07_E.VQA: h_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR08_E.VQA: h_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_BR09_E.VQA: h_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_FINL_E.VQA: h_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_LOSE_E.VQA: h_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/H_MNTG_E.VQA: h_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR01_E.VQA: o_br01_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR02_E.VQA: o_br02_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR03_E.VQA: o_br03_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR04_E.VQA: o_br04_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR05_E.VQA: o_br05_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR06_E.VQA: o_br06_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR07_E.VQA: o_br07_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR08_E.VQA: o_br08_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_BR09_E.VQA: o_br09_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_FINL_E.VQA: o_finl_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_LOSE_E.VQA: o_lose_e.vqa + ^SupportDir|Content/d2k/v2/Movies/O_MNTG_E.VQA: o_mntg_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_INT1_E.VQA: g_int1_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_INT2_E.VQA: g_int2_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_MAPS_E.VQA: g_maps_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_PLN2_E.VQA: g_pln2_e.vqa + ^SupportDir|Content/d2k/v2/Movies/G_PLNT_E.VQA: g_plnt_e.vqa + ^SupportDir|Content/d2k/v2/Movies/T_TITL_E.VQA: t_titl_e.vqa copy: music - ^Content/d2k/v2/Music/AMBUSH.AUD: ambush.aud - ^Content/d2k/v2/Music/ARAKATAK.AUD: arakatak.aud - ^Content/d2k/v2/Music/ATREGAIN.AUD: atregain.aud - ^Content/d2k/v2/Music/ENTORDOS.AUD: entordos.aud - ^Content/d2k/v2/Music/FIGHTPWR.AUD: fightpwr.aud - ^Content/d2k/v2/Music/FREMEN.AUD: fremen.aud - ^Content/d2k/v2/Music/HARK_BAT.AUD: hark_bat.aud - ^Content/d2k/v2/Music/LANDSAND.AUD: landsand.aud - ^Content/d2k/v2/Music/OPTIONS.AUD: options.aud - ^Content/d2k/v2/Music/PLOTTING.AUD: plotting.aud - ^Content/d2k/v2/Music/RISEHARK.AUD: risehark.aud - ^Content/d2k/v2/Music/ROBOTIX.AUD: robotix.aud - ^Content/d2k/v2/Music/SCORE.AUD: score.aud - ^Content/d2k/v2/Music/SOLDAPPR.AUD: soldappr.aud - ^Content/d2k/v2/Music/SPICESCT.AUD: spicesct.aud - ^Content/d2k/v2/Music/UNDERCON.AUD: undercon.aud - ^Content/d2k/v2/Music/WAITGAME.A: waitgame.aud + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: ambush.aud + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: arakatak.aud + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: atregain.aud + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: entordos.aud + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: fightpwr.aud + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: fremen.aud + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: hark_bat.aud + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: landsand.aud + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: options.aud + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: plotting.aud + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: risehark.aud + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: robotix.aud + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: score.aud + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: soldappr.aud + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: spicesct.aud + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: undercon.aud + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: waitgame.aud extract-blast: setup/setup.z - ^Content/d2k/v2/BLOXBAT.R8: + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: Offset: 702405 Length: 512750 - ^Content/d2k/v2/BLOXBASE.R8: + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: Offset: 1215155 Length: 497092 - ^Content/d2k/v2/BLOXBGBS.R8: + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: Offset: 3600976 Length: 499135 - ^Content/d2k/v2/BLOXICE.R8: + ^SupportDir|Content/d2k/v2/BLOXICE.R8: Offset: 5070262 Length: 514963 - ^Content/d2k/v2/BLOXTREE.R8: + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: Offset: 6540123 Length: 509867 - ^Content/d2k/v2/BLOXWAST.R8: + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: Offset: 8000771 Length: 508567 - ^Content/d2k/v2/FONTCOL.FNT: + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: Offset: 13530929 Length: 3011 - ^Content/d2k/v2/FONTCOL.FPL: + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: Offset: 13533940 Length: 238 - ^Content/d2k/v2/MOUSE.R8: + ^SupportDir|Content/d2k/v2/MOUSE.R8: Offset: 13558244 Length: 16996 - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: Offset: 15106058 Length: 9647 - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: Offset: 15115705 Length: 8676 - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: Offset: 15124381 Length: 9641 - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: Offset: 15134022 Length: 7371 - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: Offset: 15141393 Length: 11326 - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: Offset: 15152719 Length: 11329 - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: Offset: 15164048 Length: 8964 - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: Offset: 15173012 Length: 11336 - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: Offset: 15184348 Length: 14606 - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: Offset: 15198954 Length: 27230 - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: Offset: 15226184 Length: 19621 - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: Offset: 15245805 Length: 28781 - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: Offset: 15274586 Length: 29703 - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: Offset: 15304289 Length: 29555 - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: Offset: 15333844 Length: 27961 - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: Offset: 15361805 Length: 20925 - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: Offset: 15382730 Length: 10925 - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: Offset: 15393655 Length: 8125 - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: Offset: 15401780 Length: 26212 - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: Offset: 15427992 Length: 27166 - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: Offset: 15455158 Length: 31126 - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: Offset: 15486284 Length: 33481 - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: Offset: 15519765 Length: 17265 - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: Offset: 15537030 Length: 14523 - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: Offset: 15551553 Length: 18266 - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: Offset: 15569819 Length: 8467 - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: Offset: 15578286 Length: 9748 - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: Offset: 15588034 Length: 14264 - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: Offset: 15602298 Length: 12087 - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: Offset: 15614385 Length: 14428 - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: Offset: 15628813 Length: 16985 - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: Offset: 15645798 Length: 12638 - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: Offset: 15658436 Length: 13229 - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: Offset: 15671665 Length: 26572 - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: Offset: 15698237 Length: 12085 - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: Offset: 15710322 Length: 18232 - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: Offset: 15728554 Length: 8328 - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: Offset: 15736882 Length: 12497 - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: Offset: 15749379 Length: 9546 - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: Offset: 15758925 Length: 17135 - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: Offset: 15776060 Length: 26937 - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: Offset: 15802997 Length: 17940 - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: Offset: 15820937 Length: 14985 - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: Offset: 15835922 Length: 9089 - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: Offset: 15845011 Length: 28401 - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: Offset: 15873412 Length: 23949 - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: Offset: 15897361 Length: 29489 - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: Offset: 15926850 Length: 11016 - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: Offset: 15937866 Length: 27566 - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: Offset: 15965432 Length: 26539 - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: Offset: 15991971 Length: 30821 - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: Offset: 16022792 Length: 7978 - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: Offset: 16030770 Length: 11880 - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: Offset: 16042650 Length: 8995 - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: Offset: 16051645 Length: 10120 - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: Offset: 16061765 Length: 8999 - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: Offset: 16070764 Length: 6593 - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: Offset: 16077357 Length: 34790 - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: Offset: 16112147 Length: 35606 - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: Offset: 16147753 Length: 10303 - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: Offset: 16158056 Length: 22969 - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: Offset: 16181025 Length: 31816 - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: Offset: 16212841 Length: 19585 - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: Offset: 16232426 Length: 14563 - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: Offset: 16246989 Length: 13353 - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: Offset: 16260342 Length: 9671 - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: Offset: 16270013 Length: 15031 - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: Offset: 16285044 Length: 28368 - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: Offset: 16313412 Length: 9649 - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: Offset: 16323061 Length: 17157 - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: Offset: 16340218 Length: 13407 - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: Offset: 16353625 Length: 29910 - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: Offset: 16383535 Length: 22890 - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: Offset: 16406425 Length: 22923 - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: Offset: 16429348 Length: 34017 - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: Offset: 16463365 Length: 56714 - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: Offset: 16520079 Length: 27200 - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: Offset: 16547279 Length: 19828 - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: Offset: 16567107 Length: 13869 - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: Offset: 16580976 Length: 14197 - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: Offset: 16595173 Length: 29136 - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: Offset: 16624309 Length: 26204 - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: Offset: 16650513 Length: 24264 - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: Offset: 16674777 Length: 43921 - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: Offset: 16718698 Length: 22151 - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: Offset: 16740849 Length: 12300 - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: Offset: 16753149 Length: 21971 - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: Offset: 16775120 Length: 22041 - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: Offset: 16797161 Length: 21545 - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: Offset: 16818706 Length: 14344 - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: Offset: 16833050 Length: 28156 - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: Offset: 16861206 Length: 16983 - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: Offset: 16878189 Length: 19583 - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: Offset: 16897772 Length: 12875 - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: Offset: 16910647 Length: 20974 - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: Offset: 16931621 Length: 14699 - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: Offset: 16946320 Length: 20919 - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: Offset: 16967239 Length: 18984 - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: Offset: 16986223 Length: 11779 - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: Offset: 16998002 Length: 13980 - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: Offset: 17011982 Length: 33483 - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: Offset: 17045465 Length: 26566 - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: Offset: 17072031 Length: 25237 - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: Offset: 17097268 Length: 16072 - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: Offset: 17113340 Length: 12037 - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: Offset: 17125377 Length: 30243 - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: Offset: 17155620 Length: 31710 - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: Offset: 17187330 Length: 27450 - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: Offset: 17214780 Length: 30854 - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: Offset: 17245634 Length: 10860 - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: Offset: 17256494 Length: 19337 - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: Offset: 17275831 Length: 15004 - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: Offset: 17290835 Length: 23023 - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: Offset: 17313858 Length: 22321 - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: Offset: 17336179 Length: 21698 - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: Offset: 17357877 Length: 10282 - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: Offset: 17368159 Length: 28615 - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: Offset: 17396774 Length: 12771 - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: Offset: 17409545 Length: 9917 - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: Offset: 17419462 Length: 18502 - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: Offset: 17437964 Length: 12832 - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: Offset: 17450796 Length: 22413 - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: Offset: 17473209 Length: 29577 - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: Offset: 17502786 Length: 24798 - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: Offset: 17527584 Length: 14784 - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: Offset: 17542368 Length: 18526 - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: Offset: 17560894 Length: 12390 - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: Offset: 17573284 Length: 11851 - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: Offset: 17585135 Length: 9867 - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: Offset: 17595002 Length: 16907 - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: Offset: 17611909 Length: 17659 - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: Offset: 17629568 Length: 20337 - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: Offset: 17649905 Length: 18877 - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: Offset: 17668782 Length: 30788 - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: Offset: 17699570 Length: 18322 - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: Offset: 17717892 Length: 22178 - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: Offset: 17740070 Length: 24878 - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: Offset: 17764948 Length: 15741 - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: Offset: 17780689 Length: 14892 - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: Offset: 17795581 Length: 23026 - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: Offset: 17818607 Length: 43938 - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: Offset: 17862545 Length: 10992 - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: Offset: 17873537 Length: 19514 - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: Offset: 17893051 Length: 23895 - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: Offset: 17916946 Length: 18626 - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: Offset: 17935572 Length: 22564 - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: Offset: 17958136 Length: 18445 - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: Offset: 17976581 Length: 19492 - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: Offset: 17996073 Length: 14194 - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: Offset: 18010267 Length: 8310 - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: Offset: 18018577 Length: 8332 - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: Offset: 18026909 Length: 15789 - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: Offset: 18042698 Length: 9791 - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: Offset: 18052489 Length: 15099 - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: Offset: 18067588 Length: 14863 - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: Offset: 18082451 Length: 9753 - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: Offset: 18092204 Length: 9329 - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: Offset: 18101533 Length: 9449 - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: Offset: 18110982 Length: 15600 - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: Offset: 18126582 Length: 16157 - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: Offset: 18142739 Length: 13149 - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: Offset: 18155888 Length: 13928 - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: Offset: 18169816 Length: 16430 - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: Offset: 18186246 Length: 41640 - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: Offset: 18227886 Length: 41809 - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: Offset: 18269695 Length: 29117 - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: Offset: 18298812 Length: 36982 - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: Offset: 18335794 Length: 60681 - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: Offset: 18396475 Length: 21396 - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: Offset: 18417871 Length: 37995 - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: Offset: 18455866 Length: 32674 - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: Offset: 18488540 Length: 18399 - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: Offset: 18506939 Length: 26359 - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: Offset: 18533298 Length: 21335 - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: Offset: 18554633 Length: 28418 - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: Offset: 18583051 Length: 9269 - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: Offset: 18592320 Length: 19854 - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: Offset: 18612174 Length: 20038 - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: Offset: 18632212 Length: 16073 - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: Offset: 18648285 Length: 14873 - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: Offset: 18663158 Length: 41683 - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: Offset: 18704841 Length: 34475 - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: Offset: 18739316 Length: 34903 - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: Offset: 18774219 Length: 59613 - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: Offset: 18833832 Length: 22150 - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: Offset: 18855982 Length: 9090 - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: Offset: 18865072 Length: 21350 - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: Offset: 18886422 Length: 31478 - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: Offset: 18917900 Length: 19876 - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: Offset: 18937776 Length: 22359 - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: Offset: 18960135 Length: 28902 - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: Offset: 18989037 Length: 26855 - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: Offset: 19015892 Length: 19104 - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: Offset: 19034996 Length: 24655 - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: Offset: 19059651 Length: 23032 - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: Offset: 19082683 Length: 35588 - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: Offset: 19118271 Length: 8945 - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: Offset: 19127216 Length: 9005 - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: Offset: 19136221 Length: 9606 - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: Offset: 19145827 Length: 11671 - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: Offset: 19157498 Length: 10644 - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: Offset: 19168142 Length: 10387 - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: Offset: 19178529 Length: 17225 - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: Offset: 19195754 Length: 10077 - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: Offset: 19205831 Length: 13616 - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: Offset: 19219447 Length: 11251 - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: Offset: 19230698 Length: 8144 - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: Offset: 19238842 Length: 14865 - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: Offset: 19253707 Length: 11912 - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: Offset: 19265619 Length: 19540 - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: Offset: 19285159 Length: 10246 - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: Offset: 19295405 Length: 31148 - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: Offset: 19326553 Length: 8307 - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: Offset: 19334860 Length: 14331 - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: Offset: 19349191 Length: 11295 - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: Offset: 19360486 Length: 20437 - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: Offset: 19380923 Length: 27739 - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: Offset: 19408662 Length: 22200 - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: Offset: 19430862 Length: 9620 - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: Offset: 19440482 Length: 13368 - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: Offset: 19453850 Length: 15612 - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: Offset: 19469462 Length: 8279 - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: Offset: 19477741 Length: 11383 - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: Offset: 19489124 Length: 18511 - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: Offset: 19507635 Length: 14244 - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: Offset: 19521879 Length: 24075 - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: Offset: 19545954 Length: 26716 - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: Offset: 19572670 Length: 21716 - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: Offset: 19594386 Length: 32417 - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: Offset: 19626803 Length: 33724 - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: Offset: 19660527 Length: 21828 - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: Offset: 19682355 Length: 30404 - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: Offset: 19712759 Length: 9862 - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: Offset: 19722621 Length: 18149 - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: Offset: 19740770 Length: 14697 - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: Offset: 19755467 Length: 17316 - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: Offset: 19772783 Length: 14869 - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: Offset: 19787652 Length: 29873 - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: Offset: 19817525 Length: 16335 - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: Offset: 19833860 Length: 20565 - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: Offset: 19854425 Length: 25497 - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: Offset: 19879922 Length: 17142 - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: Offset: 19897064 Length: 20120 - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: Offset: 19917184 Length: 29921 - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: Offset: 19947105 Length: 14467 - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: Offset: 19961572 Length: 10906 - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: Offset: 19972478 Length: 25959 - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: Offset: 19998437 Length: 34175 - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: Offset: 20032612 Length: 30124 - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: Offset: 20062736 Length: 21881 - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: Offset: 20084617 Length: 20567 - ^Content/d2k/v2/SOUND.RS: + ^SupportDir|Content/d2k/v2/SOUND.RS: Offset: 20105184 Length: 1929247 - ^Content/d2k/v2/FONT.BIN: + ^SupportDir|Content/d2k/v2/FONT.BIN: Offset: 22473214 Length: 199 - ^Content/d2k/v2/PALETTE.BIN: + ^SupportDir|Content/d2k/v2/PALETTE.BIN: Offset: 22484154 Length: 815 \ No newline at end of file diff -Nru openra-20200503/mods/d2k/installer/downloads.yaml openra-20210321/mods/d2k/installer/downloads.yaml --- openra-20200503/mods/d2k/installer/downloads.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/installer/downloads.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,543 +2,543 @@ SHA1: eb9ff88ca24858bd06a752f923156a6480c25c06 MirrorList: http://www.openra.net/packages/d2k-quickinstall-mirrors.txt Extract: - ^Content/d2k/v2/BLOXBASE.R8: v2/BLOXBASE.R8 - ^Content/d2k/v2/BLOXBAT.R8: v2/BLOXBAT.R8 - ^Content/d2k/v2/BLOXBGBS.R8: v2/BLOXBGBS.R8 - ^Content/d2k/v2/BLOXICE.R8: v2/BLOXICE.R8 - ^Content/d2k/v2/BLOXTREE.R8: v2/BLOXTREE.R8 - ^Content/d2k/v2/BLOXWAST.R8: v2/BLOXWAST.R8 - ^Content/d2k/v2/FONT.BIN: v2/FONT.BIN - ^Content/d2k/v2/FONTCOL.FNT: v2/FONTCOL.FNT - ^Content/d2k/v2/FONTCOL.FPL: v2/FONTCOL.FPL - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: v2/GAMESFX/A_ECONF1.AUD - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: v2/GAMESFX/A_ECONF2.AUD - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: v2/GAMESFX/A_ECONF3.AUD - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: v2/GAMESFX/A_ESEL1.AUD - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: v2/GAMESFX/A_ESEL2.AUD - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: v2/GAMESFX/A_ESEL3.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: v2/GAMESFX/A_FCONF1.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: v2/GAMESFX/A_FCONF2.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: v2/GAMESFX/A_FCONF3.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: v2/GAMESFX/A_FCONF4.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: v2/GAMESFX/A_FSEL1.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: v2/GAMESFX/A_FSEL2.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: v2/GAMESFX/A_FSEL3.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: v2/GAMESFX/A_FSEL4.AUD - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: v2/GAMESFX/A_ICONF1.AUD - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: v2/GAMESFX/A_ICONF2.AUD - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: v2/GAMESFX/A_ICONF3.AUD - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: v2/GAMESFX/A_ISEL1.AUD - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: v2/GAMESFX/A_ISEL2.AUD - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: v2/GAMESFX/A_ISEL3.AUD - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: v2/GAMESFX/A_VCONF1.AUD - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: v2/GAMESFX/A_VCONF2.AUD - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: v2/GAMESFX/A_VCONF3.AUD - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: v2/GAMESFX/A_VSEL1.AUD - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: v2/GAMESFX/A_VSEL2.AUD - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: v2/GAMESFX/A_VSEL3.AUD - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: v2/GAMESFX/AI_1MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: v2/GAMESFX/AI_2MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: v2/GAMESFX/AI_3MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: v2/GAMESFX/AI_4MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: v2/GAMESFX/AI_5MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: v2/GAMESFX/AI_ABORT.AUD - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: v2/GAMESFX/AI_ATACK.AUD - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: v2/GAMESFX/AI_BDRDY.AUD - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: v2/GAMESFX/AI_BLOST.AUD - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: v2/GAMESFX/AI_BUILD.AUD - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: v2/GAMESFX/AI_CANCL.AUD - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: v2/GAMESFX/AI_CAPT.AUD - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: v2/GAMESFX/AI_DHRDY.AUD - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: v2/GAMESFX/AI_DPLOY.AUD - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: v2/GAMESFX/AI_ENEMY.AUD - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: v2/GAMESFX/AI_GANEW.AUD - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: v2/GAMESFX/AI_GLOAD.AUD - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: v2/GAMESFX/AI_GSAVE.AUD - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: v2/GAMESFX/AI_GUARD.AUD - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: v2/GAMESFX/AI_HATTK.AUD - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: v2/GAMESFX/AI_HOLD.AUD - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: v2/GAMESFX/AI_LAUNC.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: v2/GAMESFX/AI_MAP1A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: v2/GAMESFX/AI_MAP1B.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: v2/GAMESFX/AI_MAP1C.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: v2/GAMESFX/AI_MAP2A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: v2/GAMESFX/AI_MAP2B.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: v2/GAMESFX/AI_MAP2C.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: v2/GAMESFX/AI_MAP3A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: v2/GAMESFX/AI_MAP4A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: v2/GAMESFX/AI_MAP5A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: v2/GAMESFX/AI_MAP6A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: v2/GAMESFX/AI_MAP7A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: v2/GAMESFX/AI_MAP8A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: v2/GAMESFX/AI_MAP9A.AUD - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: v2/GAMESFX/AI_MEND.AUD - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: v2/GAMESFX/AI_MFAIL.AUD - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: v2/GAMESFX/AI_MONEY.AUD - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: v2/GAMESFX/AI_MWIN.AUD - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: v2/GAMESFX/AI_NEWOP.AUD - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: v2/GAMESFX/AI_NROOM.AUD - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: v2/GAMESFX/AI_ORDER.AUD - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: v2/GAMESFX/AI_PLACE.AUD - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: v2/GAMESFX/AI_POWER.AUD - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: v2/GAMESFX/AI_PREP.AUD - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: v2/GAMESFX/AI_PRMRY.AUD - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: v2/GAMESFX/AI_REINF.AUD - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: v2/GAMESFX/AI_RUN.AUD - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: v2/GAMESFX/AI_SELL.AUD - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: v2/GAMESFX/AI_SILOS.AUD - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: v2/GAMESFX/AI_SPORT.AUD - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: v2/GAMESFX/AI_TRAIN.AUD - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: v2/GAMESFX/AI_ULOST.AUD - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: v2/GAMESFX/AI_UNRDY.AUD - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: v2/GAMESFX/AI_UPGOP.AUD - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: v2/GAMESFX/AI_UPGRD.AUD - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: v2/GAMESFX/AI_WATTK.AUD - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: v2/GAMESFX/AI_WSIGN.AUD - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: v2/GAMESFX/G_SCONF1.AUD - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: v2/GAMESFX/G_SCONF2.AUD - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: v2/GAMESFX/G_SCONF3.AUD - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: v2/GAMESFX/G_SSEL1.AUD - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: v2/GAMESFX/G_SSEL2.AUD - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: v2/GAMESFX/G_SSEL3.AUD - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: v2/GAMESFX/H_ECONF1.AUD - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: v2/GAMESFX/H_ECONF2.AUD - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: v2/GAMESFX/H_ECONF3.AUD - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: v2/GAMESFX/H_ESEL1.AUD - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: v2/GAMESFX/H_ESEL2.AUD - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: v2/GAMESFX/H_ESEL3.AUD - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: v2/GAMESFX/H_ICONF1.AUD - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: v2/GAMESFX/H_ICONF2.AUD - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: v2/GAMESFX/H_ICONF3.AUD - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: v2/GAMESFX/H_ISEL1.AUD - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: v2/GAMESFX/H_ISEL2.AUD - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: v2/GAMESFX/H_ISEL3.AUD - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: v2/GAMESFX/H_VCONF1.AUD - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: v2/GAMESFX/H_VCONF2.AUD - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: v2/GAMESFX/H_VCONF3.AUD - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: v2/GAMESFX/H_VSEL1.AUD - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: v2/GAMESFX/H_VSEL2.AUD - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: v2/GAMESFX/H_VSEL3.AUD - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: v2/GAMESFX/HI_1MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: v2/GAMESFX/HI_2MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: v2/GAMESFX/HI_3MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: v2/GAMESFX/HI_4MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: v2/GAMESFX/HI_5MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: v2/GAMESFX/HI_ABORT.AUD - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: v2/GAMESFX/HI_ATACK.AUD - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: v2/GAMESFX/HI_BDRDY.AUD - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: v2/GAMESFX/HI_BLOST.AUD - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: v2/GAMESFX/HI_BUILD.AUD - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: v2/GAMESFX/HI_CANCL.AUD - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: v2/GAMESFX/HI_CAPT.AUD - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: v2/GAMESFX/HI_DHRDY.AUD - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: v2/GAMESFX/HI_DPLOY.AUD - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: v2/GAMESFX/HI_ENEMY.AUD - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: v2/GAMESFX/HI_GANEW.AUD - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: v2/GAMESFX/HI_GLOAD.AUD - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: v2/GAMESFX/HI_GSAVE.AUD - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: v2/GAMESFX/HI_GUARD.AUD - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: v2/GAMESFX/HI_HATTK.AUD - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: v2/GAMESFX/HI_HOLD.AUD - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: v2/GAMESFX/HI_LAUNC.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: v2/GAMESFX/HI_MAP1A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: v2/GAMESFX/HI_MAP1B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: v2/GAMESFX/HI_MAP1C.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: v2/GAMESFX/HI_MAP2A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: v2/GAMESFX/HI_MAP2B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: v2/GAMESFX/HI_MAP2C.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: v2/GAMESFX/HI_MAP3A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: v2/GAMESFX/HI_MAP3B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: v2/GAMESFX/HI_MAP4A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: v2/GAMESFX/HI_MAP4B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: v2/GAMESFX/HI_MAP5A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: v2/GAMESFX/HI_MAP6A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: v2/GAMESFX/HI_MAP6B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: v2/GAMESFX/HI_MAP7A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: v2/GAMESFX/HI_MAP9.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: v2/GAMESFX/HI_MAP9A.AUD - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: v2/GAMESFX/HI_MEND.AUD - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: v2/GAMESFX/HI_MFAIL.AUD - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: v2/GAMESFX/HI_MONEY.AUD - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: v2/GAMESFX/HI_MWIN.AUD - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: v2/GAMESFX/HI_NEWOP.AUD - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: v2/GAMESFX/HI_NROOM.AUD - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: v2/GAMESFX/HI_ORDER.AUD - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: v2/GAMESFX/HI_PLACE.AUD - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: v2/GAMESFX/HI_POWER.AUD - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: v2/GAMESFX/HI_PREP.AUD - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: v2/GAMESFX/HI_PRMRY.AUD - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: v2/GAMESFX/HI_REINF.AUD - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: v2/GAMESFX/HI_RUN.AUD - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: v2/GAMESFX/HI_SELL.AUD - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: v2/GAMESFX/HI_SILOS.AUD - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: v2/GAMESFX/HI_SPORT.AUD - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: v2/GAMESFX/HI_TRAIN.AUD - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: v2/GAMESFX/HI_ULOST.AUD - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: v2/GAMESFX/HI_UNRDY.AUD - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: v2/GAMESFX/HI_UPGOP.AUD - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: v2/GAMESFX/HI_UPGRD.AUD - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: v2/GAMESFX/HI_WATTK.AUD - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: v2/GAMESFX/HI_WSIGN.AUD - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: v2/GAMESFX/O_ECONF1.AUD - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: v2/GAMESFX/O_ECONF2.AUD - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: v2/GAMESFX/O_ECONF3.AUD - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: v2/GAMESFX/O_ESEL1.AUD - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: v2/GAMESFX/O_ESEL2.AUD - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: v2/GAMESFX/O_ESEL3.AUD - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: v2/GAMESFX/O_ICONF1.AUD - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: v2/GAMESFX/O_ICONF2.AUD - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: v2/GAMESFX/O_ICONF3.AUD - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: v2/GAMESFX/O_ISEL1.AUD - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: v2/GAMESFX/O_ISEL2.AUD - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: v2/GAMESFX/O_ISEL3.AUD - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: v2/GAMESFX/O_SCONF1.AUD - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: v2/GAMESFX/O_SCONF2.AUD - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: v2/GAMESFX/O_SCONF3.AUD - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: v2/GAMESFX/O_SSEL1.AUD - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: v2/GAMESFX/O_SSEL2.AUD - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: v2/GAMESFX/O_SSEL3.AUD - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: v2/GAMESFX/O_VCONF1.AUD - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: v2/GAMESFX/O_VCONF2.AUD - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: v2/GAMESFX/O_VCONF3.AUD - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: v2/GAMESFX/O_VSEL1.AUD - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: v2/GAMESFX/O_VSEL2.AUD - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: v2/GAMESFX/O_VSEL3.AUD - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: v2/GAMESFX/OI_1MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: v2/GAMESFX/OI_2MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: v2/GAMESFX/OI_3MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: v2/GAMESFX/OI_4MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: v2/GAMESFX/OI_5MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: v2/GAMESFX/OI_ABORT.AUD - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: v2/GAMESFX/OI_ATACK.AUD - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: v2/GAMESFX/OI_BDRDY.AUD - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: v2/GAMESFX/OI_BLOST.AUD - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: v2/GAMESFX/OI_BUILD.AUD - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: v2/GAMESFX/OI_CANCL.AUD - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: v2/GAMESFX/OI_CAPT.AUD - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: v2/GAMESFX/OI_DHRDY.AUD - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: v2/GAMESFX/OI_DPLOY.AUD - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: v2/GAMESFX/OI_ENEMY.AUD - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: v2/GAMESFX/OI_GANEW.AUD - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: v2/GAMESFX/OI_GLOAD.AUD - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: v2/GAMESFX/OI_GSAVE.AUD - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: v2/GAMESFX/OI_GUARD.AUD - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: v2/GAMESFX/OI_HATTK.AUD - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: v2/GAMESFX/OI_HOLD.AUD - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: v2/GAMESFX/OI_LAUNC.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: v2/GAMESFX/OI_MAP1A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: v2/GAMESFX/OI_MAP1B.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: v2/GAMESFX/OI_MAP1C.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: v2/GAMESFX/OI_MAP2A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: v2/GAMESFX/OI_MAP2B.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: v2/GAMESFX/OI_MAP2C.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: v2/GAMESFX/OI_MAP3A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: v2/GAMESFX/OI_MAP4A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: v2/GAMESFX/OI_MAP5A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: v2/GAMESFX/OI_MAP6A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: v2/GAMESFX/OI_MAP7A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: v2/GAMESFX/OI_MAP8A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: v2/GAMESFX/OI_MAP9A.AUD - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: v2/GAMESFX/OI_MEND.AUD - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: v2/GAMESFX/OI_MFAIL.AUD - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: v2/GAMESFX/OI_MONEY.AUD - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: v2/GAMESFX/OI_MWIN.AUD - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: v2/GAMESFX/OI_NEWOP.AUD - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: v2/GAMESFX/OI_NROOM.AUD - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: v2/GAMESFX/OI_ORDER.AUD - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: v2/GAMESFX/OI_PLACE.AUD - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: v2/GAMESFX/OI_POWER.AUD - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: v2/GAMESFX/OI_PREP.AUD - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: v2/GAMESFX/OI_PRMRY.AUD - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: v2/GAMESFX/OI_REINF.AUD - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: v2/GAMESFX/OI_RUN.AUD - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: v2/GAMESFX/OI_SELL.AUD - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: v2/GAMESFX/OI_SILOS.AUD - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: v2/GAMESFX/OI_SPORT.AUD - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: v2/GAMESFX/OI_TRAIN.AUD - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: v2/GAMESFX/OI_ULOST.AUD - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: v2/GAMESFX/OI_UNRDY.AUD - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: v2/GAMESFX/OI_UPGOP.AUD - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: v2/GAMESFX/OI_UPGRD.AUD - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: v2/GAMESFX/OI_WATTK.AUD - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: v2/GAMESFX/OI_WSIGN.AUD - ^Content/d2k/v2/MOUSE.R8: v2/MOUSE.R8 - ^Content/d2k/v2/PALETTE.BIN: v2/PALETTE.BIN - ^Content/d2k/v2/SOUND.RS: v2/SOUND.RS - ^Content/d2k/v2/BLOXXMAS.R8: v2/BLOXXMAS.R8 - ^Content/d2k/v2/DATA.R8: v2/DATA.R8 + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: v2/BLOXBASE.R8 + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: v2/BLOXBAT.R8 + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: v2/BLOXBGBS.R8 + ^SupportDir|Content/d2k/v2/BLOXICE.R8: v2/BLOXICE.R8 + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: v2/BLOXTREE.R8 + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: v2/BLOXWAST.R8 + ^SupportDir|Content/d2k/v2/FONT.BIN: v2/FONT.BIN + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: v2/FONTCOL.FNT + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: v2/FONTCOL.FPL + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: v2/GAMESFX/A_ECONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: v2/GAMESFX/A_ECONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: v2/GAMESFX/A_ECONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: v2/GAMESFX/A_ESEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: v2/GAMESFX/A_ESEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: v2/GAMESFX/A_ESEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: v2/GAMESFX/A_FCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: v2/GAMESFX/A_FCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: v2/GAMESFX/A_FCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: v2/GAMESFX/A_FCONF4.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: v2/GAMESFX/A_FSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: v2/GAMESFX/A_FSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: v2/GAMESFX/A_FSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: v2/GAMESFX/A_FSEL4.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: v2/GAMESFX/A_ICONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: v2/GAMESFX/A_ICONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: v2/GAMESFX/A_ICONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: v2/GAMESFX/A_ISEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: v2/GAMESFX/A_ISEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: v2/GAMESFX/A_ISEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: v2/GAMESFX/A_VCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: v2/GAMESFX/A_VCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: v2/GAMESFX/A_VCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: v2/GAMESFX/A_VSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: v2/GAMESFX/A_VSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: v2/GAMESFX/A_VSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: v2/GAMESFX/AI_1MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: v2/GAMESFX/AI_2MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: v2/GAMESFX/AI_3MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: v2/GAMESFX/AI_4MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: v2/GAMESFX/AI_5MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: v2/GAMESFX/AI_ABORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: v2/GAMESFX/AI_ATACK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: v2/GAMESFX/AI_BDRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: v2/GAMESFX/AI_BLOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: v2/GAMESFX/AI_BUILD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: v2/GAMESFX/AI_CANCL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: v2/GAMESFX/AI_CAPT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: v2/GAMESFX/AI_DHRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: v2/GAMESFX/AI_DPLOY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: v2/GAMESFX/AI_ENEMY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: v2/GAMESFX/AI_GANEW.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: v2/GAMESFX/AI_GLOAD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: v2/GAMESFX/AI_GSAVE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: v2/GAMESFX/AI_GUARD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: v2/GAMESFX/AI_HATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: v2/GAMESFX/AI_HOLD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: v2/GAMESFX/AI_LAUNC.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: v2/GAMESFX/AI_MAP1A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: v2/GAMESFX/AI_MAP1B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: v2/GAMESFX/AI_MAP1C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: v2/GAMESFX/AI_MAP2A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: v2/GAMESFX/AI_MAP2B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: v2/GAMESFX/AI_MAP2C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: v2/GAMESFX/AI_MAP3A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: v2/GAMESFX/AI_MAP4A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: v2/GAMESFX/AI_MAP5A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: v2/GAMESFX/AI_MAP6A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: v2/GAMESFX/AI_MAP7A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: v2/GAMESFX/AI_MAP8A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: v2/GAMESFX/AI_MAP9A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: v2/GAMESFX/AI_MEND.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: v2/GAMESFX/AI_MFAIL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: v2/GAMESFX/AI_MONEY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: v2/GAMESFX/AI_MWIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: v2/GAMESFX/AI_NEWOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: v2/GAMESFX/AI_NROOM.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: v2/GAMESFX/AI_ORDER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: v2/GAMESFX/AI_PLACE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: v2/GAMESFX/AI_POWER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: v2/GAMESFX/AI_PREP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: v2/GAMESFX/AI_PRMRY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: v2/GAMESFX/AI_REINF.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: v2/GAMESFX/AI_RUN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: v2/GAMESFX/AI_SELL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: v2/GAMESFX/AI_SILOS.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: v2/GAMESFX/AI_SPORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: v2/GAMESFX/AI_TRAIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: v2/GAMESFX/AI_ULOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: v2/GAMESFX/AI_UNRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: v2/GAMESFX/AI_UPGOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: v2/GAMESFX/AI_UPGRD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: v2/GAMESFX/AI_WATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: v2/GAMESFX/AI_WSIGN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: v2/GAMESFX/G_SCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: v2/GAMESFX/G_SCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: v2/GAMESFX/G_SCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: v2/GAMESFX/G_SSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: v2/GAMESFX/G_SSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: v2/GAMESFX/G_SSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: v2/GAMESFX/H_ECONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: v2/GAMESFX/H_ECONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: v2/GAMESFX/H_ECONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: v2/GAMESFX/H_ESEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: v2/GAMESFX/H_ESEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: v2/GAMESFX/H_ESEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: v2/GAMESFX/H_ICONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: v2/GAMESFX/H_ICONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: v2/GAMESFX/H_ICONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: v2/GAMESFX/H_ISEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: v2/GAMESFX/H_ISEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: v2/GAMESFX/H_ISEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: v2/GAMESFX/H_VCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: v2/GAMESFX/H_VCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: v2/GAMESFX/H_VCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: v2/GAMESFX/H_VSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: v2/GAMESFX/H_VSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: v2/GAMESFX/H_VSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: v2/GAMESFX/HI_1MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: v2/GAMESFX/HI_2MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: v2/GAMESFX/HI_3MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: v2/GAMESFX/HI_4MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: v2/GAMESFX/HI_5MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: v2/GAMESFX/HI_ABORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: v2/GAMESFX/HI_ATACK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: v2/GAMESFX/HI_BDRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: v2/GAMESFX/HI_BLOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: v2/GAMESFX/HI_BUILD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: v2/GAMESFX/HI_CANCL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: v2/GAMESFX/HI_CAPT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: v2/GAMESFX/HI_DHRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: v2/GAMESFX/HI_DPLOY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: v2/GAMESFX/HI_ENEMY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: v2/GAMESFX/HI_GANEW.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: v2/GAMESFX/HI_GLOAD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: v2/GAMESFX/HI_GSAVE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: v2/GAMESFX/HI_GUARD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: v2/GAMESFX/HI_HATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: v2/GAMESFX/HI_HOLD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: v2/GAMESFX/HI_LAUNC.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: v2/GAMESFX/HI_MAP1A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: v2/GAMESFX/HI_MAP1B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: v2/GAMESFX/HI_MAP1C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: v2/GAMESFX/HI_MAP2A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: v2/GAMESFX/HI_MAP2B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: v2/GAMESFX/HI_MAP2C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: v2/GAMESFX/HI_MAP3A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: v2/GAMESFX/HI_MAP3B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: v2/GAMESFX/HI_MAP4A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: v2/GAMESFX/HI_MAP4B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: v2/GAMESFX/HI_MAP5A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: v2/GAMESFX/HI_MAP6A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: v2/GAMESFX/HI_MAP6B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: v2/GAMESFX/HI_MAP7A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: v2/GAMESFX/HI_MAP9.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: v2/GAMESFX/HI_MAP9A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: v2/GAMESFX/HI_MEND.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: v2/GAMESFX/HI_MFAIL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: v2/GAMESFX/HI_MONEY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: v2/GAMESFX/HI_MWIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: v2/GAMESFX/HI_NEWOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: v2/GAMESFX/HI_NROOM.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: v2/GAMESFX/HI_ORDER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: v2/GAMESFX/HI_PLACE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: v2/GAMESFX/HI_POWER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: v2/GAMESFX/HI_PREP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: v2/GAMESFX/HI_PRMRY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: v2/GAMESFX/HI_REINF.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: v2/GAMESFX/HI_RUN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: v2/GAMESFX/HI_SELL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: v2/GAMESFX/HI_SILOS.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: v2/GAMESFX/HI_SPORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: v2/GAMESFX/HI_TRAIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: v2/GAMESFX/HI_ULOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: v2/GAMESFX/HI_UNRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: v2/GAMESFX/HI_UPGOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: v2/GAMESFX/HI_UPGRD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: v2/GAMESFX/HI_WATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: v2/GAMESFX/HI_WSIGN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: v2/GAMESFX/O_ECONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: v2/GAMESFX/O_ECONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: v2/GAMESFX/O_ECONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: v2/GAMESFX/O_ESEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: v2/GAMESFX/O_ESEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: v2/GAMESFX/O_ESEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: v2/GAMESFX/O_ICONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: v2/GAMESFX/O_ICONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: v2/GAMESFX/O_ICONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: v2/GAMESFX/O_ISEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: v2/GAMESFX/O_ISEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: v2/GAMESFX/O_ISEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: v2/GAMESFX/O_SCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: v2/GAMESFX/O_SCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: v2/GAMESFX/O_SCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: v2/GAMESFX/O_SSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: v2/GAMESFX/O_SSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: v2/GAMESFX/O_SSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: v2/GAMESFX/O_VCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: v2/GAMESFX/O_VCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: v2/GAMESFX/O_VCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: v2/GAMESFX/O_VSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: v2/GAMESFX/O_VSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: v2/GAMESFX/O_VSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: v2/GAMESFX/OI_1MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: v2/GAMESFX/OI_2MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: v2/GAMESFX/OI_3MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: v2/GAMESFX/OI_4MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: v2/GAMESFX/OI_5MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: v2/GAMESFX/OI_ABORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: v2/GAMESFX/OI_ATACK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: v2/GAMESFX/OI_BDRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: v2/GAMESFX/OI_BLOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: v2/GAMESFX/OI_BUILD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: v2/GAMESFX/OI_CANCL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: v2/GAMESFX/OI_CAPT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: v2/GAMESFX/OI_DHRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: v2/GAMESFX/OI_DPLOY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: v2/GAMESFX/OI_ENEMY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: v2/GAMESFX/OI_GANEW.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: v2/GAMESFX/OI_GLOAD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: v2/GAMESFX/OI_GSAVE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: v2/GAMESFX/OI_GUARD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: v2/GAMESFX/OI_HATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: v2/GAMESFX/OI_HOLD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: v2/GAMESFX/OI_LAUNC.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: v2/GAMESFX/OI_MAP1A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: v2/GAMESFX/OI_MAP1B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: v2/GAMESFX/OI_MAP1C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: v2/GAMESFX/OI_MAP2A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: v2/GAMESFX/OI_MAP2B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: v2/GAMESFX/OI_MAP2C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: v2/GAMESFX/OI_MAP3A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: v2/GAMESFX/OI_MAP4A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: v2/GAMESFX/OI_MAP5A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: v2/GAMESFX/OI_MAP6A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: v2/GAMESFX/OI_MAP7A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: v2/GAMESFX/OI_MAP8A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: v2/GAMESFX/OI_MAP9A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: v2/GAMESFX/OI_MEND.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: v2/GAMESFX/OI_MFAIL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: v2/GAMESFX/OI_MONEY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: v2/GAMESFX/OI_MWIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: v2/GAMESFX/OI_NEWOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: v2/GAMESFX/OI_NROOM.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: v2/GAMESFX/OI_ORDER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: v2/GAMESFX/OI_PLACE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: v2/GAMESFX/OI_POWER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: v2/GAMESFX/OI_PREP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: v2/GAMESFX/OI_PRMRY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: v2/GAMESFX/OI_REINF.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: v2/GAMESFX/OI_RUN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: v2/GAMESFX/OI_SELL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: v2/GAMESFX/OI_SILOS.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: v2/GAMESFX/OI_SPORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: v2/GAMESFX/OI_TRAIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: v2/GAMESFX/OI_ULOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: v2/GAMESFX/OI_UNRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: v2/GAMESFX/OI_UPGOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: v2/GAMESFX/OI_UPGRD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: v2/GAMESFX/OI_WATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: v2/GAMESFX/OI_WSIGN.AUD + ^SupportDir|Content/d2k/v2/MOUSE.R8: v2/MOUSE.R8 + ^SupportDir|Content/d2k/v2/PALETTE.BIN: v2/PALETTE.BIN + ^SupportDir|Content/d2k/v2/SOUND.RS: v2/SOUND.RS + ^SupportDir|Content/d2k/v2/BLOXXMAS.R8: v2/BLOXXMAS.R8 + ^SupportDir|Content/d2k/v2/DATA.R8: v2/DATA.R8 basefiles: Base Content SHA1: 82221691fe843a5a245969095f147e929c364234 MirrorList: http://www.openra.net/packages/d2k-base-mirrors.txt Extract: - ^Content/d2k/v2/BLOXBASE.R8: v2/BLOXBASE.R8 - ^Content/d2k/v2/BLOXBAT.R8: v2/BLOXBAT.R8 - ^Content/d2k/v2/BLOXBGBS.R8: v2/BLOXBGBS.R8 - ^Content/d2k/v2/BLOXICE.R8: v2/BLOXICE.R8 - ^Content/d2k/v2/BLOXTREE.R8: v2/BLOXTREE.R8 - ^Content/d2k/v2/BLOXWAST.R8: v2/BLOXWAST.R8 - ^Content/d2k/v2/FONT.BIN: v2/FONT.BIN - ^Content/d2k/v2/FONTCOL.FNT: v2/FONTCOL.FNT - ^Content/d2k/v2/FONTCOL.FPL: v2/FONTCOL.FPL - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: v2/GAMESFX/A_ECONF1.AUD - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: v2/GAMESFX/A_ECONF2.AUD - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: v2/GAMESFX/A_ECONF3.AUD - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: v2/GAMESFX/A_ESEL1.AUD - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: v2/GAMESFX/A_ESEL2.AUD - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: v2/GAMESFX/A_ESEL3.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: v2/GAMESFX/A_FCONF1.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: v2/GAMESFX/A_FCONF2.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: v2/GAMESFX/A_FCONF3.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: v2/GAMESFX/A_FCONF4.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: v2/GAMESFX/A_FSEL1.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: v2/GAMESFX/A_FSEL2.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: v2/GAMESFX/A_FSEL3.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: v2/GAMESFX/A_FSEL4.AUD - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: v2/GAMESFX/A_ICONF1.AUD - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: v2/GAMESFX/A_ICONF2.AUD - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: v2/GAMESFX/A_ICONF3.AUD - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: v2/GAMESFX/A_ISEL1.AUD - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: v2/GAMESFX/A_ISEL2.AUD - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: v2/GAMESFX/A_ISEL3.AUD - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: v2/GAMESFX/A_VCONF1.AUD - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: v2/GAMESFX/A_VCONF2.AUD - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: v2/GAMESFX/A_VCONF3.AUD - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: v2/GAMESFX/A_VSEL1.AUD - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: v2/GAMESFX/A_VSEL2.AUD - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: v2/GAMESFX/A_VSEL3.AUD - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: v2/GAMESFX/AI_1MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: v2/GAMESFX/AI_2MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: v2/GAMESFX/AI_3MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: v2/GAMESFX/AI_4MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: v2/GAMESFX/AI_5MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: v2/GAMESFX/AI_ABORT.AUD - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: v2/GAMESFX/AI_ATACK.AUD - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: v2/GAMESFX/AI_BDRDY.AUD - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: v2/GAMESFX/AI_BLOST.AUD - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: v2/GAMESFX/AI_BUILD.AUD - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: v2/GAMESFX/AI_CANCL.AUD - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: v2/GAMESFX/AI_CAPT.AUD - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: v2/GAMESFX/AI_DHRDY.AUD - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: v2/GAMESFX/AI_DPLOY.AUD - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: v2/GAMESFX/AI_ENEMY.AUD - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: v2/GAMESFX/AI_GANEW.AUD - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: v2/GAMESFX/AI_GLOAD.AUD - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: v2/GAMESFX/AI_GSAVE.AUD - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: v2/GAMESFX/AI_GUARD.AUD - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: v2/GAMESFX/AI_HATTK.AUD - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: v2/GAMESFX/AI_HOLD.AUD - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: v2/GAMESFX/AI_LAUNC.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: v2/GAMESFX/AI_MAP1A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: v2/GAMESFX/AI_MAP1B.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: v2/GAMESFX/AI_MAP1C.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: v2/GAMESFX/AI_MAP2A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: v2/GAMESFX/AI_MAP2B.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: v2/GAMESFX/AI_MAP2C.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: v2/GAMESFX/AI_MAP3A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: v2/GAMESFX/AI_MAP4A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: v2/GAMESFX/AI_MAP5A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: v2/GAMESFX/AI_MAP6A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: v2/GAMESFX/AI_MAP7A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: v2/GAMESFX/AI_MAP8A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: v2/GAMESFX/AI_MAP9A.AUD - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: v2/GAMESFX/AI_MEND.AUD - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: v2/GAMESFX/AI_MFAIL.AUD - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: v2/GAMESFX/AI_MONEY.AUD - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: v2/GAMESFX/AI_MWIN.AUD - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: v2/GAMESFX/AI_NEWOP.AUD - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: v2/GAMESFX/AI_NROOM.AUD - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: v2/GAMESFX/AI_ORDER.AUD - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: v2/GAMESFX/AI_PLACE.AUD - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: v2/GAMESFX/AI_POWER.AUD - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: v2/GAMESFX/AI_PREP.AUD - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: v2/GAMESFX/AI_PRMRY.AUD - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: v2/GAMESFX/AI_REINF.AUD - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: v2/GAMESFX/AI_RUN.AUD - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: v2/GAMESFX/AI_SELL.AUD - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: v2/GAMESFX/AI_SILOS.AUD - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: v2/GAMESFX/AI_SPORT.AUD - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: v2/GAMESFX/AI_TRAIN.AUD - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: v2/GAMESFX/AI_ULOST.AUD - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: v2/GAMESFX/AI_UNRDY.AUD - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: v2/GAMESFX/AI_UPGOP.AUD - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: v2/GAMESFX/AI_UPGRD.AUD - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: v2/GAMESFX/AI_WATTK.AUD - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: v2/GAMESFX/AI_WSIGN.AUD - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: v2/GAMESFX/G_SCONF1.AUD - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: v2/GAMESFX/G_SCONF2.AUD - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: v2/GAMESFX/G_SCONF3.AUD - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: v2/GAMESFX/G_SSEL1.AUD - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: v2/GAMESFX/G_SSEL2.AUD - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: v2/GAMESFX/G_SSEL3.AUD - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: v2/GAMESFX/H_ECONF1.AUD - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: v2/GAMESFX/H_ECONF2.AUD - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: v2/GAMESFX/H_ECONF3.AUD - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: v2/GAMESFX/H_ESEL1.AUD - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: v2/GAMESFX/H_ESEL2.AUD - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: v2/GAMESFX/H_ESEL3.AUD - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: v2/GAMESFX/H_ICONF1.AUD - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: v2/GAMESFX/H_ICONF2.AUD - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: v2/GAMESFX/H_ICONF3.AUD - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: v2/GAMESFX/H_ISEL1.AUD - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: v2/GAMESFX/H_ISEL2.AUD - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: v2/GAMESFX/H_ISEL3.AUD - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: v2/GAMESFX/H_VCONF1.AUD - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: v2/GAMESFX/H_VCONF2.AUD - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: v2/GAMESFX/H_VCONF3.AUD - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: v2/GAMESFX/H_VSEL1.AUD - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: v2/GAMESFX/H_VSEL2.AUD - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: v2/GAMESFX/H_VSEL3.AUD - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: v2/GAMESFX/HI_1MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: v2/GAMESFX/HI_2MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: v2/GAMESFX/HI_3MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: v2/GAMESFX/HI_4MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: v2/GAMESFX/HI_5MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: v2/GAMESFX/HI_ABORT.AUD - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: v2/GAMESFX/HI_ATACK.AUD - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: v2/GAMESFX/HI_BDRDY.AUD - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: v2/GAMESFX/HI_BLOST.AUD - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: v2/GAMESFX/HI_BUILD.AUD - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: v2/GAMESFX/HI_CANCL.AUD - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: v2/GAMESFX/HI_CAPT.AUD - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: v2/GAMESFX/HI_DHRDY.AUD - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: v2/GAMESFX/HI_DPLOY.AUD - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: v2/GAMESFX/HI_ENEMY.AUD - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: v2/GAMESFX/HI_GANEW.AUD - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: v2/GAMESFX/HI_GLOAD.AUD - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: v2/GAMESFX/HI_GSAVE.AUD - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: v2/GAMESFX/HI_GUARD.AUD - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: v2/GAMESFX/HI_HATTK.AUD - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: v2/GAMESFX/HI_HOLD.AUD - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: v2/GAMESFX/HI_LAUNC.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: v2/GAMESFX/HI_MAP1A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: v2/GAMESFX/HI_MAP1B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: v2/GAMESFX/HI_MAP1C.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: v2/GAMESFX/HI_MAP2A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: v2/GAMESFX/HI_MAP2B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: v2/GAMESFX/HI_MAP2C.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: v2/GAMESFX/HI_MAP3A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: v2/GAMESFX/HI_MAP3B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: v2/GAMESFX/HI_MAP4A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: v2/GAMESFX/HI_MAP4B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: v2/GAMESFX/HI_MAP5A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: v2/GAMESFX/HI_MAP6A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: v2/GAMESFX/HI_MAP6B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: v2/GAMESFX/HI_MAP7A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: v2/GAMESFX/HI_MAP9.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: v2/GAMESFX/HI_MAP9A.AUD - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: v2/GAMESFX/HI_MEND.AUD - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: v2/GAMESFX/HI_MFAIL.AUD - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: v2/GAMESFX/HI_MONEY.AUD - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: v2/GAMESFX/HI_MWIN.AUD - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: v2/GAMESFX/HI_NEWOP.AUD - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: v2/GAMESFX/HI_NROOM.AUD - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: v2/GAMESFX/HI_ORDER.AUD - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: v2/GAMESFX/HI_PLACE.AUD - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: v2/GAMESFX/HI_POWER.AUD - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: v2/GAMESFX/HI_PREP.AUD - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: v2/GAMESFX/HI_PRMRY.AUD - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: v2/GAMESFX/HI_REINF.AUD - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: v2/GAMESFX/HI_RUN.AUD - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: v2/GAMESFX/HI_SELL.AUD - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: v2/GAMESFX/HI_SILOS.AUD - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: v2/GAMESFX/HI_SPORT.AUD - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: v2/GAMESFX/HI_TRAIN.AUD - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: v2/GAMESFX/HI_ULOST.AUD - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: v2/GAMESFX/HI_UNRDY.AUD - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: v2/GAMESFX/HI_UPGOP.AUD - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: v2/GAMESFX/HI_UPGRD.AUD - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: v2/GAMESFX/HI_WATTK.AUD - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: v2/GAMESFX/HI_WSIGN.AUD - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: v2/GAMESFX/O_ECONF1.AUD - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: v2/GAMESFX/O_ECONF2.AUD - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: v2/GAMESFX/O_ECONF3.AUD - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: v2/GAMESFX/O_ESEL1.AUD - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: v2/GAMESFX/O_ESEL2.AUD - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: v2/GAMESFX/O_ESEL3.AUD - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: v2/GAMESFX/O_ICONF1.AUD - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: v2/GAMESFX/O_ICONF2.AUD - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: v2/GAMESFX/O_ICONF3.AUD - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: v2/GAMESFX/O_ISEL1.AUD - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: v2/GAMESFX/O_ISEL2.AUD - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: v2/GAMESFX/O_ISEL3.AUD - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: v2/GAMESFX/O_SCONF1.AUD - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: v2/GAMESFX/O_SCONF2.AUD - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: v2/GAMESFX/O_SCONF3.AUD - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: v2/GAMESFX/O_SSEL1.AUD - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: v2/GAMESFX/O_SSEL2.AUD - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: v2/GAMESFX/O_SSEL3.AUD - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: v2/GAMESFX/O_VCONF1.AUD - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: v2/GAMESFX/O_VCONF2.AUD - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: v2/GAMESFX/O_VCONF3.AUD - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: v2/GAMESFX/O_VSEL1.AUD - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: v2/GAMESFX/O_VSEL2.AUD - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: v2/GAMESFX/O_VSEL3.AUD - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: v2/GAMESFX/OI_1MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: v2/GAMESFX/OI_2MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: v2/GAMESFX/OI_3MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: v2/GAMESFX/OI_4MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: v2/GAMESFX/OI_5MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: v2/GAMESFX/OI_ABORT.AUD - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: v2/GAMESFX/OI_ATACK.AUD - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: v2/GAMESFX/OI_BDRDY.AUD - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: v2/GAMESFX/OI_BLOST.AUD - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: v2/GAMESFX/OI_BUILD.AUD - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: v2/GAMESFX/OI_CANCL.AUD - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: v2/GAMESFX/OI_CAPT.AUD - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: v2/GAMESFX/OI_DHRDY.AUD - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: v2/GAMESFX/OI_DPLOY.AUD - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: v2/GAMESFX/OI_ENEMY.AUD - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: v2/GAMESFX/OI_GANEW.AUD - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: v2/GAMESFX/OI_GLOAD.AUD - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: v2/GAMESFX/OI_GSAVE.AUD - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: v2/GAMESFX/OI_GUARD.AUD - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: v2/GAMESFX/OI_HATTK.AUD - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: v2/GAMESFX/OI_HOLD.AUD - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: v2/GAMESFX/OI_LAUNC.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: v2/GAMESFX/OI_MAP1A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: v2/GAMESFX/OI_MAP1B.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: v2/GAMESFX/OI_MAP1C.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: v2/GAMESFX/OI_MAP2A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: v2/GAMESFX/OI_MAP2B.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: v2/GAMESFX/OI_MAP2C.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: v2/GAMESFX/OI_MAP3A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: v2/GAMESFX/OI_MAP4A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: v2/GAMESFX/OI_MAP5A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: v2/GAMESFX/OI_MAP6A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: v2/GAMESFX/OI_MAP7A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: v2/GAMESFX/OI_MAP8A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: v2/GAMESFX/OI_MAP9A.AUD - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: v2/GAMESFX/OI_MEND.AUD - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: v2/GAMESFX/OI_MFAIL.AUD - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: v2/GAMESFX/OI_MONEY.AUD - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: v2/GAMESFX/OI_MWIN.AUD - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: v2/GAMESFX/OI_NEWOP.AUD - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: v2/GAMESFX/OI_NROOM.AUD - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: v2/GAMESFX/OI_ORDER.AUD - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: v2/GAMESFX/OI_PLACE.AUD - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: v2/GAMESFX/OI_POWER.AUD - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: v2/GAMESFX/OI_PREP.AUD - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: v2/GAMESFX/OI_PRMRY.AUD - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: v2/GAMESFX/OI_REINF.AUD - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: v2/GAMESFX/OI_RUN.AUD - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: v2/GAMESFX/OI_SELL.AUD - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: v2/GAMESFX/OI_SILOS.AUD - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: v2/GAMESFX/OI_SPORT.AUD - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: v2/GAMESFX/OI_TRAIN.AUD - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: v2/GAMESFX/OI_ULOST.AUD - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: v2/GAMESFX/OI_UNRDY.AUD - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: v2/GAMESFX/OI_UPGOP.AUD - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: v2/GAMESFX/OI_UPGRD.AUD - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: v2/GAMESFX/OI_WATTK.AUD - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: v2/GAMESFX/OI_WSIGN.AUD - ^Content/d2k/v2/MOUSE.R8: v2/MOUSE.R8 - ^Content/d2k/v2/PALETTE.BIN: v2/PALETTE.BIN - ^Content/d2k/v2/SOUND.RS: v2/SOUND.RS + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: v2/BLOXBASE.R8 + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: v2/BLOXBAT.R8 + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: v2/BLOXBGBS.R8 + ^SupportDir|Content/d2k/v2/BLOXICE.R8: v2/BLOXICE.R8 + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: v2/BLOXTREE.R8 + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: v2/BLOXWAST.R8 + ^SupportDir|Content/d2k/v2/FONT.BIN: v2/FONT.BIN + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: v2/FONTCOL.FNT + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: v2/FONTCOL.FPL + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: v2/GAMESFX/A_ECONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: v2/GAMESFX/A_ECONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: v2/GAMESFX/A_ECONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: v2/GAMESFX/A_ESEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: v2/GAMESFX/A_ESEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: v2/GAMESFX/A_ESEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: v2/GAMESFX/A_FCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: v2/GAMESFX/A_FCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: v2/GAMESFX/A_FCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: v2/GAMESFX/A_FCONF4.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: v2/GAMESFX/A_FSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: v2/GAMESFX/A_FSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: v2/GAMESFX/A_FSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: v2/GAMESFX/A_FSEL4.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: v2/GAMESFX/A_ICONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: v2/GAMESFX/A_ICONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: v2/GAMESFX/A_ICONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: v2/GAMESFX/A_ISEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: v2/GAMESFX/A_ISEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: v2/GAMESFX/A_ISEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: v2/GAMESFX/A_VCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: v2/GAMESFX/A_VCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: v2/GAMESFX/A_VCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: v2/GAMESFX/A_VSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: v2/GAMESFX/A_VSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: v2/GAMESFX/A_VSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: v2/GAMESFX/AI_1MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: v2/GAMESFX/AI_2MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: v2/GAMESFX/AI_3MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: v2/GAMESFX/AI_4MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: v2/GAMESFX/AI_5MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: v2/GAMESFX/AI_ABORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: v2/GAMESFX/AI_ATACK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: v2/GAMESFX/AI_BDRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: v2/GAMESFX/AI_BLOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: v2/GAMESFX/AI_BUILD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: v2/GAMESFX/AI_CANCL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: v2/GAMESFX/AI_CAPT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: v2/GAMESFX/AI_DHRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: v2/GAMESFX/AI_DPLOY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: v2/GAMESFX/AI_ENEMY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: v2/GAMESFX/AI_GANEW.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: v2/GAMESFX/AI_GLOAD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: v2/GAMESFX/AI_GSAVE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: v2/GAMESFX/AI_GUARD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: v2/GAMESFX/AI_HATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: v2/GAMESFX/AI_HOLD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: v2/GAMESFX/AI_LAUNC.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: v2/GAMESFX/AI_MAP1A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: v2/GAMESFX/AI_MAP1B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: v2/GAMESFX/AI_MAP1C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: v2/GAMESFX/AI_MAP2A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: v2/GAMESFX/AI_MAP2B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: v2/GAMESFX/AI_MAP2C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: v2/GAMESFX/AI_MAP3A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: v2/GAMESFX/AI_MAP4A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: v2/GAMESFX/AI_MAP5A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: v2/GAMESFX/AI_MAP6A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: v2/GAMESFX/AI_MAP7A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: v2/GAMESFX/AI_MAP8A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: v2/GAMESFX/AI_MAP9A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: v2/GAMESFX/AI_MEND.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: v2/GAMESFX/AI_MFAIL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: v2/GAMESFX/AI_MONEY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: v2/GAMESFX/AI_MWIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: v2/GAMESFX/AI_NEWOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: v2/GAMESFX/AI_NROOM.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: v2/GAMESFX/AI_ORDER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: v2/GAMESFX/AI_PLACE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: v2/GAMESFX/AI_POWER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: v2/GAMESFX/AI_PREP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: v2/GAMESFX/AI_PRMRY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: v2/GAMESFX/AI_REINF.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: v2/GAMESFX/AI_RUN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: v2/GAMESFX/AI_SELL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: v2/GAMESFX/AI_SILOS.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: v2/GAMESFX/AI_SPORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: v2/GAMESFX/AI_TRAIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: v2/GAMESFX/AI_ULOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: v2/GAMESFX/AI_UNRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: v2/GAMESFX/AI_UPGOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: v2/GAMESFX/AI_UPGRD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: v2/GAMESFX/AI_WATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: v2/GAMESFX/AI_WSIGN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: v2/GAMESFX/G_SCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: v2/GAMESFX/G_SCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: v2/GAMESFX/G_SCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: v2/GAMESFX/G_SSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: v2/GAMESFX/G_SSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: v2/GAMESFX/G_SSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: v2/GAMESFX/H_ECONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: v2/GAMESFX/H_ECONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: v2/GAMESFX/H_ECONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: v2/GAMESFX/H_ESEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: v2/GAMESFX/H_ESEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: v2/GAMESFX/H_ESEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: v2/GAMESFX/H_ICONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: v2/GAMESFX/H_ICONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: v2/GAMESFX/H_ICONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: v2/GAMESFX/H_ISEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: v2/GAMESFX/H_ISEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: v2/GAMESFX/H_ISEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: v2/GAMESFX/H_VCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: v2/GAMESFX/H_VCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: v2/GAMESFX/H_VCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: v2/GAMESFX/H_VSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: v2/GAMESFX/H_VSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: v2/GAMESFX/H_VSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: v2/GAMESFX/HI_1MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: v2/GAMESFX/HI_2MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: v2/GAMESFX/HI_3MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: v2/GAMESFX/HI_4MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: v2/GAMESFX/HI_5MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: v2/GAMESFX/HI_ABORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: v2/GAMESFX/HI_ATACK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: v2/GAMESFX/HI_BDRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: v2/GAMESFX/HI_BLOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: v2/GAMESFX/HI_BUILD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: v2/GAMESFX/HI_CANCL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: v2/GAMESFX/HI_CAPT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: v2/GAMESFX/HI_DHRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: v2/GAMESFX/HI_DPLOY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: v2/GAMESFX/HI_ENEMY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: v2/GAMESFX/HI_GANEW.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: v2/GAMESFX/HI_GLOAD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: v2/GAMESFX/HI_GSAVE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: v2/GAMESFX/HI_GUARD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: v2/GAMESFX/HI_HATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: v2/GAMESFX/HI_HOLD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: v2/GAMESFX/HI_LAUNC.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: v2/GAMESFX/HI_MAP1A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: v2/GAMESFX/HI_MAP1B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: v2/GAMESFX/HI_MAP1C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: v2/GAMESFX/HI_MAP2A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: v2/GAMESFX/HI_MAP2B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: v2/GAMESFX/HI_MAP2C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: v2/GAMESFX/HI_MAP3A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: v2/GAMESFX/HI_MAP3B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: v2/GAMESFX/HI_MAP4A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: v2/GAMESFX/HI_MAP4B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: v2/GAMESFX/HI_MAP5A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: v2/GAMESFX/HI_MAP6A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: v2/GAMESFX/HI_MAP6B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: v2/GAMESFX/HI_MAP7A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: v2/GAMESFX/HI_MAP9.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: v2/GAMESFX/HI_MAP9A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: v2/GAMESFX/HI_MEND.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: v2/GAMESFX/HI_MFAIL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: v2/GAMESFX/HI_MONEY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: v2/GAMESFX/HI_MWIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: v2/GAMESFX/HI_NEWOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: v2/GAMESFX/HI_NROOM.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: v2/GAMESFX/HI_ORDER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: v2/GAMESFX/HI_PLACE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: v2/GAMESFX/HI_POWER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: v2/GAMESFX/HI_PREP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: v2/GAMESFX/HI_PRMRY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: v2/GAMESFX/HI_REINF.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: v2/GAMESFX/HI_RUN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: v2/GAMESFX/HI_SELL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: v2/GAMESFX/HI_SILOS.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: v2/GAMESFX/HI_SPORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: v2/GAMESFX/HI_TRAIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: v2/GAMESFX/HI_ULOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: v2/GAMESFX/HI_UNRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: v2/GAMESFX/HI_UPGOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: v2/GAMESFX/HI_UPGRD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: v2/GAMESFX/HI_WATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: v2/GAMESFX/HI_WSIGN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: v2/GAMESFX/O_ECONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: v2/GAMESFX/O_ECONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: v2/GAMESFX/O_ECONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: v2/GAMESFX/O_ESEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: v2/GAMESFX/O_ESEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: v2/GAMESFX/O_ESEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: v2/GAMESFX/O_ICONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: v2/GAMESFX/O_ICONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: v2/GAMESFX/O_ICONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: v2/GAMESFX/O_ISEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: v2/GAMESFX/O_ISEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: v2/GAMESFX/O_ISEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: v2/GAMESFX/O_SCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: v2/GAMESFX/O_SCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: v2/GAMESFX/O_SCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: v2/GAMESFX/O_SSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: v2/GAMESFX/O_SSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: v2/GAMESFX/O_SSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: v2/GAMESFX/O_VCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: v2/GAMESFX/O_VCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: v2/GAMESFX/O_VCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: v2/GAMESFX/O_VSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: v2/GAMESFX/O_VSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: v2/GAMESFX/O_VSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: v2/GAMESFX/OI_1MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: v2/GAMESFX/OI_2MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: v2/GAMESFX/OI_3MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: v2/GAMESFX/OI_4MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: v2/GAMESFX/OI_5MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: v2/GAMESFX/OI_ABORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: v2/GAMESFX/OI_ATACK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: v2/GAMESFX/OI_BDRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: v2/GAMESFX/OI_BLOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: v2/GAMESFX/OI_BUILD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: v2/GAMESFX/OI_CANCL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: v2/GAMESFX/OI_CAPT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: v2/GAMESFX/OI_DHRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: v2/GAMESFX/OI_DPLOY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: v2/GAMESFX/OI_ENEMY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: v2/GAMESFX/OI_GANEW.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: v2/GAMESFX/OI_GLOAD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: v2/GAMESFX/OI_GSAVE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: v2/GAMESFX/OI_GUARD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: v2/GAMESFX/OI_HATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: v2/GAMESFX/OI_HOLD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: v2/GAMESFX/OI_LAUNC.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: v2/GAMESFX/OI_MAP1A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: v2/GAMESFX/OI_MAP1B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: v2/GAMESFX/OI_MAP1C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: v2/GAMESFX/OI_MAP2A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: v2/GAMESFX/OI_MAP2B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: v2/GAMESFX/OI_MAP2C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: v2/GAMESFX/OI_MAP3A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: v2/GAMESFX/OI_MAP4A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: v2/GAMESFX/OI_MAP5A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: v2/GAMESFX/OI_MAP6A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: v2/GAMESFX/OI_MAP7A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: v2/GAMESFX/OI_MAP8A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: v2/GAMESFX/OI_MAP9A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: v2/GAMESFX/OI_MEND.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: v2/GAMESFX/OI_MFAIL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: v2/GAMESFX/OI_MONEY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: v2/GAMESFX/OI_MWIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: v2/GAMESFX/OI_NEWOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: v2/GAMESFX/OI_NROOM.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: v2/GAMESFX/OI_ORDER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: v2/GAMESFX/OI_PLACE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: v2/GAMESFX/OI_POWER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: v2/GAMESFX/OI_PREP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: v2/GAMESFX/OI_PRMRY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: v2/GAMESFX/OI_REINF.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: v2/GAMESFX/OI_RUN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: v2/GAMESFX/OI_SELL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: v2/GAMESFX/OI_SILOS.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: v2/GAMESFX/OI_SPORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: v2/GAMESFX/OI_TRAIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: v2/GAMESFX/OI_ULOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: v2/GAMESFX/OI_UNRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: v2/GAMESFX/OI_UPGOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: v2/GAMESFX/OI_UPGRD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: v2/GAMESFX/OI_WATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: v2/GAMESFX/OI_WSIGN.AUD + ^SupportDir|Content/d2k/v2/MOUSE.R8: v2/MOUSE.R8 + ^SupportDir|Content/d2k/v2/PALETTE.BIN: v2/PALETTE.BIN + ^SupportDir|Content/d2k/v2/SOUND.RS: v2/SOUND.RS patch106: Patch 1.06 Content SHA1: 90924e5254468ec79c71e456384f5895a6c84bae MirrorList: http://www.openra.net/packages/d2k-patch106-mirrors.txt Extract: - ^Content/d2k/v2/BLOXXMAS.R8: v2/BLOXXMAS.R8 - ^Content/d2k/v2/DATA.R8: v2/DATA.R8 + ^SupportDir|Content/d2k/v2/BLOXXMAS.R8: v2/BLOXXMAS.R8 + ^SupportDir|Content/d2k/v2/DATA.R8: v2/DATA.R8 diff -Nru openra-20200503/mods/d2k/installer/gruntmods.yaml openra-20210321/mods/d2k/installer/gruntmods.yaml --- openra-20200503/mods/d2k/installer/gruntmods.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/installer/gruntmods.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,288 +7,288 @@ Dune 2000/data/DATA.R8: 2b229cf4be47104a6214237039a55329f6c45bc9 Install: copy: Dune 2000/data/Music - ^Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD - ^Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD - ^Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD - ^Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD - ^Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD - ^Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD - ^Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD - ^Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD - ^Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD - ^Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD - ^Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD - ^Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD - ^Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD - ^Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD - ^Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD - ^Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD - ^Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD + ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD: AMBUSH.AUD + ^SupportDir|Content/d2k/v2/Music/ARAKATAK.AUD: ARAKATAK.AUD + ^SupportDir|Content/d2k/v2/Music/ATREGAIN.AUD: ATREGAIN.AUD + ^SupportDir|Content/d2k/v2/Music/ENTORDOS.AUD: ENTORDOS.AUD + ^SupportDir|Content/d2k/v2/Music/FIGHTPWR.AUD: FIGHTPWR.AUD + ^SupportDir|Content/d2k/v2/Music/FREMEN.AUD: FREMEN.AUD + ^SupportDir|Content/d2k/v2/Music/HARK_BAT.AUD: HARK_BAT.AUD + ^SupportDir|Content/d2k/v2/Music/LANDSAND.AUD: LANDSAND.AUD + ^SupportDir|Content/d2k/v2/Music/OPTIONS.AUD: OPTIONS.AUD + ^SupportDir|Content/d2k/v2/Music/PLOTTING.AUD: PLOTTING.AUD + ^SupportDir|Content/d2k/v2/Music/RISEHARK.AUD: RISEHARK.AUD + ^SupportDir|Content/d2k/v2/Music/ROBOTIX.AUD: ROBOTIX.AUD + ^SupportDir|Content/d2k/v2/Music/SCORE.AUD: SCORE.AUD + ^SupportDir|Content/d2k/v2/Music/SOLDAPPR.AUD: SOLDAPPR.AUD + ^SupportDir|Content/d2k/v2/Music/SPICESCT.AUD: SPICESCT.AUD + ^SupportDir|Content/d2k/v2/Music/UNDERCON.AUD: UNDERCON.AUD + ^SupportDir|Content/d2k/v2/Music/WAITGAME.A: WAITGAME.AUD copy: Dune 2000/data - ^Content/d2k/v2/BLOXBAT.R8: BLOXBAT.R8 - ^Content/d2k/v2/BLOXBASE.R8: BLOXBASE.R8 - ^Content/d2k/v2/BLOXBGBS.R8: BLOXBGBS.R8 - ^Content/d2k/v2/BLOXICE.R8: BLOXICE.R8 - ^Content/d2k/v2/BLOXTREE.R8: BLOXTREE.R8 - ^Content/d2k/v2/BLOXWAST.R8: BLOXWAST.R8 - ^Content/d2k/v2/BLOXXMAS.R8: BLOXXMAS.R8 - ^Content/d2k/v2/DATA.R8: DATA.R8 - ^Content/d2k/v2/MOUSE.R8: MOUSE.R8 - ^Content/d2k/v2/FONTCOL.FNT: FONTCOL.FNT - ^Content/d2k/v2/FONTCOL.FPL: FONTCOL.FPL + ^SupportDir|Content/d2k/v2/BLOXBAT.R8: BLOXBAT.R8 + ^SupportDir|Content/d2k/v2/BLOXBASE.R8: BLOXBASE.R8 + ^SupportDir|Content/d2k/v2/BLOXBGBS.R8: BLOXBGBS.R8 + ^SupportDir|Content/d2k/v2/BLOXICE.R8: BLOXICE.R8 + ^SupportDir|Content/d2k/v2/BLOXTREE.R8: BLOXTREE.R8 + ^SupportDir|Content/d2k/v2/BLOXWAST.R8: BLOXWAST.R8 + ^SupportDir|Content/d2k/v2/BLOXXMAS.R8: BLOXXMAS.R8 + ^SupportDir|Content/d2k/v2/DATA.R8: DATA.R8 + ^SupportDir|Content/d2k/v2/MOUSE.R8: MOUSE.R8 + ^SupportDir|Content/d2k/v2/FONTCOL.FNT: FONTCOL.FNT + ^SupportDir|Content/d2k/v2/FONTCOL.FPL: FONTCOL.FPL copy: Dune 2000/data/bin - ^Content/d2k/v2/PALETTE.BIN: PALETTE.BIN - ^Content/d2k/v2/FONT.BIN: FONT.BIN + ^SupportDir|Content/d2k/v2/PALETTE.BIN: PALETTE.BIN + ^SupportDir|Content/d2k/v2/FONT.BIN: FONT.BIN copy: Dune 2000/data/GAMESFX - ^Content/d2k/v2/GAMESFX/A_ECONF2.AUD: A_ECONF2.AUD - ^Content/d2k/v2/GAMESFX/A_ECONF1.AUD: A_ECONF1.AUD - ^Content/d2k/v2/GAMESFX/A_ECONF3.AUD: A_ECONF3.AUD - ^Content/d2k/v2/GAMESFX/A_ESEL1.AUD: A_ESEL1.AUD - ^Content/d2k/v2/GAMESFX/A_ESEL2.AUD: A_ESEL2.AUD - ^Content/d2k/v2/GAMESFX/A_ESEL3.AUD: A_ESEL3.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF1.AUD: A_FCONF1.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF2.AUD: A_FCONF2.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF3.AUD: A_FCONF3.AUD - ^Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: OI_ENEMY.AUD - ^Content/d2k/v2/GAMESFX/AI_POWER.AUD: AI_POWER.AUD - ^Content/d2k/v2/GAMESFX/AI_PREP.AUD: AI_PREP.AUD - ^Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: AI_PRMRY.AUD - ^Content/d2k/v2/GAMESFX/AI_REINF.AUD: AI_REINF.AUD - ^Content/d2k/v2/GAMESFX/AI_GANEW.AUD: AI_GANEW.AUD - ^Content/d2k/v2/GAMESFX/HI_SPORT.AUD: HI_SPORT.AUD - ^Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: OI_GSAVE.AUD - ^Content/d2k/v2/GAMESFX/OI_GUARD.AUD: OI_GUARD.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: HI_MAP3B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: HI_MAP4A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: HI_MAP5A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: HI_MAP6A.AUD - ^Content/d2k/v2/GAMESFX/O_ECONF3.AUD: O_ECONF3.AUD - ^Content/d2k/v2/GAMESFX/O_SCONF3.AUD: O_SCONF3.AUD - ^Content/d2k/v2/GAMESFX/O_SSEL1.AUD: O_SSEL1.AUD - ^Content/d2k/v2/GAMESFX/O_SSEL2.AUD: O_SSEL2.AUD - ^Content/d2k/v2/GAMESFX/O_SSEL3.AUD: O_SSEL3.AUD - ^Content/d2k/v2/GAMESFX/O_VCONF1.AUD: O_VCONF1.AUD - ^Content/d2k/v2/GAMESFX/O_VCONF2.AUD: O_VCONF2.AUD - ^Content/d2k/v2/GAMESFX/O_VCONF3.AUD: O_VCONF3.AUD - ^Content/d2k/v2/GAMESFX/OI_MWIN.AUD: OI_MWIN.AUD - ^Content/d2k/v2/GAMESFX/O_ECONF1.AUD: O_ECONF1.AUD - ^Content/d2k/v2/GAMESFX/O_ECONF2.AUD: O_ECONF2.AUD - ^Content/d2k/v2/GAMESFX/OI_NROOM.AUD: OI_NROOM.AUD - ^Content/d2k/v2/GAMESFX/O_ESEL1.AUD: O_ESEL1.AUD - ^Content/d2k/v2/GAMESFX/O_ESEL2.AUD: O_ESEL2.AUD - ^Content/d2k/v2/GAMESFX/O_ESEL3.AUD: O_ESEL3.AUD - ^Content/d2k/v2/GAMESFX/O_ICONF1.AUD: O_ICONF1.AUD - ^Content/d2k/v2/GAMESFX/O_ICONF2.AUD: O_ICONF2.AUD - ^Content/d2k/v2/GAMESFX/O_ICONF3.AUD: O_ICONF3.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: HI_MAP4B.AUD - ^Content/d2k/v2/GAMESFX/O_ISEL2.AUD: O_ISEL2.AUD - ^Content/d2k/v2/GAMESFX/HI_BLOST.AUD: HI_BLOST.AUD - ^Content/d2k/v2/GAMESFX/HI_BUILD.AUD: HI_BUILD.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: HI_MAP6B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: HI_MAP7A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP9.AUD: HI_MAP9.AUD - ^Content/d2k/v2/GAMESFX/A_VSEL3.AUD: A_VSEL3.AUD - ^Content/d2k/v2/GAMESFX/AI_1MIN.AUD: AI_1MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_2MIN.AUD: AI_2MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_3MIN.AUD: AI_3MIN.AUD - ^Content/d2k/v2/GAMESFX/O_VSEL1.AUD: O_VSEL1.AUD - ^Content/d2k/v2/GAMESFX/HI_RUN.AUD: HI_RUN.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL1.AUD: A_FSEL1.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL2.AUD: A_FSEL2.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL3.AUD: A_FSEL3.AUD - ^Content/d2k/v2/GAMESFX/A_FSEL4.AUD: A_FSEL4.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: OI_MAP8A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: OI_MAP9A.AUD - ^Content/d2k/v2/GAMESFX/OI_MEND.AUD: OI_MEND.AUD - ^Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: OI_MFAIL.AUD - ^Content/d2k/v2/GAMESFX/AI_4MIN.AUD: AI_4MIN.AUD - ^Content/d2k/v2/GAMESFX/AI_CANCL.AUD: AI_CANCL.AUD - ^Content/d2k/v2/GAMESFX/OI_ULOST.AUD: OI_ULOST.AUD - ^Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: OI_UNRDY.AUD - ^Content/d2k/v2/GAMESFX/O_VSEL3.AUD: O_VSEL3.AUD - ^Content/d2k/v2/GAMESFX/OI_1MIN.AUD: OI_1MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: OI_MAP7A.AUD - ^Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: HI_TRAIN.AUD - ^Content/d2k/v2/GAMESFX/HI_ULOST.AUD: HI_ULOST.AUD - ^Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: HI_UNRDY.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: OI_MAP2A.AUD - ^Content/d2k/v2/GAMESFX/HI_REINF.AUD: HI_REINF.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: OI_MAP2C.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: OI_MAP3A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: OI_MAP4A.AUD - ^Content/d2k/v2/GAMESFX/OI_SPORT.AUD: OI_SPORT.AUD - ^Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: OI_UPGOP.AUD - ^Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: OI_UPGRD.AUD - ^Content/d2k/v2/GAMESFX/OI_WATTK.AUD: OI_WATTK.AUD - ^Content/d2k/v2/GAMESFX/AI_MONEY.AUD: AI_MONEY.AUD - ^Content/d2k/v2/GAMESFX/AI_SELL.AUD: AI_SELL.AUD - ^Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: HI_NEWOP.AUD - ^Content/d2k/v2/GAMESFX/AI_5MIN.AUD: AI_5MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_HATTK.AUD: OI_HATTK.AUD - ^Content/d2k/v2/GAMESFX/H_VSEL2.AUD: H_VSEL2.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: OI_MAP1B.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: OI_MAP1C.AUD - ^Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: AI_GSAVE.AUD - ^Content/d2k/v2/GAMESFX/AI_GUARD.AUD: AI_GUARD.AUD - ^Content/d2k/v2/GAMESFX/AI_HATTK.AUD: AI_HATTK.AUD - ^Content/d2k/v2/GAMESFX/AI_HOLD.AUD: AI_HOLD.AUD - ^Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: HI_UPGOP.AUD - ^Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: HI_UPGRD.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: OI_MAP2B.AUD - ^Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: HI_WSIGN.AUD - ^Content/d2k/v2/GAMESFX/HI_HATTK.AUD: HI_HATTK.AUD - ^Content/d2k/v2/GAMESFX/O_SCONF2.AUD: O_SCONF2.AUD - ^Content/d2k/v2/GAMESFX/HI_HOLD.AUD: HI_HOLD.AUD - ^Content/d2k/v2/GAMESFX/A_VSEL2.AUD: A_VSEL2.AUD - ^Content/d2k/v2/GAMESFX/AI_ATACK.AUD: AI_ATACK.AUD - ^Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: AI_BDRDY.AUD - ^Content/d2k/v2/GAMESFX/AI_BLOST.AUD: AI_BLOST.AUD - ^Content/d2k/v2/GAMESFX/AI_BUILD.AUD: AI_BUILD.AUD - ^Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: HI_GLOAD.AUD - ^Content/d2k/v2/GAMESFX/AI_CAPT.AUD: AI_CAPT.AUD - ^Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: AI_DHRDY.AUD - ^Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: AI_DPLOY.AUD - ^Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: AI_ENEMY.AUD - ^Content/d2k/v2/GAMESFX/A_VCONF1.AUD: A_VCONF1.AUD - ^Content/d2k/v2/GAMESFX/HI_PLACE.AUD: HI_PLACE.AUD - ^Content/d2k/v2/GAMESFX/HI_POWER.AUD: HI_POWER.AUD - ^Content/d2k/v2/GAMESFX/HI_PREP.AUD: HI_PREP.AUD - ^Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: HI_PRMRY.AUD - ^Content/d2k/v2/GAMESFX/OI_MONEY.AUD: OI_MONEY.AUD - ^Content/d2k/v2/GAMESFX/O_ISEL1.AUD: O_ISEL1.AUD - ^Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: OI_NEWOP.AUD - ^Content/d2k/v2/GAMESFX/A_VCONF3.AUD: A_VCONF3.AUD - ^Content/d2k/v2/GAMESFX/A_VSEL1.AUD: A_VSEL1.AUD - ^Content/d2k/v2/GAMESFX/OI_PLACE.AUD: OI_PLACE.AUD - ^Content/d2k/v2/GAMESFX/OI_POWER.AUD: OI_POWER.AUD - ^Content/d2k/v2/GAMESFX/OI_PREP.AUD: OI_PREP.AUD - ^Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: OI_PRMRY.AUD - ^Content/d2k/v2/GAMESFX/OI_REINF.AUD: OI_REINF.AUD - ^Content/d2k/v2/GAMESFX/OI_RUN.AUD: OI_RUN.AUD - ^Content/d2k/v2/GAMESFX/OI_CAPT.AUD: OI_CAPT.AUD - ^Content/d2k/v2/GAMESFX/H_ECONF1.AUD: H_ECONF1.AUD - ^Content/d2k/v2/GAMESFX/O_VSEL2.AUD: O_VSEL2.AUD - ^Content/d2k/v2/GAMESFX/H_VSEL3.AUD: H_VSEL3.AUD - ^Content/d2k/v2/GAMESFX/HI_1MIN.AUD: HI_1MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_2MIN.AUD: HI_2MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_3MIN.AUD: HI_3MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_4MIN.AUD: HI_4MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_5MIN.AUD: HI_5MIN.AUD - ^Content/d2k/v2/GAMESFX/HI_ABORT.AUD: HI_ABORT.AUD - ^Content/d2k/v2/GAMESFX/HI_ATACK.AUD: HI_ATACK.AUD - ^Content/d2k/v2/GAMESFX/HI_NROOM.AUD: HI_NROOM.AUD - ^Content/d2k/v2/GAMESFX/OI_SILOS.AUD: OI_SILOS.AUD - ^Content/d2k/v2/GAMESFX/A_FCONF4.AUD: A_FCONF4.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: OI_MAP5A.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: OI_MAP6A.AUD - ^Content/d2k/v2/GAMESFX/HI_CANCL.AUD: HI_CANCL.AUD - ^Content/d2k/v2/GAMESFX/HI_CAPT.AUD: HI_CAPT.AUD - ^Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: HI_DHRDY.AUD - ^Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: HI_DPLOY.AUD - ^Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: HI_ENEMY.AUD - ^Content/d2k/v2/GAMESFX/HI_GANEW.AUD: HI_GANEW.AUD - ^Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: OI_DHRDY.AUD - ^Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: HI_GSAVE.AUD - ^Content/d2k/v2/GAMESFX/HI_GUARD.AUD: HI_GUARD.AUD - ^Content/d2k/v2/GAMESFX/H_VSEL1.AUD: H_VSEL1.AUD - ^Content/d2k/v2/GAMESFX/OI_ORDER.AUD: OI_ORDER.AUD - ^Content/d2k/v2/GAMESFX/G_SCONF1.AUD: G_SCONF1.AUD - ^Content/d2k/v2/GAMESFX/G_SCONF2.AUD: G_SCONF2.AUD - ^Content/d2k/v2/GAMESFX/G_SCONF3.AUD: G_SCONF3.AUD - ^Content/d2k/v2/GAMESFX/G_SSEL1.AUD: G_SSEL1.AUD - ^Content/d2k/v2/GAMESFX/G_SSEL2.AUD: G_SSEL2.AUD - ^Content/d2k/v2/GAMESFX/G_SSEL3.AUD: G_SSEL3.AUD - ^Content/d2k/v2/GAMESFX/OI_SELL.AUD: OI_SELL.AUD - ^Content/d2k/v2/GAMESFX/H_ECONF2.AUD: H_ECONF2.AUD - ^Content/d2k/v2/GAMESFX/H_ECONF3.AUD: H_ECONF3.AUD - ^Content/d2k/v2/GAMESFX/H_ESEL1.AUD: H_ESEL1.AUD - ^Content/d2k/v2/GAMESFX/H_ESEL2.AUD: H_ESEL2.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: AI_MAP2C.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: AI_MAP3A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: AI_MAP4A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: AI_MAP5A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: AI_MAP6A.AUD - ^Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: HI_BDRDY.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: AI_MAP8A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: AI_MAP9A.AUD - ^Content/d2k/v2/GAMESFX/AI_MEND.AUD: AI_MEND.AUD - ^Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: AI_MFAIL.AUD - ^Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: AI_GLOAD.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: HI_MAP9A.AUD - ^Content/d2k/v2/GAMESFX/HI_MEND.AUD: HI_MEND.AUD - ^Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: HI_MFAIL.AUD - ^Content/d2k/v2/GAMESFX/HI_MONEY.AUD: HI_MONEY.AUD - ^Content/d2k/v2/GAMESFX/HI_MWIN.AUD: HI_MWIN.AUD - ^Content/d2k/v2/GAMESFX/HI_WATTK.AUD: HI_WATTK.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: AI_MAP1A.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: AI_MAP1B.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: AI_MAP1C.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: AI_MAP2A.AUD - ^Content/d2k/v2/GAMESFX/AI_ABORT.AUD: AI_ABORT.AUD - ^Content/d2k/v2/GAMESFX/H_ESEL3.AUD: H_ESEL3.AUD - ^Content/d2k/v2/GAMESFX/AI_SILOS.AUD: AI_SILOS.AUD - ^Content/d2k/v2/GAMESFX/AI_SPORT.AUD: AI_SPORT.AUD - ^Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: AI_TRAIN.AUD - ^Content/d2k/v2/GAMESFX/AI_ULOST.AUD: AI_ULOST.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: AI_MAP7A.AUD - ^Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: AI_UPGOP.AUD - ^Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: AI_UPGRD.AUD - ^Content/d2k/v2/GAMESFX/AI_WATTK.AUD: AI_WATTK.AUD - ^Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: AI_WSIGN.AUD - ^Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: AI_MAP2B.AUD - ^Content/d2k/v2/GAMESFX/A_ICONF1.AUD: A_ICONF1.AUD - ^Content/d2k/v2/GAMESFX/A_ICONF2.AUD: A_ICONF2.AUD - ^Content/d2k/v2/GAMESFX/A_ICONF3.AUD: A_ICONF3.AUD - ^Content/d2k/v2/GAMESFX/A_ISEL1.AUD: A_ISEL1.AUD - ^Content/d2k/v2/GAMESFX/OI_CANCL.AUD: OI_CANCL.AUD - ^Content/d2k/v2/GAMESFX/H_ISEL2.AUD: H_ISEL2.AUD - ^Content/d2k/v2/GAMESFX/H_ISEL3.AUD: H_ISEL3.AUD - ^Content/d2k/v2/GAMESFX/H_VCONF1.AUD: H_VCONF1.AUD - ^Content/d2k/v2/GAMESFX/H_VCONF2.AUD: H_VCONF2.AUD - ^Content/d2k/v2/GAMESFX/H_VCONF3.AUD: H_VCONF3.AUD - ^Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: OI_TRAIN.AUD - ^Content/d2k/v2/GAMESFX/HI_ORDER.AUD: HI_ORDER.AUD - ^Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: OI_WSIGN.AUD - ^Content/d2k/v2/GAMESFX/OI_BLOST.AUD: OI_BLOST.AUD - ^Content/d2k/v2/GAMESFX/OI_BUILD.AUD: OI_BUILD.AUD - ^Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: AI_LAUNC.AUD - ^Content/d2k/v2/GAMESFX/A_ISEL3.AUD: A_ISEL3.AUD - ^Content/d2k/v2/GAMESFX/A_VCONF2.AUD: A_VCONF2.AUD - ^Content/d2k/v2/GAMESFX/OI_HOLD.AUD: OI_HOLD.AUD - ^Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: OI_LAUNC.AUD - ^Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: OI_MAP1A.AUD - ^Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: HI_LAUNC.AUD - ^Content/d2k/v2/GAMESFX/H_ICONF1.AUD: H_ICONF1.AUD - ^Content/d2k/v2/GAMESFX/H_ICONF2.AUD: H_ICONF2.AUD - ^Content/d2k/v2/GAMESFX/H_ICONF3.AUD: H_ICONF3.AUD - ^Content/d2k/v2/GAMESFX/H_ISEL1.AUD: H_ISEL1.AUD - ^Content/d2k/v2/GAMESFX/A_ISEL2.AUD: A_ISEL2.AUD - ^Content/d2k/v2/GAMESFX/AI_RUN.AUD: AI_RUN.AUD - ^Content/d2k/v2/GAMESFX/HI_SILOS.AUD: HI_SILOS.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: HI_MAP1A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: HI_MAP1B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: HI_MAP1C.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: HI_MAP2A.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: HI_MAP2B.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: HI_MAP2C.AUD - ^Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: HI_MAP3A.AUD - ^Content/d2k/v2/GAMESFX/O_ISEL3.AUD: O_ISEL3.AUD - ^Content/d2k/v2/GAMESFX/O_SCONF1.AUD: O_SCONF1.AUD - ^Content/d2k/v2/GAMESFX/OI_2MIN.AUD: OI_2MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_3MIN.AUD: OI_3MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_4MIN.AUD: OI_4MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_5MIN.AUD: OI_5MIN.AUD - ^Content/d2k/v2/GAMESFX/OI_ABORT.AUD: OI_ABORT.AUD - ^Content/d2k/v2/GAMESFX/OI_ATACK.AUD: OI_ATACK.AUD - ^Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: OI_BDRDY.AUD - ^Content/d2k/v2/GAMESFX/HI_SELL.AUD: HI_SELL.AUD - ^Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: OI_DPLOY.AUD - ^Content/d2k/v2/GAMESFX/AI_PLACE.AUD: AI_PLACE.AUD - ^Content/d2k/v2/GAMESFX/OI_GANEW.AUD: OI_GANEW.AUD - ^Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: OI_GLOAD.AUD - ^Content/d2k/v2/GAMESFX/AI_MWIN.AUD: AI_MWIN.AUD - ^Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: AI_NEWOP.AUD - ^Content/d2k/v2/GAMESFX/AI_NROOM.AUD: AI_NROOM.AUD - ^Content/d2k/v2/GAMESFX/AI_ORDER.AUD: AI_ORDER.AUD - ^Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: AI_UNRDY.AUD - ^Content/d2k/v2/SOUND.RS: SOUND.RS + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF2.AUD: A_ECONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF1.AUD: A_ECONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ECONF3.AUD: A_ECONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL1.AUD: A_ESEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL2.AUD: A_ESEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ESEL3.AUD: A_ESEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF1.AUD: A_FCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF2.AUD: A_FCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF3.AUD: A_FCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ENEMY.AUD: OI_ENEMY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_POWER.AUD: AI_POWER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PREP.AUD: AI_PREP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PRMRY.AUD: AI_PRMRY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_REINF.AUD: AI_REINF.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GANEW.AUD: AI_GANEW.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SPORT.AUD: HI_SPORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GSAVE.AUD: OI_GSAVE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GUARD.AUD: OI_GUARD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3B.AUD: HI_MAP3B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4A.AUD: HI_MAP4A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP5A.AUD: HI_MAP5A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6A.AUD: HI_MAP6A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF3.AUD: O_ECONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF3.AUD: O_SCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL1.AUD: O_SSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL2.AUD: O_SSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SSEL3.AUD: O_SSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF1.AUD: O_VCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF2.AUD: O_VCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VCONF3.AUD: O_VCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MWIN.AUD: OI_MWIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF1.AUD: O_ECONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ECONF2.AUD: O_ECONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NROOM.AUD: OI_NROOM.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL1.AUD: O_ESEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL2.AUD: O_ESEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ESEL3.AUD: O_ESEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF1.AUD: O_ICONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF2.AUD: O_ICONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ICONF3.AUD: O_ICONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP4B.AUD: HI_MAP4B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL2.AUD: O_ISEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BLOST.AUD: HI_BLOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BUILD.AUD: HI_BUILD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP6B.AUD: HI_MAP6B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP7A.AUD: HI_MAP7A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9.AUD: HI_MAP9.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL3.AUD: A_VSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_1MIN.AUD: AI_1MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_2MIN.AUD: AI_2MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_3MIN.AUD: AI_3MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL1.AUD: O_VSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_RUN.AUD: HI_RUN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL1.AUD: A_FSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL2.AUD: A_FSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL3.AUD: A_FSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FSEL4.AUD: A_FSEL4.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP8A.AUD: OI_MAP8A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP9A.AUD: OI_MAP9A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MEND.AUD: OI_MEND.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MFAIL.AUD: OI_MFAIL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_4MIN.AUD: AI_4MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CANCL.AUD: AI_CANCL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ULOST.AUD: OI_ULOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UNRDY.AUD: OI_UNRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL3.AUD: O_VSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_1MIN.AUD: OI_1MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP7A.AUD: OI_MAP7A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_TRAIN.AUD: HI_TRAIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ULOST.AUD: HI_ULOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UNRDY.AUD: HI_UNRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2A.AUD: OI_MAP2A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_REINF.AUD: HI_REINF.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2C.AUD: OI_MAP2C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP3A.AUD: OI_MAP3A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP4A.AUD: OI_MAP4A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SPORT.AUD: OI_SPORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGOP.AUD: OI_UPGOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_UPGRD.AUD: OI_UPGRD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WATTK.AUD: OI_WATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MONEY.AUD: AI_MONEY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SELL.AUD: AI_SELL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NEWOP.AUD: HI_NEWOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_5MIN.AUD: AI_5MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HATTK.AUD: OI_HATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL2.AUD: H_VSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1B.AUD: OI_MAP1B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1C.AUD: OI_MAP1C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GSAVE.AUD: AI_GSAVE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GUARD.AUD: AI_GUARD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HATTK.AUD: AI_HATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_HOLD.AUD: AI_HOLD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGOP.AUD: HI_UPGOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_UPGRD.AUD: HI_UPGRD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP2B.AUD: OI_MAP2B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WSIGN.AUD: HI_WSIGN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HATTK.AUD: HI_HATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF2.AUD: O_SCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_HOLD.AUD: HI_HOLD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL2.AUD: A_VSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ATACK.AUD: AI_ATACK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BDRDY.AUD: AI_BDRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BLOST.AUD: AI_BLOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_BUILD.AUD: AI_BUILD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GLOAD.AUD: HI_GLOAD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_CAPT.AUD: AI_CAPT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DHRDY.AUD: AI_DHRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_DPLOY.AUD: AI_DPLOY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ENEMY.AUD: AI_ENEMY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF1.AUD: A_VCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PLACE.AUD: HI_PLACE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_POWER.AUD: HI_POWER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PREP.AUD: HI_PREP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_PRMRY.AUD: HI_PRMRY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MONEY.AUD: OI_MONEY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL1.AUD: O_ISEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_NEWOP.AUD: OI_NEWOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF3.AUD: A_VCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VSEL1.AUD: A_VSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PLACE.AUD: OI_PLACE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_POWER.AUD: OI_POWER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PREP.AUD: OI_PREP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_PRMRY.AUD: OI_PRMRY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_REINF.AUD: OI_REINF.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_RUN.AUD: OI_RUN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CAPT.AUD: OI_CAPT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF1.AUD: H_ECONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_VSEL2.AUD: O_VSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL3.AUD: H_VSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_1MIN.AUD: HI_1MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_2MIN.AUD: HI_2MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_3MIN.AUD: HI_3MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_4MIN.AUD: HI_4MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_5MIN.AUD: HI_5MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ABORT.AUD: HI_ABORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ATACK.AUD: HI_ATACK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_NROOM.AUD: HI_NROOM.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SILOS.AUD: OI_SILOS.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_FCONF4.AUD: A_FCONF4.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP5A.AUD: OI_MAP5A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP6A.AUD: OI_MAP6A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CANCL.AUD: HI_CANCL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_CAPT.AUD: HI_CAPT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DHRDY.AUD: HI_DHRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_DPLOY.AUD: HI_DPLOY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ENEMY.AUD: HI_ENEMY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GANEW.AUD: HI_GANEW.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DHRDY.AUD: OI_DHRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GSAVE.AUD: HI_GSAVE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_GUARD.AUD: HI_GUARD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VSEL1.AUD: H_VSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ORDER.AUD: OI_ORDER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF1.AUD: G_SCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF2.AUD: G_SCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SCONF3.AUD: G_SCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL1.AUD: G_SSEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL2.AUD: G_SSEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/G_SSEL3.AUD: G_SSEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_SELL.AUD: OI_SELL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF2.AUD: H_ECONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ECONF3.AUD: H_ECONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL1.AUD: H_ESEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL2.AUD: H_ESEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2C.AUD: AI_MAP2C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP3A.AUD: AI_MAP3A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP4A.AUD: AI_MAP4A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP5A.AUD: AI_MAP5A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP6A.AUD: AI_MAP6A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_BDRDY.AUD: HI_BDRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP8A.AUD: AI_MAP8A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP9A.AUD: AI_MAP9A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MEND.AUD: AI_MEND.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MFAIL.AUD: AI_MFAIL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_GLOAD.AUD: AI_GLOAD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP9A.AUD: HI_MAP9A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MEND.AUD: HI_MEND.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MFAIL.AUD: HI_MFAIL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MONEY.AUD: HI_MONEY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MWIN.AUD: HI_MWIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_WATTK.AUD: HI_WATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1A.AUD: AI_MAP1A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1B.AUD: AI_MAP1B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP1C.AUD: AI_MAP1C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2A.AUD: AI_MAP2A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ABORT.AUD: AI_ABORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ESEL3.AUD: H_ESEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SILOS.AUD: AI_SILOS.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_SPORT.AUD: AI_SPORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_TRAIN.AUD: AI_TRAIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ULOST.AUD: AI_ULOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP7A.AUD: AI_MAP7A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGOP.AUD: AI_UPGOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UPGRD.AUD: AI_UPGRD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WATTK.AUD: AI_WATTK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_WSIGN.AUD: AI_WSIGN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MAP2B.AUD: AI_MAP2B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF1.AUD: A_ICONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF2.AUD: A_ICONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ICONF3.AUD: A_ICONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL1.AUD: A_ISEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_CANCL.AUD: OI_CANCL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL2.AUD: H_ISEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL3.AUD: H_ISEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF1.AUD: H_VCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF2.AUD: H_VCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_VCONF3.AUD: H_VCONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_TRAIN.AUD: OI_TRAIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_ORDER.AUD: HI_ORDER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_WSIGN.AUD: OI_WSIGN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BLOST.AUD: OI_BLOST.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BUILD.AUD: OI_BUILD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_LAUNC.AUD: AI_LAUNC.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL3.AUD: A_ISEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_VCONF2.AUD: A_VCONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_HOLD.AUD: OI_HOLD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_LAUNC.AUD: OI_LAUNC.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_MAP1A.AUD: OI_MAP1A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_LAUNC.AUD: HI_LAUNC.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF1.AUD: H_ICONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF2.AUD: H_ICONF2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ICONF3.AUD: H_ICONF3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/H_ISEL1.AUD: H_ISEL1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/A_ISEL2.AUD: A_ISEL2.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_RUN.AUD: AI_RUN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SILOS.AUD: HI_SILOS.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1A.AUD: HI_MAP1A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1B.AUD: HI_MAP1B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP1C.AUD: HI_MAP1C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2A.AUD: HI_MAP2A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2B.AUD: HI_MAP2B.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP2C.AUD: HI_MAP2C.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_MAP3A.AUD: HI_MAP3A.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_ISEL3.AUD: O_ISEL3.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/O_SCONF1.AUD: O_SCONF1.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_2MIN.AUD: OI_2MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_3MIN.AUD: OI_3MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_4MIN.AUD: OI_4MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_5MIN.AUD: OI_5MIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ABORT.AUD: OI_ABORT.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_ATACK.AUD: OI_ATACK.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_BDRDY.AUD: OI_BDRDY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/HI_SELL.AUD: HI_SELL.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_DPLOY.AUD: OI_DPLOY.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_PLACE.AUD: AI_PLACE.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GANEW.AUD: OI_GANEW.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/OI_GLOAD.AUD: OI_GLOAD.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_MWIN.AUD: AI_MWIN.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NEWOP.AUD: AI_NEWOP.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_NROOM.AUD: AI_NROOM.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_ORDER.AUD: AI_ORDER.AUD + ^SupportDir|Content/d2k/v2/GAMESFX/AI_UNRDY.AUD: AI_UNRDY.AUD + ^SupportDir|Content/d2k/v2/SOUND.RS: SOUND.RS diff -Nru openra-20200503/mods/d2k/maps/atreides-01a/map.yaml openra-20210321/mods/d2k/maps/atreides-01a/map.yaml --- openra-20200503/mods/d2k/maps/atreides-01a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/atreides-01a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -74,7 +74,7 @@ Actor9: light_inf Location: 14,14 Owner: Atreides - Facing: 128 + Facing: 512 Actor10: light_inf Location: 12,19 Owner: Harkonnen diff -Nru openra-20200503/mods/d2k/maps/atreides-03a/rules.yaml openra-20210321/mods/d2k/maps/atreides-03a/rules.yaml --- openra-20200503/mods/d2k/maps/atreides-03a/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/atreides-03a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -6,7 +6,7 @@ LuaScript: Scripts: campaign-global.lua, atreides03a.lua, atreides03a-AI.lua MissionData: - Briefing: Bring the Atreides forces up to combat strength - quickly. Guard against surprise attacks and ensure Spice production.\n\nThe Ordos forces are light but numerous. To combat the Ordos, you have been granted license to produce Quads, which have a greater anti-vehicle capability than Trikes. Upgrade your Light Factories to allow production of these units.\n\nMeet any agression with overwhelming force.\n\nGood luck.\n + Briefing: Bring the Atreides forces up to combat strength - quickly. Guard against surprise attacks and ensure Spice production.\n\nThe Ordos forces are light but numerous. To combat the Ordos, you have been granted license to produce Quads, which have a greater anti-vehicle capability than Trikes. Upgrade your Light Factories to allow production of these units.\n\nMeet any aggression with overwhelming force.\n\nGood luck.\n BriefingVideo: A_BR03_E.VQA MapOptions: TechLevel: low diff -Nru openra-20200503/mods/d2k/maps/atreides-03b/rules.yaml openra-20210321/mods/d2k/maps/atreides-03b/rules.yaml --- openra-20200503/mods/d2k/maps/atreides-03b/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/atreides-03b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -6,7 +6,7 @@ LuaScript: Scripts: campaign-global.lua, atreides03b.lua, atreides03b-AI.lua MissionData: - Briefing: Bring the Atreides forces up to combat strength - quickly. Guard against surprise attacks and ensure Spice production.\n\nThe Ordos forces are light but numerous. To combat the Ordos, you have been granted license to produce Quads, which have a greater anti-vehicle capability than Trikes. Upgrade your Light Factories to allow production of these units.\n\nMeet any agression with overwhelming force.\n\nGood luck.\n + Briefing: Bring the Atreides forces up to combat strength - quickly. Guard against surprise attacks and ensure Spice production.\n\nThe Ordos forces are light but numerous. To combat the Ordos, you have been granted license to produce Quads, which have a greater anti-vehicle capability than Trikes. Upgrade your Light Factories to allow production of these units.\n\nMeet any aggression with overwhelming force.\n\nGood luck.\n BriefingVideo: A_BR03_E.VQA MapOptions: TechLevel: low diff -Nru openra-20200503/mods/d2k/maps/atreides-05/map.yaml openra-20210321/mods/d2k/maps/atreides-05/map.yaml --- openra-20200503/mods/d2k/maps/atreides-05/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/atreides-05/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -43,7 +43,7 @@ Faction: harkonnen LockColor: True Color: FE0000 - Enemies: Atreides + Enemies: Atreides, Creeps Bot: campaign PlayerReference@Smugglers: Name: Smugglers @@ -52,7 +52,7 @@ LockColor: True Color: 542209 Allies: Mercenaries - Enemies: Atreides + Enemies: Atreides, Creeps Bot: campaign PlayerReference@Mercenaries: Name: Mercenaries @@ -61,7 +61,7 @@ LockColor: True Color: DDDD00 Allies: Smugglers - Enemies: Atreides + Enemies: Atreides, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-01a/map.yaml openra-20210321/mods/d2k/maps/harkonnen-01a/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-01a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-01a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -42,7 +42,7 @@ Faction: atreides LockColor: True Color: 9191FF - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-01b/map.yaml openra-20210321/mods/d2k/maps/harkonnen-01b/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-01b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-01b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -42,7 +42,7 @@ Faction: atreides LockColor: True Color: 9191FF - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-02a/map.yaml openra-20210321/mods/d2k/maps/harkonnen-02a/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-02a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-02a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -41,7 +41,7 @@ Faction: atreides LockColor: True Color: 9191FF - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-02b/map.yaml openra-20210321/mods/d2k/maps/harkonnen-02b/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-02b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-02b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -41,7 +41,7 @@ Faction: atreides LockColor: True Color: 9191FF - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-03a/map.yaml openra-20210321/mods/d2k/maps/harkonnen-03a/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-03a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-03a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -41,7 +41,7 @@ Faction: atreides LockColor: True Color: 9191FF - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-03b/harkonnen03b.lua openra-20210321/mods/d2k/maps/harkonnen-03b/harkonnen03b.lua --- openra-20200503/mods/d2k/maps/harkonnen-03b/harkonnen03b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-03b/harkonnen03b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -63,7 +63,7 @@ hard = 9 } -AtreidesHunters = +AtreidesHunters = { { "trooper", "trooper", "trooper" }, { "trike", "light_inf", "light_inf", "light_inf", "light_inf" }, @@ -78,7 +78,7 @@ { AtreidesEntry8.Location, AtreidesRally8.Location } } -AtreidesHunterPaths = +AtreidesHunterPaths = { { AtreidesEntry6.Location, AtreidesRally6.Location }, { AtreidesEntry5.Location, AtreidesRally5.Location }, diff -Nru openra-20200503/mods/d2k/maps/harkonnen-03b/map.yaml openra-20210321/mods/d2k/maps/harkonnen-03b/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-03b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-03b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -41,7 +41,7 @@ Faction: atreides LockColor: True Color: 9191FF - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-04/harkonnen04.lua openra-20210321/mods/d2k/maps/harkonnen-04/harkonnen04.lua --- openra-20200503/mods/d2k/maps/harkonnen-04/harkonnen04.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-04/harkonnen04.lua 2021-03-21 11:10:05.000000000 +0000 @@ -71,7 +71,7 @@ AtreidesHunters = { "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper" } -FremenHunters = +FremenHunters = { { "fremen", "fremen", "fremen" }, { "combat_tank_a", "combat_tank_a", "combat_tank_a" }, @@ -79,7 +79,7 @@ } InitialAtreidesReinforcements = -{ +{ { "trooper", "trooper", "trooper", "trooper", "light_inf", "light_inf", "light_inf", "light_inf" }, { "combat_tank_a", "combat_tank_a", "quad", "trike" } } @@ -98,7 +98,7 @@ { FremenEntry6.Location, FremenRally6.Location } } -FremenHunterPaths = +FremenHunterPaths = { { FremenEntry1.Location, FremenRally1.Location }, { FremenEntry2.Location, FremenRally2.Location }, diff -Nru openra-20200503/mods/d2k/maps/harkonnen-04/map.yaml openra-20210321/mods/d2k/maps/harkonnen-04/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-04/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-04/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -42,7 +42,7 @@ LockColor: True Color: 9191FF Allies: Fremen - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Fremen: Name: Fremen @@ -51,7 +51,7 @@ LockColor: True Color: DDDDDD Allies: Atreides - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign Actors: @@ -82,7 +82,6 @@ FGunt1: medium_gun_turret Location: 61,14 Owner: Fremen - TurretFacing: 0 Actor9: wall Location: 63,14 Owner: Fremen @@ -209,11 +208,9 @@ AGunt1: medium_gun_turret Location: 23,72 Owner: Atreides - TurretFacing: 0 AGunt2: medium_gun_turret Location: 29,72 Owner: Atreides - TurretFacing: 0 Actor52: wall Location: 30,72 Owner: Atreides @@ -301,7 +298,6 @@ FGunt2: medium_gun_turret Location: 21,86 Owner: Fremen - TurretFacing: 0 Actor81: fremen Location: 14,87 Owner: Fremen diff -Nru openra-20200503/mods/d2k/maps/harkonnen-05/harkonnen05.lua openra-20210321/mods/d2k/maps/harkonnen-05/harkonnen05.lua --- openra-20200503/mods/d2k/maps/harkonnen-05/harkonnen05.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-05/harkonnen05.lua 2021-03-21 11:10:05.000000000 +0000 @@ -81,14 +81,14 @@ hard = 8 } -OrdosHunters = +OrdosHunters = { { "combat_tank_o", "combat_tank_o" }, { "missile_tank" } } InitialOrdosReinforcements = -{ +{ { "trooper", "trooper", "trooper", "trooper", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf" }, { "combat_tank_o", "combat_tank_o", "quad", "quad", "raider", "raider" } } @@ -117,13 +117,13 @@ { OrdosEntry12.Location, OrdosEntry12.Location }, } -HarkonnenReinforcements = +HarkonnenReinforcements = { { "trooper", "trooper", "trooper", "trooper" }, { "combat_tank_h", "combat_tank_h", "combat_tank_h", "combat_tank_h" } } -HarkonnenPaths = +HarkonnenPaths = { { HarkonnenEntry1.Location, HarkonnenRally1.Location }, { HarkonnenEntry2.Location, HarkonnenRally2.Location } @@ -172,7 +172,7 @@ end Media.DisplayMessage("Enemy carryall drop detected!", "Mentat") - + OrdosReinforcementNotification(currentWave, totalWaves) end) end diff -Nru openra-20200503/mods/d2k/maps/harkonnen-05/map.yaml openra-20210321/mods/d2k/maps/harkonnen-05/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-05/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-05/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -42,7 +42,7 @@ LockColor: True Color: B3EAA5 Allies: Ordos Small Base, Corrino - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Ordos Small Base: Name: Ordos Small Base @@ -51,7 +51,7 @@ LockColor: True Color: B3EAA5 Allies: Ordos Main Base, Corrino - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Corrino: Name: Corrino @@ -60,7 +60,7 @@ LockColor: True Color: 7D00FE Allies: Ordos Main Base, Ordos Small Base - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-06a/harkonnen06a.lua openra-20210321/mods/d2k/maps/harkonnen-06a/harkonnen06a.lua --- openra-20200503/mods/d2k/maps/harkonnen-06a/harkonnen06a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-06a/harkonnen06a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -78,7 +78,7 @@ } InitialOrdosReinforcements = -{ +{ { "trooper", "trooper", "trooper", "trooper", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf" }, { "combat_tank_o", "combat_tank_o", "quad", "quad", "raider", "raider" } } @@ -101,13 +101,13 @@ { OrdosEntry10.Location, OrdosRally10.Location } } -HarkonnenReinforcements = +HarkonnenReinforcements = { { "combat_tank_h", "combat_tank_h" }, { "missile_tank", "missile_tank" } } -HarkonnenPaths = +HarkonnenPaths = { { HarkonnenEntry1.Location, HarkonnenRally1.Location }, { HarkonnenEntry2.Location, HarkonnenRally2.Location } diff -Nru openra-20200503/mods/d2k/maps/harkonnen-06a/map.yaml openra-20210321/mods/d2k/maps/harkonnen-06a/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-06a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-06a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -42,7 +42,7 @@ LockColor: True Color: B3EAA5 Allies: Ordos Small Base - Enemies: Harkonnen, Smugglers - Enemy to Ordos, Smugglers - Enemy to Both + Enemies: Harkonnen, Smugglers - Enemy to Ordos, Smugglers - Enemy to Both, Creeps Bot: campaign PlayerReference@Ordos Small Base: Name: Ordos Small Base @@ -51,7 +51,7 @@ LockColor: True Color: B3EAA5 Allies: Ordos Main Base - Enemies: Harkonnen, Smugglers - Enemy to Ordos, Smugglers - Enemy to Both + Enemies: Harkonnen, Smugglers - Enemy to Ordos, Smugglers - Enemy to Both, Creeps Bot: campaign PlayerReference@Smugglers - Neutral: Name: Smugglers - Neutral @@ -61,6 +61,7 @@ LockColor: True Color: 542209 Bot: campaign + Enemies: Creeps PlayerReference@Smugglers - Enemy to Harkonnen: Name: Smugglers - Enemy to Harkonnen NonCombatant: True @@ -68,7 +69,7 @@ Faction: smuggler LockColor: True Color: 542209 - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Smugglers - Enemy to Ordos: Name: Smugglers - Enemy to Ordos @@ -77,7 +78,7 @@ Faction: smuggler LockColor: True Color: 542209 - Enemies: Ordos Main Base, Ordos Small Base + Enemies: Ordos Main Base, Ordos Small Base, Creeps Bot: campaign PlayerReference@Smugglers - Enemy to Both: Name: Smugglers - Enemy to Both @@ -86,7 +87,7 @@ Faction: smuggler LockColor: True Color: 542209 - Enemies: Harkonnen, Ordos Main Base, Ordos Small Base + Enemies: Harkonnen, Ordos Main Base, Ordos Small Base, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-06b/harkonnen06b.lua openra-20210321/mods/d2k/maps/harkonnen-06b/harkonnen06b.lua --- openra-20200503/mods/d2k/maps/harkonnen-06b/harkonnen06b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-06b/harkonnen06b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -78,7 +78,7 @@ } InitialOrdosReinforcements = -{ +{ { "trooper", "trooper", "trooper", "trooper", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf" }, { "combat_tank_o", "combat_tank_o", "quad", "quad", "raider", "raider" } } diff -Nru openra-20200503/mods/d2k/maps/harkonnen-06b/map.yaml openra-20210321/mods/d2k/maps/harkonnen-06b/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-06b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-06b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -42,7 +42,7 @@ LockColor: True Color: B3EAA5 Allies: Ordos Small Base - Enemies: Harkonnen, Smugglers - Enemy to Ordos, Smugglers - Enemy to Both + Enemies: Harkonnen, Smugglers - Enemy to Ordos, Smugglers - Enemy to Both, Creeps Bot: campaign PlayerReference@Ordos Small Base: Name: Ordos Small Base @@ -51,7 +51,7 @@ LockColor: True Color: B3EAA5 Allies: Ordos Main Base - Enemies: Harkonnen, Smugglers - Enemy to Ordos, Smugglers - Enemy to Both + Enemies: Harkonnen, Smugglers - Enemy to Ordos, Smugglers - Enemy to Both, Creeps Bot: campaign PlayerReference@Smugglers - Neutral: Name: Smugglers - Neutral @@ -61,6 +61,7 @@ LockColor: True Color: 542209 Bot: campaign + Enemies: Creeps PlayerReference@Smugglers - Enemy to Harkonnen: Name: Smugglers - Enemy to Harkonnen NonCombatant: True @@ -68,7 +69,7 @@ Faction: smuggler LockColor: True Color: 542209 - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Smugglers - Enemy to Ordos: Name: Smugglers - Enemy to Ordos @@ -77,7 +78,7 @@ Faction: smuggler LockColor: True Color: 542209 - Enemies: Ordos Main Base, Ordos Small Base + Enemies: Ordos Main Base, Ordos Small Base, Creeps Bot: campaign PlayerReference@Smugglers - Enemy to Both: Name: Smugglers - Enemy to Both @@ -86,7 +87,7 @@ Faction: smuggler LockColor: True Color: 542209 - Enemies: Harkonnen, Ordos Main Base, Ordos Small Base + Enemies: Harkonnen, Ordos Main Base, Ordos Small Base, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-07/harkonnen07.lua openra-20210321/mods/d2k/maps/harkonnen-07/harkonnen07.lua --- openra-20200503/mods/d2k/maps/harkonnen-07/harkonnen07.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-07/harkonnen07.lua 2021-03-21 11:10:05.000000000 +0000 @@ -163,7 +163,7 @@ end) if #targets > 0 then - AHiTechFactory.SendAirstrike(Utils.Random(targets).CenterPosition, true, 0) + AHiTechFactory.TargetAirstrike(Utils.Random(targets).CenterPosition) end Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) diff -Nru openra-20200503/mods/d2k/maps/harkonnen-07/map.yaml openra-20210321/mods/d2k/maps/harkonnen-07/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-07/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-07/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -42,7 +42,7 @@ LockColor: True Color: 9191FF Allies: Atreides Small Base, Corrino - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Atreides Small Base: Name: Atreides Small Base @@ -51,7 +51,7 @@ LockColor: True Color: 9191FF Allies: Atreides Main Base, Corrino - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Corrino: Name: Corrino @@ -60,7 +60,7 @@ LockColor: True Color: 7D00FE Allies: Atreides Main Base, Atreides Small Base - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign Actors: @@ -145,7 +145,7 @@ HEngineer: engineer Location: 51,19 Owner: Harkonnen - Facing: 128 + Facing: 512 Actor27: wall Location: 74,19 Owner: Atreides Main Base @@ -173,11 +173,11 @@ Actor35: trike Location: 50,20 Owner: Harkonnen - Facing: 128 + Facing: 512 Actor36: quad Location: 52,20 Owner: Harkonnen - Facing: 128 + Facing: 512 Actor37: carryall Location: 8,21 Owner: Atreides Small Base diff -Nru openra-20200503/mods/d2k/maps/harkonnen-08/harkonnen08.lua openra-20210321/mods/d2k/maps/harkonnen-08/harkonnen08.lua --- openra-20200503/mods/d2k/maps/harkonnen-08/harkonnen08.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-08/harkonnen08.lua 2021-03-21 11:10:05.000000000 +0000 @@ -133,7 +133,7 @@ end) if #targets > 0 then - AHiTechFactory.SendAirstrike(Utils.Random(targets).CenterPosition, true, 0) + AHiTechFactory.TargetAirstrike(Utils.Random(targets).CenterPosition) end Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) diff -Nru openra-20200503/mods/d2k/maps/harkonnen-08/map.yaml openra-20210321/mods/d2k/maps/harkonnen-08/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-08/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-08/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -43,7 +43,7 @@ LockColor: True Color: 9191FF Allies: Ordos, Ordos Aligned Mercenaries - Enemies: Harkonnen, Harkonnen Aligned Mercenaries + Enemies: Harkonnen, Harkonnen Aligned Mercenaries, Creeps Bot: campaign PlayerReference@Neutral Atreides: Name: Neutral Atreides @@ -52,6 +52,7 @@ LockColor: True Color: 9191FF Bot: campaign + Enemies: Creeps PlayerReference@Ordos: Name: Ordos LockFaction: True @@ -59,7 +60,7 @@ LockColor: True Color: B3EAA5 Allies: Ordos Aligned Atreides, Ordos Aligned Mercenaries - Enemies: Harkonnen, Harkonnen Aligned Mercenaries + Enemies: Harkonnen, Harkonnen Aligned Mercenaries, Creeps Bot: campaign PlayerReference@Ordos Aligned Mercenaries: Name: Ordos Aligned Mercenaries @@ -68,7 +69,7 @@ LockColor: True Color: DDDD00 Allies: Ordos, Ordos Aligned Atreides - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Harkonnen Aligned Mercenaries: Name: Harkonnen Aligned Mercenaries @@ -77,7 +78,7 @@ LockColor: True Color: DDDD00 Allies: Harkonnen - Enemies: Ordos, Ordos Aligned Atreides + Enemies: Ordos, Ordos Aligned Atreides, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-09a/harkonnen09a.lua openra-20210321/mods/d2k/maps/harkonnen-09a/harkonnen09a.lua --- openra-20200503/mods/d2k/maps/harkonnen-09a/harkonnen09a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-09a/harkonnen09a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -96,7 +96,7 @@ } InitialAtreidesReinforcements = -{ +{ { "trooper", "trooper", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf" }, { "trooper", "trooper", "trooper", "combat_tank_a", "combat_tank_a" }, { "combat_tank_a", "combat_tank_a", "quad", "quad", "trike" }, @@ -140,7 +140,7 @@ if CStarport.IsDead or CStarport.Owner ~= corrino_main then return end - + reinforcements = Utils.Random(CorrinoStarportReinforcements[Difficulty]) local units = Reinforcements.ReinforceWithTransport(corrino_main, "frigate", reinforcements, { CorrinoStarportEntry.Location, CStarport.Location + CVec.New(1, 1) }, { CorrinoStarportExit.Location })[2] @@ -178,7 +178,7 @@ end) if #targets > 0 then - AHiTechFactory.SendAirstrike(Utils.Random(targets).CenterPosition, true, 0) + AHiTechFactory.TargetAirstrike(Utils.Random(targets).CenterPosition) end Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) diff -Nru openra-20200503/mods/d2k/maps/harkonnen-09a/map.yaml openra-20210321/mods/d2k/maps/harkonnen-09a/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-09a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-09a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -42,7 +42,7 @@ LockColor: True Color: 9191FF Allies: Atreides Small Base 1, Atreides Small Base 2, Corrino Main Base, Corrino Small Base - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Atreides Small Base 1: Name: Atreides Small Base 1 @@ -51,7 +51,7 @@ LockColor: True Color: 9191FF Allies: Atreides Main Base, Atreides Small Base 2, Corrino Main Base, Corrino Small Base - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Atreides Small Base 2: Name: Atreides Small Base 2 @@ -60,7 +60,7 @@ LockColor: True Color: 9191FF Allies: Atreides Main Base, Atreides Small Base 1, Corrino Main Base, Corrino Small Base - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Corrino Main Base: Name: Corrino Main Base @@ -69,7 +69,7 @@ LockColor: True Color: 7D00FE Allies: Atreides Main Base, Atreides Small Base 1, Atreides Small Base 2, Corrino Small Base - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Corrino Small Base: Name: Corrino Small Base @@ -78,7 +78,7 @@ LockColor: True Color: 7D00FE Allies: Atreides Main Base, Atreides Small Base 1, Atreides Small Base 2, Corrino Main Base - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/harkonnen-09b/harkonnen09b.lua openra-20210321/mods/d2k/maps/harkonnen-09b/harkonnen09b.lua --- openra-20200503/mods/d2k/maps/harkonnen-09b/harkonnen09b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-09b/harkonnen09b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -101,7 +101,7 @@ } InitialAtreidesReinforcements = -{ +{ { "combat_tank_a", "combat_tank_a", "quad", "trike" }, { "trooper", "trooper", "trooper", "trooper", "trooper", "combat_tank_a" }, { "combat_tank_a", "combat_tank_a", "quad", "quad", "trike" } @@ -146,7 +146,7 @@ if CStarport.IsDead or CStarport.Owner ~= corrino_small then return end - + reinforcements = Utils.Random(CorrinoStarportReinforcements[Difficulty]) local units = Reinforcements.ReinforceWithTransport(corrino_small, "frigate", reinforcements, { CorrinoStarportEntry.Location, CStarport.Location + CVec.New(1, 1) }, { CorrinoStarportExit.Location })[2] @@ -184,7 +184,7 @@ end) if #targets > 0 then - AHiTechFactory.SendAirstrike(Utils.Random(targets).CenterPosition, true, 0) + AHiTechFactory.TargetAirstrike(Utils.Random(targets).CenterPosition) end Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) diff -Nru openra-20200503/mods/d2k/maps/harkonnen-09b/map.yaml openra-20210321/mods/d2k/maps/harkonnen-09b/map.yaml --- openra-20200503/mods/d2k/maps/harkonnen-09b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/harkonnen-09b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -42,7 +42,7 @@ LockColor: True Color: 9191FF Allies: Atreides Small Base, Corrino Main Base, Corrino Small Base - Enemies: Harkonnen, Smugglers - Enemy to AI, Smugglers - Enemy to Both + Enemies: Harkonnen, Smugglers - Enemy to AI, Smugglers - Enemy to Both, Creeps Bot: campaign PlayerReference@Atreides Small Base: Name: Atreides Small Base @@ -51,7 +51,7 @@ LockColor: True Color: 9191FF Allies: Atreides Main Base, Corrino Main Base, Corrino Small Base - Enemies: Harkonnen, Smugglers - Enemy to AI, Smugglers - Enemy to Both + Enemies: Harkonnen, Smugglers - Enemy to AI, Smugglers - Enemy to Both, Creeps Bot: campaign PlayerReference@Corrino Main Base: Name: Corrino Main Base @@ -60,7 +60,7 @@ LockColor: True Color: 7D00FE Allies: Atreides Main Base, Atreides Small Base, Corrino Small Base - Enemies: Harkonnen, Smugglers - Enemy to AI, Smugglers - Enemy to Both + Enemies: Harkonnen, Smugglers - Enemy to AI, Smugglers - Enemy to Both, Creeps Bot: campaign PlayerReference@Corrino Small Base: Name: Corrino Small Base @@ -69,7 +69,7 @@ LockColor: True Color: 7D00FE Allies: Atreides Main Base, Atreides Small Base, Corrino Main Base - Enemies: Harkonnen, Smugglers - Enemy to AI, Smugglers - Enemy to Both + Enemies: Harkonnen, Smugglers - Enemy to AI, Smugglers - Enemy to Both, Creeps Bot: campaign PlayerReference@Smugglers - Neutral: Name: Smugglers - Neutral @@ -79,6 +79,7 @@ LockColor: True Color: 542209 Bot: campaign + Enemies: Creeps PlayerReference@Smugglers - Enemy to Harkonnen: Name: Smugglers - Enemy to Harkonnen NonCombatant: True @@ -86,7 +87,7 @@ Faction: smuggler LockColor: True Color: 542209 - Enemies: Harkonnen + Enemies: Harkonnen, Creeps Bot: campaign PlayerReference@Smugglers - Enemy to AI: Name: Smugglers - Enemy to AI @@ -95,7 +96,7 @@ Faction: smuggler LockColor: True Color: 542209 - Enemies: Atreides Main Base, Atreides Small Base, Corrino Main Base, Corrino Small Base + Enemies: Atreides Main Base, Atreides Small Base, Corrino Main Base, Corrino Small Base, Creeps Bot: campaign PlayerReference@Smugglers - Enemy to Both: Name: Smugglers - Enemy to Both @@ -104,7 +105,7 @@ Faction: smuggler LockColor: True Color: 542209 - Enemies: Harkonnen, Atreides Main Base, Atreides Small Base, Corrino Main Base, Corrino Small Base + Enemies: Harkonnen, Atreides Main Base, Atreides Small Base, Corrino Main Base, Corrino Small Base, Creeps Bot: campaign Actors: @@ -893,61 +894,51 @@ Location: 107,77 SubCell: 3 Facing: 0 - TurretFacing: 0 Actor261: light_inf Owner: Smugglers - Neutral Location: 112,78 SubCell: 3 Facing: 0 - TurretFacing: 0 Actor262: light_inf Owner: Smugglers - Neutral Location: 111,68 SubCell: 3 Facing: 0 - TurretFacing: 0 Actor263: light_inf Owner: Smugglers - Neutral Location: 116,68 SubCell: 3 Facing: 0 - TurretFacing: 0 Actor264: light_inf Owner: Smugglers - Neutral Location: 118,75 SubCell: 3 Facing: 0 - TurretFacing: 0 Actor265: light_inf Owner: Smugglers - Neutral Location: 112,73 SubCell: 3 Facing: 0 - TurretFacing: 0 Actor266: trooper Owner: Smugglers - Neutral Location: 121,73 SubCell: 3 Facing: 0 - TurretFacing: 0 Actor267: trooper Owner: Smugglers - Neutral Location: 109,75 SubCell: 3 Facing: 0 - TurretFacing: 0 Actor268: trooper Owner: Smugglers - Neutral Location: 110,79 SubCell: 3 Facing: 0 - TurretFacing: 0 Actor269: trooper Owner: Smugglers - Neutral Location: 109,70 SubCell: 3 Facing: 0 - TurretFacing: 0 HarkonnenRally: waypoint Owner: Neutral Location: 8,18 diff -Nru openra-20200503/mods/d2k/maps/ordos-01a/map.yaml openra-20210321/mods/d2k/maps/ordos-01a/map.yaml --- openra-20200503/mods/d2k/maps/ordos-01a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-01a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -43,7 +43,7 @@ Faction: harkonnen LockColor: True Color: FE0000 - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/ordos-01b/map.yaml openra-20210321/mods/d2k/maps/ordos-01b/map.yaml --- openra-20200503/mods/d2k/maps/ordos-01b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-01b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -43,7 +43,7 @@ Faction: harkonnen LockColor: True Color: FE0000 - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/ordos-02a/map.yaml openra-20210321/mods/d2k/maps/ordos-02a/map.yaml --- openra-20200503/mods/d2k/maps/ordos-02a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-02a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -43,7 +43,7 @@ Faction: harkonnen LockColor: True Color: FE0000 - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/ordos-02b/map.yaml openra-20210321/mods/d2k/maps/ordos-02b/map.yaml --- openra-20200503/mods/d2k/maps/ordos-02b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-02b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -43,7 +43,7 @@ Faction: harkonnen LockColor: True Color: FE0000 - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/ordos-03a/map.yaml openra-20210321/mods/d2k/maps/ordos-03a/map.yaml --- openra-20200503/mods/d2k/maps/ordos-03a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-03a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -43,7 +43,7 @@ Faction: harkonnen LockColor: True Color: FE0000 - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/ordos-03b/map.yaml openra-20210321/mods/d2k/maps/ordos-03b/map.yaml --- openra-20200503/mods/d2k/maps/ordos-03b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-03b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -43,7 +43,7 @@ Faction: harkonnen LockColor: True Color: FE0000 - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign Actors: diff -Nru openra-20200503/mods/d2k/maps/ordos-03b/ordos03b.lua openra-20210321/mods/d2k/maps/ordos-03b/ordos03b.lua --- openra-20200503/mods/d2k/maps/ordos-03b/ordos03b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-03b/ordos03b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -71,7 +71,7 @@ { "trike", "trike" } } -HarkonnenHunterPaths = +HarkonnenHunterPaths = { { HarkonnenEntry1.Location, HarkonnenRally1.Location }, { HarkonnenEntry2.Location, HarkonnenRally2.Location }, diff -Nru openra-20200503/mods/d2k/maps/ordos-04/map.yaml openra-20210321/mods/d2k/maps/ordos-04/map.yaml --- openra-20200503/mods/d2k/maps/ordos-04/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-04/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -44,7 +44,7 @@ LockColor: True Color: FE0000 Allies: Smugglers - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign PlayerReference@Smugglers: Name: Smugglers @@ -53,7 +53,7 @@ LockColor: True Color: 542209 Allies: Harkonnen - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign Actors: @@ -66,7 +66,6 @@ HGunTurret1: medium_gun_turret Location: 38,3 Owner: Harkonnen - TurretFacing: 0 Actor3: wall Location: 42,3 Owner: Smugglers @@ -88,7 +87,6 @@ HGunTurret2: medium_gun_turret Location: 38,7 Owner: Harkonnen - TurretFacing: 0 Actor10: trooper Location: 39,7 Owner: Harkonnen @@ -179,7 +177,6 @@ SGunTurret1: medium_gun_turret Location: 42,10 Owner: Smugglers - TurretFacing: 0 Actor40: wall Location: 43,10 Owner: Smugglers @@ -237,7 +234,6 @@ SGunTurret2: medium_gun_turret Location: 42,13 Owner: Smugglers - TurretFacing: 0 Actor59: wall Location: 43,13 Owner: Smugglers @@ -304,7 +300,6 @@ SGunTurret3: medium_gun_turret Location: 57,20 Owner: Smugglers - TurretFacing: 0 HPower1: wind_trap Location: 44,21 Owner: Harkonnen @@ -314,7 +309,6 @@ SGunTurret4: medium_gun_turret Location: 63,21 Owner: Smugglers - TurretFacing: 0 Actor90: wall Location: 64,21 Owner: Smugglers @@ -336,7 +330,6 @@ HGunTurret4: medium_gun_turret Location: 47,29 Owner: Harkonnen - TurretFacing: 0 Actor97: wall Location: 48,29 Owner: Harkonnen @@ -355,7 +348,6 @@ HGunTurret5: medium_gun_turret Location: 11,32 Owner: Harkonnen - TurretFacing: 0 Actor103: light_inf Location: 12,32 Owner: Harkonnen diff -Nru openra-20200503/mods/d2k/maps/ordos-04/ordos04.lua openra-20210321/mods/d2k/maps/ordos-04/ordos04.lua --- openra-20200503/mods/d2k/maps/ordos-04/ordos04.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-04/ordos04.lua 2021-03-21 11:10:05.000000000 +0000 @@ -7,7 +7,7 @@ information, see COPYING. ]] -Base = +Base = { Harkonnen = { HConyard, HRefinery, HHeavyFactory, HLightFactory, HGunTurret1, HGunTurret2, HGunTurret3, HGunTurret4, HGunTurret5, HBarracks, HPower1, HPower2, HPower3, HPower4 }, Smugglers = { SOutpost, SHeavyFactory, SLightFactory, SGunTurret1, SGunTurret2, SGunTurret3, SGunTurret4, SBarracks, SPower1, SPower2, SPower3 } @@ -27,7 +27,7 @@ hard = DateTime.Minutes(1) + DateTime.Seconds(30) } -InitialReinforcements = +InitialReinforcements = { Harkonnen = { "combat_tank_h", "combat_tank_h", "trike", "quad" }, Smugglers = { "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper" } diff -Nru openra-20200503/mods/d2k/maps/ordos-05/map.yaml openra-20210321/mods/d2k/maps/ordos-05/map.yaml --- openra-20200503/mods/d2k/maps/ordos-05/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-05/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -44,7 +44,7 @@ LockColor: True Color: 9191FF Allies: AtreidesSmallBase1, AtreidesSmallBase2 - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign PlayerReference@AtreidesSmallBase1: Name: AtreidesSmallBase1 @@ -53,7 +53,7 @@ LockColor: True Color: 9191FF Allies: AtreidesMainBase, AtreidesSmallBase2, AtreidesSmallBase3 - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign PlayerReference@AtreidesSmallBase2: Name: AtreidesSmallBase2 @@ -62,7 +62,7 @@ LockColor: True Color: 9191FF Allies: AtreidesMainBase, AtreidesSmallBase1, AtreidesSmallBase3 - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign PlayerReference@AtreidesSmallBase3: Name: AtreidesSmallBase3 @@ -71,7 +71,7 @@ LockColor: True Color: 9191FF Allies: AtreidesMainBase, AtreidesSmallBase1, AtreidesSmallBase2 - Enemies: Ordos + Enemies: Ordos, Creeps Bot: campaign Actors: @@ -96,7 +96,7 @@ AGunt1: medium_gun_turret Location: 14,5 Owner: AtreidesMainBase - TurretFacing: 192 + TurretFacing: 768 APower1: wind_trap Location: 3,6 Owner: AtreidesMainBase @@ -118,7 +118,7 @@ AGunt2: medium_gun_turret Location: 17,8 Owner: AtreidesMainBase - TurretFacing: 224 + TurretFacing: 896 APower2: wind_trap Location: 5,9 Owner: AtreidesMainBase @@ -179,7 +179,7 @@ AGunt3: medium_gun_turret Location: 15,17 Owner: AtreidesMainBase - TurretFacing: 160 + TurretFacing: 640 Actor34: light_inf Location: 11,18 Owner: AtreidesMainBase @@ -210,11 +210,11 @@ Actor43: trike Location: 34,20 Owner: AtreidesSmallBase1 - Facing: 192 + Facing: 768 AGunt6: medium_gun_turret Location: 35,20 Owner: AtreidesSmallBase1 - TurretFacing: 192 + TurretFacing: 768 Actor45: spicebloom.spawnpoint Location: 60,20 Owner: Neutral @@ -233,11 +233,11 @@ Actor50: trike Location: 34,23 Owner: AtreidesSmallBase1 - Facing: 192 + Facing: 768 AGunt7: medium_gun_turret Location: 35,23 Owner: AtreidesSmallBase1 - TurretFacing: 192 + TurretFacing: 768 Actor52: spicebloom.spawnpoint Location: 78,23 Owner: Neutral @@ -259,11 +259,11 @@ AGunt4: medium_gun_turret Location: 2,25 Owner: AtreidesMainBase - TurretFacing: 128 + TurretFacing: 512 AGunt5: medium_gun_turret Location: 5,25 Owner: AtreidesMainBase - TurretFacing: 128 + TurretFacing: 512 Actor60: harvester Location: 26,25 Owner: AtreidesSmallBase1 @@ -303,7 +303,6 @@ AGunt8: medium_gun_turret Location: 44,49 Owner: AtreidesSmallBase2 - TurretFacing: 0 Actor73: wall Location: 44,50 Owner: AtreidesSmallBase2 @@ -313,7 +312,7 @@ AGunt9: medium_gun_turret Location: 38,51 Owner: AtreidesSmallBase2 - TurretFacing: 32 + TurretFacing: 128 Actor76: wall Location: 39,51 Owner: AtreidesSmallBase2 @@ -338,7 +337,7 @@ AGunt10: medium_gun_turret Location: 46,53 Owner: AtreidesSmallBase2 - TurretFacing: 224 + TurretFacing: 896 Actor84: wall Location: 38,54 Owner: AtreidesSmallBase2 @@ -381,7 +380,6 @@ AGunt11: medium_gun_turret Location: 64,57 Owner: AtreidesSmallBase3 - TurretFacing: 0 Actor98: wall Location: 65,57 Owner: AtreidesSmallBase3 @@ -439,7 +437,7 @@ AGunt12: medium_gun_turret Location: 74,72 Owner: AtreidesSmallBase3 - TurretFacing: 160 + TurretFacing: 640 Actor117: wall Location: 75,72 Owner: AtreidesSmallBase3 diff -Nru openra-20200503/mods/d2k/maps/ordos-05/ordos05-AI.lua openra-20210321/mods/d2k/maps/ordos-05/ordos05-AI.lua --- openra-20200503/mods/d2k/maps/ordos-05/ordos05-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-05/ordos05-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -42,7 +42,7 @@ local vehiclesToBuild = function() return { Utils.Random(EnemyVehicleTypes) } end local tanksToBuild = function() return EnemyTankType end local attackTresholdSize = AttackGroupSize[Difficulty] * 2.5 - + ProduceUnits(atreides_main, ABarracks1, delay, infantryToBuild, AttackGroupSize[Difficulty], attackTresholdSize) ProduceUnits(atreides_main, ALightFactory, delay, vehiclesToBuild, AttackGroupSize[Difficulty], attackTresholdSize) ProduceUnits(atreides_main, AHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackTresholdSize) @@ -50,7 +50,7 @@ ProduceUnits(atreides_small_1, ABarracks2, delay, infantryToBuild, AttackGroupSize[Difficulty], attackTresholdSize) ProduceUnits(atreides_small_2, ABarracks3, delay, infantryToBuild, AttackGroupSize[Difficulty], attackTresholdSize) - + AIProductionActivated = true end diff -Nru openra-20200503/mods/d2k/maps/ordos-05/ordos05.lua openra-20210321/mods/d2k/maps/ordos-05/ordos05.lua --- openra-20200503/mods/d2k/maps/ordos-05/ordos05.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-05/ordos05.lua 2021-03-21 11:10:05.000000000 +0000 @@ -7,7 +7,7 @@ information, see COPYING. ]] -Base = +Base = { AtreidesMainBase = { AConyard, APower1, APower2, APower3, ABarracks1, ARefinery1, ALightFactory, AHeavyFactory, AGunt1, AGunt2, AGunt3, AGunt4, AGunt5 }, AtreidesSmallBase1 = { APower4, APower5, ABarracks2, ARefinery2, AGunt6, AGunt7 }, @@ -70,7 +70,7 @@ { AtreidesEntry8.Location, AtreidesRally8.Location } } -InitialReinforcements = +InitialReinforcements = { AtreidesMainBase = { "combat_tank_a", "combat_tank_a", "quad", "quad", "trike", "light_inf", "light_inf", "light_inf", "light_inf" }, AtreidesSmallBase1 = { "trooper", "trooper", "trooper", "light_inf", "light_inf", "light_inf", "light_inf" }, diff -Nru openra-20200503/mods/d2k/maps/ordos-06a/map.yaml openra-20210321/mods/d2k/maps/ordos-06a/map.yaml --- openra-20200503/mods/d2k/maps/ordos-06a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-06a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -96,7 +96,7 @@ Owner: Ordos ARock1: large_gun_turret Location: 20,5 - Facing: 160 + Facing: 640 Owner: Atreides Actor14: wall Location: 65,5 @@ -190,7 +190,7 @@ Owner: Atreides ARock2: large_gun_turret Location: 16,12 - Facing: 160 + Facing: 640 Owner: Atreides Actor45: wall Location: 70,12 @@ -251,14 +251,14 @@ Owner: Atreides ARock3: large_gun_turret Location: 10,23 - Facing: 192 + Facing: 768 Owner: Atreides Actor65: wall Location: 11,23 Owner: Atreides AGunt1: medium_gun_turret Location: 12,23 - Facing: 192 + Facing: 768 Owner: Atreides Actor67: wormspawner Location: 26,23 @@ -450,7 +450,7 @@ Owner: Neutral HGunt3: medium_gun_turret Location: 19,76 - Facing: 32 + Facing: 128 Owner: Harkonnen Actor130: wall Location: 20,76 @@ -475,7 +475,7 @@ Owner: Harkonnen HRock: large_gun_turret Location: 38,77 - Facing: 192 + Facing: 768 Owner: Harkonnen HPower8: wind_trap Location: 23,78 @@ -497,7 +497,7 @@ Owner: Harkonnen HGunt4: medium_gun_turret Location: 19,80 - Facing: 64 + Facing: 256 Owner: Harkonnen Actor145: wall Location: 39,80 diff -Nru openra-20200503/mods/d2k/maps/ordos-06a/ordos06a.lua openra-20210321/mods/d2k/maps/ordos-06a/ordos06a.lua --- openra-20200503/mods/d2k/maps/ordos-06a/ordos06a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/ordos-06a/ordos06a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -115,7 +115,7 @@ hard = 6 } -InitialReinforcements = +InitialReinforcements = { Atreides = { "combat_tank_a", "quad", "quad", "trike", "trike" }, Harkonnen = { "trooper", "trooper", "trooper", "trooper", "trooper", "combat_tank_h" } diff -Nru openra-20200503/mods/d2k/maps/shellmap/d2k-shellmap.lua openra-20210321/mods/d2k/maps/shellmap/d2k-shellmap.lua --- openra-20200503/mods/d2k/maps/shellmap/d2k-shellmap.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/shellmap/d2k-shellmap.lua 2021-03-21 11:10:05.000000000 +0000 @@ -147,8 +147,10 @@ Tick = function() ticks = ticks + 1 - local t = (ticks + 45) % (360 * speed) * (math.pi / 180) / speed; - Camera.Position = viewportOrigin + WVec.New(19200 * math.sin(t), 28800 * math.cos(t), 0) + if ticks > 1 or not Map.IsPausedShellmap then + local t = (ticks + 45) % (360 * speed) * (math.pi / 180) / speed; + Camera.Position = viewportOrigin + WVec.New(19200 * math.sin(t), 28800 * math.cos(t), 0) + end end WorldLoaded = function() diff -Nru openra-20200503/mods/d2k/maps/shellmap/map.yaml openra-20210321/mods/d2k/maps/shellmap/map.yaml --- openra-20200503/mods/d2k/maps/shellmap/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/maps/shellmap/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -78,37 +78,32 @@ smg_raider: raider Owner: Smugglers Location: 53,57 - Facing: 32 + Facing: 128 smg_light1: light_inf Owner: Smugglers Location: 59,61 SubCell: 3 - Facing: 160 - TurretFacing: 160 + Facing: 640 smg_light2: light_inf Owner: Smugglers Location: 53,63 SubCell: 3 - Facing: 96 - TurretFacing: 96 + Facing: 384 smg_light3: light_inf Owner: Smugglers Location: 57,57 SubCell: 3 Facing: 0 - TurretFacing: 0 smg_troop1: trooper Owner: Smugglers Location: 60,59 SubCell: 3 - Facing: 192 - TurretFacing: 192 + Facing: 768 smg_troop2: trooper Owner: Smugglers Location: 54,60 SubCell: 3 - Facing: 64 - TurretFacing: 64 + Facing: 256 atr_cyard: construction_yard Owner: Atreides Location: 90,90 @@ -148,7 +143,7 @@ atr_rckt1: large_gun_turret Owner: Atreides Location: 84,76 - TurretFacing: 32 + TurretFacing: 128 Actor47: wall Owner: Atreides Location: 85,76 @@ -164,7 +159,6 @@ atr_gunt1: medium_gun_turret Owner: Atreides Location: 92,78 - TurretFacing: 0 atr_pad: repair_pad Owner: Atreides Location: 81,90 @@ -183,7 +177,7 @@ atr_gunt2: medium_gun_turret Owner: Atreides Location: 71,87 - TurretFacing: 96 + TurretFacing: 384 Actor58: wall Owner: Atreides Location: 70,87 @@ -205,11 +199,10 @@ atr_rckt2: large_gun_turret Owner: Atreides Location: 78,81 - TurretFacing: 0 atr_rckt3: large_gun_turret Owner: Atreides Location: 75,82 - TurretFacing: 32 + TurretFacing: 128 atr_wind7: wind_trap Owner: Atreides Location: 84,85 @@ -264,11 +257,11 @@ har_rckt1: large_gun_turret Owner: Harkonnen Location: 87,33 - TurretFacing: 128 + TurretFacing: 512 har_gunt1: medium_gun_turret Owner: Harkonnen Location: 89,33 - TurretFacing: 128 + TurretFacing: 512 Actor92: wall Owner: Harkonnen Location: 78,31 @@ -296,19 +289,19 @@ har_gunt2: medium_gun_turret Owner: Harkonnen Location: 80,18 - TurretFacing: 64 + TurretFacing: 256 har_rckt2: large_gun_turret Owner: Harkonnen Location: 77,21 - TurretFacing: 32 + TurretFacing: 128 har_rckt3: large_gun_turret Owner: Harkonnen Location: 78,30 - TurretFacing: 160 + TurretFacing: 640 har_gunt3: medium_gun_turret Owner: Harkonnen Location: 73,23 - TurretFacing: 64 + TurretFacing: 256 har_wind5: wind_trap Owner: Ordos Location: 35,17 @@ -360,11 +353,11 @@ ord_gunt1: medium_gun_turret Owner: Ordos Location: 21,32 - TurretFacing: 128 + TurretFacing: 512 ord_gunt2: medium_gun_turret Owner: Ordos Location: 17,32 - TurretFacing: 128 + TurretFacing: 512 Actor123: wall Owner: Ordos Location: 29,34 @@ -389,11 +382,11 @@ ord_rckt1: large_gun_turret Owner: Ordos Location: 37,33 - TurretFacing: 128 + TurretFacing: 512 ord_rckt3: large_gun_turret Owner: Ordos Location: 29,33 - TurretFacing: 128 + TurretFacing: 512 ord_lfac: light_factory Owner: Ordos Location: 19,21 @@ -460,11 +453,9 @@ cor_gunt1: medium_gun_turret Owner: Corrino Location: 20,87 - TurretFacing: 0 cor_rckt1: large_gun_turret Owner: Corrino Location: 20,85 - TurretFacing: 0 Actor154: wall Owner: Corrino Location: 23,83 @@ -474,7 +465,7 @@ cor_gunt2: medium_gun_turret Owner: Corrino Location: 23,84 - TurretFacing: 32 + TurretFacing: 128 Actor158: wall Owner: Corrino Location: 35,84 @@ -484,7 +475,7 @@ cor_gunt3: medium_gun_turret Owner: Corrino Location: 36,84 - TurretFacing: 192 + TurretFacing: 768 Actor162: wall Owner: Corrino Location: 36,80 @@ -494,7 +485,7 @@ cor_rckt2: large_gun_turret Owner: Corrino Location: 36,79 - TurretFacing: 160 + TurretFacing: 640 cor_htech: high_tech_factory Owner: Corrino Location: 37,91 @@ -552,67 +543,57 @@ ord_siege1: siege_tank Owner: Ordos Location: 33,32 - Facing: 128 - TurretFacing: 128 + Facing: 512 ord_siege2: siege_tank Owner: Ordos Location: 22,31 - Facing: 160 - TurretFacing: 160 + Facing: 640 ord_missile: missile_tank Owner: Ordos Location: 34,20 - Facing: 160 + Facing: 640 ord_raider: raider Owner: Ordos Location: 23,23 - Facing: 128 + Facing: 512 ord_combat1: combat_tank_o Owner: Ordos Location: 33,27 - Facing: 64 - TurretFacing: 64 + Facing: 256 ord_combat2: combat_tank_o Owner: Ordos Location: 28,28 - Facing: 128 - TurretFacing: 128 + Facing: 512 ord_troop1: trooper Owner: Ordos Location: 39,30 SubCell: 3 Facing: 0 - TurretFacing: 0 ord_troop2: trooper Owner: Ordos Location: 36,29 SubCell: 3 Facing: 0 - TurretFacing: 0 ord_light1: light_inf Owner: Ordos Location: 17,24 SubCell: 3 Facing: 0 - TurretFacing: 0 ord_light2: light_inf Owner: Ordos Location: 21,29 SubCell: 3 Facing: 0 - TurretFacing: 0 ord_light3: light_inf Owner: Ordos Location: 20,20 SubCell: 3 Facing: 0 - TurretFacing: 0 ord_engi: engineer Owner: Ordos Location: 32,18 SubCell: 3 Facing: 0 - TurretFacing: 0 ord_carry1: carryall Owner: Ordos Location: 27,25 @@ -628,58 +609,49 @@ har_missile: missile_tank Owner: Harkonnen Location: 93,29 - Facing: 128 + Facing: 512 har_siege1: siege_tank Owner: Harkonnen Location: 89,32 - Facing: 128 - TurretFacing: 128 + Facing: 512 har_siege2: siege_tank Owner: Harkonnen Location: 74,24 - Facing: 32 - TurretFacing: 32 + Facing: 128 har_combat1: combat_tank_h Owner: Harkonnen Location: 79,25 - Facing: 96 - TurretFacing: 96 + Facing: 384 har_light1: light_inf Owner: Harkonnen Location: 91,28 SubCell: 3 Facing: 0 - TurretFacing: 0 har_light2: light_inf Owner: Harkonnen Location: 94,24 SubCell: 3 Facing: 0 - TurretFacing: 0 har_sardaukar: mpsardaukar Owner: Harkonnen Location: 82,28 SubCell: 3 - Facing: 128 - TurretFacing: 128 + Facing: 512 har_troop1: trooper Owner: Harkonnen Location: 79,31 SubCell: 3 - Facing: 160 - TurretFacing: 160 + Facing: 640 har_troop2: trooper Owner: Harkonnen Location: 79,18 SubCell: 3 - Facing: 64 - TurretFacing: 64 + Facing: 256 har_troop3: trooper Owner: Harkonnen Location: 84,23 SubCell: 3 Facing: 0 - TurretFacing: 0 har_quad: quad Owner: Harkonnen Location: 90,27 @@ -687,27 +659,23 @@ art_missile: missile_tank Owner: Atreides Location: 70,82 - Facing: 32 + Facing: 128 atr_combat1: combat_tank_a Owner: Atreides Location: 90,85 Facing: 0 - TurretFacing: 0 atr_combat2: combat_tank_a Owner: Atreides Location: 81,88 - Facing: 128 - TurretFacing: 128 + Facing: 512 atr_siege1: siege_tank Owner: Atreides Location: 85,77 - Facing: 32 - TurretFacing: 32 + Facing: 128 atr_siege2: siege_tank Owner: Atreides Location: 71,86 - Facing: 96 - TurretFacing: 96 + Facing: 384 atr_carry1: carryall Owner: Atreides Location: 94,86 @@ -729,97 +697,81 @@ Location: 89,79 SubCell: 3 Facing: 0 - TurretFacing: 0 atr_light2: light_inf Owner: Atreides Location: 74,87 SubCell: 3 - Facing: 128 - TurretFacing: 128 + Facing: 512 atr_light3: light_inf Owner: Atreides Location: 80,93 SubCell: 3 Facing: 0 - TurretFacing: 0 atr_gren: grenadier Owner: Atreides Location: 80,84 SubCell: 3 Facing: 0 - TurretFacing: 0 atr_trooper1: trooper Owner: Atreides Location: 94,84 SubCell: 3 Facing: 0 - TurretFacing: 0 atr_trooper2: trooper Owner: Atreides Location: 85,89 SubCell: 3 Facing: 0 - TurretFacing: 0 cor_missile: missile_tank Owner: Corrino Location: 41,91 - Facing: 160 + Facing: 640 cor_combat1: combat_tank_h Owner: Corrino Location: 38,85 Facing: 0 - TurretFacing: 0 cor_combat2: combat_tank_h Owner: Corrino Location: 21,84 Facing: 0 - TurretFacing: 0 cor_siege1: siege_tank Owner: Corrino Location: 35,85 - Facing: 224 - TurretFacing: 224 + Facing: 896 cor_siege2: siege_tank Owner: Corrino Location: 20,88 Facing: 0 - TurretFacing: 0 cor_sardaukar1: sardaukar Owner: Corrino Location: 40,85 SubCell: 3 Facing: 0 - TurretFacing: 0 cor_sardaukar2: sardaukar Owner: Corrino Location: 30,85 SubCell: 3 Facing: 0 - TurretFacing: 0 cor_sardaukar3: sardaukar Owner: Corrino Location: 23,89 SubCell: 3 - Facing: 128 - TurretFacing: 128 + Facing: 512 cor_sardaukar4: sardaukar Owner: Corrino Location: 30,91 SubCell: 3 Facing: 0 - TurretFacing: 0 cor_sardaukar5: sardaukar Owner: Corrino Location: 17,88 SubCell: 3 Facing: 0 - TurretFacing: 0 cor_sardaukar6: sardaukar Owner: Corrino Location: 33,81 SubCell: 3 - Facing: 192 - TurretFacing: 192 + Facing: 768 Actor245: wormspawner Owner: Neutral Location: 80,48 @@ -871,26 +823,22 @@ har_combat2: combat_tank_h Owner: Harkonnen Location: 88,29 - Facing: 64 - TurretFacing: 64 + Facing: 256 atr_engi: engineer Owner: Atreides Location: 86,85 SubCell: 3 Facing: 0 - TurretFacing: 0 cor_engi: engineer Owner: Corrino Location: 35,89 SubCell: 3 Facing: 0 - TurretFacing: 0 har_engi: engineer Owner: Harkonnen Location: 77,29 SubCell: 3 Facing: 0 - TurretFacing: 0 smg_silo2: silo Owner: Smugglers Location: 54,63 @@ -955,7 +903,7 @@ atr_gunt3: medium_gun_turret Owner: Atreides Location: 71,94 - TurretFacing: 64 + TurretFacing: 256 Actor283: wall Owner: Ordos Location: 33,28 @@ -965,11 +913,11 @@ ord_rckt2: large_gun_turret Owner: Ordos Location: 33,29 - TurretFacing: 224 + TurretFacing: 896 ord_gunt3: medium_gun_turret Owner: Ordos Location: 33,33 - TurretFacing: 128 + TurretFacing: 512 Actor287: wall Owner: Corrino Location: 38,86 @@ -979,7 +927,6 @@ cor_rckt3: large_gun_turret Owner: Corrino Location: 39,86 - TurretFacing: 0 cor_wind6: wind_trap Owner: Corrino Location: 25,88 diff -Nru openra-20200503/mods/d2k/metrics.yaml openra-20210321/mods/d2k/metrics.yaml --- openra-20200503/mods/d2k/metrics.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/metrics.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,11 +7,3 @@ FactionSuffix-smuggler: ordos FactionSuffix-mercenary: ordos TextfieldColorHighlight: 7f4d29 - ChatLineSound: ChatLine - ClickDisabledSound: ClickDisabledSound - ClickSound: ClickSound - ChatMessageColor: FFFFFF - SystemMessageColor: FFFF00 - NormalSelectionColor: FFFFFF - AltSelectionColor: 00FFFF - CtrlSelectionColor: FFFF00 diff -Nru openra-20200503/mods/d2k/mod.yaml openra-20210321/mods/d2k/mod.yaml --- openra-20200503/mods/d2k/mod.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/mod.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,13 +7,13 @@ PackageFormats: D2kSoundResources Packages: - ~^Content/d2k/v2/ - ~^Content/d2k/v2/GAMESFX - ~^Content/d2k/v2/Movies - ~^Content/d2k/v2/Music - . + ~^SupportDir|Content/d2k/v2/ + ~^SupportDir|Content/d2k/v2/GAMESFX + ~^SupportDir|Content/d2k/v2/Movies + ~^SupportDir|Content/d2k/v2/Music + ^EngineDir $d2k: d2k - ./mods/common: common + ^EngineDir|mods/common: common ~SOUND.RS d2k|bits @@ -23,7 +23,7 @@ MapFolders: d2k|maps: System - ~^maps/d2k/{DEV_VERSION}: User + ~^SupportDir|maps/d2k/{DEV_VERSION}: User Rules: d2k|rules/misc.yaml @@ -61,9 +61,9 @@ d2k|chrome.yaml Assemblies: - common|OpenRA.Mods.Common.dll - common|OpenRA.Mods.Cnc.dll - d2k|OpenRA.Mods.D2k.dll + ^BinDir|OpenRA.Mods.Common.dll + ^BinDir|OpenRA.Mods.Cnc.dll + ^BinDir|OpenRA.Mods.D2k.dll ChromeLayout: common|chrome/ingame.yaml @@ -239,20 +239,20 @@ QuickDownload: quickinstall Packages: base: Base Game Files - TestFiles: ^Content/d2k/v2/BLOXBASE.R8, ^Content/d2k/v2/BLOXBAT.R8, ^Content/d2k/v2/BLOXBGBS.R8, ^Content/d2k/v2/BLOXICE.R8, ^Content/d2k/v2/BLOXTREE.R8, ^Content/d2k/v2/BLOXWAST.R8, ^Content/d2k/v2/SOUND.RS, ^Content/d2k/v2/PALETTE.BIN, ^Content/d2k/v2/FONT.BIN, ^Content/d2k/v2/FONTCOL.FNT, ^Content/d2k/v2/FONTCOL.FPL + TestFiles: ^SupportDir|Content/d2k/v2/BLOXBASE.R8, ^SupportDir|Content/d2k/v2/BLOXBAT.R8, ^SupportDir|Content/d2k/v2/BLOXBGBS.R8, ^SupportDir|Content/d2k/v2/BLOXICE.R8, ^SupportDir|Content/d2k/v2/BLOXTREE.R8, ^SupportDir|Content/d2k/v2/BLOXWAST.R8, ^SupportDir|Content/d2k/v2/SOUND.RS, ^SupportDir|Content/d2k/v2/PALETTE.BIN, ^SupportDir|Content/d2k/v2/FONT.BIN, ^SupportDir|Content/d2k/v2/FONTCOL.FNT, ^SupportDir|Content/d2k/v2/FONTCOL.FPL Sources: d2k-a, d2k-a-linux, d2k-b, d2k-b-linux, d2k-c, d2k-c-linux, d2k-d, d2k-d-linux, d2k-e, d2k-e-linux, gruntmods Required: true Download: basefiles patch: 1.06 Patch Content - TestFiles: ^Content/d2k/v2/DATA.R8, ^Content/d2k/v2/BLOXXMAS.R8 + TestFiles: ^SupportDir|Content/d2k/v2/DATA.R8, ^SupportDir|Content/d2k/v2/BLOXXMAS.R8 Sources: gruntmods Required: true Download: patch106 music: Game Music - TestFiles: ^Content/d2k/v2/Music/AMBUSH.AUD + TestFiles: ^SupportDir|Content/d2k/v2/Music/AMBUSH.AUD, ^SupportDir|Content/d2k/v2/Music/WAITGAME.AUD Sources: d2k-a, d2k-a-linux, d2k-b, d2k-b-linux, d2k-c, d2k-c-linux, d2k-d, d2k-d-linux, d2k-e, d2k-e-linux, gruntmods movies: Campaign Briefings - TestFiles: ^Content/d2k/v2/Movies/A_BR01_E.VQA + TestFiles: ^SupportDir|Content/d2k/v2/Movies/A_BR01_E.VQA Sources: d2k-a, d2k-a-linux, d2k-b, d2k-b-linux, d2k-c, d2k-c-linux, d2k-d, d2k-d-linux, d2k-e, d2k-e-linux Downloads: d2k|installer/downloads.yaml @@ -264,3 +264,6 @@ d2k|installer/d2k-e.yaml d2k|installer/downloads.yaml d2k|installer/gruntmods.yaml + +DiscordService: + ApplicationId: 712711732770111550 diff -Nru openra-20200503/mods/d2k/rules/aircraft.yaml openra-20210321/mods/d2k/rules/aircraft.yaml --- openra-20200503/mods/d2k/rules/aircraft.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/aircraft.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,6 +2,8 @@ Inherits: ^Plane Valued: Cost: 1100 + UpdatesPlayerStatistics: + AddToAssetsValue: false Tooltip: Name: Carryall Health: @@ -11,15 +13,14 @@ Aircraft: CruiseAltitude: 2160 CruisingCondition: cruising - InitialFacing: 0 Speed: 144 - TurnSpeed: 4 + TurnSpeed: 16 LandableTerrainTypes: Sand, Rock, Transition, Spice, SpiceSand, Dune, Concrete Repulsable: False AirborneCondition: airborne CanSlide: True VTOL: true - IdleTurnSpeed: 1 + IdleTurnSpeed: 4 Targetable@GROUND: TargetTypes: Ground, Vehicle RequiresCondition: !airborne @@ -38,17 +39,19 @@ LocalOffset: 0, 0, -128 RenderSprites: Image: carryall - SelfHealing: + ChangesHealth: Step: 50 Delay: 3 - HealIfBelow: 50 + StartIfBelow: 50 Buildable: - BuildDuration: 648 - BuildDurationModifier: 40 + BuildDuration: 750 + BuildDurationModifier: 100 Description: Large winged, planet-bound ship\n Automatically lifts harvesters from and to Spice.\n Lifts vehicles to Repair Pads when ordered. carryall: Inherits: carryall.reinforce + UpdatesPlayerStatistics: + AddToAssetsValue: true -Carryall: AutoCarryall: BeforeLoadDelay: 10 @@ -78,7 +81,7 @@ Aircraft: IdleBehavior: LeaveMap Speed: 189 - TurnSpeed: 1 + TurnSpeed: 4 Repulsable: False MaximumPitch: 20 CruiseAltitude: 2048 @@ -88,7 +91,6 @@ -AppearsOnRadar: Cargo: MaxWeight: 20 - PipCount: 10 RejectsOrders: ornithopter: @@ -102,7 +104,7 @@ Type: light Aircraft: Speed: 224 - TurnSpeed: 2 + TurnSpeed: 8 Repulsable: False CruiseAltitude: 1920 AmmoPool: @@ -120,7 +122,7 @@ Tooltip: Name: Ornithopter Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 224 RenderSprites: Image: ornithopter @@ -130,7 +132,7 @@ Tooltip: Name: Carryall Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 144 CanSlide: True VTOL: true @@ -145,7 +147,7 @@ Moves: False Velocity: 0c128 Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 CanSlide: True VTOL: true RenderSprites: diff -Nru openra-20200503/mods/d2k/rules/ai.yaml openra-20210321/mods/d2k/rules/ai.yaml --- openra-20200503/mods/d2k/rules/ai.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/ai.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -219,8 +219,9 @@ RequiresCondition: enable-omnius-ai SquadSize: 8 MaxBaseRadius: 40 - ExcludeFromSquadsTypes: harvester, mcv + ExcludeFromSquadsTypes: harvester, mcv, carryall, carryall.reinforce ConstructionYardTypes: construction_yard + IgnoredEnemyTargetTypes: Creep UnitBuilderBotModule@omnius: RequiresCondition: enable-omnius-ai UnitQueues: Infantry, Vehicle, Armor, Starport, Aircraft @@ -262,8 +263,9 @@ RequiresCondition: enable-vidious-ai SquadSize: 6 MaxBaseRadius: 40 - ExcludeFromSquadsTypes: harvester, mcv + ExcludeFromSquadsTypes: harvester, mcv, carryall, carryall.reinforce ConstructionYardTypes: construction_yard + IgnoredEnemyTargetTypes: Creep UnitBuilderBotModule@vidious: RequiresCondition: enable-vidious-ai UnitQueues: Infantry, Vehicle, Armor, Starport, Aircraft @@ -300,8 +302,9 @@ RequiresCondition: enable-gladius-ai SquadSize: 10 MaxBaseRadius: 40 - ExcludeFromSquadsTypes: harvester, mcv + ExcludeFromSquadsTypes: harvester, mcv, carryall, carryall.reinforce ConstructionYardTypes: construction_yard + IgnoredEnemyTargetTypes: Creep UnitBuilderBotModule@gladius: RequiresCondition: enable-gladius-ai UnitQueues: Infantry, Vehicle, Armor, Starport, Aircraft diff -Nru openra-20200503/mods/d2k/rules/arrakis.yaml openra-20210321/mods/d2k/rules/arrakis.yaml --- openra-20200503/mods/d2k/rules/arrakis.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/arrakis.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ Sequence: grow3 BodyOrientation: QuantizedFacings: 1 - ConditionManager: GrantConditionOnTerrain: Condition: clearsand TerrainTypes: SpiceSand @@ -64,7 +63,7 @@ Actor: spicebloom.spawnpoint HitShape: Type: Circle - Radius: 512 + Radius: 16 MapEditorData: Categories: System Interactable: @@ -80,7 +79,7 @@ HP: 100000 HitShape: Type: Circle - Radius: 256 + Radius: 16 Armor: Type: heavy Mobile: @@ -125,7 +124,6 @@ TerrainTypes: Sand, Dune, SpiceSand, Spice MovingInterval: 3 RequiresCondition: !attacking - ConditionManager: RevealOnFire: Duration: 50 Radius: 2c512 @@ -136,17 +134,17 @@ Inherits: ^Building Tooltip: Name: Fremen Sietch - Building: + D2kBuilding: Footprint: xx xx Dimensions: 2,2 TerrainTypes: Cliff + DamageTerrainTypes: Health: HP: 60000 Armor: Type: wood RevealsShroud: Range: 10c0 - -DamagedByTerrain: -GivesBuildableArea: -Sellable: -Capturable: diff -Nru openra-20200503/mods/d2k/rules/campaign-rules.yaml openra-20210321/mods/d2k/rules/campaign-rules.yaml --- openra-20200503/mods/d2k/rules/campaign-rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/campaign-rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,6 +2,7 @@ -ConquestVictoryConditions: MissionObjectives: EarlyGameOver: true + GameOverDelay: 3000 Shroud: FogCheckboxLocked: True FogCheckboxEnabled: True @@ -32,3 +33,11 @@ TechLevelDropdownLocked: True ShortGameCheckboxLocked: True ShortGameCheckboxEnabled: False + +^AutoTargetGroundAssaultMove: + GrantConditionOnBotOwner@BOTOWNER: + Bots: campaign + +^AutoTargetAllAssaultMove: + GrantConditionOnBotOwner@BOTOWNER: + Bots: campaign diff -Nru openra-20200503/mods/d2k/rules/defaults.yaml openra-20210321/mods/d2k/rules/defaults.yaml --- openra-20200503/mods/d2k/rules/defaults.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/defaults.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -5,7 +5,6 @@ GivesExperience: PlayerExperienceModifier: 1 ScriptTriggers: - ConditionManager: RenderDebugState: ^SpriteActor: @@ -85,53 +84,55 @@ InaccuracyMultiplier@RANK-ELITE: RequiresCondition: rank-elite Modifier: 50 - SelfHealing@ELITE: + ChangesHealth@ELITE: Step: 0 PercentageStep: 4 Delay: 125 - HealIfBelow: 100 + StartIfBelow: 100 DamageCooldown: 125 RequiresCondition: rank-elite WithDecoration@RANK-1: Image: rank Sequence: rank-veteran-1 Palette: effect - ReferencePoint: Bottom, Right + Position: BottomRight + Margin: 5, 6 RequiresCondition: rank-veteran == 1 - ZOffset: 256 WithDecoration@RANK-2: Image: rank Sequence: rank-veteran-2 Palette: effect - ReferencePoint: Bottom, Right + Position: BottomRight + Margin: 5, 6 RequiresCondition: rank-veteran == 2 - ZOffset: 256 WithDecoration@RANK-3: Image: rank Sequence: rank-veteran-3 Palette: effect - ReferencePoint: Bottom, Right + Position: BottomRight + Margin: 5, 6 RequiresCondition: rank-veteran == 3 - ZOffset: 256 WithDecoration@RANK-ELITE: Image: rank Sequence: rank-elite Palette: effect - ReferencePoint: Bottom, Right + Position: BottomRight + Margin: 5, 6 RequiresCondition: rank-elite - ZOffset: 256 ^AutoTargetGround: AutoTarget: AttackAnythingCondition: stance-attackanything AutoTargetPriority@DEFAULT: RequiresCondition: !stance-attackanything - ValidTargets: Infantry, Vehicle, Creep, Water, Defense + ValidTargets: Infantry, Vehicle, Water, Defense InvalidTargets: NoAutoTarget AutoTargetPriority@ATTACKANYTHING: RequiresCondition: stance-attackanything - ValidTargets: Infantry, Vehicle, Creep, Water, Structure, Defense + ValidTargets: Infantry, Vehicle, Water, Structure, Defense InvalidTargets: NoAutoTarget + AutoTargetPriority@CREEPS: + ValidTargets: Creep ^AutoTargetGroundAssaultMove: Inherits: ^AutoTargetGround @@ -139,7 +140,16 @@ RequiresCondition: !stance-attackanything && !assault-move AutoTargetPriority@ATTACKANYTHING: RequiresCondition: stance-attackanything || assault-move + GrantConditionOnBotOwner@BOTOWNER: + Condition: bot-owned + Bots: omnius, vidious, gladius + GrantCondition@IGNORECREEPS: + Condition: ignore-creeps + RequiresCondition: bot-owned && (attack-move || assault-move) + AutoTargetPriority@CREEPS: + RequiresCondition: !ignore-creeps AttackMove: + AttackMoveCondition: attack-move AssaultMoveCondition: assault-move ^AutoTargetAll: @@ -147,12 +157,14 @@ AttackAnythingCondition: stance-attackanything AutoTargetPriority@DEFAULT: RequiresCondition: !stance-attackanything - ValidTargets: Infantry, Vehicle, Creep, Water, Air, Defense + ValidTargets: Infantry, Vehicle, Water, Air, Defense InvalidTargets: NoAutoTarget AutoTargetPriority@ATTACKANYTHING: RequiresCondition: stance-attackanything - ValidTargets: Infantry, Vehicle, Creep, Water, Air, Structure, Defense + ValidTargets: Infantry, Vehicle, Water, Air, Structure, Defense InvalidTargets: NoAutoTarget + AutoTargetPriority@CREEPS: + ValidTargets: Creep ^AutoTargetAllAssaultMove: Inherits: ^AutoTargetAll @@ -160,24 +172,37 @@ RequiresCondition: !stance-attackanything && !assault-move AutoTargetPriority@ATTACKANYTHING: RequiresCondition: stance-attackanything || assault-move + GrantConditionOnBotOwner@BOTOWNER: + Condition: bot-owned + Bots: omnius, vidious, gladius + GrantCondition@IGNORECREEPS: + Condition: ignore-creeps + RequiresCondition: bot-owned && (attack-move || assault-move) + AutoTargetPriority@CREEPS: + RequiresCondition: !ignore-creeps AttackMove: + AttackMoveCondition: attack-move AssaultMoveCondition: assault-move +^PlayerHandicaps: + HandicapFirepowerMultiplier: + HandicapDamageMultiplier: + HandicapProductionTimeMultiplier: + ^Vehicle: Inherits@1: ^ExistsInWorld Inherits@2: ^SpriteActor Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Tooltip: GenericName: Unit Huntable: OwnerLostAction: Action: Kill Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Locomotor: vehicle PauseOnCondition: notmobile - SelectionDecorations: - WithSpriteControlGroupDecoration: Selectable: Bounds: 32,32 Targetable: @@ -185,7 +210,6 @@ Passenger: CargoType: Vehicle AttackMove: - DrawLineToTarget: HiddenUnderFog: ActorLostNotification: Repairable: @@ -205,15 +229,16 @@ LockedCondition: notmobile WithDecoration@CARRYALL: Image: pips + Margin: 7, 9 Sequence: pickup-indicator - ReferencePoint: Top, Left - ZOffset: 256 RequiresCondition: carryall-reserved RevealOnFire: RevealOnDeath: Duration: 100 Radius: 2c512 HitShape: + Type: Circle + Radius: 16 MapEditorData: Categories: Vehicle @@ -231,12 +256,14 @@ Type: light HiddenUnderFog: Type: CenterPosition - AlwaysVisibleStances: None + AlwaysVisibleRelationships: None Tooltip: GenericName: Destroyed Unit ScriptTriggers: WithFacingSpriteBody: HitShape: + Type: Circle + Radius: 16 MapEditorData: Categories: Husk @@ -244,9 +271,6 @@ Inherits: ^Husk Husk: AllowedTerrain: Sand, Rock, Transition, Concrete, Spice, SpiceSand, SpiceBlobs, Dune - Burns: - Damage: 10 - Interval: 4 Targetable: TargetTypes: Ground, Vehicle RequiresForceFire: true @@ -255,6 +279,14 @@ Explodes: Weapon: UnitExplodeMed EmptyWeapon: UnitExplodeMed + WithIdleOverlay@Burns: + Image: fire + Sequence: 1 + IsDecoration: True + ChangesHealth: + Step: -10 + StartIfBelow: 101 + Delay: 4 ^AircraftHusk: Inherits: ^Husk @@ -272,6 +304,7 @@ Inherits@2: ^GainsExperience Inherits@3: ^SpriteActor Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Tooltip: GenericName: Unit Huntable: @@ -284,9 +317,8 @@ RevealsShroud: Range: 3c768 Mobile: + AlwaysTurnInPlace: true Locomotor: foot - SelectionDecorations: - WithSpriteControlGroupDecoration: Selectable: Bounds: 24,24,0,-4 DecorationBounds: 12,20,0,-4 @@ -309,10 +341,8 @@ BulletDeath: 4 CrushedSequence: die-crushed AttackMove: - DrawLineToTarget: Passenger: CargoType: Infantry - PipType: Green HiddenUnderFog: ActorLostNotification: Crushable: @@ -335,7 +365,7 @@ Duration: 100 HitShape: Type: Circle - Radius: 96 + Radius: 16 MapEditorData: Categories: Infantry AttackFrontal: @@ -343,6 +373,7 @@ ^Plane: Inherits@1: ^ExistsInWorld Inherits@2: ^SpriteActor + Inherits@handicaps: ^PlayerHandicaps Interactable: Tooltip: GenericName: Unit @@ -353,13 +384,14 @@ UseLocation: true HiddenUnderFog: Type: GroundPosition - AlwaysVisibleStances: None + AlwaysVisibleRelationships: None ActorLostNotification: AttackMove: - DrawLineToTarget: WithFacingSpriteBody: WithShadow: HitShape: + Type: Circle + Radius: 16 MapEditorData: Categories: Aircraft @@ -367,13 +399,12 @@ Inherits@1: ^ExistsInWorld Inherits@2: ^SpriteActor Inherits@selection: ^SelectableBuilding + Inherits@handicaps: ^PlayerHandicaps Tooltip: GenericName: Structure Huntable: OwnerLostAction: Action: Kill - SelectionDecorations: - WithSpriteControlGroupDecoration: RevealsShroud: Targetable: TargetTypes: Ground, C4, Structure @@ -382,12 +413,14 @@ Type: Rectangle TopLeft: -512, -512 BottomRight: 512, 512 - Building: + D2kBuilding: Dimensions: 1,1 Footprint: x TerrainTypes: Rock, Concrete BuildSounds: BUILD1.WAV + ConcretePrerequisites: global-auto-concrete D2kActorPreviewPlaceBuildingPreview: + RequiresPrerequisites: !global-auto-concrete OverridePalette: placebuilding RequiresBuildableArea: AreaTypes: building @@ -425,12 +458,6 @@ SellSounds: BUILD1.WAV Guardable: Range: 3c0 - DamagedByTerrain: - Damage: 500 - DamageInterval: 100 - Terrain: Rock - DamageThreshold: 50 - StartOnThreshold: true ThrowsShrapnel: Weapons: Debris, Debris2, Debris3, Debris4 Pieces: 2, 5 @@ -449,7 +476,7 @@ WithBuildingRepairDecoration: Image: allyrepair Sequence: repair - ReferencePoint: Center + Position: Center Palette: player IsPlayerPalette: True @@ -457,18 +484,23 @@ Inherits: ^Building Inherits@selection: ^SelectableCombatBuilding WithSpriteTurret: + RequiresCondition: !build-incomplete AttackTurreted: + RequiresCondition: !build-incomplete RenderRangeCircle: DetectCloaked: Range: 1c768 -GivesBuildableArea: - -WithMakeAnimation: - -WithCrumbleOverlay: + WithMakeAnimation: + BodyNames: make -Capturable: - -WithSpriteBody: + WithSpriteBody: + Name: make + Sequence: invisible Sellable: RequiresCondition: !being-demolished WithWallSpriteBody: + RequiresCondition: !build-incomplete LineBuildNode: Types: turret ThrowsShrapnel: @@ -510,7 +542,7 @@ Sequence: offline Palette: chrome RequiresCondition: powerdown - ReferencePoint: Center + Position: Center Offsets: repairing: 10, 0 PowerMultiplier@POWERDOWN: @@ -522,25 +554,60 @@ Offsets: powerdown: -10, 0 +^Selectable: + Selectable: + SelectionDecorations: + WithSpriteControlGroupDecoration: + Margin: -1, -1 + DrawLineToTarget: + ^SelectableCombatUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 10 PriorityModifiers: Ctrl ^SelectableSupportUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 8 PriorityModifiers: Ctrl, Alt ^SelectableEconomicUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 6 PriorityModifiers: Ctrl, Alt ^SelectableCombatBuilding: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 4 ^SelectableBuilding: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 2 + +^PrimaryBuilding: + PrimaryBuilding: + PrimaryCondition: primary + ProductionQueues: Building + SelectionNotification: PrimaryBuildingSelected + WithTextDecoration@primary: + RequiresCondition: primary + Position: Top + Margin: 0, 5 + RequiresSelection: true + Text: PRIMARY + +^Upgradeable: + GrantConditionOnPrerequisite@UPGRADEABLE: + Condition: stardecoration + WithDecoration@upgraded: + RequiresCondition: stardecoration + Position: TopRight + Margin: 6, 8 + RequiresSelection: true + Image: pips + Sequence: tag-upgraded diff -Nru openra-20200503/mods/d2k/rules/infantry.yaml openra-20210321/mods/d2k/rules/infantry.yaml --- openra-20200503/mods/d2k/rules/infantry.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/infantry.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,8 +4,8 @@ Buildable: Queue: Infantry BuildPaletteOrder: 10 - BuildDuration: 54 - BuildDurationModifier: 40 + BuildDuration: 62 + BuildDurationModifier: 100 Description: General-purpose infantry\n Strong vs Infantry\n Weak vs Vehicles, Artillery Valued: Cost: 50 @@ -29,8 +29,8 @@ Queue: Infantry BuildPaletteOrder: 30 Prerequisites: upgrade.barracks, ~techlevel.medium - BuildDuration: 108 - BuildDurationModifier: 40 + BuildDuration: 125 + BuildDurationModifier: 100 Description: Infiltrates and captures enemy structures\n Strong vs Buildings\n Weak vs Everything Valued: Cost: 400 @@ -61,8 +61,8 @@ Queue: Infantry BuildPaletteOrder: 20 Prerequisites: upgrade.barracks, ~techlevel.medium - BuildDuration: 73 - BuildDurationModifier: 40 + BuildDuration: 85 + BuildDurationModifier: 100 Description: Anti-tank infantry\n Strong vs Tanks\n Weak vs Infantry, Artillery Valued: Cost: 90 @@ -91,8 +91,8 @@ Queue: Infantry BuildPaletteOrder: 40 Prerequisites: upgrade.barracks, ~techlevel.high - BuildDuration: 108 - BuildDurationModifier: 40 + BuildDuration: 125 + BuildDurationModifier: 100 Description: Attracts nearby worms when deployed\n Unarmed Valued: Cost: 200 @@ -110,7 +110,7 @@ GrantConditionOnDeploy: DeployedCondition: deployed UndeployedCondition: undeployed - Facing: 128 + Facing: 512 AllowedTerrainTypes: Sand, Spice, Dune, SpiceSand WithInfantryBody: RequiresCondition: undeployed @@ -182,8 +182,8 @@ Queue: Infantry BuildPaletteOrder: 60 Prerequisites: ~barracks.atreides, upgrade.barracks, high_tech_factory, ~techlevel.medium - BuildDuration: 81 ## Wasn't converted, copied from Sardauker who has same value in TibEd. - BuildDurationModifier: 40 + BuildDuration: 94 + BuildDurationModifier: 100 Description: Infantry armed with grenades. \n Strong vs Buildings, Infantry\n Weak vs Vehicles Valued: Cost: 80 @@ -214,8 +214,8 @@ Queue: Infantry BuildPaletteOrder: 50 Prerequisites: ~palace.sardaukar, ~techlevel.high - BuildDuration: 81 - BuildDurationModifier: 40 + BuildDuration: 94 + BuildDurationModifier: 100 Description: Elite assault infantry of Corrino\n Strong vs Infantry, Vehicles\n Weak vs Artillery Valued: Cost: 120 @@ -248,7 +248,8 @@ Queue: Infantry BuildPaletteOrder: 70 Prerequisites: ~barracks.harkonnen, upgrade.barracks, high_tech_factory, ~techlevel.medium - BuildDuration: 133 + BuildDuration: 160 + BuildDurationModifier: 100 Description: Elite assault infantry of Harkonnen\n Strong vs Infantry, Vehicles\n Weak vs Artillery Valued: Cost: 200 diff -Nru openra-20200503/mods/d2k/rules/misc.yaml openra-20210321/mods/d2k/rules/misc.yaml --- openra-20200503/mods/d2k/rules/misc.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/misc.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -172,7 +172,7 @@ carryall.colorpicker: Inherits: carryall Aircraft: - InitialFacing: 104 + InitialFacing: 416 -Buildable: -MapEditorData: RenderSprites: @@ -222,8 +222,8 @@ Prerequisites: construction_yard Queue: Upgrade BuildLimit: 1 - BuildDuration: 590 - BuildDurationModifier: 40 + BuildDuration: 625 + BuildDurationModifier: 100 Description: Unlocks additional construction options \n(Large Concrete Slab, Rocket Turret) Valued: Cost: 1000 @@ -247,8 +247,8 @@ Prerequisites: barracks Queue: Upgrade BuildLimit: 1 - BuildDuration: 290 - BuildDurationModifier: 40 + BuildDuration: 208 + BuildDurationModifier: 100 Description: Unlocks additional infantry \n(Trooper, Engineer, Thumper Infantry) \n\nRequired to unlock faction specific infantry \n(Atreides: Grenadier, Harkonnen: Sardaukar) Valued: Cost: 500 @@ -272,8 +272,8 @@ Prerequisites: light_factory Queue: Upgrade BuildLimit: 1 - BuildDuration: 215 - BuildDurationModifier: 40 + BuildDuration: 268 + BuildDurationModifier: 100 Description: Unlocks additional light unit \n(Missile Quad) \n\nRequired to unlock faction specific light unit \n(Ordos: Stealth Raider Trike) Valued: Cost: 400 @@ -297,8 +297,8 @@ Prerequisites: heavy_factory Queue: Upgrade BuildLimit: 1 - BuildDuration: 380 - BuildDurationModifier: 40 + BuildDuration: 468 + BuildDurationModifier: 100 Description: Unlocks additional construction options \n(Repair Pad, IX Research Center) \n\nUnlocks additional heavy units \n(Siege Tank, Missile Tank, MCV) Valued: Cost: 800 @@ -323,8 +323,8 @@ Prerequisites: ~hightech.atreides, ~techlevel.superweapons Queue: Upgrade BuildLimit: 1 - BuildDuration: 720 - BuildDurationModifier: 40 + BuildDuration: 937 + BuildDurationModifier: 100 Description: Unlocks the Atreides Air Strike superweapon Valued: Cost: 1500 diff -Nru openra-20200503/mods/d2k/rules/player.yaml openra-20210321/mods/d2k/rules/player.yaml --- openra-20200503/mods/d2k/rules/player.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/player.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ ClassicProductionQueue@Building: Type: Building DisplayOrder: 0 - BuildDurationModifier: 250 LowPowerModifier: 300 ReadyAudio: BuildingReady BlockedAudio: NoRoom @@ -19,10 +18,10 @@ OnHoldAudio: OnHold CancelledAudio: Cancelled SpeedUp: true + BuildTimeSpeedReduction: 100, 66, 50 ClassicProductionQueue@Infantry: Type: Infantry DisplayOrder: 1 - BuildDurationModifier: 250 LowPowerModifier: 300 ReadyAudio: UnitReady BlockedAudio: NoRoom @@ -30,10 +29,10 @@ OnHoldAudio: OnHold CancelledAudio: Cancelled SpeedUp: true + BuildTimeSpeedReduction: 100, 66, 50 ClassicProductionQueue@Vehicle: Type: Vehicle DisplayOrder: 2 - BuildDurationModifier: 250 LowPowerModifier: 300 ReadyAudio: UnitReady BlockedAudio: NoRoom @@ -41,10 +40,10 @@ OnHoldAudio: OnHold CancelledAudio: Cancelled SpeedUp: true + BuildTimeSpeedReduction: 100, 66, 50 ClassicProductionQueue@Armor: Type: Armor DisplayOrder: 3 - BuildDurationModifier: 250 LowPowerModifier: 300 ReadyAudio: UnitReady BlockedAudio: NoRoom @@ -52,6 +51,7 @@ OnHoldAudio: OnHold CancelledAudio: Cancelled SpeedUp: true + BuildTimeSpeedReduction: 100, 66, 50 ClassicProductionQueue@Starport: Type: Starport DisplayOrder: 4 @@ -63,7 +63,6 @@ ClassicProductionQueue@Aircraft: Type: Aircraft DisplayOrder: 5 - BuildDurationModifier: 312 LowPowerModifier: 300 ReadyAudio: UnitReady BlockedAudio: NoRoom @@ -71,9 +70,9 @@ OnHoldAudio: OnHold CancelledAudio: Cancelled SpeedUp: true + BuildTimeSpeedReduction: 100, 66, 50 ClassicProductionQueue@Upgrade: # Upgrade is defined after others so it won't be automatically selected by ProductionQueueFromSelection. Type: Upgrade - BuildDurationModifier: 250 ReadyAudio: NewOptions BlockedAudio: NoRoom QueuedAudio: Upgrading @@ -99,10 +98,17 @@ CashTickUpNotification: CashTickUp CashTickDownNotification: CashTickDown DeveloperMode: - CheckboxDisplayOrder: 7 + CheckboxDisplayOrder: 8 BaseAttackNotifier: Shroud: FogCheckboxDisplayOrder: 3 + LobbyPrerequisiteCheckbox@AUTOCONCRETE: + ID: autoconcrete + Label: Automatic Concrete + Description: Concrete foundations are automatically created beneath buildings + Enabled: False + DisplayOrder: 7 + Prerequisites: global-auto-concrete FrozenActorLayer: HarvesterAttackNotifier: PlayerStatistics: @@ -150,6 +156,5 @@ ResourceStorageWarning: AdviceInterval: 26 PlayerExperience: - ConditionManager: GameSaveViewportManager: PlayerRadarTerrain: diff -Nru openra-20200503/mods/d2k/rules/structures.yaml openra-20210321/mods/d2k/rules/structures.yaml --- openra-20200503/mods/d2k/rules/structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,7 +1,7 @@ ^concrete: AlwaysVisible: Interactable: - Building: + D2kBuilding: TerrainTypes: Rock BuildSounds: CHUNG.WAV AllowInvalidPlacement: true @@ -9,9 +9,6 @@ RequiresBuildableArea: AreaTypes: building Adjacent: 4 - LaysTerrain: - Template: 88 - TerrainTypes: Rock Tooltip: Name: Concrete GenericName: Structure @@ -25,7 +22,7 @@ concretea: Inherits: ^concrete - Building: + D2kBuilding: Footprint: xx xx Dimensions: 2,2 Tooltip: @@ -34,12 +31,13 @@ Cost: 20 Buildable: BuildPaletteOrder: 110 - BuildDuration: 54 - BuildDurationModifier: 40 + Prerequisites: ~!global-auto-concrete + BuildDuration: 62 + BuildDurationModifier: 100 concreteb: Inherits: ^concrete - Building: + D2kBuilding: Footprint: xxx xxx xxx Dimensions: 3,3 Tooltip: @@ -48,22 +46,21 @@ Cost: 50 Buildable: BuildPaletteOrder: 210 - Prerequisites: upgrade.conyard - BuildDuration: 81 - BuildDurationModifier: 40 + Prerequisites: upgrade.conyard, ~!global-auto-concrete + BuildDuration: 94 + BuildDurationModifier: 100 construction_yard: Inherits: ^Building + Inherits@PRIMARY: ^PrimaryBuilding + Inherits@UPGRADEABLE: ^Upgradeable Buildable: Description: Produces structures. - -DamagedByTerrain: - Building: + D2kBuilding: Footprint: xxx xxx === Dimensions: 3,3 LocalCenterOffset: 0,-512,0 - LaysTerrain: - TerrainTypes: Rock - Template: 88 + -ConcretePrerequisites: WithBuildingBib: Selectable: Bounds: 96,64 @@ -103,26 +100,10 @@ RequiresCondition: !build-incomplete Palette: d2k PrimaryBuilding: - PrimaryCondition: primary ProductionQueues: Building - SelectionNotification: PrimaryBuildingSelected ProvidesPrerequisite@buildingname: - GrantConditionOnPrerequisite: + GrantConditionOnPrerequisite@UPGRADEABLE: Prerequisites: upgrade.conyard - Condition: stardecoration - WithDecoration@upgraded: - RequiresSelection: true - Image: pips - Sequence: tag-upgraded - ReferencePoint: Top, Right - ZOffset: 256 - RequiresCondition: stardecoration - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary RevealOnDeath: Radius: 5c768 @@ -131,8 +112,8 @@ Buildable: Queue: Building BuildPaletteOrder: 120 - BuildDuration: 180 - BuildDurationModifier: 40 + BuildDuration: 208 + BuildDurationModifier: 100 Description: Provides power for other structures. Selectable: Bounds: 64,64 @@ -140,7 +121,7 @@ Cost: 225 Tooltip: Name: Wind Trap - Building: + D2kBuilding: Footprint: xx xx == Dimensions: 2,3 LocalCenterOffset: 0,-512,0 @@ -174,12 +155,14 @@ barracks: Inherits: ^Building + Inherits@PRIMARY: ^PrimaryBuilding + Inherits@UPGRADEABLE: ^Upgradeable Buildable: Prerequisites: wind_trap Queue: Building BuildPaletteOrder: 220 - BuildDuration: 231 - BuildDurationModifier: 40 + BuildDuration: 268 + BuildDurationModifier: 100 Description: Trains infantry. Selectable: Bounds: 64,64 @@ -187,7 +170,7 @@ Cost: 225 Tooltip: Name: Barracks - Building: + D2kBuilding: Footprint: xx xx == Dimensions: 2,3 LocalCenterOffset: 0,-512,0 @@ -211,9 +194,7 @@ Production: Produces: Infantry, Upgrade PrimaryBuilding: - PrimaryCondition: primary ProductionQueues: Infantry - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Infantry ProvidesPrerequisite@atreides: @@ -236,22 +217,8 @@ corrino: barracks.harkonnen WithBuildingBib: ProvidesPrerequisite@buildingname: - GrantConditionOnPrerequisite: + GrantConditionOnPrerequisite@UPGRADEABLE: Prerequisites: upgrade.barracks - Condition: stardecoration - WithDecoration@upgraded: - RequiresSelection: true - Image: pips - Sequence: tag-upgraded - ReferencePoint: Top, Right - ZOffset: 256 - RequiresCondition: stardecoration - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary RevealOnDeath: Radius: 3c768 @@ -261,8 +228,8 @@ Prerequisites: wind_trap Queue: Building BuildPaletteOrder: 130 - BuildDuration: 540 - BuildDurationModifier: 40 + BuildDuration: 625 + BuildDurationModifier: 100 Description: Harvesters unload Spice here for processing. Selectable: Bounds: 96,64 @@ -270,7 +237,7 @@ Cost: 1500 Tooltip: Name: Spice Refinery - Building: + D2kBuilding: Footprint: =xx xx= === Dimensions: 3,3 LocalCenterOffset: 0,-512,0 @@ -289,12 +256,10 @@ RevealsShroud: Range: 3c768 Refinery: - DockAngle: 160 + DockAngle: 640 DockOffset: 2,1 TickRate: 20 StoresResources: - PipColor: green - PipCount: 10 Capacity: 2000 CustomSellValue: Value: 500 @@ -320,6 +285,11 @@ Power: Amount: -75 ProvidesPrerequisite@buildingname: + WithResourceStoragePipsDecoration: + Position: BottomLeft + Margin: 1, 4 + RequiresSelection: true + PipCount: 10 silo: Inherits: ^Building @@ -327,8 +297,8 @@ Prerequisites: refinery Queue: Building BuildPaletteOrder: 310 - BuildDuration: 135 - BuildDurationModifier: 40 + BuildDuration: 156 + BuildDurationModifier: 100 Description: Stores excess harvested Spice. Selectable: Bounds: 32,32 @@ -356,8 +326,6 @@ WithResourceLevelSpriteBody: Sequence: stages StoresResources: - PipColor: green - PipCount: 5 Capacity: 2000 -SpawnActorsOnSell: Power: @@ -370,15 +338,22 @@ Range: 2c0, 5c0 RevealOnDeath: Radius: 2c768 + WithResourceStoragePipsDecoration: + Position: BottomLeft + Margin: 1, 4 + RequiresSelection: true + PipCount: 5 light_factory: Inherits: ^Building + Inherits@PRIMARY: ^PrimaryBuilding + Inherits@UPGRADEABLE: ^Upgradeable Buildable: Prerequisites: refinery Queue: Building BuildPaletteOrder: 230 - BuildDuration: 277 - BuildDurationModifier: 40 + BuildDuration: 321 + BuildDurationModifier: 100 Description: Produces light vehicles. Selectable: Bounds: 96,64 @@ -386,7 +361,7 @@ Cost: 500 Tooltip: Name: Light Factory - Building: + D2kBuilding: Footprint: xxx xx= === Dimensions: 3,3 LocalCenterOffset: 0,-512,0 @@ -423,9 +398,7 @@ Production: Produces: Vehicle, Upgrade PrimaryBuilding: - PrimaryCondition: primary ProductionQueues: Vehicle - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Vehicle ProvidesPrerequisite@atreides: @@ -446,31 +419,19 @@ ProvidesPrerequisite@buildingname: Power: Amount: -125 - GrantConditionOnPrerequisite: + GrantConditionOnPrerequisite@UPGRADEABLE: Prerequisites: upgrade.light - Condition: stardecoration - WithDecoration@upgraded: - RequiresSelection: true - Image: pips - Sequence: tag-upgraded - ReferencePoint: Top, Right - ZOffset: 256 - RequiresCondition: stardecoration - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary heavy_factory: Inherits: ^Building + Inherits@PRIMARY: ^PrimaryBuilding + Inherits@UPGRADEABLE: ^Upgradeable Buildable: Prerequisites: refinery Queue: Building BuildPaletteOrder: 330 - BuildDuration: 648 - BuildDurationModifier: 40 + BuildDuration: 750 + BuildDurationModifier: 100 Description: Produces heavy vehicles. Selectable: Bounds: 96,96 @@ -478,7 +439,7 @@ Cost: 1000 Tooltip: Name: Heavy Factory - Building: + D2kBuilding: Footprint: _x_ xxx =xX === Dimensions: 3,4 LocalCenterOffset: 0,-512,0 @@ -504,9 +465,7 @@ Production: Produces: Armor, Upgrade PrimaryBuilding: - PrimaryCondition: primary ProductionQueues: Armor - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Armor ProvidesPrerequisite@atreides: @@ -549,22 +508,8 @@ Power: Amount: -150 ProvidesPrerequisite@buildingname: - GrantConditionOnPrerequisite: + GrantConditionOnPrerequisite@UPGRADEABLE: Prerequisites: upgrade.heavy - Condition: stardecoration - WithDecoration@upgraded: - RequiresSelection: true - Image: pips - Sequence: tag-upgraded - ReferencePoint: Top, Right - ZOffset: 256 - RequiresCondition: stardecoration - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary outpost: Inherits: ^Building @@ -573,8 +518,8 @@ Prerequisites: barracks, ~techlevel.medium Queue: Building BuildPaletteOrder: 320 - BuildDuration: 270 - BuildDurationModifier: 40 + BuildDuration: 312 + BuildDurationModifier: 100 Description: Provides a radar map of the battlefield.\n Requires power to operate. Selectable: Bounds: 96,64 @@ -582,7 +527,7 @@ Cost: 750 Tooltip: Name: Outpost - Building: + D2kBuilding: Footprint: xxx xxx === Dimensions: 3,3 LocalCenterOffset: 0,-512,0 @@ -618,18 +563,19 @@ starport: Inherits: ^Building + Inherits@PRIMARY: ^PrimaryBuilding Tooltip: Name: Starport Buildable: Prerequisites: heavy_factory, outpost, ~techlevel.high Queue: Building BuildPaletteOrder: 530 - BuildDuration: 540 - BuildDurationModifier: 40 + BuildDuration: 625 + BuildDurationModifier: 100 Description: Dropzone for quick reinforcements, at a price. Valued: Cost: 1500 - Building: + D2kBuilding: Footprint: xxx x=x =x= Dimensions: 3,3 Selectable: @@ -672,9 +618,7 @@ ProductionBar: ProductionType: Starport PrimaryBuilding: - PrimaryCondition: primary ProductionQueues: Starport - SelectionNotification: PrimaryBuildingSelected ProvidesPrerequisite@atreides: Prerequisite: starport.atreides Factions: atreides @@ -696,12 +640,6 @@ Power: Amount: -150 ProvidesPrerequisite@buildingname: - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary wall: Inherits@1: ^SpriteActor @@ -715,18 +653,20 @@ Queue: Building Prerequisites: barracks BuildPaletteOrder: 410 - BuildDuration: 54 - BuildDurationModifier: 40 + BuildDuration: 62 + BuildDurationModifier: 100 Description: Stop units and blocks enemy fire. Valued: Cost: 20 CustomSellValue: Value: 0 + UpdatesPlayerStatistics: + AddToAssetsValue: false Tooltip: Name: Concrete Wall GenericName: Structure AppearsOnRadar: - Building: + D2kBuilding: BuildSounds: CHUNG.WAV TerrainTypes: Rock, Concrete FootprintPlaceBuildingPreview: @@ -779,19 +719,15 @@ Queue: Building Prerequisites: barracks BuildPaletteOrder: 510 - BuildDuration: 231 - BuildDurationModifier: 40 + BuildDuration: 268 + BuildDurationModifier: 100 Description: Defensive structure.\n Strong vs Tanks\n Weak vs Infantry, Aircraft Valued: Cost: 550 Tooltip: Name: Gun Turret - Building: - BuildSounds: CHUNG.WAV RequiresBuildableArea: Adjacent: 4 - Sellable: - SellSounds: CHUNG.WAV Selectable: Bounds: 32,32 DecorationBounds: 32,40,0,-8 @@ -805,8 +741,9 @@ QuantizedFacings: 32 WithMuzzleOverlay: Turreted: - TurnSpeed: 6 - InitialFacing: 128 + TurnSpeed: 24 + InitialFacing: 512 + RealignDelay: -1 Armament: Weapon: 110mm_Gun LocalOffset: 512,0,432 @@ -826,19 +763,15 @@ Queue: Building Prerequisites: outpost, upgrade.conyard, ~techlevel.medium BuildPaletteOrder: 610 - BuildDuration: 270 - BuildDurationModifier: 40 + BuildDuration: 312 + BuildDurationModifier: 100 Description: Defensive structure.\n Strong vs Infantry, Aircraft\n Weak vs Tanks\n\n Requires power to operate. Valued: Cost: 750 Tooltip: Name: Rocket Turret - Building: - BuildSounds: CHUNG.WAV RequiresBuildableArea: Adjacent: 4 - Sellable: - SellSounds: CHUNG.WAV Selectable: Bounds: 32,32 DecorationBounds: 32,40,0,-8 @@ -854,8 +787,9 @@ Weapon: TowerMissile LocalOffset: 256,384,768, 256,-384,768 Turreted: - TurnSpeed: 8 - InitialFacing: 128 + TurnSpeed: 32 + InitialFacing: 512 + RealignDelay: -1 Power: Amount: -60 RevealOnDeath: @@ -869,14 +803,14 @@ Queue: Building Prerequisites: heavy_factory, upgrade.heavy, ~techlevel.medium BuildPaletteOrder: 430 - BuildDuration: 324 - BuildDurationModifier: 40 + BuildDuration: 375 + BuildDurationModifier: 100 Description: Repairs vehicles.\n Allows construction of MCVs Valued: Cost: 800 Tooltip: Name: Repair Pad - Building: + D2kBuilding: Footprint: +++ +++ +++ Dimensions: 3,3 Health: @@ -919,12 +853,14 @@ high_tech_factory: Inherits: ^Building + Inherits@PRIMARY: ^PrimaryBuilding + Inherits@UPGRADEABLE: ^Upgradeable Buildable: Prerequisites: outpost, ~techlevel.medium Queue: Building BuildPaletteOrder: 420 - BuildDuration: 405 - BuildDurationModifier: 40 + BuildDuration: 468 + BuildDurationModifier: 100 Description: Unlocks advanced technology. Selectable: Bounds: 96,96 @@ -937,13 +873,11 @@ ProductionBar: ProductionType: Aircraft PrimaryBuilding: - PrimaryCondition: primary ProductionQueues: Aircraft - SelectionNotification: PrimaryBuildingSelected Exit: SpawnOffset: 0,0,728 ExitCell: 0,0 - Building: + D2kBuilding: Footprint: _X_ xxx XXX === Dimensions: 3,4 LocalCenterOffset: 0,-512,0 @@ -995,22 +929,8 @@ SupportPowerPaletteOrder: 10 Power: Amount: -75 - GrantConditionOnPrerequisite: + GrantConditionOnPrerequisite@UPGRADEABLE: Prerequisites: upgrade.hightech - Condition: stardecoration - WithDecoration@upgraded: - RequiresSelection: true - Image: pips - Sequence: tag-upgraded - ReferencePoint: Top, Right - ZOffset: 256 - RequiresCondition: stardecoration - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary research_centre: Inherits: ^Building @@ -1018,8 +938,8 @@ Queue: Building Prerequisites: outpost, heavy_factory, upgrade.heavy, ~techlevel.high BuildPaletteOrder: 520 - BuildDuration: 270 - BuildDurationModifier: 40 + BuildDuration: 312 + BuildDurationModifier: 100 Description: Unlocks advanced tanks. Selectable: Bounds: 96,96 @@ -1027,7 +947,7 @@ Cost: 1000 Tooltip: Name: IX Research Center - Building: + D2kBuilding: Footprint: _X_ xxx XXX === Dimensions: 3,4 LocalCenterOffset: 0,-512,0 @@ -1064,13 +984,14 @@ palace: Inherits: ^Building + Inherits@PRIMARY: ^PrimaryBuilding Inherits@IDISABLE: ^DisableOnLowPowerOrPowerDown Buildable: Prerequisites: research_centre, ~techlevel.high Queue: Building BuildPaletteOrder: 620 - BuildDuration: 810 - BuildDurationModifier: 40 + BuildDuration: 937 + BuildDurationModifier: 100 Description: Unlocks elite infantry and weapons. Selectable: Bounds: 96,96 @@ -1078,7 +999,7 @@ Cost: 1600 Tooltip: Name: Palace - Building: + D2kBuilding: Footprint: xx= xxx =xx Dimensions: 3,3 Health: @@ -1108,7 +1029,7 @@ corrino: palace.corrino WithBuildingBib: HasMinibib: True - WithNukeLaunchOverlay: + WithSupportPowerActivationOverlay: RequiresCondition: !build-incomplete && !launchpad-damaged && harkonnen GrantConditionOnDamageState@LAUNCHPADDAMAGED: Condition: launchpad-damaged @@ -1127,14 +1048,8 @@ Prerequisite: palace.sardaukar Factions: corrino PrimaryBuilding: - PrimaryCondition: primary RequiresCondition: atreides || ordos - SelectionNotification: PrimaryBuildingSelected WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - ZOffset: 256 RequiresCondition: primary && (atreides || ordos) NukePower: Cursor: nuke @@ -1147,7 +1062,7 @@ LongDesc: Launches an atomic missile at a target location BeginChargeSpeechNotification: DeathHandMissilePrepping EndChargeSpeechNotification: DeathHandMissileReady - LaunchSpeechNotification: MissileLaunchDetected + IncomingSpeechNotification: MissileLaunchDetected MissileWeapon: deathhand MissileDelay: 18 SpawnOffset: 32,816,0 diff -Nru openra-20200503/mods/d2k/rules/vehicles.yaml openra-20210321/mods/d2k/rules/vehicles.yaml --- openra-20200503/mods/d2k/rules/vehicles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/vehicles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -5,8 +5,8 @@ Prerequisites: repair_pad, upgrade.heavy, ~techlevel.medium Queue: Armor BuildPaletteOrder: 110 - BuildDuration: 648 - BuildDurationModifier: 40 + BuildDuration: 750 + BuildDurationModifier: 100 Description: Deploys into another Construction Yard\n Unarmed Valued: Cost: 2000 @@ -30,7 +30,7 @@ Weapon: UnitExplodeLarge EmptyWeapon: UnitExplodeLarge Transforms: - Facing: 16 + Facing: 64 IntoActor: construction_yard Offset: -1,-1 TransformSounds: BUILD1.WAV @@ -41,11 +41,10 @@ EffectiveOwnerFromOwner: true AttractsWorms: Intensity: 700 - SelectionDecorations: - SelfHealing: + ChangesHealth: Step: 50 Delay: 3 - HealIfBelow: 50 + StartIfBelow: 50 -RevealOnFire: harvester: @@ -55,8 +54,8 @@ Queue: Armor Prerequisites: refinery BuildPaletteOrder: 10 - BuildDuration: 540 - BuildDurationModifier: 40 + BuildDuration: 625 + BuildDurationModifier: 100 Description: Collects Spice for processing\n Unarmed Valued: Cost: 1200 @@ -66,7 +65,6 @@ Class: harvester DecorationBounds: 42,42 Harvester: - PipCount: 7 Capacity: 28 HarvestFacings: 8 Resources: Spice @@ -94,12 +92,16 @@ WithDockingAnimation: AttractsWorms: Intensity: 700 - SelectionDecorations: - SelfHealing: + ChangesHealth: Step: 50 Delay: 3 - HealIfBelow: 50 + StartIfBelow: 50 -RevealOnFire: + WithHarvesterPipsDecoration: + Position: BottomLeft + Margin: 1, 4 + RequiresSelection: true + PipCount: 7 trike: Inherits: ^Vehicle @@ -109,8 +111,8 @@ Queue: Vehicle BuildPaletteOrder: 10 Prerequisites: ~light.trike - BuildDuration: 194 - BuildDurationModifier: 40 + BuildDuration: 225 + BuildDurationModifier: 100 Description: Fast scout\n Strong vs Infantry\n Weak vs Tanks Valued: Cost: 300 @@ -125,7 +127,7 @@ Armor: Type: wood Mobile: - TurnSpeed: 10 + TurnSpeed: 40 Speed: 128 RevealsShroud: Range: 4c768 @@ -152,8 +154,8 @@ Queue: Vehicle Prerequisites: upgrade.light, ~techlevel.medium BuildPaletteOrder: 20 - BuildDuration: 277 - BuildDurationModifier: 40 + BuildDuration: 321 + BuildDurationModifier: 100 Description: Missile Scout\n Strong vs Vehicles\n Weak vs Infantry Valued: Cost: 400 @@ -166,7 +168,7 @@ Armor: Type: light Mobile: - TurnSpeed: 8 + TurnSpeed: 32 Speed: 96 RevealsShroud: Range: 4c768 @@ -190,8 +192,8 @@ Queue: Armor Prerequisites: upgrade.heavy, ~techlevel.medium BuildPaletteOrder: 50 - BuildDuration: 324 - BuildDurationModifier: 40 + BuildDuration: 375 + BuildDurationModifier: 100 Description: Siege Artillery\n Strong vs Infantry, Buildings\n Weak vs Tanks Valued: Cost: 700 @@ -205,11 +207,11 @@ Type: light Mobile: Speed: 43 - TurnSpeed: 3 + TurnSpeed: 12 RevealsShroud: Range: 6c768 Turreted: - TurnSpeed: 3 + TurnSpeed: 12 Offset: 0,0,-32 Armament: Weapon: 155mm @@ -246,14 +248,14 @@ Queue: Armor Prerequisites: ~heavy.missile_tank, upgrade.heavy, research_centre, ~techlevel.high BuildPaletteOrder: 60 - BuildDuration: 441 - BuildDurationModifier: 40 + BuildDuration: 512 + BuildDurationModifier: 100 Description: Rocket Artillery\n Strong vs Vehicles, Buildings, Aircraft\n Weak vs Infantry Valued: Cost: 900 Mobile: Speed: 64 - TurnSpeed: 5 + TurnSpeed: 20 Health: HP: 13000 Armor: @@ -286,8 +288,8 @@ Queue: Armor BuildPaletteOrder: 100 Prerequisites: ~heavy.atreides, research_centre, ~techlevel.high - BuildDuration: 486 - BuildDurationModifier: 40 + BuildDuration: 562 + BuildDurationModifier: 100 Description: Fires sonic shocks\n Strong vs Infantry, Vehicles\n Weak vs Artillery Valued: Cost: 1000 @@ -300,7 +302,7 @@ Armor: Type: light Mobile: - TurnSpeed: 3 + TurnSpeed: 12 Speed: 31 RevealsShroud: Range: 5c768 @@ -326,8 +328,8 @@ Queue: Armor BuildPaletteOrder: 100 Prerequisites: ~heavy.harkonnen, research_centre, ~techlevel.high - BuildDuration: 540 - BuildDurationModifier: 40 + BuildDuration: 625 + BuildDurationModifier: 100 Description: Super Heavy Tank\n Strong vs Tanks\n Weak vs Artillery Valued: Cost: 1050 @@ -340,7 +342,7 @@ Armor: Type: heavy Mobile: - TurnSpeed: 3 + TurnSpeed: 12 Speed: 31 Locomotor: devastator RequiresCondition: !overload @@ -383,11 +385,10 @@ GrantsCondition: meltdown AttractsWorms: Intensity: 700 - SelectionDecorations: - SelfHealing: + ChangesHealth: Step: 50 Delay: 3 - HealIfBelow: 50 + StartIfBelow: 50 Selectable: DecorationBounds: 44,38,0,0 @@ -399,8 +400,8 @@ Queue: Vehicle BuildPaletteOrder: 10 Prerequisites: ~light.raider - BuildDuration: 194 - BuildDurationModifier: 40 + BuildDuration: 225 + BuildDurationModifier: 100 Description: Improved Scout\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks Valued: Cost: 350 @@ -413,7 +414,7 @@ Armor: Type: wood Mobile: - TurnSpeed: 10 + TurnSpeed: 40 Speed: 149 RevealsShroud: Range: 4c768 @@ -437,8 +438,8 @@ Buildable: Prerequisites: ~light.ordos, upgrade.light, high_tech_factory, ~techlevel.medium BuildPaletteOrder: 30 - BuildDuration: 194 ## Copied from Raider, not included in conversion. Both have same "BuildSpeed" in TibEd - BuildDurationModifier: 40 + BuildDuration: 225 + BuildDurationModifier: 100 Description: Invisible Raider Trike\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks Valued: Cost: 400 @@ -474,11 +475,11 @@ Queue: Armor BuildPaletteOrder: 50 Prerequisites: ~heavy.ordos, research_centre, ~techlevel.high - BuildDuration: 486 - BuildDurationModifier: 40 + BuildDuration: 562 + BuildDurationModifier: 100 Description: Fires a warhead which changes\nthe allegiance of enemy vehicles Mobile: - TurnSpeed: 3 + TurnSpeed: 12 Speed: 53 Health: HP: 11000 @@ -509,8 +510,8 @@ Buildable: Queue: Armor BuildPaletteOrder: 40 - BuildDuration: 373 - BuildDurationModifier: 40 + BuildDuration: 432 + BuildDurationModifier: 100 Description: Main Battle Tank\n Strong vs Tanks\n Weak vs Infantry Valued: Cost: 700 @@ -524,11 +525,11 @@ Type: heavy Mobile: Speed: 75 - TurnSpeed: 5 + TurnSpeed: 20 RevealsShroud: Range: 5c768 Turreted: - TurnSpeed: 5 + TurnSpeed: 20 RealignDelay: 0 Armament: Weapon: 80mm_A @@ -577,7 +578,7 @@ Buildable: Prerequisites: ~heavy.ordos_combat Turreted: - TurnSpeed: 5 + TurnSpeed: 20 Armament: Weapon: 80mm_O Mobile: diff -Nru openra-20200503/mods/d2k/rules/world.yaml openra-20210321/mods/d2k/rules/world.yaml --- openra-20200503/mods/d2k/rules/world.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/rules/world.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -110,7 +110,6 @@ ResourceType@Spice: Type: Spice Name: Spice - PipColor: green ResourceType: 1 Palette: d2k TerrainType: Spice @@ -119,6 +118,8 @@ ValuePerUnit: 25 AllowedTerrainTypes: SpiceSand AllowUnderActors: true + D2kResourceRenderer: + RenderTypes: Spice World: Inherits: ^BaseWorld @@ -145,18 +146,14 @@ WarheadDebugOverlay: BuildableTerrainLayer: ResourceLayer: - D2kResourceRenderer: - RenderTypes: Spice ResourceClaimLayer: CustomTerrainDebugOverlay: SmudgeLayer@Rock: Type: RockCrater Sequence: rockcraters - SmokePercentage: 0 SmudgeLayer@Sand: Type: SandCrater Sequence: sandcraters - SmokePercentage: 0 MapCreeps: CheckboxLabel: Worms CheckboxDescription: Worms roam the map and devour unprepared forces @@ -243,7 +240,7 @@ Inherits: ^BaseWorld EditorActorLayer: EditorCursorLayer: - D2kEditorResourceLayer: + EditorResourceLayer: EditorSelectionLayer: LoadWidgetAtGameStart: EditorActionManager: diff -Nru openra-20200503/mods/d2k/sequences/structures.yaml openra-20210321/mods/d2k/sequences/structures.yaml --- openra-20200503/mods/d2k/sequences/structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/sequences/structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -22,6 +22,8 @@ Offset: -30,-24 medium_gun_turret: + invisible: DATA.R8 + Start: 38 idle: DATA.R8 Frames: 2821, 2824, 2822, 2832, 2825, 2826, 2836, 2829, 2823, 2833, 2827, 2828, 2834, 2830, 2831, 2835 Length: 16 @@ -34,10 +36,13 @@ Start: 4577 Length: 8 Offset: -16,16 + ZOffset: 1024 crumble-overlay: DATA.R8 - Start: 4585 + Start: 4584 Length: 7 Offset: -16,16 + Tick: 200 + ZOffset: 1024 turret: DATA.R8 Start: 2837 Facings: -32 @@ -53,6 +58,8 @@ Offset: -30,-24 large_gun_turret: + invisible: DATA.R8 + Start: 38 idle: DATA.R8 Frames: 2821, 2824, 2822, 2832, 2825, 2826, 2836, 2829, 2823, 2833, 2827, 2828, 2834, 2830, 2831, 2835 Length: 16 @@ -65,10 +72,13 @@ Start: 4577 Length: 8 Offset: -16,16 + ZOffset: 1024 crumble-overlay: DATA.R8 - Start: 4585 + Start: 4584 Length: 7 Offset: -16,16 + Tick: 200 + ZOffset: 1024 turret: DATA.R8 Start: 2885 Facings: -32 @@ -421,6 +431,7 @@ Length: 7 Offset: -16,16 Tick: 200 + ZOffset: 1024 icon: DATA.R8 Start: 4348 Offset: -30,-24 @@ -931,6 +942,7 @@ Length: 7 Offset: -16,16 Tick: 200 + ZOffset: 1024 icon: DATA.R8 Start: 4349 Offset: -30,-24 @@ -1333,6 +1345,7 @@ Start: 4584 Length: 7 Offset: -16,16 + ZOffset: 1024 Tick: 200 icon: DATA.R8 Start: 4350 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/d2k/uibits/glyphs-2x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/d2k/uibits/glyphs-2x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/d2k/uibits/glyphs-3x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/d2k/uibits/glyphs-3x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/d2k/uibits/glyphs.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/d2k/uibits/glyphs.png differ diff -Nru openra-20200503/mods/d2k/weapons/debris.yaml openra-20210321/mods/d2k/weapons/debris.yaml --- openra-20200503/mods/d2k/weapons/debris.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/weapons/debris.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -11,9 +11,9 @@ BounceCount: 3 BounceRangeModifier: 20 Warhead@1Dam: SpreadDamage - Spread: 320 - Falloff: 100, 60, 30, 15, 0 Damage: 1500 + Spread: 512 + Falloff: 100, 0 Versus: none: 20 wall: 50 @@ -26,6 +26,7 @@ cy: 20 harvester: 50 DamageTypes: Prone50Percent, TriggerProne, SmallExplosionDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Smu: LeaveSmudge SmudgeType: SandCrater InvalidTargets: Vehicle, Structure @@ -44,6 +45,7 @@ TrailInterval: 1 Warhead@1Dam: SpreadDamage Damage: 2500 + Spread: 1c0 Versus: none: 90 wall: 5 diff -Nru openra-20200503/mods/d2k/weapons/largeguns.yaml openra-20210321/mods/d2k/weapons/largeguns.yaml --- openra-20200503/mods/d2k/weapons/largeguns.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/weapons/largeguns.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,12 +4,13 @@ Report: MEDTANK1.WAV Projectile: Bullet Speed: 562 - Inaccuracy: 380 + Inaccuracy: 128 + InaccuracyType: PerCellIncrement Image: 120mm Warhead@1Dam: SpreadDamage - Spread: 256 - Falloff: 100, 50, 25, 0 Damage: 2700 + Spread: 512 + Falloff: 100, 0 Versus: none: 20 wall: 50 @@ -20,6 +21,7 @@ cy: 20 harvester: 50 DamageTypes: Prone50Percent, TriggerProne, SmallExplosionDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Smu: LeaveSmudge SmudgeType: SandCrater, RockCrater InvalidTargets: Vehicle, Structure @@ -39,7 +41,7 @@ Blockable: false Warhead@1Dam: SpreadDamage Damage: 2900 - Warhead@2Concrete: DamagesConcrete + Warhead@4Concrete: DamagesConcrete Damage: 2900 80mm_A: @@ -59,10 +61,8 @@ Report: TANKHVY1.WAV Projectile: Bullet Speed: 281 - Inaccuracy: 0 Image: doubleblastbullet Warhead@1Dam: SpreadDamage - Spread: 384 Damage: 6500 Versus: none: 50 @@ -73,7 +73,7 @@ invulnerable: 0 cy: 40 harvester: 100 - Warhead@2Concrete: DamagesConcrete + Warhead@4Concrete: DamagesConcrete Damage: 3250 Warhead@3Eff: CreateEffect Explosions: shockwave @@ -89,13 +89,11 @@ Blockable: false Shadow: true LaunchAngle: 62 - Inaccuracy: 768 ContrailLength: 20 Image: 155mm Warhead@1Dam: SpreadDamage - Spread: 416 - Falloff: 100, 65, 35, 20, 0 Damage: 4500 + Spread: 1c0 Versus: none: 125 wall: 100 @@ -107,7 +105,7 @@ cy: 20 harvester: 25 DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath - Warhead@2Concrete: DamagesConcrete + Warhead@4Concrete: DamagesConcrete Damage: 5625 Warhead@3Eff: CreateEffect Explosions: med_explosion diff -Nru openra-20200503/mods/d2k/weapons/missiles.yaml openra-20210321/mods/d2k/weapons/missiles.yaml --- openra-20200503/mods/d2k/weapons/missiles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/weapons/missiles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -5,15 +5,16 @@ Projectile: Bullet Blockable: false Speed: 281 - Inaccuracy: 256 + Inaccuracy: 128 + InaccuracyType: PerCellIncrement Image: RPG TrailImage: bazooka_trail2 TrailPalette: effect75alpha TrailInterval: 1 Warhead@1Dam: SpreadDamage - Spread: 192 - Falloff: 100, 50, 25, 0 Damage: 3000 + Spread: 512 + Falloff: 100, 0 Versus: none: 8 wall: 75 @@ -25,6 +26,7 @@ cy: 20 harvester: 50 DamageTypes: Prone50Percent, TriggerProne, SmallExplosionDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Smu: LeaveSmudge SmudgeType: SandCrater, RockCrater InvalidTargets: Vehicle, Structure @@ -32,7 +34,7 @@ Explosions: tiny_explosion ImpactActors: false ValidTargets: Ground, Air - Warhead@3Concrete: DamagesConcrete + Warhead@4Concrete: DamagesConcrete Damage: 240 ^Missile: @@ -42,17 +44,15 @@ MinRange: 0c512 Projectile: Missile Shadow: true - HorizontalRateOfTurn: 3 + HorizontalRateOfTurn: 12 RangeLimit: 6c614 - Inaccuracy: 384 CruiseAltitude: 1c0 MinimumLaunchAngle: 64 - VerticalRateOfTurn: 10 + VerticalRateOfTurn: 40 Image: MISSILE2 TrailImage: large_trail Speed: 288 Warhead@1Dam: SpreadDamage - Spread: 256 Damage: 4800 Versus: none: 15 @@ -64,7 +64,7 @@ invulnerable: 0 cy: 30 harvester: 50 - Warhead@2Concrete: DamagesConcrete + Warhead@4Concrete: DamagesConcrete Damage: 720 Warhead@3Eff: CreateEffect Explosions: small_explosion @@ -80,7 +80,6 @@ Projectile: Bullet Speed: 352 Warhead@1Dam: SpreadDamage - Spread: 160 Damage: 2500 Versus: none: 25 @@ -92,7 +91,7 @@ invulnerable: 0 cy: 20 harvester: 50 - Warhead@2Concrete: DamagesConcrete + Warhead@4Concrete: DamagesConcrete Damage: 625 Warhead@3Eff: CreateEffect Explosions: rocket_explosion @@ -105,7 +104,7 @@ BurstDelays: 60 ValidTargets: Ground, Air Projectile: Missile - HorizontalRateOfTurn: 1 + HorizontalRateOfTurn: 4 Warhead@1Dam: SpreadDamage ValidTargets: Ground, Air DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath @@ -118,12 +117,11 @@ Range: 6c0 ValidTargets: Ground, Air Projectile: Missile - Inaccuracy: 96 RangeLimit: 7c204 Warhead@1Dam: SpreadDamage Damage: 6000 ValidTargets: Ground, Air - Warhead@2Concrete: DamagesConcrete + Warhead@4Concrete: DamagesConcrete Damage: 900 DeviatorMissile: @@ -133,12 +131,14 @@ Report: MISSLE1.WAV Projectile: Missile RangeLimit: 6c0 + Inaccuracy: 96 Image: MISSILE TrailImage: deviator_trail TrailPalette: deviatorgas TrailUsePlayerPalette: true Warhead@1Dam: SpreadDamage Damage: 1000 + Spread: 480 Versus: none: 100 wall: 100 @@ -155,9 +155,9 @@ ExplosionPalette: deviatorgas UsePlayerPalette: true -ImpactSounds: - Warhead@4OwnerChange: ChangeOwner + Warhead@5OwnerChange: ChangeOwner Range: 512 Duration: 375 InvalidTargets: Infantry, Structure - Warhead@5Concrete: DamagesConcrete + Warhead@4Concrete: DamagesConcrete Damage: 1000 diff -Nru openra-20200503/mods/d2k/weapons/other.yaml openra-20210321/mods/d2k/weapons/other.yaml --- openra-20200503/mods/d2k/weapons/other.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/weapons/other.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,6 +4,8 @@ Report: SONIC1.WAV Projectile: AreaBeam Speed: 0c128 + Inaccuracy: 128 + InaccuracyType: PerCellIncrement Duration: 4 # Has a length of 0c512 DamageInterval: 3 # Travels 0c384 between impacts, will hit a target roughly three times Width: 0c512 @@ -17,7 +19,7 @@ Falloff: 100, 100 Damage: 860 AffectsParent: false - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy Versus: none: 200 wall: 50 @@ -34,7 +36,7 @@ Falloff: 100, 100 Damage: 430 # Only does half damage to friendly units AffectsParent: false - ValidStances: Ally + ValidRelationships: Ally Versus: none: 200 wall: 50 @@ -53,7 +55,7 @@ ReloadDelay: 10 InvalidTargets: Structure, Infantry Range: 1c512 - Warhead@1Dam: TargetDamage # HACK: The warhead is needed for targeting + Warhead@NeededForTargeting: TargetDamage InvalidTargets: Structure, Infantry OrniBomb: @@ -67,9 +69,9 @@ Acceleration: 0, 0, 0 Shadow: true Warhead@1Dam: SpreadDamage - Spread: 320 - Falloff: 100, 60, 30, 15, 0 Damage: 7500 #400 in original, reduce when bombers can do multiple passes + Spread: 1c0 + Falloff: 100, 0 Versus: none: 90 wall: 50 @@ -81,6 +83,7 @@ cy: 25 harvester: 60 DamageTypes: Prone50Percent, TriggerProne, SmallExplosionDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Smu: LeaveSmudge SmudgeType: SandCrater, RockCrater InvalidTargets: Vehicle, Structure @@ -144,20 +147,21 @@ cy: 25 harvester: 60 DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Smu: LeaveSmudge SmudgeType: SandCrater, RockCrater InvalidTargets: Vehicle, Structure Warhead@3Eff: CreateEffect Explosions: large_explosion ImpactSounds: EXPLSML4.WAV - Warhead@2Concrete: DamagesConcrete + Warhead@4Concrete: DamagesConcrete Damage: 4500 CrateExplosion: Warhead@1Dam: SpreadDamage - Spread: 320 - Falloff: 100, 60, 30, 15, 0 Damage: 5000 + Spread: 1c0 + Falloff: 100, 0 Versus: none: 90 wall: 5 @@ -170,6 +174,7 @@ harvester: 25 AffectsParent: true DamageTypes: Prone50Percent, TriggerProne, SmallExplosionDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Eff: CreateEffect Explosions: large_explosion ImpactSounds: EXPLSML4.WAV @@ -213,13 +218,14 @@ Speed: 160 Blockable: false LaunchAngle: 128 - Inaccuracy: 416 + Inaccuracy: 128 + InaccuracyType: PerCellIncrement Image: grenade Shadow: true Warhead@1Dam: SpreadDamage - Spread: 320 - Falloff: 100, 65, 35, 20, 0 Damage: 1500 + Spread: 1c0 + Falloff: 100, 0 Versus: none: 125 wood: 70 @@ -229,6 +235,7 @@ cy: 20 harvester: 25 DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Smu: LeaveSmudge SmudgeType: SandCrater InvalidTargets: Vehicle, Structure @@ -241,9 +248,9 @@ GrenDeath: Warhead@1Dam: SpreadDamage - Spread: 320 - Falloff: 100, 60, 30, 15, 0 Damage: 1500 + Spread: 1c0 + Falloff: 100, 0 Versus: none: 125 wood: 70 @@ -253,6 +260,7 @@ cy: 20 harvester: 25 DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Smu: LeaveSmudge SmudgeType: SandCrater, RockCrater Warhead@3Eff: CreateEffect @@ -264,9 +272,9 @@ SardDeath: Warhead@1Dam: SpreadDamage - Spread: 256 - Falloff: 100, 50, 25, 0 Damage: 3000 + Spread: 512 + Falloff: 100, 0 Versus: none: 15 wall: 75 @@ -277,6 +285,7 @@ cy: 30 harvester: 50 DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Smu: LeaveSmudge SmudgeType: SandCrater, RockCrater Warhead@3Eff: CreateEffect @@ -294,9 +303,9 @@ TrailImage: large_trail Image: 120mm Warhead@1Dam: SpreadDamage - Spread: 320 - Falloff: 100, 60, 30, 15, 0 Damage: 750 + Spread: 1c0 + Falloff: 100, 0 Versus: none: 90 wall: 5 @@ -308,6 +317,7 @@ cy: 20 harvester: 25 DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath + DamageCalculationType: ClosestTargetablePosition AffectsParent: true Warhead@2Res: CreateResource AddsResourceType: Spice @@ -321,9 +331,9 @@ Range: 0c8 Projectile: InstantHit Warhead@1Dam: SpreadDamage - Spread: 320 - Falloff: 100, 60, 30, 15, 0 Damage: 7500 + Spread: 320 + Falloff: 100, 0 Versus: none: 90 wall: 5 @@ -335,13 +345,14 @@ cy: 20 harvester: 25 DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath + DamageCalculationType: ClosestTargetablePosition AffectsParent: true PlasmaExplosion: Warhead@1Dam: SpreadDamage - Spread: 2c0 - Falloff: 100, 37, 0 Damage: 20000 + Spread: 3c0 + Falloff: 100, 0 Versus: None: 100 Wood: 100 @@ -349,6 +360,7 @@ Heavy: 100 Concrete: 60 DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Smu: LeaveSmudge SmudgeType: SandCrater Warhead@3Eff: CreateEffect diff -Nru openra-20200503/mods/d2k/weapons/smallguns.yaml openra-20210321/mods/d2k/weapons/smallguns.yaml --- openra-20200503/mods/d2k/weapons/smallguns.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/d2k/weapons/smallguns.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -3,10 +3,12 @@ Range: 2c512 Report: MGUN2.WAV Projectile: InstantHit + Inaccuracy: 128 + InaccuracyType: PerCellIncrement Warhead@1Dam: SpreadDamage - Spread: 128 - Falloff: 100, 50, 25, 0 Damage: 1250 + Spread: 480 + Falloff: 100, 0 Versus: wall: 10 building: 25 @@ -17,6 +19,7 @@ cy: 20 harvester: 25 DamageTypes: Prone50Percent, TriggerProne, BulletDeath + DamageCalculationType: ClosestTargetablePosition Warhead@2Eff: CreateEffect Explosions: piffs ImpactActors: false @@ -36,6 +39,7 @@ M_LMG: Inherits: ^MG ReloadDelay: 40 + ValidTargets: Infantry M_LMG_H: Inherits: M_LMG @@ -46,9 +50,10 @@ ReloadDelay: 40 Range: 3c512 Report: 20MMGUN1.WAV + InvalidTargets: Infantry Warhead@1Dam: SpreadDamage - Spread: 192 Damage: 2500 + Spread: 512 Versus: none: 25 wall: 100 @@ -59,7 +64,7 @@ invulnerable: 0 cy: 20 harvester: 50 - Warhead@2Concrete: DamagesConcrete + Warhead@3Concrete: DamagesConcrete Damage: 625 M_HMG_H: @@ -80,10 +85,8 @@ Range: 3c0 Report: 20MMGUN1.WAV Warhead@1Dam: SpreadDamage - Spread: 160 - Falloff: 100, 60, 30, 0 Damage: 1800 - Warhead@2Concrete: DamagesConcrete + Warhead@3Concrete: DamagesConcrete Damage: 1800 HMGo: diff -Nru openra-20200503/mods/modcontent/chrome.yaml openra-20210321/mods/modcontent/chrome.yaml --- openra-20200503/mods/modcontent/chrome.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/modcontent/chrome.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -102,10 +102,10 @@ scrollpanel-button-pressed: Inherits: panel-thinborder-light -scrollbar: +scrollpanel-decorations: Inherits: ^Chrome Regions: - down_arrow: 453, 512, 16, 16 - down_pressed: 453, 512, 16, 16 - up_arrow: 470, 512, 16, 16 - up_pressed: 470, 512, 16, 16 + down: 453, 512, 16, 16 + down-pressed: 453, 512, 16, 16 + up: 470, 512, 16, 16 + up-pressed: 470, 512, 16, 16 diff -Nru openra-20200503/mods/modcontent/content.yaml openra-20210321/mods/modcontent/content.yaml --- openra-20200503/mods/modcontent/content.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/modcontent/content.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -21,7 +21,7 @@ Align: Center Font: MediumBold Label@HEADER_TEMPLATE: - Y: 66 + Y: 66 Width: PARENT_RIGHT Height: 16 Align: Center @@ -43,7 +43,7 @@ Width: 275 Height: 23 Label@REQUIRED: - X: 185 + X: 185 Width: 90 Height: 23 Align: Center diff -Nru openra-20200503/mods/modcontent/mod.yaml openra-20210321/mods/modcontent/mod.yaml --- openra-20200503/mods/modcontent/mod.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/modcontent/mod.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,9 +4,9 @@ Hidden: true Packages: - . - ./mods/modcontent: modcontent - ./mods/common: common + ^EngineDir + ^EngineDir|mods/modcontent: modcontent + ^EngineDir|mods/common: common Rules: modcontent|rules.yaml @@ -18,7 +18,7 @@ modcontent|chrome.yaml Assemblies: - common|OpenRA.Mods.Common.dll + ^BinDir|OpenRA.Mods.Common.dll ChromeLayout: modcontent|content.yaml @@ -27,9 +27,9 @@ modcontent|notifications.yaml LoadScreen: ModContentLoadScreen - Image: ./mods/modcontent/chrome.png - Image2x: ./mods/modcontent/chrome-2x.png - Image3x: ./mods/modcontent/chrome-3x.png + Image: ^EngineDir|mods/modcontent/chrome.png + Image2x: ^EngineDir|mods/modcontent/chrome-2x.png + Image3x: ^EngineDir|mods/modcontent/chrome-3x.png ChromeMetrics: common|metrics.yaml diff -Nru openra-20200503/mods/ra/audio/voices.yaml openra-20210321/mods/ra/audio/voices.yaml --- openra-20200503/mods/ra/audio/voices.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/audio/voices.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -46,9 +46,9 @@ MechanicVoice: Voices: - Select: mhuh1,mhowdy1,myes1,mrise1 - Move: mboss1,mhear1 - Action: mhotdig1,mwrench1 + Select: mhuh1,mhowdy1,mlaff1 + Move: mboss1,mhear1,myes1,mrise1 + Action: mhotdig1,mwrench1,myeehaw1 Die: dedman1,dedman2,dedman3,dedman4,dedman5,dedman7,dedman8 Burned: dedman10 Zapped: dedman6 @@ -117,8 +117,8 @@ ShokVoice: Voices: - Select: jchrge1,jjuice1,jjump1,jpower1 - Move: jdance1,jyes1 + Select: jjuice1,jjump1,jyes1 + Move: jdance1,jchrge1,jpower1 Attack: jburn1,jcrisp1,jshock1,jlight1 Die: dedman1,dedman2,dedman3,dedman4,dedman5,dedman7,dedman8 Burned: dedman10 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/bits/c11.shp and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/bits/c11.shp differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/bits/c3.shp and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/bits/c3.shp differ diff -Nru openra-20200503/mods/ra/bits/scripts/campaign-global.lua openra-20210321/mods/ra/bits/scripts/campaign-global.lua --- openra-20200503/mods/ra/bits/scripts/campaign-global.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/bits/scripts/campaign-global.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,39 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] + +AttackAircraftTargets = { } +InitializeAttackAircraft = function(aircraft, enemyPlayer) + Trigger.OnIdle(aircraft, function() + local actorId = tostring(aircraft) + local target = AttackAircraftTargets[actorId] + + if not target or not target.IsInWorld then + target = ChooseRandomTarget(aircraft, enemyPlayer) + end + + if target then + AttackAircraftTargets[actorId] = target + aircraft.Attack(target) + else + AttackAircraftTargets[actorId] = nil + aircraft.ReturnToBase() + end + end) +end + +ChooseRandomTarget = function(unit, enemyPlayer) + local target = nil + local enemies = Utils.Where(enemyPlayer.GetActors(), function(self) + return self.HasProperty("Health") and unit.CanTarget(self) and not Utils.Any({ "sbag", "fenc", "brik", "cycl", "barb" }, function(type) return self.Type == type end) + end) + if #enemies > 0 then + target = Utils.Random(enemies) + end + return target +end Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/bits/tag-spy.shp and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/bits/tag-spy.shp differ diff -Nru openra-20200503/mods/ra/chrome/ingame-observer.yaml openra-20210321/mods/ra/chrome/ingame-observer.yaml --- openra-20200503/mods/ra/chrome/ingame-observer.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/chrome/ingame-observer.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -108,7 +108,7 @@ Height: 16 Label@LABEL: X: 40 - Width: 60 + Width: PARENT_RIGHT Height: 25 Shadow: True Label@NOFLAG_LABEL: @@ -925,7 +925,7 @@ X: PARENT_RIGHT - 200 Y: 0 Width: 200 - Height: PARENT_BOTTOM + Height: PARENT_BOTTOM Image@FLAG: X: 5 Y: 4 diff -Nru openra-20200503/mods/ra/chrome/ingame-player.yaml openra-20210321/mods/ra/chrome/ingame-player.yaml --- openra-20200503/mods/ra/chrome/ingame-player.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/chrome/ingame-player.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -572,8 +572,8 @@ Image@ICON: X: 6 Y: 3 - ImageCollection: scrollbar - ImageName: up_arrow + ImageCollection: scrollpanel-decorations + ImageName: up Button@SCROLL_DOWN_BUTTON: Logic: AddFactionSuffixLogic Y: 211 @@ -587,8 +587,8 @@ Image@ICON: X: 6 Y: 3 - ImageCollection: scrollbar - ImageName: down_arrow + ImageCollection: scrollpanel-decorations + ImageName: down Image@SIDEBAR_MONEYBIN: Logic: AddFactionSuffixLogic X: WINDOW_RIGHT - 250 diff -Nru openra-20200503/mods/ra/chrome.yaml openra-20210321/mods/ra/chrome.yaml --- openra-20200503/mods/ra/chrome.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/chrome.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -135,7 +135,7 @@ production-tooltip-time: 136, 51, 16, 16 production-tooltip-power: 102, 51, 16, 16 production-tooltip-cost: 68, 51, 16, 16 - indicator-muted: 68, 145, 26, 24 + indicator-muted: 221, 17, 26, 24 commandbar: Inherits: ^Sidebar @@ -320,14 +320,15 @@ # completely black tile dialog5: Inherits: ^Dialog - PanelRegion: 579, 387, 0, 0, 64, 64, 0, 0 + PanelRegion: 580, 388, 0, 0, 62, 62, 0, 0 PanelSides: Center lobby-bits: Inherits: ^Glyphs Regions: - spawn-unclaimed: 91, 119, 22, 22 spawn-claimed: 68, 119, 22, 22 + spawn-unclaimed: 91, 119, 22, 22 + spawn-disabled: 114, 119, 22, 22 admin: 170, 0, 6, 5 colorpicker: 68, 119, 22, 22 huepicker: 136, 0, 7, 15 @@ -362,9 +363,9 @@ Inherits: ^Glyphs Regions: unowned: 68, 119, 22, 22 - critical_unowned: 114, 119, 22, 22 - enemy_owned: 137, 119, 22, 22 - player_owned: 183, 119, 22, 22 + critical_unowned: 137, 119, 22, 22 + enemy_owned: 160, 119, 22, 22 + player_owned: 160, 142, 22, 22 flags: Inherits: ^Glyphs @@ -394,18 +395,6 @@ prev: 68, 0, 16, 16 fastforward: 85, 0, 16, 16 -scrollbar: - Inherits: ^Glyphs - Regions: - down_arrow: 68, 17, 16, 16 - down_pressed: 85, 17, 16, 16 - up_arrow: 102, 17, 16, 16 - up_pressed: 119, 17, 16, 16 - right_arrow: 136, 17, 16, 16 - right_pressed: 153, 17, 16, 16 - left_arrow: 170, 17, 16, 16 - left_pressed: 187, 17, 16, 16 - progressbar-bg: Inherits: button-pressed @@ -533,6 +522,12 @@ Inherits: ^Dialog PanelRegion: 897, 1, 2, 2, 122, 122, 2, 2 +checkbox-highlighted-hover: + Inherits: checkbox-highlighted + +checkbox-highlighted-disabled: + Inherits: checkbox-disabled + scrollitem-selected: Inherits: button-pressed @@ -559,8 +554,34 @@ PanelRegion: 650, 389, 39, 39, 38, 38, 39, 39 PanelSides: Edges -dropdown: +scrollpanel-decorations: + Inherits: ^Glyphs + Regions: + down: 68, 17, 16, 16 + down-pressed: 68, 17, 16, 16 + down-disabled: 85, 17, 16, 16 + up: 102, 17, 16, 16 + up-pressed: 102, 17, 16, 16 + up-disabled: 119, 17, 16, 16 + right: 136, 17, 16, 16 + right-pressed: 136, 17, 16, 16 + right-disabled: 153, 17, 16, 16 + left: 170, 17, 16, 16 + left-pressed: 170, 17, 16, 16 + left-disabled: 187, 17, 16, 16 + +dropdown-decorations: + Inherits: ^Glyphs + Regions: + marker: 68, 17, 16, 16 + marker-pressed: 68, 17, 16, 16 + marker-disabled: 85, 17, 16, 16 + +dropdown-separators: Inherits: ^Dialog Regions: separator: 513, 2, 1, 19 - observer-separator: 769, 257, 1, 19 + separator-hover: 513, 130, 1, 19 + separator-pressed: 766, 2, 1, 19 + separator-disabled: 513, 258, 1, 19 + observer-separator: 769, 258, 1, 19 diff -Nru openra-20200503/mods/ra/hotkeys.yaml openra-20210321/mods/ra/hotkeys.yaml --- openra-20200503/mods/ra/hotkeys.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/hotkeys.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -19,7 +19,7 @@ Types: Production, Player ProductionTypeNaval: I - Description: Naval Tab + Description: Naval Tab Types: Production, Player PowerDown: X diff -Nru openra-20200503/mods/ra/installer/aftermath.yaml openra-20210321/mods/ra/installer/aftermath.yaml --- openra-20200503/mods/ra/installer/aftermath.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/installer/aftermath.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,113 +4,113 @@ SETUP/INSTALL/PATCH.RTP: 5bce93f834f9322ddaa7233242e5b6c7fea0bf17 Install: extract-raw: SETUP/INSTALL/PATCH.RTP - ^Content/ra/v2/expand/expand2.mix: + ^SupportDir|Content/ra/v2/expand/expand2.mix: Offset: 4712984 Length: 469922 - ^Content/ra/v2/expand/hires1.mix: + ^SupportDir|Content/ra/v2/expand/hires1.mix: Offset: 5182981 Length: 90264 - ^Content/ra/v2/expand/lores1.mix: + ^SupportDir|Content/ra/v2/expand/lores1.mix: Offset: 5273320 Length: 57076 extract-raw: MAIN.MIX - ^Content/ra/v2/expand/await.aud: + ^SupportDir|Content/ra/v2/expand/await.aud: Offset: 158698809 Length: 2972788 - ^Content/ra/v2/expand/bog.aud: + ^SupportDir|Content/ra/v2/expand/bog.aud: Offset: 244351833 Length: 2386955 - ^Content/ra/v2/expand/float_v2.aud: + ^SupportDir|Content/ra/v2/expand/float_v2.aud: Offset: 246738788 Length: 3090115 - ^Content/ra/v2/expand/gloom.aud: + ^SupportDir|Content/ra/v2/expand/gloom.aud: Offset: 249828903 Length: 2662851 - ^Content/ra/v2/expand/grndwire.aud: + ^SupportDir|Content/ra/v2/expand/grndwire.aud: Offset: 252491754 Length: 2573611 - ^Content/ra/v2/expand/rpt.aud: + ^SupportDir|Content/ra/v2/expand/rpt.aud: Offset: 255065365 Length: 3092259 - ^Content/ra/v2/expand/search.aud: + ^SupportDir|Content/ra/v2/expand/search.aud: Offset: 258157624 Length: 3104091 - ^Content/ra/v2/expand/traction.aud: + ^SupportDir|Content/ra/v2/expand/traction.aud: Offset: 261261715 Length: 2668003 - ^Content/ra/v2/expand/wastelnd.aud: + ^SupportDir|Content/ra/v2/expand/wastelnd.aud: Offset: 263929718 Length: 2721563 - ^Content/ra/v2/expand/chrotnk1.aud: + ^SupportDir|Content/ra/v2/expand/chrotnk1.aud: Offset: 267714446 Length: 22900 - ^Content/ra/v2/expand/fixit1.aud: + ^SupportDir|Content/ra/v2/expand/fixit1.aud: Offset: 267959424 Length: 10707 - ^Content/ra/v2/expand/jburn1.aud: + ^SupportDir|Content/ra/v2/expand/jburn1.aud: Offset: 268105462 Length: 23091 - ^Content/ra/v2/expand/jchrge1.aud: + ^SupportDir|Content/ra/v2/expand/jchrge1.aud: Offset: 268128553 Length: 14219 - ^Content/ra/v2/expand/jcrisp1.aud: + ^SupportDir|Content/ra/v2/expand/jcrisp1.aud: Offset: 268142772 Length: 18211 - ^Content/ra/v2/expand/jdance1.aud: + ^SupportDir|Content/ra/v2/expand/jdance1.aud: Offset: 268160983 Length: 14315 - ^Content/ra/v2/expand/jjuice1.aud: + ^SupportDir|Content/ra/v2/expand/jjuice1.aud: Offset: 268175298 Length: 9699 - ^Content/ra/v2/expand/jjump1.aud: + ^SupportDir|Content/ra/v2/expand/jjump1.aud: Offset: 268184997 Length: 8219 - ^Content/ra/v2/expand/jlight1.aud: + ^SupportDir|Content/ra/v2/expand/jlight1.aud: Offset: 268193216 Length: 9875 - ^Content/ra/v2/expand/jpower1.aud: + ^SupportDir|Content/ra/v2/expand/jpower1.aud: Offset: 268203091 Length: 13571 - ^Content/ra/v2/expand/jshock1.aud: + ^SupportDir|Content/ra/v2/expand/jshock1.aud: Offset: 268216662 Length: 14771 - ^Content/ra/v2/expand/jyes1.aud: + ^SupportDir|Content/ra/v2/expand/jyes1.aud: Offset: 268231433 Length: 13795 - ^Content/ra/v2/expand/madchrg2.aud: + ^SupportDir|Content/ra/v2/expand/madchrg2.aud: Offset: 268361344 Length: 19782 - ^Content/ra/v2/expand/madexplo.aud: + ^SupportDir|Content/ra/v2/expand/madexplo.aud: Offset: 268381126 Length: 26572 - ^Content/ra/v2/expand/mboss1.aud: + ^SupportDir|Content/ra/v2/expand/mboss1.aud: Offset: 268413174 Length: 20147 - ^Content/ra/v2/expand/mhear1.aud: + ^SupportDir|Content/ra/v2/expand/mhear1.aud: Offset: 268438509 Length: 6714 - ^Content/ra/v2/expand/mhotdig1.aud: + ^SupportDir|Content/ra/v2/expand/mhotdig1.aud: Offset: 268445223 Length: 10674 - ^Content/ra/v2/expand/mhowdy1.aud: + ^SupportDir|Content/ra/v2/expand/mhowdy1.aud: Offset: 268455897 Length: 6714 - ^Content/ra/v2/expand/mhuh1.aud: + ^SupportDir|Content/ra/v2/expand/mhuh1.aud: Offset: 268462611 Length: 4117 - ^Content/ra/v2/expand/mlaff1.aud: + ^SupportDir|Content/ra/v2/expand/mlaff1.aud: Offset: 268527415 Length: 24133 - ^Content/ra/v2/expand/mrise1.aud: + ^SupportDir|Content/ra/v2/expand/mrise1.aud: Offset: 268564948 Length: 13523 - ^Content/ra/v2/expand/mwrench1.aud: + ^SupportDir|Content/ra/v2/expand/mwrench1.aud: Offset: 268578471 Length: 10780 - ^Content/ra/v2/expand/myeehaw1.aud: + ^SupportDir|Content/ra/v2/expand/myeehaw1.aud: Offset: 268589251 Length: 18912 - ^Content/ra/v2/expand/myes1.aud: + ^SupportDir|Content/ra/v2/expand/myes1.aud: Offset: 268608163 Length: 9073 aftermath-linux: Aftermath Expansion Disc (English) @@ -119,112 +119,112 @@ setup/install/patch.rtp: 5bce93f834f9322ddaa7233242e5b6c7fea0bf17 Install: extract-raw: setup/install/patch.rtp - ^Content/ra/v2/expand/expand2.mix: + ^SupportDir|Content/ra/v2/expand/expand2.mix: Offset: 4712984 Length: 469922 - ^Content/ra/v2/expand/hires1.mix: + ^SupportDir|Content/ra/v2/expand/hires1.mix: Offset: 5182981 Length: 90264 - ^Content/ra/v2/expand/lores1.mix: + ^SupportDir|Content/ra/v2/expand/lores1.mix: Offset: 5273320 Length: 57076 extract-raw: main.mix - ^Content/ra/v2/expand/await.aud: + ^SupportDir|Content/ra/v2/expand/await.aud: Offset: 158698809 Length: 2972788 - ^Content/ra/v2/expand/bog.aud: + ^SupportDir|Content/ra/v2/expand/bog.aud: Offset: 244351833 Length: 2386955 - ^Content/ra/v2/expand/float_v2.aud: + ^SupportDir|Content/ra/v2/expand/float_v2.aud: Offset: 246738788 Length: 3090115 - ^Content/ra/v2/expand/gloom.aud: + ^SupportDir|Content/ra/v2/expand/gloom.aud: Offset: 249828903 Length: 2662851 - ^Content/ra/v2/expand/grndwire.aud: + ^SupportDir|Content/ra/v2/expand/grndwire.aud: Offset: 252491754 Length: 2573611 - ^Content/ra/v2/expand/rpt.aud: + ^SupportDir|Content/ra/v2/expand/rpt.aud: Offset: 255065365 Length: 3092259 - ^Content/ra/v2/expand/search.aud: + ^SupportDir|Content/ra/v2/expand/search.aud: Offset: 258157624 Length: 3104091 - ^Content/ra/v2/expand/traction.aud: + ^SupportDir|Content/ra/v2/expand/traction.aud: Offset: 261261715 Length: 2668003 - ^Content/ra/v2/expand/wastelnd.aud: + ^SupportDir|Content/ra/v2/expand/wastelnd.aud: Offset: 263929718 Length: 2721563 - ^Content/ra/v2/expand/chrotnk1.aud: + ^SupportDir|Content/ra/v2/expand/chrotnk1.aud: Offset: 267714446 Length: 22900 - ^Content/ra/v2/expand/fixit1.aud: + ^SupportDir|Content/ra/v2/expand/fixit1.aud: Offset: 267959424 Length: 10707 - ^Content/ra/v2/expand/jburn1.aud: + ^SupportDir|Content/ra/v2/expand/jburn1.aud: Offset: 268105462 Length: 23091 - ^Content/ra/v2/expand/jchrge1.aud: + ^SupportDir|Content/ra/v2/expand/jchrge1.aud: Offset: 268128553 Length: 14219 - ^Content/ra/v2/expand/jcrisp1.aud: + ^SupportDir|Content/ra/v2/expand/jcrisp1.aud: Offset: 268142772 Length: 18211 - ^Content/ra/v2/expand/jdance1.aud: + ^SupportDir|Content/ra/v2/expand/jdance1.aud: Offset: 268160983 Length: 14315 - ^Content/ra/v2/expand/jjuice1.aud: + ^SupportDir|Content/ra/v2/expand/jjuice1.aud: Offset: 268175298 Length: 9699 - ^Content/ra/v2/expand/jjump1.aud: + ^SupportDir|Content/ra/v2/expand/jjump1.aud: Offset: 268184997 Length: 8219 - ^Content/ra/v2/expand/jlight1.aud: + ^SupportDir|Content/ra/v2/expand/jlight1.aud: Offset: 268193216 Length: 9875 - ^Content/ra/v2/expand/jpower1.aud: + ^SupportDir|Content/ra/v2/expand/jpower1.aud: Offset: 268203091 Length: 13571 - ^Content/ra/v2/expand/jshock1.aud: + ^SupportDir|Content/ra/v2/expand/jshock1.aud: Offset: 268216662 Length: 14771 - ^Content/ra/v2/expand/jyes1.aud: + ^SupportDir|Content/ra/v2/expand/jyes1.aud: Offset: 268231433 Length: 13795 - ^Content/ra/v2/expand/madchrg2.aud: + ^SupportDir|Content/ra/v2/expand/madchrg2.aud: Offset: 268361344 Length: 19782 - ^Content/ra/v2/expand/madexplo.aud: + ^SupportDir|Content/ra/v2/expand/madexplo.aud: Offset: 268381126 Length: 26572 - ^Content/ra/v2/expand/mboss1.aud: + ^SupportDir|Content/ra/v2/expand/mboss1.aud: Offset: 268413174 Length: 20147 - ^Content/ra/v2/expand/mhear1.aud: + ^SupportDir|Content/ra/v2/expand/mhear1.aud: Offset: 268438509 Length: 6714 - ^Content/ra/v2/expand/mhotdig1.aud: + ^SupportDir|Content/ra/v2/expand/mhotdig1.aud: Offset: 268445223 Length: 10674 - ^Content/ra/v2/expand/mhowdy1.aud: + ^SupportDir|Content/ra/v2/expand/mhowdy1.aud: Offset: 268455897 Length: 6714 - ^Content/ra/v2/expand/mhuh1.aud: + ^SupportDir|Content/ra/v2/expand/mhuh1.aud: Offset: 268462611 Length: 4117 - ^Content/ra/v2/expand/mlaff1.aud: + ^SupportDir|Content/ra/v2/expand/mlaff1.aud: Offset: 268527415 Length: 24133 - ^Content/ra/v2/expand/mrise1.aud: + ^SupportDir|Content/ra/v2/expand/mrise1.aud: Offset: 268564948 Length: 13523 - ^Content/ra/v2/expand/mwrench1.aud: + ^SupportDir|Content/ra/v2/expand/mwrench1.aud: Offset: 268578471 Length: 10780 - ^Content/ra/v2/expand/myeehaw1.aud: + ^SupportDir|Content/ra/v2/expand/myeehaw1.aud: Offset: 268589251 Length: 18912 - ^Content/ra/v2/expand/myes1.aud: + ^SupportDir|Content/ra/v2/expand/myes1.aud: Offset: 268608163 Length: 9073 \ No newline at end of file diff -Nru openra-20200503/mods/ra/installer/allies95.yaml openra-20210321/mods/ra/installer/allies95.yaml --- openra-20200503/mods/ra/installer/allies95.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/installer/allies95.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -5,194 +5,194 @@ INSTALL/REDALERT.MIX: 0e58f4b54f44f6cd29fecf8cf379d33cf2d4caef Install: extract-raw: INSTALL/REDALERT.MIX - ^Content/ra/v2/hires.mix: + ^SupportDir|Content/ra/v2/hires.mix: Offset: 650612 Length: 5817417 - ^Content/ra/v2/local.mix: + ^SupportDir|Content/ra/v2/local.mix: Offset: 6468029 Length: 3829837 - ^Content/ra/v2/lores.mix: + ^SupportDir|Content/ra/v2/lores.mix: Offset: 10297866 Length: 754800 - ^Content/ra/v2/speech.mix: + ^SupportDir|Content/ra/v2/speech.mix: Offset: 23042864 Length: 2003464 extract-raw: MAIN.MIX - ^Content/ra/v2/conquer.mix: + ^SupportDir|Content/ra/v2/conquer.mix: Offset: 236 Length: 2177047 - ^Content/ra/v2/interior.mix: + ^SupportDir|Content/ra/v2/interior.mix: Offset: 17172192 Length: 247425 - ^Content/ra/v2/movies/aagun.vqa: + ^SupportDir|Content/ra/v2/movies/aagun.vqa: Offset: 37694331 Length: 3295512 - ^Content/ra/v2/movies/aftrmath.vqa: + ^SupportDir|Content/ra/v2/movies/aftrmath.vqa: Offset: 40989843 Length: 2455774 - ^Content/ra/v2/movies/ally1.vqa: + ^SupportDir|Content/ra/v2/movies/ally1.vqa: Offset: 43445617 Length: 13536324 - ^Content/ra/v2/movies/ally10.vqa: + ^SupportDir|Content/ra/v2/movies/ally10.vqa: Offset: 56981941 Length: 21506358 - ^Content/ra/v2/movies/ally10b.vqa: + ^SupportDir|Content/ra/v2/movies/ally10b.vqa: Offset: 78488299 Length: 2565152 - ^Content/ra/v2/movies/ally11.vqa: + ^SupportDir|Content/ra/v2/movies/ally11.vqa: Offset: 81053451 Length: 13600398 - ^Content/ra/v2/movies/ally12.vqa: + ^SupportDir|Content/ra/v2/movies/ally12.vqa: Offset: 94653849 Length: 7719544 - ^Content/ra/v2/movies/ally14.vqa: + ^SupportDir|Content/ra/v2/movies/ally14.vqa: Offset: 102373393 Length: 11659080 - ^Content/ra/v2/movies/ally2.vqa: + ^SupportDir|Content/ra/v2/movies/ally2.vqa: Offset: 114032473 Length: 8014018 - ^Content/ra/v2/movies/ally4.vqa: + ^SupportDir|Content/ra/v2/movies/ally4.vqa: Offset: 122046491 Length: 9441906 - ^Content/ra/v2/movies/ally5.vqa: + ^SupportDir|Content/ra/v2/movies/ally5.vqa: Offset: 131488397 Length: 21900328 - ^Content/ra/v2/movies/ally6.vqa: + ^SupportDir|Content/ra/v2/movies/ally6.vqa: Offset: 153388725 Length: 26454212 - ^Content/ra/v2/movies/ally8.vqa: + ^SupportDir|Content/ra/v2/movies/ally8.vqa: Offset: 179842937 Length: 15401062 - ^Content/ra/v2/movies/ally9.vqa: + ^SupportDir|Content/ra/v2/movies/ally9.vqa: Offset: 195243999 Length: 14901460 - ^Content/ra/v2/movies/allyend.vqa: + ^SupportDir|Content/ra/v2/movies/allyend.vqa: Offset: 210145459 Length: 27285692 - ^Content/ra/v2/movies/allymorf.vqa: + ^SupportDir|Content/ra/v2/movies/allymorf.vqa: Offset: 237431151 Length: 916964 - ^Content/ra/v2/movies/apcescpe.vqa: + ^SupportDir|Content/ra/v2/movies/apcescpe.vqa: Offset: 238348115 Length: 1627564 - ^Content/ra/v2/movies/assess.vqa: + ^SupportDir|Content/ra/v2/movies/assess.vqa: Offset: 239975679 Length: 2929218 - ^Content/ra/v2/movies/battle.vqa: + ^SupportDir|Content/ra/v2/movies/battle.vqa: Offset: 242904897 Length: 2881110 - ^Content/ra/v2/movies/binoc.vqa: + ^SupportDir|Content/ra/v2/movies/binoc.vqa: Offset: 245786007 Length: 4045856 - ^Content/ra/v2/movies/bmap.vqa: + ^SupportDir|Content/ra/v2/movies/bmap.vqa: Offset: 249831863 Length: 2414312 - ^Content/ra/v2/movies/brdgtilt.vqa: + ^SupportDir|Content/ra/v2/movies/brdgtilt.vqa: Offset: 252246175 Length: 1581318 - ^Content/ra/v2/movies/crontest.vqa: + ^SupportDir|Content/ra/v2/movies/crontest.vqa: Offset: 253827493 Length: 2036620 - ^Content/ra/v2/movies/cronfail.vqa: + ^SupportDir|Content/ra/v2/movies/cronfail.vqa: Offset: 255864113 Length: 1717214 - ^Content/ra/v2/movies/destroyr.vqa: + ^SupportDir|Content/ra/v2/movies/destroyr.vqa: Offset: 257581327 Length: 2178828 - ^Content/ra/v2/movies/dud.vqa: + ^SupportDir|Content/ra/v2/movies/dud.vqa: Offset: 259760155 Length: 3110418 - ^Content/ra/v2/movies/elevator.vqa: + ^SupportDir|Content/ra/v2/movies/elevator.vqa: Offset: 262870573 Length: 1741894 - ^Content/ra/v2/movies/flare.vqa: + ^SupportDir|Content/ra/v2/movies/flare.vqa: Offset: 264612467 Length: 1731744 - ^Content/ra/v2/movies/frozen.vqa: + ^SupportDir|Content/ra/v2/movies/frozen.vqa: Offset: 266344211 Length: 1836994 - ^Content/ra/v2/movies/grvestne.vqa: + ^SupportDir|Content/ra/v2/movies/grvestne.vqa: Offset: 268181205 Length: 3155668 - ^Content/ra/v2/movies/landing.vqa: + ^SupportDir|Content/ra/v2/movies/landing.vqa: Offset: 271336873 Length: 2374106 - ^Content/ra/v2/movies/masasslt.vqa: + ^SupportDir|Content/ra/v2/movies/masasslt.vqa: Offset: 273710979 Length: 5354700 - ^Content/ra/v2/movies/mcv.vqa: + ^SupportDir|Content/ra/v2/movies/mcv.vqa: Offset: 279065679 Length: 1296036 - ^Content/ra/v2/movies/mcv_land.vqa: + ^SupportDir|Content/ra/v2/movies/mcv_land.vqa: Offset: 280361715 Length: 1424358 - ^Content/ra/v2/movies/montpass.vqa: + ^SupportDir|Content/ra/v2/movies/montpass.vqa: Offset: 281786073 Length: 1701852 - ^Content/ra/v2/movies/oildrum.vqa: + ^SupportDir|Content/ra/v2/movies/oildrum.vqa: Offset: 283487925 Length: 2430792 - ^Content/ra/v2/movies/overrun.vqa: + ^SupportDir|Content/ra/v2/movies/overrun.vqa: Offset: 285918717 Length: 2174548 - ^Content/ra/v2/movies/prolog.vqa: + ^SupportDir|Content/ra/v2/movies/prolog.vqa: Offset: 288093265 Length: 28658198 - ^Content/ra/v2/movies/redintro.vqa: + ^SupportDir|Content/ra/v2/movies/redintro.vqa: Offset: 316751463 Length: 2269452 - ^Content/ra/v2/movies/shipsink.vqa: + ^SupportDir|Content/ra/v2/movies/shipsink.vqa: Offset: 319020915 Length: 3150030 - ^Content/ra/v2/movies/shorbom1.vqa: + ^SupportDir|Content/ra/v2/movies/shorbom1.vqa: Offset: 322170945 Length: 4046650 - ^Content/ra/v2/movies/shorbom2.vqa: + ^SupportDir|Content/ra/v2/movies/shorbom2.vqa: Offset: 326217595 Length: 2150364 - ^Content/ra/v2/movies/shorbomb.vqa: + ^SupportDir|Content/ra/v2/movies/shorbomb.vqa: Offset: 328367959 Length: 6111616 - ^Content/ra/v2/movies/snowbomb.vqa: + ^SupportDir|Content/ra/v2/movies/snowbomb.vqa: Offset: 334479575 Length: 2465762 - ^Content/ra/v2/movies/soviet1.vqa: + ^SupportDir|Content/ra/v2/movies/soviet1.vqa: Offset: 336945337 Length: 24112060 - ^Content/ra/v2/movies/sovtstar.vqa: + ^SupportDir|Content/ra/v2/movies/sovtstar.vqa: Offset: 361057397 Length: 670794 - ^Content/ra/v2/movies/spy.vqa: + ^SupportDir|Content/ra/v2/movies/spy.vqa: Offset: 361728191 Length: 1646808 - ^Content/ra/v2/movies/tanya1.vqa: + ^SupportDir|Content/ra/v2/movies/tanya1.vqa: Offset: 363374999 Length: 13389684 - ^Content/ra/v2/movies/tanya2.vqa: + ^SupportDir|Content/ra/v2/movies/tanya2.vqa: Offset: 376764683 Length: 4103388 - ^Content/ra/v2/movies/toofar.vqa: + ^SupportDir|Content/ra/v2/movies/toofar.vqa: Offset: 380868071 Length: 4244572 - ^Content/ra/v2/movies/trinity.vqa: + ^SupportDir|Content/ra/v2/movies/trinity.vqa: Offset: 385112643 Length: 1669310 - ^Content/ra/v2/scores.mix: + ^SupportDir|Content/ra/v2/scores.mix: Offset: 386781953 Length: 64171360 - ^Content/ra/v2/snow.mix: + ^SupportDir|Content/ra/v2/snow.mix: Offset: 450953313 Length: 1030861 - ^Content/ra/v2/sounds.mix: + ^SupportDir|Content/ra/v2/sounds.mix: Offset: 451984174 Length: 1006778 - ^Content/ra/v2/russian.mix: + ^SupportDir|Content/ra/v2/russian.mix: Offset: 452990952 Length: 266077 - ^Content/ra/v2/allies.mix: + ^SupportDir|Content/ra/v2/allies.mix: Offset: 453257029 Length: 309406 - ^Content/ra/v2/temperat.mix: + ^SupportDir|Content/ra/v2/temperat.mix: Offset: 453566435 Length: 1038859 @@ -202,193 +202,193 @@ install/redalert.mix: 0e58f4b54f44f6cd29fecf8cf379d33cf2d4caef Install: extract-raw: install/redalert.mix - ^Content/ra/v2/hires.mix: + ^SupportDir|Content/ra/v2/hires.mix: Offset: 650612 Length: 5817417 - ^Content/ra/v2/local.mix: + ^SupportDir|Content/ra/v2/local.mix: Offset: 6468029 Length: 3829837 - ^Content/ra/v2/lores.mix: + ^SupportDir|Content/ra/v2/lores.mix: Offset: 10297866 Length: 754800 - ^Content/ra/v2/speech.mix: + ^SupportDir|Content/ra/v2/speech.mix: Offset: 23042864 Length: 2003464 extract-raw: main.mix - ^Content/ra/v2/conquer.mix: + ^SupportDir|Content/ra/v2/conquer.mix: Offset: 236 Length: 2177047 - ^Content/ra/v2/interior.mix: + ^SupportDir|Content/ra/v2/interior.mix: Offset: 17172192 Length: 247425 - ^Content/ra/v2/movies/aagun.vqa: + ^SupportDir|Content/ra/v2/movies/aagun.vqa: Offset: 37694331 Length: 3295512 - ^Content/ra/v2/movies/aftrmath.vqa: + ^SupportDir|Content/ra/v2/movies/aftrmath.vqa: Offset: 40989843 Length: 2455774 - ^Content/ra/v2/movies/ally1.vqa: + ^SupportDir|Content/ra/v2/movies/ally1.vqa: Offset: 43445617 Length: 13536324 - ^Content/ra/v2/movies/ally10.vqa: + ^SupportDir|Content/ra/v2/movies/ally10.vqa: Offset: 56981941 Length: 21506358 - ^Content/ra/v2/movies/ally10b.vqa: + ^SupportDir|Content/ra/v2/movies/ally10b.vqa: Offset: 78488299 Length: 2565152 - ^Content/ra/v2/movies/ally11.vqa: + ^SupportDir|Content/ra/v2/movies/ally11.vqa: Offset: 81053451 Length: 13600398 - ^Content/ra/v2/movies/ally12.vqa: + ^SupportDir|Content/ra/v2/movies/ally12.vqa: Offset: 94653849 Length: 7719544 - ^Content/ra/v2/movies/ally14.vqa: + ^SupportDir|Content/ra/v2/movies/ally14.vqa: Offset: 102373393 Length: 11659080 - ^Content/ra/v2/movies/ally2.vqa: + ^SupportDir|Content/ra/v2/movies/ally2.vqa: Offset: 114032473 Length: 8014018 - ^Content/ra/v2/movies/ally4.vqa: + ^SupportDir|Content/ra/v2/movies/ally4.vqa: Offset: 122046491 Length: 9441906 - ^Content/ra/v2/movies/ally5.vqa: + ^SupportDir|Content/ra/v2/movies/ally5.vqa: Offset: 131488397 Length: 21900328 - ^Content/ra/v2/movies/ally6.vqa: + ^SupportDir|Content/ra/v2/movies/ally6.vqa: Offset: 153388725 Length: 26454212 - ^Content/ra/v2/movies/ally8.vqa: + ^SupportDir|Content/ra/v2/movies/ally8.vqa: Offset: 179842937 Length: 15401062 - ^Content/ra/v2/movies/ally9.vqa: + ^SupportDir|Content/ra/v2/movies/ally9.vqa: Offset: 195243999 Length: 14901460 - ^Content/ra/v2/movies/allyend.vqa: + ^SupportDir|Content/ra/v2/movies/allyend.vqa: Offset: 210145459 Length: 27285692 - ^Content/ra/v2/movies/allymorf.vqa: + ^SupportDir|Content/ra/v2/movies/allymorf.vqa: Offset: 237431151 Length: 916964 - ^Content/ra/v2/movies/apcescpe.vqa: + ^SupportDir|Content/ra/v2/movies/apcescpe.vqa: Offset: 238348115 Length: 1627564 - ^Content/ra/v2/movies/assess.vqa: + ^SupportDir|Content/ra/v2/movies/assess.vqa: Offset: 239975679 Length: 2929218 - ^Content/ra/v2/movies/battle.vqa: + ^SupportDir|Content/ra/v2/movies/battle.vqa: Offset: 242904897 Length: 2881110 - ^Content/ra/v2/movies/binoc.vqa: + ^SupportDir|Content/ra/v2/movies/binoc.vqa: Offset: 245786007 Length: 4045856 - ^Content/ra/v2/movies/bmap.vqa: + ^SupportDir|Content/ra/v2/movies/bmap.vqa: Offset: 249831863 Length: 2414312 - ^Content/ra/v2/movies/brdgtilt.vqa: + ^SupportDir|Content/ra/v2/movies/brdgtilt.vqa: Offset: 252246175 Length: 1581318 - ^Content/ra/v2/movies/crontest.vqa: + ^SupportDir|Content/ra/v2/movies/crontest.vqa: Offset: 253827493 Length: 2036620 - ^Content/ra/v2/movies/cronfail.vqa: + ^SupportDir|Content/ra/v2/movies/cronfail.vqa: Offset: 255864113 Length: 1717214 - ^Content/ra/v2/movies/destroyr.vqa: + ^SupportDir|Content/ra/v2/movies/destroyr.vqa: Offset: 257581327 Length: 2178828 - ^Content/ra/v2/movies/dud.vqa: + ^SupportDir|Content/ra/v2/movies/dud.vqa: Offset: 259760155 Length: 3110418 - ^Content/ra/v2/movies/elevator.vqa: + ^SupportDir|Content/ra/v2/movies/elevator.vqa: Offset: 262870573 Length: 1741894 - ^Content/ra/v2/movies/flare.vqa: + ^SupportDir|Content/ra/v2/movies/flare.vqa: Offset: 264612467 Length: 1731744 - ^Content/ra/v2/movies/frozen.vqa: + ^SupportDir|Content/ra/v2/movies/frozen.vqa: Offset: 266344211 Length: 1836994 - ^Content/ra/v2/movies/grvestne.vqa: + ^SupportDir|Content/ra/v2/movies/grvestne.vqa: Offset: 268181205 Length: 3155668 - ^Content/ra/v2/movies/landing.vqa: + ^SupportDir|Content/ra/v2/movies/landing.vqa: Offset: 271336873 Length: 2374106 - ^Content/ra/v2/movies/masasslt.vqa: + ^SupportDir|Content/ra/v2/movies/masasslt.vqa: Offset: 273710979 Length: 5354700 - ^Content/ra/v2/movies/mcv.vqa: + ^SupportDir|Content/ra/v2/movies/mcv.vqa: Offset: 279065679 Length: 1296036 - ^Content/ra/v2/movies/mcv_land.vqa: + ^SupportDir|Content/ra/v2/movies/mcv_land.vqa: Offset: 280361715 Length: 1424358 - ^Content/ra/v2/movies/montpass.vqa: + ^SupportDir|Content/ra/v2/movies/montpass.vqa: Offset: 281786073 Length: 1701852 - ^Content/ra/v2/movies/oildrum.vqa: + ^SupportDir|Content/ra/v2/movies/oildrum.vqa: Offset: 283487925 Length: 2430792 - ^Content/ra/v2/movies/overrun.vqa: + ^SupportDir|Content/ra/v2/movies/overrun.vqa: Offset: 285918717 Length: 2174548 - ^Content/ra/v2/movies/prolog.vqa: + ^SupportDir|Content/ra/v2/movies/prolog.vqa: Offset: 288093265 Length: 28658198 - ^Content/ra/v2/movies/redintro.vqa: + ^SupportDir|Content/ra/v2/movies/redintro.vqa: Offset: 316751463 Length: 2269452 - ^Content/ra/v2/movies/shipsink.vqa: + ^SupportDir|Content/ra/v2/movies/shipsink.vqa: Offset: 319020915 Length: 3150030 - ^Content/ra/v2/movies/shorbom1.vqa: + ^SupportDir|Content/ra/v2/movies/shorbom1.vqa: Offset: 322170945 Length: 4046650 - ^Content/ra/v2/movies/shorbom2.vqa: + ^SupportDir|Content/ra/v2/movies/shorbom2.vqa: Offset: 326217595 Length: 2150364 - ^Content/ra/v2/movies/shorbomb.vqa: + ^SupportDir|Content/ra/v2/movies/shorbomb.vqa: Offset: 328367959 Length: 6111616 - ^Content/ra/v2/movies/snowbomb.vqa: + ^SupportDir|Content/ra/v2/movies/snowbomb.vqa: Offset: 334479575 Length: 2465762 - ^Content/ra/v2/movies/soviet1.vqa: + ^SupportDir|Content/ra/v2/movies/soviet1.vqa: Offset: 336945337 Length: 24112060 - ^Content/ra/v2/movies/sovtstar.vqa: + ^SupportDir|Content/ra/v2/movies/sovtstar.vqa: Offset: 361057397 Length: 670794 - ^Content/ra/v2/movies/spy.vqa: + ^SupportDir|Content/ra/v2/movies/spy.vqa: Offset: 361728191 Length: 1646808 - ^Content/ra/v2/movies/tanya1.vqa: + ^SupportDir|Content/ra/v2/movies/tanya1.vqa: Offset: 363374999 Length: 13389684 - ^Content/ra/v2/movies/tanya2.vqa: + ^SupportDir|Content/ra/v2/movies/tanya2.vqa: Offset: 376764683 Length: 4103388 - ^Content/ra/v2/movies/toofar.vqa: + ^SupportDir|Content/ra/v2/movies/toofar.vqa: Offset: 380868071 Length: 4244572 - ^Content/ra/v2/movies/trinity.vqa: + ^SupportDir|Content/ra/v2/movies/trinity.vqa: Offset: 385112643 Length: 1669310 - ^Content/ra/v2/scores.mix: + ^SupportDir|Content/ra/v2/scores.mix: Offset: 386781953 Length: 64171360 - ^Content/ra/v2/snow.mix: + ^SupportDir|Content/ra/v2/snow.mix: Offset: 450953313 Length: 1030861 - ^Content/ra/v2/sounds.mix: + ^SupportDir|Content/ra/v2/sounds.mix: Offset: 451984174 Length: 1006778 - ^Content/ra/v2/russian.mix: + ^SupportDir|Content/ra/v2/russian.mix: Offset: 452990952 Length: 266077 - ^Content/ra/v2/allies.mix: + ^SupportDir|Content/ra/v2/allies.mix: Offset: 453257029 Length: 309406 - ^Content/ra/v2/temperat.mix: + ^SupportDir|Content/ra/v2/temperat.mix: Offset: 453566435 Length: 1038859 \ No newline at end of file diff -Nru openra-20200503/mods/ra/installer/cnc95.yaml openra-20210321/mods/ra/installer/cnc95.yaml --- openra-20200503/mods/ra/installer/cnc95.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/installer/cnc95.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -3,10 +3,10 @@ CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30 Install: copy: . - ^Content/ra/v2/cnc/desert.mix: DESERT.MIX + ^SupportDir|Content/ra/v2/cnc/desert.mix: DESERT.MIX cnc95-linux: C&C Gold (GDI or Nod Disc, English) IDFiles: conquer.mix: 833e02a09aae694659eb312d3838367f681d1b30 Install: copy: . - ^Content/ra/v2/cnc/desert.mix: desert.mix \ No newline at end of file + ^SupportDir|Content/ra/v2/cnc/desert.mix: desert.mix \ No newline at end of file diff -Nru openra-20200503/mods/ra/installer/counterstrike.yaml openra-20210321/mods/ra/installer/counterstrike.yaml --- openra-20200503/mods/ra/installer/counterstrike.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/installer/counterstrike.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,28 +4,28 @@ SETUP/INSTALL/CSTRIKE.RTP: fae8ba82db71574f6ecd8fb4ff4026fcb65d2adc Install: extract-raw: MAIN.MIX - ^Content/ra/v2/expand/2nd_hand.aud: + ^SupportDir|Content/ra/v2/expand/2nd_hand.aud: Offset: 209070947 Length: 3070092 - ^Content/ra/v2/expand/araziod.aud: + ^SupportDir|Content/ra/v2/expand/araziod.aud: Offset: 212141039 Length: 2941132 - ^Content/ra/v2/expand/backstab.aud: + ^SupportDir|Content/ra/v2/expand/backstab.aud: Offset: 215082171 Length: 3178252 - ^Content/ra/v2/expand/chaos2.aud: + ^SupportDir|Content/ra/v2/expand/chaos2.aud: Offset: 218260423 Length: 2860068 - ^Content/ra/v2/expand/shut_it.aud: + ^SupportDir|Content/ra/v2/expand/shut_it.aud: Offset: 221120491 Length: 2991979 - ^Content/ra/v2/expand/twinmix1.aud: + ^SupportDir|Content/ra/v2/expand/twinmix1.aud: Offset: 224112470 Length: 2536972 - ^Content/ra/v2/expand/under3.aud: + ^SupportDir|Content/ra/v2/expand/under3.aud: Offset: 226649442 Length: 2812788 - ^Content/ra/v2/expand/vr2.aud: + ^SupportDir|Content/ra/v2/expand/vr2.aud: Offset: 229462230 Length: 2920396 counterstrike-linux: Counterstrike Expansion Disc (English) @@ -34,27 +34,27 @@ setup/install/cstrike.rtp: fae8ba82db71574f6ecd8fb4ff4026fcb65d2adc Install: extract-raw: main.mix - ^Content/ra/v2/expand/2nd_hand.aud: + ^SupportDir|Content/ra/v2/expand/2nd_hand.aud: Offset: 209070947 Length: 3070092 - ^Content/ra/v2/expand/araziod.aud: + ^SupportDir|Content/ra/v2/expand/araziod.aud: Offset: 212141039 Length: 2941132 - ^Content/ra/v2/expand/backstab.aud: + ^SupportDir|Content/ra/v2/expand/backstab.aud: Offset: 215082171 Length: 3178252 - ^Content/ra/v2/expand/chaos2.aud: + ^SupportDir|Content/ra/v2/expand/chaos2.aud: Offset: 218260423 Length: 2860068 - ^Content/ra/v2/expand/shut_it.aud: + ^SupportDir|Content/ra/v2/expand/shut_it.aud: Offset: 221120491 Length: 2991979 - ^Content/ra/v2/expand/twinmix1.aud: + ^SupportDir|Content/ra/v2/expand/twinmix1.aud: Offset: 224112470 Length: 2536972 - ^Content/ra/v2/expand/under3.aud: + ^SupportDir|Content/ra/v2/expand/under3.aud: Offset: 226649442 Length: 2812788 - ^Content/ra/v2/expand/vr2.aud: + ^SupportDir|Content/ra/v2/expand/vr2.aud: Offset: 229462230 Length: 2920396 \ No newline at end of file diff -Nru openra-20200503/mods/ra/installer/downloads.yaml openra-20210321/mods/ra/installer/downloads.yaml --- openra-20200503/mods/ra/installer/downloads.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/installer/downloads.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,102 +2,96 @@ SHA1: 44241f68e69db9511db82cf83c174737ccda300b MirrorList: http://www.openra.net/packages/ra-quickinstall-mirrors.txt Extract: - ^Content/ra/v2/allies.mix: allies.mix - ^Content/ra/v2/conquer.mix: conquer.mix - ^Content/ra/v2/hires.mix: hires.mix - ^Content/ra/v2/interior.mix: interior.mix - ^Content/ra/v2/local.mix: local.mix - ^Content/ra/v2/lores.mix: lores.mix - ^Content/ra/v2/russian.mix: russian.mix - ^Content/ra/v2/snow.mix: snow.mix - ^Content/ra/v2/sounds.mix: sounds.mix - ^Content/ra/v2/speech.mix: speech.mix - ^Content/ra/v2/temperat.mix: temperat.mix - ^Content/ra/v2/expand/chrotnk1.aud: expand/chrotnk1.aud - ^Content/ra/v2/expand/expand2.mix: expand/expand2.mix - ^Content/ra/v2/expand/fixit1.aud: expand/fixit1.aud - ^Content/ra/v2/expand/hires1.mix: expand/hires1.mix - ^Content/ra/v2/expand/jburn1.aud: expand/jburn1.aud - ^Content/ra/v2/expand/jchrge1.aud: expand/jchrge1.aud - ^Content/ra/v2/expand/jcrisp1.aud: expand/jcrisp1.aud - ^Content/ra/v2/expand/jdance1.aud: expand/jdance1.aud - ^Content/ra/v2/expand/jjuice1.aud: expand/jjuice1.aud - ^Content/ra/v2/expand/jjump1.aud: expand/jjump1.aud - ^Content/ra/v2/expand/jlight1.aud: expand/jlight1.aud - ^Content/ra/v2/expand/jpower1.aud: expand/jpower1.aud - ^Content/ra/v2/expand/jshock1.aud: expand/jshock1.aud - ^Content/ra/v2/expand/jyes1.aud: expand/jyes1.aud - ^Content/ra/v2/expand/lores1.mix: expand/lores1.mix - ^Content/ra/v2/expand/madchrg2.aud: expand/madchrg2.aud - ^Content/ra/v2/expand/madexplo.aud: expand/madexplo.aud - ^Content/ra/v2/expand/mboss1.aud: expand/mboss1.aud - ^Content/ra/v2/expand/mhear1.aud: expand/mhear1.aud - ^Content/ra/v2/expand/mhotdig1.aud: expand/mhotdig1.aud - ^Content/ra/v2/expand/mhowdy1.aud: expand/mhowdy1.aud - ^Content/ra/v2/expand/mhuh1.aud: expand/mhuh1.aud - ^Content/ra/v2/expand/mlaff1.aud: expand/mlaff1.aud - ^Content/ra/v2/expand/mrise1.aud: expand/mrise1.aud - ^Content/ra/v2/expand/mwrench1.aud: expand/mwrench1.aud - ^Content/ra/v2/expand/myeehaw1.aud: expand/myeehaw1.aud - ^Content/ra/v2/expand/myes1.aud: expand/myes1.aud - ^Content/ra/v2/cnc/desert.mix: cnc/desert.mix + ^SupportDir|Content/ra/v2/allies.mix: allies.mix + ^SupportDir|Content/ra/v2/conquer.mix: conquer.mix + ^SupportDir|Content/ra/v2/hires.mix: hires.mix + ^SupportDir|Content/ra/v2/interior.mix: interior.mix + ^SupportDir|Content/ra/v2/local.mix: local.mix + ^SupportDir|Content/ra/v2/lores.mix: lores.mix + ^SupportDir|Content/ra/v2/russian.mix: russian.mix + ^SupportDir|Content/ra/v2/snow.mix: snow.mix + ^SupportDir|Content/ra/v2/sounds.mix: sounds.mix + ^SupportDir|Content/ra/v2/speech.mix: speech.mix + ^SupportDir|Content/ra/v2/temperat.mix: temperat.mix + ^SupportDir|Content/ra/v2/expand/chrotnk1.aud: expand/chrotnk1.aud + ^SupportDir|Content/ra/v2/expand/expand2.mix: expand/expand2.mix + ^SupportDir|Content/ra/v2/expand/fixit1.aud: expand/fixit1.aud + ^SupportDir|Content/ra/v2/expand/hires1.mix: expand/hires1.mix + ^SupportDir|Content/ra/v2/expand/jburn1.aud: expand/jburn1.aud + ^SupportDir|Content/ra/v2/expand/jchrge1.aud: expand/jchrge1.aud + ^SupportDir|Content/ra/v2/expand/jcrisp1.aud: expand/jcrisp1.aud + ^SupportDir|Content/ra/v2/expand/jdance1.aud: expand/jdance1.aud + ^SupportDir|Content/ra/v2/expand/jjuice1.aud: expand/jjuice1.aud + ^SupportDir|Content/ra/v2/expand/jjump1.aud: expand/jjump1.aud + ^SupportDir|Content/ra/v2/expand/jlight1.aud: expand/jlight1.aud + ^SupportDir|Content/ra/v2/expand/jpower1.aud: expand/jpower1.aud + ^SupportDir|Content/ra/v2/expand/jshock1.aud: expand/jshock1.aud + ^SupportDir|Content/ra/v2/expand/jyes1.aud: expand/jyes1.aud + ^SupportDir|Content/ra/v2/expand/lores1.mix: expand/lores1.mix + ^SupportDir|Content/ra/v2/expand/madchrg2.aud: expand/madchrg2.aud + ^SupportDir|Content/ra/v2/expand/madexplo.aud: expand/madexplo.aud + ^SupportDir|Content/ra/v2/expand/mboss1.aud: expand/mboss1.aud + ^SupportDir|Content/ra/v2/expand/mhear1.aud: expand/mhear1.aud + ^SupportDir|Content/ra/v2/expand/mhotdig1.aud: expand/mhotdig1.aud + ^SupportDir|Content/ra/v2/expand/mhowdy1.aud: expand/mhowdy1.aud + ^SupportDir|Content/ra/v2/expand/mhuh1.aud: expand/mhuh1.aud + ^SupportDir|Content/ra/v2/expand/mlaff1.aud: expand/mlaff1.aud + ^SupportDir|Content/ra/v2/expand/mrise1.aud: expand/mrise1.aud + ^SupportDir|Content/ra/v2/expand/mwrench1.aud: expand/mwrench1.aud + ^SupportDir|Content/ra/v2/expand/myeehaw1.aud: expand/myeehaw1.aud + ^SupportDir|Content/ra/v2/expand/myes1.aud: expand/myes1.aud + ^SupportDir|Content/ra/v2/cnc/desert.mix: cnc/desert.mix basefiles: Base Freeware Content SHA1: aa022b208a3b45b4a45c00fdae22ccf3c6de3e5c MirrorList: http://www.openra.net/packages/ra-base-mirrors.txt Extract: - ^Content/ra/v2/allies.mix: allies.mix - ^Content/ra/v2/conquer.mix: conquer.mix - ^Content/ra/v2/hires.mix: hires.mix - ^Content/ra/v2/interior.mix: interior.mix - ^Content/ra/v2/local.mix: local.mix - ^Content/ra/v2/lores.mix: lores.mix - ^Content/ra/v2/russian.mix: russian.mix - ^Content/ra/v2/snow.mix: snow.mix - ^Content/ra/v2/sounds.mix: sounds.mix - ^Content/ra/v2/speech.mix: speech.mix - ^Content/ra/v2/temperat.mix: temperat.mix + ^SupportDir|Content/ra/v2/allies.mix: allies.mix + ^SupportDir|Content/ra/v2/conquer.mix: conquer.mix + ^SupportDir|Content/ra/v2/hires.mix: hires.mix + ^SupportDir|Content/ra/v2/interior.mix: interior.mix + ^SupportDir|Content/ra/v2/local.mix: local.mix + ^SupportDir|Content/ra/v2/lores.mix: lores.mix + ^SupportDir|Content/ra/v2/russian.mix: russian.mix + ^SupportDir|Content/ra/v2/snow.mix: snow.mix + ^SupportDir|Content/ra/v2/sounds.mix: sounds.mix + ^SupportDir|Content/ra/v2/speech.mix: speech.mix + ^SupportDir|Content/ra/v2/temperat.mix: temperat.mix aftermath: Aftermath Expansion Files SHA1: d511d4363b485e11c63eecf96d4365d42ec4ef5e MirrorList: http://www.openra.net/packages/ra-aftermath-mirrors.txt Extract: - ^Content/ra/v2/expand/chrotnk1.aud: expand/chrotnk1.aud - ^Content/ra/v2/expand/expand2.mix: expand/expand2.mix - ^Content/ra/v2/expand/fixit1.aud: expand/fixit1.aud - ^Content/ra/v2/expand/hires1.mix: expand/hires1.mix - ^Content/ra/v2/expand/jburn1.aud: expand/jburn1.aud - ^Content/ra/v2/expand/jchrge1.aud: expand/jchrge1.aud - ^Content/ra/v2/expand/jcrisp1.aud: expand/jcrisp1.aud - ^Content/ra/v2/expand/jdance1.aud: expand/jdance1.aud - ^Content/ra/v2/expand/jjuice1.aud: expand/jjuice1.aud - ^Content/ra/v2/expand/jjump1.aud: expand/jjump1.aud - ^Content/ra/v2/expand/jlight1.aud: expand/jlight1.aud - ^Content/ra/v2/expand/jpower1.aud: expand/jpower1.aud - ^Content/ra/v2/expand/jshock1.aud: expand/jshock1.aud - ^Content/ra/v2/expand/jyes1.aud: expand/jyes1.aud - ^Content/ra/v2/expand/lores1.mix: expand/lores1.mix - ^Content/ra/v2/expand/madchrg2.aud: expand/madchrg2.aud - ^Content/ra/v2/expand/madexplo.aud: expand/madexplo.aud - ^Content/ra/v2/expand/mboss1.aud: expand/mboss1.aud - ^Content/ra/v2/expand/mhear1.aud: expand/mhear1.aud - ^Content/ra/v2/expand/mhotdig1.aud: expand/mhotdig1.aud - ^Content/ra/v2/expand/mhowdy1.aud: expand/mhowdy1.aud - ^Content/ra/v2/expand/mhuh1.aud: expand/mhuh1.aud - ^Content/ra/v2/expand/mlaff1.aud: expand/mlaff1.aud - ^Content/ra/v2/expand/mrise1.aud: expand/mrise1.aud - ^Content/ra/v2/expand/mwrench1.aud: expand/mwrench1.aud - ^Content/ra/v2/expand/myeehaw1.aud: expand/myeehaw1.aud - ^Content/ra/v2/expand/myes1.aud: expand/myes1.aud + ^SupportDir|Content/ra/v2/expand/chrotnk1.aud: expand/chrotnk1.aud + ^SupportDir|Content/ra/v2/expand/expand2.mix: expand/expand2.mix + ^SupportDir|Content/ra/v2/expand/fixit1.aud: expand/fixit1.aud + ^SupportDir|Content/ra/v2/expand/hires1.mix: expand/hires1.mix + ^SupportDir|Content/ra/v2/expand/jburn1.aud: expand/jburn1.aud + ^SupportDir|Content/ra/v2/expand/jchrge1.aud: expand/jchrge1.aud + ^SupportDir|Content/ra/v2/expand/jcrisp1.aud: expand/jcrisp1.aud + ^SupportDir|Content/ra/v2/expand/jdance1.aud: expand/jdance1.aud + ^SupportDir|Content/ra/v2/expand/jjuice1.aud: expand/jjuice1.aud + ^SupportDir|Content/ra/v2/expand/jjump1.aud: expand/jjump1.aud + ^SupportDir|Content/ra/v2/expand/jlight1.aud: expand/jlight1.aud + ^SupportDir|Content/ra/v2/expand/jpower1.aud: expand/jpower1.aud + ^SupportDir|Content/ra/v2/expand/jshock1.aud: expand/jshock1.aud + ^SupportDir|Content/ra/v2/expand/jyes1.aud: expand/jyes1.aud + ^SupportDir|Content/ra/v2/expand/lores1.mix: expand/lores1.mix + ^SupportDir|Content/ra/v2/expand/madchrg2.aud: expand/madchrg2.aud + ^SupportDir|Content/ra/v2/expand/madexplo.aud: expand/madexplo.aud + ^SupportDir|Content/ra/v2/expand/mboss1.aud: expand/mboss1.aud + ^SupportDir|Content/ra/v2/expand/mhear1.aud: expand/mhear1.aud + ^SupportDir|Content/ra/v2/expand/mhotdig1.aud: expand/mhotdig1.aud + ^SupportDir|Content/ra/v2/expand/mhowdy1.aud: expand/mhowdy1.aud + ^SupportDir|Content/ra/v2/expand/mhuh1.aud: expand/mhuh1.aud + ^SupportDir|Content/ra/v2/expand/mlaff1.aud: expand/mlaff1.aud + ^SupportDir|Content/ra/v2/expand/mrise1.aud: expand/mrise1.aud + ^SupportDir|Content/ra/v2/expand/mwrench1.aud: expand/mwrench1.aud + ^SupportDir|Content/ra/v2/expand/myeehaw1.aud: expand/myeehaw1.aud + ^SupportDir|Content/ra/v2/expand/myes1.aud: expand/myes1.aud cncdesert: C&C Desert Tileset SHA1: 039849f16e39e4722e8c838a393c8a0d6529fd59 MirrorList: http://www.openra.net/packages/ra-cncdesert-mirrors.txt Extract: - ^Content/ra/v2/cnc/desert.mix: cnc/desert.mix - -music: Freeware Music - SHA1: 134200e10b6e85b2d9bd4f0fe370ab57b75d1563 - MirrorList: http://www.openra.net/packages/ra-scores-mirrors.txt - Extract: - ^Content/ra/v2/scores.mix: scores.mix + ^SupportDir|Content/ra/v2/cnc/desert.mix: cnc/desert.mix diff -Nru openra-20200503/mods/ra/installer/firstdecade.yaml openra-20210321/mods/ra/installer/firstdecade.yaml --- openra-20200503/mods/ra/installer/firstdecade.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/installer/firstdecade.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -10,439 +10,439 @@ 4: data4.cab 5: data5.cab Extract: - ^Content/ra/v2/main.mix: Red Alert\\MAIN.MIX - ^Content/ra/v2/redalert.mix: Red Alert\\REDALERT.MIX - ^Content/ra/v2/expand/hires1.mix: Red Alert\\HIRES1.MIX - ^Content/ra/v2/expand/lores1.mix: Red Alert\\LORES1.MIX - ^Content/ra/v2/expand/expand2.mix: Red Alert\\EXPAND2.MIX - ^Content/ra/v2/cnc/desert.mix: CnC\\DESERT.MIX - extract-raw: ^Content/ra/v2/redalert.mix - ^Content/ra/v2/hires.mix: + ^SupportDir|Content/ra/v2/main.mix: Red Alert\\MAIN.MIX + ^SupportDir|Content/ra/v2/redalert.mix: Red Alert\\REDALERT.MIX + ^SupportDir|Content/ra/v2/expand/hires1.mix: Red Alert\\HIRES1.MIX + ^SupportDir|Content/ra/v2/expand/lores1.mix: Red Alert\\LORES1.MIX + ^SupportDir|Content/ra/v2/expand/expand2.mix: Red Alert\\EXPAND2.MIX + ^SupportDir|Content/ra/v2/cnc/desert.mix: CnC\\DESERT.MIX + extract-raw: ^SupportDir|Content/ra/v2/redalert.mix + ^SupportDir|Content/ra/v2/hires.mix: Offset: 650612 Length: 5817417 - ^Content/ra/v2/local.mix: + ^SupportDir|Content/ra/v2/local.mix: Offset: 6468029 Length: 3829837 - ^Content/ra/v2/lores.mix: + ^SupportDir|Content/ra/v2/lores.mix: Offset: 10297866 Length: 754800 - ^Content/ra/v2/speech.mix: + ^SupportDir|Content/ra/v2/speech.mix: Offset: 23042864 Length: 2003464 - delete: ^Content/ra/v2/redalert.mix - extract-raw: ^Content/ra/v2/main.mix - ^Content/ra/v2/movies/aagun.vqa: + delete: ^SupportDir|Content/ra/v2/redalert.mix + extract-raw: ^SupportDir|Content/ra/v2/main.mix + ^SupportDir|Content/ra/v2/movies/aagun.vqa: Offset: 668669829 Length: 3295512 - ^Content/ra/v2/movies/aftrmath.vqa: + ^SupportDir|Content/ra/v2/movies/aftrmath.vqa: Offset: 671965341 Length: 2455774 - ^Content/ra/v2/movies/ally12.vqa: + ^SupportDir|Content/ra/v2/movies/ally12.vqa: Offset: 430652277 Length: 7719544 - ^Content/ra/v2/movies/ally14.vqa: + ^SupportDir|Content/ra/v2/movies/ally14.vqa: Offset: 438371821 Length: 11659080 - ^Content/ra/v2/movies/allyend.vqa: + ^SupportDir|Content/ra/v2/movies/allyend.vqa: Offset: 450030901 Length: 27285692 - ^Content/ra/v2/movies/allymorf.vqa: + ^SupportDir|Content/ra/v2/movies/allymorf.vqa: Offset: 477316593 Length: 916964 - ^Content/ra/v2/movies/apcescpe.vqa: + ^SupportDir|Content/ra/v2/movies/apcescpe.vqa: Offset: 483950063 Length: 1627564 - ^Content/ra/v2/movies/assess.vqa: + ^SupportDir|Content/ra/v2/movies/assess.vqa: Offset: 485577627 Length: 2929218 - ^Content/ra/v2/movies/battle.vqa: + ^SupportDir|Content/ra/v2/movies/battle.vqa: Offset: 488506845 Length: 2881110 - ^Content/ra/v2/movies/binoc.vqa: + ^SupportDir|Content/ra/v2/movies/binoc.vqa: Offset: 491387955 Length: 4045856 - ^Content/ra/v2/movies/bmap.vqa: + ^SupportDir|Content/ra/v2/movies/bmap.vqa: Offset: 495433811 Length: 2411294 - ^Content/ra/v2/movies/brdgtilt.vqa: + ^SupportDir|Content/ra/v2/movies/brdgtilt.vqa: Offset: 497845105 Length: 1581318 - ^Content/ra/v2/movies/cronfail.vqa: + ^SupportDir|Content/ra/v2/movies/cronfail.vqa: Offset: 499426423 Length: 1717214 - ^Content/ra/v2/movies/crontest.vqa: + ^SupportDir|Content/ra/v2/movies/crontest.vqa: Offset: 501143637 Length: 2036620 - ^Content/ra/v2/movies/destroyr.vqa: + ^SupportDir|Content/ra/v2/movies/destroyr.vqa: Offset: 503180257 Length: 2178828 - ^Content/ra/v2/movies/dud.vqa: + ^SupportDir|Content/ra/v2/movies/dud.vqa: Offset: 505359085 Length: 3110418 - ^Content/ra/v2/movies/elevator.vqa: + ^SupportDir|Content/ra/v2/movies/elevator.vqa: Offset: 508469503 Length: 1741894 - ^Content/ra/v2/movies/flare.vqa: + ^SupportDir|Content/ra/v2/movies/flare.vqa: Offset: 511722609 Length: 1731744 - ^Content/ra/v2/movies/frozen.vqa: + ^SupportDir|Content/ra/v2/movies/frozen.vqa: Offset: 513454353 Length: 1836994 - ^Content/ra/v2/movies/grvestne.vqa: + ^SupportDir|Content/ra/v2/movies/grvestne.vqa: Offset: 515291347 Length: 3155668 - ^Content/ra/v2/movies/landing.vqa: + ^SupportDir|Content/ra/v2/movies/landing.vqa: Offset: 518447015 Length: 2374106 - ^Content/ra/v2/movies/masasslt.vqa: + ^SupportDir|Content/ra/v2/movies/masasslt.vqa: Offset: 520821121 Length: 5354700 - ^Content/ra/v2/movies/mcv.vqa: + ^SupportDir|Content/ra/v2/movies/mcv.vqa: Offset: 526175821 Length: 1296036 - ^Content/ra/v2/movies/mcv_land.vqa: + ^SupportDir|Content/ra/v2/movies/mcv_land.vqa: Offset: 527471857 Length: 1424358 - ^Content/ra/v2/movies/montpass.vqa: + ^SupportDir|Content/ra/v2/movies/montpass.vqa: Offset: 528896215 Length: 1701852 - ^Content/ra/v2/movies/oildrum.vqa: + ^SupportDir|Content/ra/v2/movies/oildrum.vqa: Offset: 530598067 Length: 2430792 - ^Content/ra/v2/movies/overrun.vqa: + ^SupportDir|Content/ra/v2/movies/overrun.vqa: Offset: 533028859 Length: 2174548 - ^Content/ra/v2/movies/prolog.vqa: + ^SupportDir|Content/ra/v2/movies/prolog.vqa: Offset: 535203407 Length: 28658198 - ^Content/ra/v2/movies/redintro.vqa: + ^SupportDir|Content/ra/v2/movies/redintro.vqa: Offset: 563861605 Length: 2269452 - ^Content/ra/v2/movies/shipsink.vqa: + ^SupportDir|Content/ra/v2/movies/shipsink.vqa: Offset: 567961011 Length: 3150030 - ^Content/ra/v2/movies/shorbom1.vqa: + ^SupportDir|Content/ra/v2/movies/shorbom1.vqa: Offset: 571111041 Length: 4046650 - ^Content/ra/v2/movies/shorbom2.vqa: + ^SupportDir|Content/ra/v2/movies/shorbom2.vqa: Offset: 575157691 Length: 2150364 - ^Content/ra/v2/movies/shorbomb.vqa: + ^SupportDir|Content/ra/v2/movies/shorbomb.vqa: Offset: 577308055 Length: 6111616 - ^Content/ra/v2/movies/snowbomb.vqa: + ^SupportDir|Content/ra/v2/movies/snowbomb.vqa: Offset: 583419671 Length: 2465762 - ^Content/ra/v2/movies/soviet1.vqa: + ^SupportDir|Content/ra/v2/movies/soviet1.vqa: Offset: 594906599 Length: 24112060 - ^Content/ra/v2/movies/sovtstar.vqa: + ^SupportDir|Content/ra/v2/movies/sovtstar.vqa: Offset: 619018659 Length: 670794 - ^Content/ra/v2/movies/spy.vqa: + ^SupportDir|Content/ra/v2/movies/spy.vqa: Offset: 619689453 Length: 1646808 - ^Content/ra/v2/movies/tanya1.vqa: + ^SupportDir|Content/ra/v2/movies/tanya1.vqa: Offset: 621336261 Length: 13389684 - ^Content/ra/v2/movies/tanya2.vqa: + ^SupportDir|Content/ra/v2/movies/tanya2.vqa: Offset: 634725945 Length: 4103388 - ^Content/ra/v2/movies/toofar.vqa: + ^SupportDir|Content/ra/v2/movies/toofar.vqa: Offset: 640625425 Length: 4244572 - ^Content/ra/v2/movies/trinity.vqa: + ^SupportDir|Content/ra/v2/movies/trinity.vqa: Offset: 644869997 Length: 1669310 - ^Content/ra/v2/movies/ally1.vqa: + ^SupportDir|Content/ra/v2/movies/ally1.vqa: Offset: 674421115 Length: 13536324 - ^Content/ra/v2/movies/ally2.vqa: + ^SupportDir|Content/ra/v2/movies/ally2.vqa: Offset: 687957439 Length: 8014018 - ^Content/ra/v2/movies/ally4.vqa: + ^SupportDir|Content/ra/v2/movies/ally4.vqa: Offset: 695971457 Length: 9441906 - ^Content/ra/v2/movies/ally5.vqa: + ^SupportDir|Content/ra/v2/movies/ally5.vqa: Offset: 705413363 Length: 21900328 - ^Content/ra/v2/movies/ally6.vqa: + ^SupportDir|Content/ra/v2/movies/ally6.vqa: Offset: 727313691 Length: 26454212 - ^Content/ra/v2/movies/ally8.vqa: + ^SupportDir|Content/ra/v2/movies/ally8.vqa: Offset: 753767903 Length: 15401062 - ^Content/ra/v2/movies/ally9.vqa: + ^SupportDir|Content/ra/v2/movies/ally9.vqa: Offset: 769168965 Length: 14901460 - ^Content/ra/v2/movies/ally10.vqa: + ^SupportDir|Content/ra/v2/movies/ally10.vqa: Offset: 784070425 Length: 21506358 - ^Content/ra/v2/movies/ally10b.vqa: + ^SupportDir|Content/ra/v2/movies/ally10b.vqa: Offset: 805576783 Length: 2565152 - ^Content/ra/v2/movies/ally11.vqa: + ^SupportDir|Content/ra/v2/movies/ally11.vqa: Offset: 808142713 Length: 13600398 - ^Content/ra/v2/interior.mix: + ^SupportDir|Content/ra/v2/interior.mix: Offset: 821743111 Length: 249490 - ^Content/ra/v2/conquer.mix: + ^SupportDir|Content/ra/v2/conquer.mix: Offset: 840028549 Length: 2192279 - ^Content/ra/v2/allies.mix: + ^SupportDir|Content/ra/v2/allies.mix: Offset: 842220828 Length: 319181 - ^Content/ra/v2/temperat.mix: + ^SupportDir|Content/ra/v2/temperat.mix: Offset: 842540009 Length: 1043672 - ^Content/ra/v2/sounds.mix: + ^SupportDir|Content/ra/v2/sounds.mix: Offset: 843583681 Length: 1385637 - ^Content/ra/v2/snow.mix: + ^SupportDir|Content/ra/v2/snow.mix: Offset: 844969318 Length: 1035716 - ^Content/ra/v2/scores.mix: + ^SupportDir|Content/ra/v2/scores.mix: Offset: 846005034 Length: 67742203 - ^Content/ra/v2/russian.mix: + ^SupportDir|Content/ra/v2/russian.mix: Offset: 913747237 Length: 274732 - ^Content/ra/v2/movies/double.vqa: + ^SupportDir|Content/ra/v2/movies/double.vqa: Offset: 915739478 Length: 1608508 - ^Content/ra/v2/movies/dpthchrg.vqa: + ^SupportDir|Content/ra/v2/movies/dpthchrg.vqa: Offset: 917347986 Length: 3048762 - ^Content/ra/v2/movies/execute.vqa: + ^SupportDir|Content/ra/v2/movies/execute.vqa: Offset: 920396748 Length: 1511212 - ^Content/ra/v2/movies/flare.vqa: + ^SupportDir|Content/ra/v2/movies/flare.vqa: Offset: 921907960 Length: 1731744 - ^Content/ra/v2/movies/landing.vqa: + ^SupportDir|Content/ra/v2/movies/landing.vqa: Offset: 923639704 Length: 2374106 - ^Content/ra/v2/movies/mcvbrdge.vqa: + ^SupportDir|Content/ra/v2/movies/mcvbrdge.vqa: Offset: 926013810 Length: 2124412 - ^Content/ra/v2/movies/mig.vqa: + ^SupportDir|Content/ra/v2/movies/mig.vqa: Offset: 928138222 Length: 6745398 - ^Content/ra/v2/movies/movingin.vqa: + ^SupportDir|Content/ra/v2/movies/movingin.vqa: Offset: 934883620 Length: 1185550 - ^Content/ra/v2/movies/mtnkfact.vqa: + ^SupportDir|Content/ra/v2/movies/mtnkfact.vqa: Offset: 936069170 Length: 3168076 - ^Content/ra/v2/movies/nukestok.vqa: + ^SupportDir|Content/ra/v2/movies/nukestok.vqa: Offset: 939237246 Length: 1877536 - ^Content/ra/v2/movies/onthprwl.vqa: + ^SupportDir|Content/ra/v2/movies/onthprwl.vqa: Offset: 941114782 Length: 2648948 - ^Content/ra/v2/movies/periscop.vqa: + ^SupportDir|Content/ra/v2/movies/periscop.vqa: Offset: 943763730 Length: 2099110 - ^Content/ra/v2/movies/prolog.vqa: + ^SupportDir|Content/ra/v2/movies/prolog.vqa: Offset: 945862840 Length: 28658198 - ^Content/ra/v2/movies/radrraid.vqa: + ^SupportDir|Content/ra/v2/movies/radrraid.vqa: Offset: 974521038 Length: 1561740 - ^Content/ra/v2/movies/redintro.vqa: + ^SupportDir|Content/ra/v2/movies/redintro.vqa: Offset: 976082778 Length: 2269452 - ^Content/ra/v2/movies/search.vqa: + ^SupportDir|Content/ra/v2/movies/search.vqa: Offset: 978352230 Length: 2298940 - ^Content/ra/v2/movies/sfrozen.vqa: + ^SupportDir|Content/ra/v2/movies/sfrozen.vqa: Offset: 980651170 Length: 1829954 - ^Content/ra/v2/movies/sitduck.vqa: + ^SupportDir|Content/ra/v2/movies/sitduck.vqa: Offset: 982481124 Length: 3650212 - ^Content/ra/v2/movies/slntsrvc.vqa: + ^SupportDir|Content/ra/v2/movies/slntsrvc.vqa: Offset: 986131336 Length: 1774986 - ^Content/ra/v2/movies/snowbomb.vqa: + ^SupportDir|Content/ra/v2/movies/snowbomb.vqa: Offset: 987906322 Length: 2465762 - ^Content/ra/v2/movies/snstrafe.vqa: + ^SupportDir|Content/ra/v2/movies/snstrafe.vqa: Offset: 990372084 Length: 2473362 - ^Content/ra/v2/movies/sovbatl.vqa: + ^SupportDir|Content/ra/v2/movies/sovbatl.vqa: Offset: 992845446 Length: 3439876 - ^Content/ra/v2/movies/sovcemet.vqa: + ^SupportDir|Content/ra/v2/movies/sovcemet.vqa: Offset: 996285322 Length: 3107928 - ^Content/ra/v2/movies/sovfinal.vqa: + ^SupportDir|Content/ra/v2/movies/sovfinal.vqa: Offset: 999393250 Length: 35169890 - ^Content/ra/v2/movies/soviet1.vqa: + ^SupportDir|Content/ra/v2/movies/soviet1.vqa: Offset: 1034563140 Length: 24112060 - ^Content/ra/v2/movies/soviet2.vqa: + ^SupportDir|Content/ra/v2/movies/soviet2.vqa: Offset: 1058675200 Length: 9494814 - ^Content/ra/v2/movies/soviet3.vqa: + ^SupportDir|Content/ra/v2/movies/soviet3.vqa: Offset: 1068170014 Length: 17229910 - ^Content/ra/v2/movies/soviet4.vqa: + ^SupportDir|Content/ra/v2/movies/soviet4.vqa: Offset: 1085399924 Length: 7236290 - ^Content/ra/v2/movies/soviet5.vqa: + ^SupportDir|Content/ra/v2/movies/soviet5.vqa: Offset: 1092636214 Length: 18986154 - ^Content/ra/v2/movies/soviet6.vqa: + ^SupportDir|Content/ra/v2/movies/soviet6.vqa: Offset: 1111622368 Length: 6782016 - ^Content/ra/v2/movies/soviet7.vqa: + ^SupportDir|Content/ra/v2/movies/soviet7.vqa: Offset: 1118404384 Length: 5637552 - ^Content/ra/v2/movies/soviet8.vqa: + ^SupportDir|Content/ra/v2/movies/soviet8.vqa: Offset: 1124041936 Length: 28905880 - ^Content/ra/v2/movies/soviet9.vqa: + ^SupportDir|Content/ra/v2/movies/soviet9.vqa: Offset: 1152947816 Length: 31809450 - ^Content/ra/v2/movies/soviet10.vqa: + ^SupportDir|Content/ra/v2/movies/soviet10.vqa: Offset: 1184757266 Length: 10102944 - ^Content/ra/v2/movies/soviet11.vqa: + ^SupportDir|Content/ra/v2/movies/soviet11.vqa: Offset: 1194860210 Length: 16685840 - ^Content/ra/v2/movies/soviet12.vqa: + ^SupportDir|Content/ra/v2/movies/soviet12.vqa: Offset: 1211546050 Length: 11532038 - ^Content/ra/v2/movies/soviet13.vqa: + ^SupportDir|Content/ra/v2/movies/soviet13.vqa: Offset: 1223078088 Length: 15210482 - ^Content/ra/v2/movies/soviet14.vqa: + ^SupportDir|Content/ra/v2/movies/soviet14.vqa: Offset: 1238288570 Length: 24358232 - ^Content/ra/v2/movies/sovmcv.vqa: + ^SupportDir|Content/ra/v2/movies/sovmcv.vqa: Offset: 1262646802 Length: 1292126 - ^Content/ra/v2/movies/sovtstar.vqa: + ^SupportDir|Content/ra/v2/movies/sovtstar.vqa: Offset: 1263938928 Length: 670794 - ^Content/ra/v2/movies/spotter.vqa: + ^SupportDir|Content/ra/v2/movies/spotter.vqa: Offset: 1264609722 Length: 1346422 - ^Content/ra/v2/movies/strafe.vqa: + ^SupportDir|Content/ra/v2/movies/strafe.vqa: Offset: 1265956144 Length: 1226956 - ^Content/ra/v2/movies/take_off.vqa: + ^SupportDir|Content/ra/v2/movies/take_off.vqa: Offset: 1267183100 Length: 1419370 - ^Content/ra/v2/movies/tesla.vqa: + ^SupportDir|Content/ra/v2/movies/tesla.vqa: Offset: 1268602470 Length: 1796092 - ^Content/ra/v2/movies/v2rocket.vqa: + ^SupportDir|Content/ra/v2/movies/v2rocket.vqa: Offset: 1270398562 Length: 1856524 - ^Content/ra/v2/movies/aagun.vqa: + ^SupportDir|Content/ra/v2/movies/aagun.vqa: Offset: 1292529084 Length: 3295512 - ^Content/ra/v2/movies/airfield.vqa: + ^SupportDir|Content/ra/v2/movies/airfield.vqa: Offset: 1295824596 Length: 2696058 - ^Content/ra/v2/movies/ally1.vqa: + ^SupportDir|Content/ra/v2/movies/ally1.vqa: Offset: 1298520654 Length: 13536324 - ^Content/ra/v2/movies/allymorf.vqa: + ^SupportDir|Content/ra/v2/movies/allymorf.vqa: Offset: 1312056978 Length: 916964 - ^Content/ra/v2/movies/averted.vqa: + ^SupportDir|Content/ra/v2/movies/averted.vqa: Offset: 1312973942 Length: 1902556 - ^Content/ra/v2/movies/beachead.vqa: + ^SupportDir|Content/ra/v2/movies/beachead.vqa: Offset: 1314876498 Length: 4891790 - ^Content/ra/v2/movies/bmap.vqa: + ^SupportDir|Content/ra/v2/movies/bmap.vqa: Offset: 1319768288 Length: 2414312 - ^Content/ra/v2/movies/bombrun.vqa: + ^SupportDir|Content/ra/v2/movies/bombrun.vqa: Offset: 1322182600 Length: 5167450 - ^Content/ra/v2/movies/countdwn.vqa: + ^SupportDir|Content/ra/v2/movies/countdwn.vqa: Offset: 1327350050 Length: 2005906 - ^Content/ra/v2/movies/cronfail.vqa: + ^SupportDir|Content/ra/v2/movies/cronfail.vqa: Offset: 1329356707 Length: 1717214 - ^Content/ra/v2/expand/chrotnk1.aud: + ^SupportDir|Content/ra/v2/expand/chrotnk1.aud: Offset: 843615985 Length: 22900 - ^Content/ra/v2/expand/fixit1.aud: + ^SupportDir|Content/ra/v2/expand/fixit1.aud: Offset: 843860963 Length: 10707 - ^Content/ra/v2/expand/jburn1.aud: + ^SupportDir|Content/ra/v2/expand/jburn1.aud: Offset: 844007001 Length: 23091 - ^Content/ra/v2/expand/jchrge1.aud: + ^SupportDir|Content/ra/v2/expand/jchrge1.aud: Offset: 844030092 Length: 14219 - ^Content/ra/v2/expand/jcrisp1.aud: + ^SupportDir|Content/ra/v2/expand/jcrisp1.aud: Offset: 844044311 Length: 18211 - ^Content/ra/v2/expand/jdance1.aud: + ^SupportDir|Content/ra/v2/expand/jdance1.aud: Offset: 844062522 Length: 14315 - ^Content/ra/v2/expand/jjuice1.aud: + ^SupportDir|Content/ra/v2/expand/jjuice1.aud: Offset: 844076837 Length: 9699 - ^Content/ra/v2/expand/jjump1.aud: + ^SupportDir|Content/ra/v2/expand/jjump1.aud: Offset: 844086536 Length: 8219 - ^Content/ra/v2/expand/jlight1.aud: + ^SupportDir|Content/ra/v2/expand/jlight1.aud: Offset: 844094755 Length: 9875 - ^Content/ra/v2/expand/jpower1.aud: + ^SupportDir|Content/ra/v2/expand/jpower1.aud: Offset: 844104630 Length: 13571 - ^Content/ra/v2/expand/jshock1.aud: + ^SupportDir|Content/ra/v2/expand/jshock1.aud: Offset: 844118201 Length: 14771 - ^Content/ra/v2/expand/jyes1.aud: + ^SupportDir|Content/ra/v2/expand/jyes1.aud: Offset: 844132972 Length: 13795 - ^Content/ra/v2/expand/madchrg2.aud: + ^SupportDir|Content/ra/v2/expand/madchrg2.aud: Offset: 844262883 Length: 19782 - ^Content/ra/v2/expand/madexplo.aud: + ^SupportDir|Content/ra/v2/expand/madexplo.aud: Offset: 844282665 Length: 26572 - ^Content/ra/v2/expand/mboss1.aud: + ^SupportDir|Content/ra/v2/expand/mboss1.aud: Offset: 844314713 Length: 20147 - ^Content/ra/v2/expand/mhear1.aud: + ^SupportDir|Content/ra/v2/expand/mhear1.aud: Offset: 844340048 Length: 6714 - ^Content/ra/v2/expand/mhotdig1.aud: + ^SupportDir|Content/ra/v2/expand/mhotdig1.aud: Offset: 844346762 Length: 10674 - ^Content/ra/v2/expand/mhowdy1.aud: + ^SupportDir|Content/ra/v2/expand/mhowdy1.aud: Offset: 844357436 Length: 6714 - ^Content/ra/v2/expand/mhuh1.aud: + ^SupportDir|Content/ra/v2/expand/mhuh1.aud: Offset: 844364150 Length: 4117 - ^Content/ra/v2/expand/mlaff1.aud: + ^SupportDir|Content/ra/v2/expand/mlaff1.aud: Offset: 844428954 Length: 24133 - ^Content/ra/v2/expand/mrise1.aud: + ^SupportDir|Content/ra/v2/expand/mrise1.aud: Offset: 844466487 Length: 13523 - ^Content/ra/v2/expand/mwrench1.aud: + ^SupportDir|Content/ra/v2/expand/mwrench1.aud: Offset: 844480010 Length: 10780 - ^Content/ra/v2/expand/myeehaw1.aud: + ^SupportDir|Content/ra/v2/expand/myeehaw1.aud: Offset: 844490790 Length: 18912 - ^Content/ra/v2/expand/myes1.aud: + ^SupportDir|Content/ra/v2/expand/myes1.aud: Offset: 844509702 Length: 9073 - delete: ^Content/ra/v2/main.mix \ No newline at end of file + delete: ^SupportDir|Content/ra/v2/main.mix \ No newline at end of file diff -Nru openra-20200503/mods/ra/installer/origin.yaml openra-20210321/mods/ra/installer/origin.yaml --- openra-20200503/mods/ra/installer/origin.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/installer/origin.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,452 +7,452 @@ REDALERT.MIX: 0e58f4b54f44f6cd29fecf8cf379d33cf2d4caef Install: copy: . - ^Content/ra/v2/expand/2nd_hand.aud: 2nd_hand.aud - ^Content/ra/v2/expand/araziod.aud: araziod.aud - ^Content/ra/v2/expand/await.aud: await.aud - ^Content/ra/v2/expand/backstab.aud: backstab.aud - ^Content/ra/v2/expand/bog.aud: bog.aud - ^Content/ra/v2/expand/chaos2.aud: chaos2.aud - ^Content/ra/v2/expand/float_v2.aud: float_v2.aud - ^Content/ra/v2/expand/gloom.aud: gloom.aud - ^Content/ra/v2/expand/grndwire.aud: grndwire.aud - ^Content/ra/v2/expand/rpt.aud: rpt.aud - ^Content/ra/v2/expand/search.aud: search.aud - ^Content/ra/v2/expand/shut_it.aud: shut_it.aud - ^Content/ra/v2/expand/traction.aud: traction.aud - ^Content/ra/v2/expand/twinmix1.aud: twinmix1.aud - ^Content/ra/v2/expand/under3.aud: under3.aud - ^Content/ra/v2/expand/vr2.aud: vr2.aud - ^Content/ra/v2/expand/wastelnd.aud: wastelnd.aud - ^Content/ra/v2/expand/expand2.mix: EXPAND2.MIX - ^Content/ra/v2/expand/hires1.mix: HIRES1.MIX - ^Content/ra/v2/expand/lores1.mix: LORES1.MIX + ^SupportDir|Content/ra/v2/expand/2nd_hand.aud: 2nd_hand.aud + ^SupportDir|Content/ra/v2/expand/araziod.aud: araziod.aud + ^SupportDir|Content/ra/v2/expand/await.aud: await.aud + ^SupportDir|Content/ra/v2/expand/backstab.aud: backstab.aud + ^SupportDir|Content/ra/v2/expand/bog.aud: bog.aud + ^SupportDir|Content/ra/v2/expand/chaos2.aud: chaos2.aud + ^SupportDir|Content/ra/v2/expand/float_v2.aud: float_v2.aud + ^SupportDir|Content/ra/v2/expand/gloom.aud: gloom.aud + ^SupportDir|Content/ra/v2/expand/grndwire.aud: grndwire.aud + ^SupportDir|Content/ra/v2/expand/rpt.aud: rpt.aud + ^SupportDir|Content/ra/v2/expand/search.aud: search.aud + ^SupportDir|Content/ra/v2/expand/shut_it.aud: shut_it.aud + ^SupportDir|Content/ra/v2/expand/traction.aud: traction.aud + ^SupportDir|Content/ra/v2/expand/twinmix1.aud: twinmix1.aud + ^SupportDir|Content/ra/v2/expand/under3.aud: under3.aud + ^SupportDir|Content/ra/v2/expand/vr2.aud: vr2.aud + ^SupportDir|Content/ra/v2/expand/wastelnd.aud: wastelnd.aud + ^SupportDir|Content/ra/v2/expand/expand2.mix: EXPAND2.MIX + ^SupportDir|Content/ra/v2/expand/hires1.mix: HIRES1.MIX + ^SupportDir|Content/ra/v2/expand/lores1.mix: LORES1.MIX extract-raw: REDALERT.MIX - ^Content/ra/v2/hires.mix: + ^SupportDir|Content/ra/v2/hires.mix: Offset: 650612 Length: 5817417 - ^Content/ra/v2/local.mix: + ^SupportDir|Content/ra/v2/local.mix: Offset: 6468029 Length: 3829837 - ^Content/ra/v2/lores.mix: + ^SupportDir|Content/ra/v2/lores.mix: Offset: 10297866 Length: 754800 - ^Content/ra/v2/speech.mix: + ^SupportDir|Content/ra/v2/speech.mix: Offset: 23042864 Length: 2003464 extract-raw: MAIN.MIX - ^Content/ra/v2/movies/aagun.vqa: + ^SupportDir|Content/ra/v2/movies/aagun.vqa: Offset: 668669829 Length: 3295512 - ^Content/ra/v2/movies/aftrmath.vqa: + ^SupportDir|Content/ra/v2/movies/aftrmath.vqa: Offset: 671965341 Length: 2455774 - ^Content/ra/v2/movies/ally12.vqa: + ^SupportDir|Content/ra/v2/movies/ally12.vqa: Offset: 430652277 Length: 7719544 - ^Content/ra/v2/movies/ally14.vqa: + ^SupportDir|Content/ra/v2/movies/ally14.vqa: Offset: 438371821 Length: 11659080 - ^Content/ra/v2/movies/allyend.vqa: + ^SupportDir|Content/ra/v2/movies/allyend.vqa: Offset: 450030901 Length: 27285692 - ^Content/ra/v2/movies/allymorf.vqa: + ^SupportDir|Content/ra/v2/movies/allymorf.vqa: Offset: 477316593 Length: 916964 - ^Content/ra/v2/movies/apcescpe.vqa: + ^SupportDir|Content/ra/v2/movies/apcescpe.vqa: Offset: 483950063 Length: 1627564 - ^Content/ra/v2/movies/assess.vqa: + ^SupportDir|Content/ra/v2/movies/assess.vqa: Offset: 485577627 Length: 2929218 - ^Content/ra/v2/movies/battle.vqa: + ^SupportDir|Content/ra/v2/movies/battle.vqa: Offset: 488506845 Length: 2881110 - ^Content/ra/v2/movies/binoc.vqa: + ^SupportDir|Content/ra/v2/movies/binoc.vqa: Offset: 491387955 Length: 4045856 - ^Content/ra/v2/movies/bmap.vqa: + ^SupportDir|Content/ra/v2/movies/bmap.vqa: Offset: 495433811 Length: 2411294 - ^Content/ra/v2/movies/brdgtilt.vqa: + ^SupportDir|Content/ra/v2/movies/brdgtilt.vqa: Offset: 497845105 Length: 1581318 - ^Content/ra/v2/movies/cronfail.vqa: + ^SupportDir|Content/ra/v2/movies/cronfail.vqa: Offset: 499426423 Length: 1717214 - ^Content/ra/v2/movies/crontest.vqa: + ^SupportDir|Content/ra/v2/movies/crontest.vqa: Offset: 501143637 Length: 2036620 - ^Content/ra/v2/movies/destroyr.vqa: + ^SupportDir|Content/ra/v2/movies/destroyr.vqa: Offset: 503180257 Length: 2178828 - ^Content/ra/v2/movies/dud.vqa: + ^SupportDir|Content/ra/v2/movies/dud.vqa: Offset: 505359085 Length: 3110418 - ^Content/ra/v2/movies/elevator.vqa: + ^SupportDir|Content/ra/v2/movies/elevator.vqa: Offset: 508469503 Length: 1741894 - ^Content/ra/v2/movies/flare.vqa: + ^SupportDir|Content/ra/v2/movies/flare.vqa: Offset: 511722609 Length: 1731744 - ^Content/ra/v2/movies/frozen.vqa: + ^SupportDir|Content/ra/v2/movies/frozen.vqa: Offset: 513454353 Length: 1836994 - ^Content/ra/v2/movies/grvestne.vqa: + ^SupportDir|Content/ra/v2/movies/grvestne.vqa: Offset: 515291347 Length: 3155668 - ^Content/ra/v2/movies/landing.vqa: + ^SupportDir|Content/ra/v2/movies/landing.vqa: Offset: 518447015 Length: 2374106 - ^Content/ra/v2/movies/masasslt.vqa: + ^SupportDir|Content/ra/v2/movies/masasslt.vqa: Offset: 520821121 Length: 5354700 - ^Content/ra/v2/movies/mcv.vqa: + ^SupportDir|Content/ra/v2/movies/mcv.vqa: Offset: 526175821 Length: 1296036 - ^Content/ra/v2/movies/mcv_land.vqa: + ^SupportDir|Content/ra/v2/movies/mcv_land.vqa: Offset: 527471857 Length: 1424358 - ^Content/ra/v2/movies/montpass.vqa: + ^SupportDir|Content/ra/v2/movies/montpass.vqa: Offset: 528896215 Length: 1701852 - ^Content/ra/v2/movies/oildrum.vqa: + ^SupportDir|Content/ra/v2/movies/oildrum.vqa: Offset: 530598067 Length: 2430792 - ^Content/ra/v2/movies/overrun.vqa: + ^SupportDir|Content/ra/v2/movies/overrun.vqa: Offset: 533028859 Length: 2174548 - ^Content/ra/v2/movies/prolog.vqa: + ^SupportDir|Content/ra/v2/movies/prolog.vqa: Offset: 535203407 Length: 28658198 - ^Content/ra/v2/movies/redintro.vqa: + ^SupportDir|Content/ra/v2/movies/redintro.vqa: Offset: 563861605 Length: 2269452 - ^Content/ra/v2/movies/shipsink.vqa: + ^SupportDir|Content/ra/v2/movies/shipsink.vqa: Offset: 567961011 Length: 3150030 - ^Content/ra/v2/movies/shorbom1.vqa: + ^SupportDir|Content/ra/v2/movies/shorbom1.vqa: Offset: 571111041 Length: 4046650 - ^Content/ra/v2/movies/shorbom2.vqa: + ^SupportDir|Content/ra/v2/movies/shorbom2.vqa: Offset: 575157691 Length: 2150364 - ^Content/ra/v2/movies/shorbomb.vqa: + ^SupportDir|Content/ra/v2/movies/shorbomb.vqa: Offset: 577308055 Length: 6111616 - ^Content/ra/v2/movies/snowbomb.vqa: + ^SupportDir|Content/ra/v2/movies/snowbomb.vqa: Offset: 583419671 Length: 2465762 - ^Content/ra/v2/movies/soviet1.vqa: + ^SupportDir|Content/ra/v2/movies/soviet1.vqa: Offset: 594906599 Length: 24112060 - ^Content/ra/v2/movies/sovtstar.vqa: + ^SupportDir|Content/ra/v2/movies/sovtstar.vqa: Offset: 619018659 Length: 670794 - ^Content/ra/v2/movies/spy.vqa: + ^SupportDir|Content/ra/v2/movies/spy.vqa: Offset: 619689453 Length: 1646808 - ^Content/ra/v2/movies/tanya1.vqa: + ^SupportDir|Content/ra/v2/movies/tanya1.vqa: Offset: 621336261 Length: 13389684 - ^Content/ra/v2/movies/tanya2.vqa: + ^SupportDir|Content/ra/v2/movies/tanya2.vqa: Offset: 634725945 Length: 4103388 - ^Content/ra/v2/movies/toofar.vqa: + ^SupportDir|Content/ra/v2/movies/toofar.vqa: Offset: 640625425 Length: 4244572 - ^Content/ra/v2/movies/trinity.vqa: + ^SupportDir|Content/ra/v2/movies/trinity.vqa: Offset: 644869997 Length: 1669310 - ^Content/ra/v2/movies/ally1.vqa: + ^SupportDir|Content/ra/v2/movies/ally1.vqa: Offset: 674421115 Length: 13536324 - ^Content/ra/v2/movies/ally2.vqa: + ^SupportDir|Content/ra/v2/movies/ally2.vqa: Offset: 687957439 Length: 8014018 - ^Content/ra/v2/movies/ally4.vqa: + ^SupportDir|Content/ra/v2/movies/ally4.vqa: Offset: 695971457 Length: 9441906 - ^Content/ra/v2/movies/ally5.vqa: + ^SupportDir|Content/ra/v2/movies/ally5.vqa: Offset: 705413363 Length: 21900328 - ^Content/ra/v2/movies/ally6.vqa: + ^SupportDir|Content/ra/v2/movies/ally6.vqa: Offset: 727313691 Length: 26454212 - ^Content/ra/v2/movies/ally8.vqa: + ^SupportDir|Content/ra/v2/movies/ally8.vqa: Offset: 753767903 Length: 15401062 - ^Content/ra/v2/movies/ally9.vqa: + ^SupportDir|Content/ra/v2/movies/ally9.vqa: Offset: 769168965 Length: 14901460 - ^Content/ra/v2/movies/ally10.vqa: + ^SupportDir|Content/ra/v2/movies/ally10.vqa: Offset: 784070425 Length: 21506358 - ^Content/ra/v2/movies/ally10b.vqa: + ^SupportDir|Content/ra/v2/movies/ally10b.vqa: Offset: 805576783 Length: 2565152 - ^Content/ra/v2/movies/ally11.vqa: + ^SupportDir|Content/ra/v2/movies/ally11.vqa: Offset: 808142713 Length: 13600398 - ^Content/ra/v2/interior.mix: + ^SupportDir|Content/ra/v2/interior.mix: Offset: 821743111 Length: 249490 - ^Content/ra/v2/conquer.mix: + ^SupportDir|Content/ra/v2/conquer.mix: Offset: 840028549 Length: 2192279 - ^Content/ra/v2/allies.mix: + ^SupportDir|Content/ra/v2/allies.mix: Offset: 842220828 Length: 319181 - ^Content/ra/v2/temperat.mix: + ^SupportDir|Content/ra/v2/temperat.mix: Offset: 842540009 Length: 1043672 - ^Content/ra/v2/sounds.mix: + ^SupportDir|Content/ra/v2/sounds.mix: Offset: 843583681 Length: 1385637 - ^Content/ra/v2/snow.mix: + ^SupportDir|Content/ra/v2/snow.mix: Offset: 844969318 Length: 1035716 - ^Content/ra/v2/scores.mix: + ^SupportDir|Content/ra/v2/scores.mix: Offset: 846005034 Length: 67742203 - ^Content/ra/v2/russian.mix: + ^SupportDir|Content/ra/v2/russian.mix: Offset: 913747237 Length: 274732 - ^Content/ra/v2/movies/double.vqa: + ^SupportDir|Content/ra/v2/movies/double.vqa: Offset: 915739478 Length: 1608508 - ^Content/ra/v2/movies/dpthchrg.vqa: + ^SupportDir|Content/ra/v2/movies/dpthchrg.vqa: Offset: 917347986 Length: 3048762 - ^Content/ra/v2/movies/execute.vqa: + ^SupportDir|Content/ra/v2/movies/execute.vqa: Offset: 920396748 Length: 1511212 - ^Content/ra/v2/movies/flare.vqa: + ^SupportDir|Content/ra/v2/movies/flare.vqa: Offset: 921907960 Length: 1731744 - ^Content/ra/v2/movies/landing.vqa: + ^SupportDir|Content/ra/v2/movies/landing.vqa: Offset: 923639704 Length: 2374106 - ^Content/ra/v2/movies/mcvbrdge.vqa: + ^SupportDir|Content/ra/v2/movies/mcvbrdge.vqa: Offset: 926013810 Length: 2124412 - ^Content/ra/v2/movies/mig.vqa: + ^SupportDir|Content/ra/v2/movies/mig.vqa: Offset: 928138222 Length: 6745398 - ^Content/ra/v2/movies/movingin.vqa: + ^SupportDir|Content/ra/v2/movies/movingin.vqa: Offset: 934883620 Length: 1185550 - ^Content/ra/v2/movies/mtnkfact.vqa: + ^SupportDir|Content/ra/v2/movies/mtnkfact.vqa: Offset: 936069170 Length: 3168076 - ^Content/ra/v2/movies/nukestok.vqa: + ^SupportDir|Content/ra/v2/movies/nukestok.vqa: Offset: 939237246 Length: 1877536 - ^Content/ra/v2/movies/onthprwl.vqa: + ^SupportDir|Content/ra/v2/movies/onthprwl.vqa: Offset: 941114782 Length: 2648948 - ^Content/ra/v2/movies/periscop.vqa: + ^SupportDir|Content/ra/v2/movies/periscop.vqa: Offset: 943763730 Length: 2099110 - ^Content/ra/v2/movies/prolog.vqa: + ^SupportDir|Content/ra/v2/movies/prolog.vqa: Offset: 945862840 Length: 28658198 - ^Content/ra/v2/movies/radrraid.vqa: + ^SupportDir|Content/ra/v2/movies/radrraid.vqa: Offset: 974521038 Length: 1561740 - ^Content/ra/v2/movies/redintro.vqa: + ^SupportDir|Content/ra/v2/movies/redintro.vqa: Offset: 976082778 Length: 2269452 - ^Content/ra/v2/movies/search.vqa: + ^SupportDir|Content/ra/v2/movies/search.vqa: Offset: 978352230 Length: 2298940 - ^Content/ra/v2/movies/sfrozen.vqa: + ^SupportDir|Content/ra/v2/movies/sfrozen.vqa: Offset: 980651170 Length: 1829954 - ^Content/ra/v2/movies/sitduck.vqa: + ^SupportDir|Content/ra/v2/movies/sitduck.vqa: Offset: 982481124 Length: 3650212 - ^Content/ra/v2/movies/slntsrvc.vqa: + ^SupportDir|Content/ra/v2/movies/slntsrvc.vqa: Offset: 986131336 Length: 1774986 - ^Content/ra/v2/movies/snowbomb.vqa: + ^SupportDir|Content/ra/v2/movies/snowbomb.vqa: Offset: 987906322 Length: 2465762 - ^Content/ra/v2/movies/snstrafe.vqa: + ^SupportDir|Content/ra/v2/movies/snstrafe.vqa: Offset: 990372084 Length: 2473362 - ^Content/ra/v2/movies/sovbatl.vqa: + ^SupportDir|Content/ra/v2/movies/sovbatl.vqa: Offset: 992845446 Length: 3439876 - ^Content/ra/v2/movies/sovcemet.vqa: + ^SupportDir|Content/ra/v2/movies/sovcemet.vqa: Offset: 996285322 Length: 3107928 - ^Content/ra/v2/movies/sovfinal.vqa: + ^SupportDir|Content/ra/v2/movies/sovfinal.vqa: Offset: 999393250 Length: 35169890 - ^Content/ra/v2/movies/soviet1.vqa: + ^SupportDir|Content/ra/v2/movies/soviet1.vqa: Offset: 1034563140 Length: 24112060 - ^Content/ra/v2/movies/soviet2.vqa: + ^SupportDir|Content/ra/v2/movies/soviet2.vqa: Offset: 1058675200 Length: 9494814 - ^Content/ra/v2/movies/soviet3.vqa: + ^SupportDir|Content/ra/v2/movies/soviet3.vqa: Offset: 1068170014 Length: 17229910 - ^Content/ra/v2/movies/soviet4.vqa: + ^SupportDir|Content/ra/v2/movies/soviet4.vqa: Offset: 1085399924 Length: 7236290 - ^Content/ra/v2/movies/soviet5.vqa: + ^SupportDir|Content/ra/v2/movies/soviet5.vqa: Offset: 1092636214 Length: 18986154 - ^Content/ra/v2/movies/soviet6.vqa: + ^SupportDir|Content/ra/v2/movies/soviet6.vqa: Offset: 1111622368 Length: 6782016 - ^Content/ra/v2/movies/soviet7.vqa: + ^SupportDir|Content/ra/v2/movies/soviet7.vqa: Offset: 1118404384 Length: 5637552 - ^Content/ra/v2/movies/soviet8.vqa: + ^SupportDir|Content/ra/v2/movies/soviet8.vqa: Offset: 1124041936 Length: 28905880 - ^Content/ra/v2/movies/soviet9.vqa: + ^SupportDir|Content/ra/v2/movies/soviet9.vqa: Offset: 1152947816 Length: 31809450 - ^Content/ra/v2/movies/soviet10.vqa: + ^SupportDir|Content/ra/v2/movies/soviet10.vqa: Offset: 1184757266 Length: 10102944 - ^Content/ra/v2/movies/soviet11.vqa: + ^SupportDir|Content/ra/v2/movies/soviet11.vqa: Offset: 1194860210 Length: 16685840 - ^Content/ra/v2/movies/soviet12.vqa: + ^SupportDir|Content/ra/v2/movies/soviet12.vqa: Offset: 1211546050 Length: 11532038 - ^Content/ra/v2/movies/soviet13.vqa: + ^SupportDir|Content/ra/v2/movies/soviet13.vqa: Offset: 1223078088 Length: 15210482 - ^Content/ra/v2/movies/soviet14.vqa: + ^SupportDir|Content/ra/v2/movies/soviet14.vqa: Offset: 1238288570 Length: 24358232 - ^Content/ra/v2/movies/sovmcv.vqa: + ^SupportDir|Content/ra/v2/movies/sovmcv.vqa: Offset: 1262646802 Length: 1292126 - ^Content/ra/v2/movies/sovtstar.vqa: + ^SupportDir|Content/ra/v2/movies/sovtstar.vqa: Offset: 1263938928 Length: 670794 - ^Content/ra/v2/movies/spotter.vqa: + ^SupportDir|Content/ra/v2/movies/spotter.vqa: Offset: 1264609722 Length: 1346422 - ^Content/ra/v2/movies/strafe.vqa: + ^SupportDir|Content/ra/v2/movies/strafe.vqa: Offset: 1265956144 Length: 1226956 - ^Content/ra/v2/movies/take_off.vqa: + ^SupportDir|Content/ra/v2/movies/take_off.vqa: Offset: 1267183100 Length: 1419370 - ^Content/ra/v2/movies/tesla.vqa: + ^SupportDir|Content/ra/v2/movies/tesla.vqa: Offset: 1268602470 Length: 1796092 - ^Content/ra/v2/movies/v2rocket.vqa: + ^SupportDir|Content/ra/v2/movies/v2rocket.vqa: Offset: 1270398562 Length: 1856524 - ^Content/ra/v2/movies/aagun.vqa: + ^SupportDir|Content/ra/v2/movies/aagun.vqa: Offset: 1292529084 Length: 3295512 - ^Content/ra/v2/movies/airfield.vqa: + ^SupportDir|Content/ra/v2/movies/airfield.vqa: Offset: 1295824596 Length: 2696058 - ^Content/ra/v2/movies/ally1.vqa: + ^SupportDir|Content/ra/v2/movies/ally1.vqa: Offset: 1298520654 Length: 13536324 - ^Content/ra/v2/movies/allymorf.vqa: + ^SupportDir|Content/ra/v2/movies/allymorf.vqa: Offset: 1312056978 Length: 916964 - ^Content/ra/v2/movies/averted.vqa: + ^SupportDir|Content/ra/v2/movies/averted.vqa: Offset: 1312973942 Length: 1902556 - ^Content/ra/v2/movies/beachead.vqa: + ^SupportDir|Content/ra/v2/movies/beachead.vqa: Offset: 1314876498 Length: 4891790 - ^Content/ra/v2/movies/bmap.vqa: + ^SupportDir|Content/ra/v2/movies/bmap.vqa: Offset: 1319768288 Length: 2414312 - ^Content/ra/v2/movies/bombrun.vqa: + ^SupportDir|Content/ra/v2/movies/bombrun.vqa: Offset: 1322182600 Length: 5167450 - ^Content/ra/v2/movies/countdwn.vqa: + ^SupportDir|Content/ra/v2/movies/countdwn.vqa: Offset: 1327350050 Length: 2005906 - ^Content/ra/v2/movies/cronfail.vqa: + ^SupportDir|Content/ra/v2/movies/cronfail.vqa: Offset: 1329356707 Length: 1717214 - ^Content/ra/v2/expand/chrotnk1.aud: + ^SupportDir|Content/ra/v2/expand/chrotnk1.aud: Offset: 843615985 Length: 22900 - ^Content/ra/v2/expand/fixit1.aud: + ^SupportDir|Content/ra/v2/expand/fixit1.aud: Offset: 843860963 Length: 10707 - ^Content/ra/v2/expand/jburn1.aud: + ^SupportDir|Content/ra/v2/expand/jburn1.aud: Offset: 844007001 Length: 23091 - ^Content/ra/v2/expand/jchrge1.aud: + ^SupportDir|Content/ra/v2/expand/jchrge1.aud: Offset: 844030092 Length: 14219 - ^Content/ra/v2/expand/jcrisp1.aud: + ^SupportDir|Content/ra/v2/expand/jcrisp1.aud: Offset: 844044311 Length: 18211 - ^Content/ra/v2/expand/jdance1.aud: + ^SupportDir|Content/ra/v2/expand/jdance1.aud: Offset: 844062522 Length: 14315 - ^Content/ra/v2/expand/jjuice1.aud: + ^SupportDir|Content/ra/v2/expand/jjuice1.aud: Offset: 844076837 Length: 9699 - ^Content/ra/v2/expand/jjump1.aud: + ^SupportDir|Content/ra/v2/expand/jjump1.aud: Offset: 844086536 Length: 8219 - ^Content/ra/v2/expand/jlight1.aud: + ^SupportDir|Content/ra/v2/expand/jlight1.aud: Offset: 844094755 Length: 9875 - ^Content/ra/v2/expand/jpower1.aud: + ^SupportDir|Content/ra/v2/expand/jpower1.aud: Offset: 844104630 Length: 13571 - ^Content/ra/v2/expand/jshock1.aud: + ^SupportDir|Content/ra/v2/expand/jshock1.aud: Offset: 844118201 Length: 14771 - ^Content/ra/v2/expand/jyes1.aud: + ^SupportDir|Content/ra/v2/expand/jyes1.aud: Offset: 844132972 Length: 13795 - ^Content/ra/v2/expand/madchrg2.aud: + ^SupportDir|Content/ra/v2/expand/madchrg2.aud: Offset: 844262883 Length: 19782 - ^Content/ra/v2/expand/madexplo.aud: + ^SupportDir|Content/ra/v2/expand/madexplo.aud: Offset: 844282665 Length: 26572 - ^Content/ra/v2/expand/mboss1.aud: + ^SupportDir|Content/ra/v2/expand/mboss1.aud: Offset: 844314713 Length: 20147 - ^Content/ra/v2/expand/mhear1.aud: + ^SupportDir|Content/ra/v2/expand/mhear1.aud: Offset: 844340048 Length: 6714 - ^Content/ra/v2/expand/mhotdig1.aud: + ^SupportDir|Content/ra/v2/expand/mhotdig1.aud: Offset: 844346762 Length: 10674 - ^Content/ra/v2/expand/mhowdy1.aud: + ^SupportDir|Content/ra/v2/expand/mhowdy1.aud: Offset: 844357436 Length: 6714 - ^Content/ra/v2/expand/mhuh1.aud: + ^SupportDir|Content/ra/v2/expand/mhuh1.aud: Offset: 844364150 Length: 4117 - ^Content/ra/v2/expand/mlaff1.aud: + ^SupportDir|Content/ra/v2/expand/mlaff1.aud: Offset: 844428954 Length: 24133 - ^Content/ra/v2/expand/mrise1.aud: + ^SupportDir|Content/ra/v2/expand/mrise1.aud: Offset: 844466487 Length: 13523 - ^Content/ra/v2/expand/mwrench1.aud: + ^SupportDir|Content/ra/v2/expand/mwrench1.aud: Offset: 844480010 Length: 10780 - ^Content/ra/v2/expand/myeehaw1.aud: + ^SupportDir|Content/ra/v2/expand/myeehaw1.aud: Offset: 844490790 Length: 18912 - ^Content/ra/v2/expand/myes1.aud: + ^SupportDir|Content/ra/v2/expand/myes1.aud: Offset: 844509702 Length: 9073 @@ -465,4 +465,4 @@ CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30 Install: copy: . - ^Content/ra/v2/cnc/desert.mix: DESERT.MIX \ No newline at end of file + ^SupportDir|Content/ra/v2/cnc/desert.mix: DESERT.MIX \ No newline at end of file diff -Nru openra-20200503/mods/ra/installer/soviet95.yaml openra-20210321/mods/ra/installer/soviet95.yaml --- openra-20200503/mods/ra/installer/soviet95.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/installer/soviet95.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -5,206 +5,206 @@ INSTALL/REDALERT.MIX: 0e58f4b54f44f6cd29fecf8cf379d33cf2d4caef Install: extract-raw: INSTALL/REDALERT.MIX - ^Content/ra/v2/hires.mix: + ^SupportDir|Content/ra/v2/hires.mix: Offset: 650612 Length: 5817417 - ^Content/ra/v2/local.mix: + ^SupportDir|Content/ra/v2/local.mix: Offset: 6468029 Length: 3829837 - ^Content/ra/v2/lores.mix: + ^SupportDir|Content/ra/v2/lores.mix: Offset: 10297866 Length: 754800 - ^Content/ra/v2/speech.mix: + ^SupportDir|Content/ra/v2/speech.mix: Offset: 23042864 Length: 2003464 extract-raw: MAIN.MIX - ^Content/ra/v2/conquer.mix: + ^SupportDir|Content/ra/v2/conquer.mix: Offset: 236 Length: 2177047 - ^Content/ra/v2/interior.mix: + ^SupportDir|Content/ra/v2/interior.mix: Offset: 17172192 Length: 247425 - ^Content/ra/v2/movies/aagun.vqa: + ^SupportDir|Content/ra/v2/movies/aagun.vqa: Offset: 37694379 Length: 3295512 - ^Content/ra/v2/movies/cronfail.vqa: + ^SupportDir|Content/ra/v2/movies/cronfail.vqa: Offset: 40989891 Length: 1717214 - ^Content/ra/v2/movies/airfield.vqa: + ^SupportDir|Content/ra/v2/movies/airfield.vqa: Offset: 42707105 Length: 2696058 - ^Content/ra/v2/movies/ally1.vqa: + ^SupportDir|Content/ra/v2/movies/ally1.vqa: Offset: 45403163 Length: 13536324 - ^Content/ra/v2/movies/allymorf.vqa: + ^SupportDir|Content/ra/v2/movies/allymorf.vqa: Offset: 58939487 Length: 916964 - ^Content/ra/v2/movies/averted.vqa: + ^SupportDir|Content/ra/v2/movies/averted.vqa: Offset: 59856451 Length: 1902556 - ^Content/ra/v2/movies/beachead.vqa: + ^SupportDir|Content/ra/v2/movies/beachead.vqa: Offset: 61759007 Length: 4891790 - ^Content/ra/v2/movies/bmap.vqa: + ^SupportDir|Content/ra/v2/movies/bmap.vqa: Offset: 66650797 Length: 2414312 - ^Content/ra/v2/movies/bombrun.vqa: + ^SupportDir|Content/ra/v2/movies/bombrun.vqa: Offset: 69065109 Length: 5167450 - ^Content/ra/v2/movies/countdwn.vqa: + ^SupportDir|Content/ra/v2/movies/countdwn.vqa: Offset: 74232559 Length: 2005906 - ^Content/ra/v2/movies/double.vqa: + ^SupportDir|Content/ra/v2/movies/double.vqa: Offset: 76238465 Length: 1608508 - ^Content/ra/v2/movies/dpthchrg.vqa: + ^SupportDir|Content/ra/v2/movies/dpthchrg.vqa: Offset: 77846973 Length: 3048762 - ^Content/ra/v2/movies/execute.vqa: + ^SupportDir|Content/ra/v2/movies/execute.vqa: Offset: 80895735 Length: 1511212 - ^Content/ra/v2/movies/flare.vqa: + ^SupportDir|Content/ra/v2/movies/flare.vqa: Offset: 82406947 Length: 1731744 - ^Content/ra/v2/movies/landing.vqa: + ^SupportDir|Content/ra/v2/movies/landing.vqa: Offset: 84138691 Length: 2374106 - ^Content/ra/v2/movies/mcvbrdge.vqa: + ^SupportDir|Content/ra/v2/movies/mcvbrdge.vqa: Offset: 86512797 Length: 2124412 - ^Content/ra/v2/movies/mig.vqa: + ^SupportDir|Content/ra/v2/movies/mig.vqa: Offset: 88637209 Length: 6745398 - ^Content/ra/v2/movies/movingin.vqa: + ^SupportDir|Content/ra/v2/movies/movingin.vqa: Offset: 95382607 Length: 1185550 - ^Content/ra/v2/movies/mtnkfact.vqa: + ^SupportDir|Content/ra/v2/movies/mtnkfact.vqa: Offset: 96568157 Length: 3168076 - ^Content/ra/v2/movies/nukestok.vqa: + ^SupportDir|Content/ra/v2/movies/nukestok.vqa: Offset: 99736233 Length: 1877536 - ^Content/ra/v2/movies/onthprwl.vqa: + ^SupportDir|Content/ra/v2/movies/onthprwl.vqa: Offset: 101613769 Length: 2648948 - ^Content/ra/v2/movies/periscop.vqa: + ^SupportDir|Content/ra/v2/movies/periscop.vqa: Offset: 104262717 Length: 2099110 - ^Content/ra/v2/movies/prolog.vqa: + ^SupportDir|Content/ra/v2/movies/prolog.vqa: Offset: 106361827 Length: 28658198 - ^Content/ra/v2/movies/radrraid.vqa: + ^SupportDir|Content/ra/v2/movies/radrraid.vqa: Offset: 135020025 Length: 1561740 - ^Content/ra/v2/movies/redintro.vqa: + ^SupportDir|Content/ra/v2/movies/redintro.vqa: Offset: 136581765 Length: 2269452 - ^Content/ra/v2/movies/search.vqa: + ^SupportDir|Content/ra/v2/movies/search.vqa: Offset: 138851217 Length: 2298940 - ^Content/ra/v2/movies/sfrozen.vqa: + ^SupportDir|Content/ra/v2/movies/sfrozen.vqa: Offset: 141150157 Length: 1829954 - ^Content/ra/v2/movies/sitduck.vqa: + ^SupportDir|Content/ra/v2/movies/sitduck.vqa: Offset: 142980111 Length: 3650212 - ^Content/ra/v2/movies/slntsrvc.vqa: + ^SupportDir|Content/ra/v2/movies/slntsrvc.vqa: Offset: 146630323 Length: 1774986 - ^Content/ra/v2/movies/snowbomb.vqa: + ^SupportDir|Content/ra/v2/movies/snowbomb.vqa: Offset: 148405309 Length: 2465762 - ^Content/ra/v2/movies/snstrafe.vqa: + ^SupportDir|Content/ra/v2/movies/snstrafe.vqa: Offset: 150871071 Length: 2473362 - ^Content/ra/v2/movies/sovbatl.vqa: + ^SupportDir|Content/ra/v2/movies/sovbatl.vqa: Offset: 153344433 Length: 3439876 - ^Content/ra/v2/movies/sovcemet.vqa: + ^SupportDir|Content/ra/v2/movies/sovcemet.vqa: Offset: 156784309 Length: 3107928 - ^Content/ra/v2/movies/sovfinal.vqa: + ^SupportDir|Content/ra/v2/movies/sovfinal.vqa: Offset: 159892237 Length: 35169890 - ^Content/ra/v2/movies/soviet1.vqa: + ^SupportDir|Content/ra/v2/movies/soviet1.vqa: Offset: 195062127 Length: 24112060 - ^Content/ra/v2/movies/soviet10.vqa: + ^SupportDir|Content/ra/v2/movies/soviet10.vqa: Offset: 219174187 Length: 10102944 - ^Content/ra/v2/movies/soviet11.vqa: + ^SupportDir|Content/ra/v2/movies/soviet11.vqa: Offset: 229277131 Length: 16685840 - ^Content/ra/v2/movies/soviet12.vqa: + ^SupportDir|Content/ra/v2/movies/soviet12.vqa: Offset: 245962971 Length: 11532038 - ^Content/ra/v2/movies/soviet13.vqa: + ^SupportDir|Content/ra/v2/movies/soviet13.vqa: Offset: 257495009 Length: 15210482 - ^Content/ra/v2/movies/soviet14.vqa: + ^SupportDir|Content/ra/v2/movies/soviet14.vqa: Offset: 272705491 Length: 24358232 - ^Content/ra/v2/movies/soviet2.vqa: + ^SupportDir|Content/ra/v2/movies/soviet2.vqa: Offset: 297063723 Length: 9494814 - ^Content/ra/v2/movies/soviet3.vqa: + ^SupportDir|Content/ra/v2/movies/soviet3.vqa: Offset: 306558537 Length: 17229910 - ^Content/ra/v2/movies/soviet4.vqa: + ^SupportDir|Content/ra/v2/movies/soviet4.vqa: Offset: 323788447 Length: 7236290 - ^Content/ra/v2/movies/soviet5.vqa: + ^SupportDir|Content/ra/v2/movies/soviet5.vqa: Offset: 331024737 Length: 18986154 - ^Content/ra/v2/movies/soviet6.vqa: + ^SupportDir|Content/ra/v2/movies/soviet6.vqa: Offset: 350010891 Length: 6782016 - ^Content/ra/v2/movies/soviet7.vqa: + ^SupportDir|Content/ra/v2/movies/soviet7.vqa: Offset: 356792907 Length: 5637552 - ^Content/ra/v2/movies/soviet8.vqa: + ^SupportDir|Content/ra/v2/movies/soviet8.vqa: Offset: 362430459 Length: 28905880 - ^Content/ra/v2/movies/soviet9.vqa: + ^SupportDir|Content/ra/v2/movies/soviet9.vqa: Offset: 391336339 Length: 31809450 - ^Content/ra/v2/movies/sovmcv.vqa: + ^SupportDir|Content/ra/v2/movies/sovmcv.vqa: Offset: 423145789 Length: 1292126 - ^Content/ra/v2/movies/sovtstar.vqa: + ^SupportDir|Content/ra/v2/movies/sovtstar.vqa: Offset: 424437915 Length: 670794 - ^Content/ra/v2/movies/spotter.vqa: + ^SupportDir|Content/ra/v2/movies/spotter.vqa: Offset: 425108709 Length: 1346422 - ^Content/ra/v2/movies/strafe.vqa: + ^SupportDir|Content/ra/v2/movies/strafe.vqa: Offset: 426455131 Length: 1226956 - ^Content/ra/v2/movies/take_off.vqa: + ^SupportDir|Content/ra/v2/movies/take_off.vqa: Offset: 427682087 Length: 1419370 - ^Content/ra/v2/movies/tesla.vqa: + ^SupportDir|Content/ra/v2/movies/tesla.vqa: Offset: 429101457 Length: 1796092 - ^Content/ra/v2/movies/v2rocket.vqa: + ^SupportDir|Content/ra/v2/movies/v2rocket.vqa: Offset: 430897549 Length: 1856524 - ^Content/ra/v2/scores.mix: + ^SupportDir|Content/ra/v2/scores.mix: Offset: 432754073 Length: 64171360 - ^Content/ra/v2/snow.mix: + ^SupportDir|Content/ra/v2/snow.mix: Offset: 496925433 Length: 1030861 - ^Content/ra/v2/russian.mix: + ^SupportDir|Content/ra/v2/russian.mix: Offset: 497956294 Length: 266077 - ^Content/ra/v2/allies.mix: + ^SupportDir|Content/ra/v2/allies.mix: Offset: 498222371 Length: 309406 - ^Content/ra/v2/sounds.mix: + ^SupportDir|Content/ra/v2/sounds.mix: Offset: 498531777 Length: 1006778 - ^Content/ra/v2/temperat.mix: + ^SupportDir|Content/ra/v2/temperat.mix: Offset: 499538555 Length: 1038859 soviet-linux: Red Alert 95 (Soviet Disc, English) @@ -213,205 +213,205 @@ install/redalert.mix: 0e58f4b54f44f6cd29fecf8cf379d33cf2d4caef Install: extract-raw: install/redalert.mix - ^Content/ra/v2/hires.mix: + ^SupportDir|Content/ra/v2/hires.mix: Offset: 650612 Length: 5817417 - ^Content/ra/v2/local.mix: + ^SupportDir|Content/ra/v2/local.mix: Offset: 6468029 Length: 3829837 - ^Content/ra/v2/lores.mix: + ^SupportDir|Content/ra/v2/lores.mix: Offset: 10297866 Length: 754800 - ^Content/ra/v2/speech.mix: + ^SupportDir|Content/ra/v2/speech.mix: Offset: 23042864 Length: 2003464 extract-raw: main.mix - ^Content/ra/v2/conquer.mix: + ^SupportDir|Content/ra/v2/conquer.mix: Offset: 236 Length: 2177047 - ^Content/ra/v2/interior.mix: + ^SupportDir|Content/ra/v2/interior.mix: Offset: 17172192 Length: 247425 - ^Content/ra/v2/movies/aagun.vqa: + ^SupportDir|Content/ra/v2/movies/aagun.vqa: Offset: 37694379 Length: 3295512 - ^Content/ra/v2/movies/cronfail.vqa: + ^SupportDir|Content/ra/v2/movies/cronfail.vqa: Offset: 40989891 Length: 1717214 - ^Content/ra/v2/movies/airfield.vqa: + ^SupportDir|Content/ra/v2/movies/airfield.vqa: Offset: 42707105 Length: 2696058 - ^Content/ra/v2/movies/ally1.vqa: + ^SupportDir|Content/ra/v2/movies/ally1.vqa: Offset: 45403163 Length: 13536324 - ^Content/ra/v2/movies/allymorf.vqa: + ^SupportDir|Content/ra/v2/movies/allymorf.vqa: Offset: 58939487 Length: 916964 - ^Content/ra/v2/movies/averted.vqa: + ^SupportDir|Content/ra/v2/movies/averted.vqa: Offset: 59856451 Length: 1902556 - ^Content/ra/v2/movies/beachead.vqa: + ^SupportDir|Content/ra/v2/movies/beachead.vqa: Offset: 61759007 Length: 4891790 - ^Content/ra/v2/movies/bmap.vqa: + ^SupportDir|Content/ra/v2/movies/bmap.vqa: Offset: 66650797 Length: 2414312 - ^Content/ra/v2/movies/bombrun.vqa: + ^SupportDir|Content/ra/v2/movies/bombrun.vqa: Offset: 69065109 Length: 5167450 - ^Content/ra/v2/movies/countdwn.vqa: + ^SupportDir|Content/ra/v2/movies/countdwn.vqa: Offset: 74232559 Length: 2005906 - ^Content/ra/v2/movies/double.vqa: + ^SupportDir|Content/ra/v2/movies/double.vqa: Offset: 76238465 Length: 1608508 - ^Content/ra/v2/movies/dpthchrg.vqa: + ^SupportDir|Content/ra/v2/movies/dpthchrg.vqa: Offset: 77846973 Length: 3048762 - ^Content/ra/v2/movies/execute.vqa: + ^SupportDir|Content/ra/v2/movies/execute.vqa: Offset: 80895735 Length: 1511212 - ^Content/ra/v2/movies/flare.vqa: + ^SupportDir|Content/ra/v2/movies/flare.vqa: Offset: 82406947 Length: 1731744 - ^Content/ra/v2/movies/landing.vqa: + ^SupportDir|Content/ra/v2/movies/landing.vqa: Offset: 84138691 Length: 2374106 - ^Content/ra/v2/movies/mcvbrdge.vqa: + ^SupportDir|Content/ra/v2/movies/mcvbrdge.vqa: Offset: 86512797 Length: 2124412 - ^Content/ra/v2/movies/mig.vqa: + ^SupportDir|Content/ra/v2/movies/mig.vqa: Offset: 88637209 Length: 6745398 - ^Content/ra/v2/movies/movingin.vqa: + ^SupportDir|Content/ra/v2/movies/movingin.vqa: Offset: 95382607 Length: 1185550 - ^Content/ra/v2/movies/mtnkfact.vqa: + ^SupportDir|Content/ra/v2/movies/mtnkfact.vqa: Offset: 96568157 Length: 3168076 - ^Content/ra/v2/movies/nukestok.vqa: + ^SupportDir|Content/ra/v2/movies/nukestok.vqa: Offset: 99736233 Length: 1877536 - ^Content/ra/v2/movies/onthprwl.vqa: + ^SupportDir|Content/ra/v2/movies/onthprwl.vqa: Offset: 101613769 Length: 2648948 - ^Content/ra/v2/movies/periscop.vqa: + ^SupportDir|Content/ra/v2/movies/periscop.vqa: Offset: 104262717 Length: 2099110 - ^Content/ra/v2/movies/prolog.vqa: + ^SupportDir|Content/ra/v2/movies/prolog.vqa: Offset: 106361827 Length: 28658198 - ^Content/ra/v2/movies/radrraid.vqa: + ^SupportDir|Content/ra/v2/movies/radrraid.vqa: Offset: 135020025 Length: 1561740 - ^Content/ra/v2/movies/redintro.vqa: + ^SupportDir|Content/ra/v2/movies/redintro.vqa: Offset: 136581765 Length: 2269452 - ^Content/ra/v2/movies/search.vqa: + ^SupportDir|Content/ra/v2/movies/search.vqa: Offset: 138851217 Length: 2298940 - ^Content/ra/v2/movies/sfrozen.vqa: + ^SupportDir|Content/ra/v2/movies/sfrozen.vqa: Offset: 141150157 Length: 1829954 - ^Content/ra/v2/movies/sitduck.vqa: + ^SupportDir|Content/ra/v2/movies/sitduck.vqa: Offset: 142980111 Length: 3650212 - ^Content/ra/v2/movies/slntsrvc.vqa: + ^SupportDir|Content/ra/v2/movies/slntsrvc.vqa: Offset: 146630323 Length: 1774986 - ^Content/ra/v2/movies/snowbomb.vqa: + ^SupportDir|Content/ra/v2/movies/snowbomb.vqa: Offset: 148405309 Length: 2465762 - ^Content/ra/v2/movies/snstrafe.vqa: + ^SupportDir|Content/ra/v2/movies/snstrafe.vqa: Offset: 150871071 Length: 2473362 - ^Content/ra/v2/movies/sovbatl.vqa: + ^SupportDir|Content/ra/v2/movies/sovbatl.vqa: Offset: 153344433 Length: 3439876 - ^Content/ra/v2/movies/sovcemet.vqa: + ^SupportDir|Content/ra/v2/movies/sovcemet.vqa: Offset: 156784309 Length: 3107928 - ^Content/ra/v2/movies/sovfinal.vqa: + ^SupportDir|Content/ra/v2/movies/sovfinal.vqa: Offset: 159892237 Length: 35169890 - ^Content/ra/v2/movies/soviet1.vqa: + ^SupportDir|Content/ra/v2/movies/soviet1.vqa: Offset: 195062127 Length: 24112060 - ^Content/ra/v2/movies/soviet10.vqa: + ^SupportDir|Content/ra/v2/movies/soviet10.vqa: Offset: 219174187 Length: 10102944 - ^Content/ra/v2/movies/soviet11.vqa: + ^SupportDir|Content/ra/v2/movies/soviet11.vqa: Offset: 229277131 Length: 16685840 - ^Content/ra/v2/movies/soviet12.vqa: + ^SupportDir|Content/ra/v2/movies/soviet12.vqa: Offset: 245962971 Length: 11532038 - ^Content/ra/v2/movies/soviet13.vqa: + ^SupportDir|Content/ra/v2/movies/soviet13.vqa: Offset: 257495009 Length: 15210482 - ^Content/ra/v2/movies/soviet14.vqa: + ^SupportDir|Content/ra/v2/movies/soviet14.vqa: Offset: 272705491 Length: 24358232 - ^Content/ra/v2/movies/soviet2.vqa: + ^SupportDir|Content/ra/v2/movies/soviet2.vqa: Offset: 297063723 Length: 9494814 - ^Content/ra/v2/movies/soviet3.vqa: + ^SupportDir|Content/ra/v2/movies/soviet3.vqa: Offset: 306558537 Length: 17229910 - ^Content/ra/v2/movies/soviet4.vqa: + ^SupportDir|Content/ra/v2/movies/soviet4.vqa: Offset: 323788447 Length: 7236290 - ^Content/ra/v2/movies/soviet5.vqa: + ^SupportDir|Content/ra/v2/movies/soviet5.vqa: Offset: 331024737 Length: 18986154 - ^Content/ra/v2/movies/soviet6.vqa: + ^SupportDir|Content/ra/v2/movies/soviet6.vqa: Offset: 350010891 Length: 6782016 - ^Content/ra/v2/movies/soviet7.vqa: + ^SupportDir|Content/ra/v2/movies/soviet7.vqa: Offset: 356792907 Length: 5637552 - ^Content/ra/v2/movies/soviet8.vqa: + ^SupportDir|Content/ra/v2/movies/soviet8.vqa: Offset: 362430459 Length: 28905880 - ^Content/ra/v2/movies/soviet9.vqa: + ^SupportDir|Content/ra/v2/movies/soviet9.vqa: Offset: 391336339 Length: 31809450 - ^Content/ra/v2/movies/sovmcv.vqa: + ^SupportDir|Content/ra/v2/movies/sovmcv.vqa: Offset: 423145789 Length: 1292126 - ^Content/ra/v2/movies/sovtstar.vqa: + ^SupportDir|Content/ra/v2/movies/sovtstar.vqa: Offset: 424437915 Length: 670794 - ^Content/ra/v2/movies/spotter.vqa: + ^SupportDir|Content/ra/v2/movies/spotter.vqa: Offset: 425108709 Length: 1346422 - ^Content/ra/v2/movies/strafe.vqa: + ^SupportDir|Content/ra/v2/movies/strafe.vqa: Offset: 426455131 Length: 1226956 - ^Content/ra/v2/movies/take_off.vqa: + ^SupportDir|Content/ra/v2/movies/take_off.vqa: Offset: 427682087 Length: 1419370 - ^Content/ra/v2/movies/tesla.vqa: + ^SupportDir|Content/ra/v2/movies/tesla.vqa: Offset: 429101457 Length: 1796092 - ^Content/ra/v2/movies/v2rocket.vqa: + ^SupportDir|Content/ra/v2/movies/v2rocket.vqa: Offset: 430897549 Length: 1856524 - ^Content/ra/v2/scores.mix: + ^SupportDir|Content/ra/v2/scores.mix: Offset: 432754073 Length: 64171360 - ^Content/ra/v2/snow.mix: + ^SupportDir|Content/ra/v2/snow.mix: Offset: 496925433 Length: 1030861 - ^Content/ra/v2/russian.mix: + ^SupportDir|Content/ra/v2/russian.mix: Offset: 497956294 Length: 266077 - ^Content/ra/v2/allies.mix: + ^SupportDir|Content/ra/v2/allies.mix: Offset: 498222371 Length: 309406 - ^Content/ra/v2/sounds.mix: + ^SupportDir|Content/ra/v2/sounds.mix: Offset: 498531777 Length: 1006778 - ^Content/ra/v2/temperat.mix: + ^SupportDir|Content/ra/v2/temperat.mix: Offset: 499538555 Length: 1038859 \ No newline at end of file Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/agenda.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/agenda.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/alaska-anarchy-redux.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/alaska-anarchy-redux.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/all-connected.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/all-connected.oramap differ diff -Nru openra-20200503/mods/ra/maps/allies-01/allies01.lua openra-20210321/mods/ra/maps/allies-01/allies01.lua --- openra-20200503/mods/ra/maps/allies-01/allies01.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-01/allies01.lua 2021-03-21 11:10:05.000000000 +0000 @@ -123,6 +123,12 @@ collateralDamage = true end +LostMate = function() + if not Civilian2.IsDead then + Civilian2.Panic() + end +end + CreateEinstein = function() player.MarkCompletedObjective(FindEinsteinObjective) Media.PlaySpeechNotification(player, "ObjectiveMet") @@ -205,6 +211,7 @@ collateralDamage = false civilianTeam = { Civilian1, Civilian2 } Trigger.OnAnyKilled(civilianTeam, CiviliansKilled) + Trigger.OnKilled(Civilian1, LostMate) SetUnitStances() diff -Nru openra-20200503/mods/ra/maps/allies-01/map.yaml openra-20210321/mods/ra/maps/allies-01/map.yaml --- openra-20200503/mods/ra/maps/allies-01/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-01/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -190,15 +190,15 @@ Actor47: jeep Location: 63,50 Owner: Greece - Facing: 128 + Facing: 512 Actor49: jeep Location: 62,50 Owner: Greece - Facing: 128 + Facing: 512 Actor50: jeep Location: 64,50 Owner: Greece - Facing: 128 + Facing: 512 Actor55: e2 Location: 73,66 Owner: USSR @@ -206,47 +206,47 @@ Actor56: e1 Location: 62,67 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 4 Actor57: e1 Location: 67,67 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 Actor58: e1 Location: 65,67 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 Actor59: e1 Location: 56,60 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 1 Actor63: e1 Location: 58,60 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 1 Actor64: e1 Location: 64,49 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 1 Actor65: e1 Location: 63,49 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 0 Actor66: e1 Location: 62,49 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 2 Actor69: e2 Location: 62,56 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 1 Actor70: e2 Location: 62,56 @@ -255,12 +255,12 @@ Actor71: e1 Location: 64,49 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 2 Actor72: e1 Location: 62,49 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 1 Actor48: fenc Location: 53,60 @@ -371,12 +371,12 @@ LabGuard2: e1 Location: 63,63 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 0 LabGuard3: e1 Location: 61,63 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 0 Patrol1: dog Location: 63,59 diff -Nru openra-20200503/mods/ra/maps/allies-02/map.yaml openra-20210321/mods/ra/maps/allies-02/map.yaml --- openra-20200503/mods/ra/maps/allies-02/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-02/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -307,122 +307,122 @@ Actor97: dog Location: 65,68 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 3 Actor98: dog Location: 65,66 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 2 Actor99: dog Location: 59,70 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 2 Actor100: e2 Location: 61,56 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 3 Actor101: e2 Location: 59,57 Owner: USSR - Facing: 224 + Facing: 896 SubCell: 4 Actor102: e2 Location: 64,67 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 0 Actor103: e1 Location: 78,74 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 2 Actor104: e1 Location: 80,74 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 0 Actor105: e1 Location: 56,68 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 Actor107: e1 Location: 73,60 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 2 Actor108: e1 Location: 74,61 Owner: USSR - Facing: 224 + Facing: 896 SubCell: 1 Actor109: e1 Location: 72,60 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 0 Actor115: e1 Location: 60,64 Owner: USSR - Facing: 224 + Facing: 896 SubCell: 3 Actor116: e2 Location: 68,45 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 0 Actor118: e1 Location: 57,69 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 1 Actor119: e2 Location: 60,70 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 0 Actor120: e1 Location: 89,48 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 1 Actor121: e1 Location: 87,48 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 4 Actor122: e1 Location: 87,48 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 1 Actor123: e1 Location: 88,48 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 4 Actor124: e1 Location: 88,49 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 1 Actor125: dog Location: 78,75 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 1 Actor126: e1 Location: 71,61 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 0 Actor127: dog Location: 70,61 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 4 Actor136: e2 Location: 69,66 @@ -431,12 +431,12 @@ Actor137: e2 Location: 73,51 Owner: USSR - Facing: 224 + Facing: 896 SubCell: 4 Actor138: medi Location: 88,48 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 1 Actor139: fenc Location: 57,75 @@ -562,56 +562,56 @@ Harvester: harv Location: 55,65 Owner: USSR - Facing: 160 + Facing: 640 PathGuard1: e1 Location: 50,72 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 4 PathGuard2: e1 Location: 49,58 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 0 PathGuard3: e1 Location: 51,58 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 1 PathGuard4: e1 Location: 60,78 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 4 PathGuard5: e2 Location: 62,79 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 4 PathGuard6: e1 Location: 48,72 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 0 PathGuard7: e1 Location: 50,46 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 1 PathGuard8: e1 Location: 49,47 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 0 PathGuard9: e2 Location: 49,49 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 1 PathGuard10: e2 Location: 47,46 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 3 PathGuard11: e2 Location: 48,63 @@ -620,22 +620,22 @@ PathGuard12: e1 Location: 49,63 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 2 PathGuard13: e1 Location: 74,81 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 3 PathGuard14: e2 Location: 75,83 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 0 PathGuard15: e1 Location: 57,82 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 1 TruckEntryPoint: waypoint Location: 49,44 diff -Nru openra-20200503/mods/ra/maps/allies-03a/allies03a.lua openra-20210321/mods/ra/maps/allies-03a/allies03a.lua --- openra-20200503/mods/ra/maps/allies-03a/allies03a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-03a/allies03a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -73,14 +73,14 @@ SendUSSRParadrops = function() local powerproxy = Actor.Create("powerproxy.paratroopers", false, { Owner = ussr }) - local aircraftA = powerproxy.ActivateParatroopers(ParadropLZ.CenterPosition, 128 + 32) + local aircraftA = powerproxy.TargetParatroopers(ParadropLZ.CenterPosition, Angle.SouthEast) Utils.Do(aircraftA, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) end) end) - local aircraftB = powerproxy.ActivateParatroopers(ParadropLZ.CenterPosition, 128 - 32) + local aircraftB = powerproxy.TargetParatroopers(ParadropLZ.CenterPosition, Angle.SouthWest) Utils.Do(aircraftB, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) diff -Nru openra-20200503/mods/ra/maps/allies-03a/map.yaml openra-20210321/mods/ra/maps/allies-03a/map.yaml --- openra-20200503/mods/ra/maps/allies-03a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-03a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -759,101 +759,101 @@ Location: 76,66 Owner: USSR Health: 52 - Facing: 224 + Facing: 896 Actor250: e1.autotarget Location: 42,56 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 3 Actor251: e1.autotarget Location: 51,53 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 4 Actor252: e1.autotarget Location: 47,53 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 3 Actor253: e2 Location: 79,66 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 2 Actor254: e2 Location: 80,67 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 1 Actor255: e2 Location: 79,68 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 0 Actor256: e2 Location: 80,68 Owner: USSR - Facing: 224 + Facing: 896 SubCell: 1 Actor259: e1.autotarget Location: 54,55 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 2 Actor260: e1.autotarget Location: 70,65 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 4 Actor261: e2.autotarget Location: 71,65 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 2 Actor262: dog Location: 69,63 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 1 Actor263: e1.autotarget Location: 72,62 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 1 Actor264: e1.autotarget Location: 74,62 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 1 Actor270: e1.autotarget Location: 65,71 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 0 Actor271: e1.autotarget Location: 64,70 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 0 Actor272: e1.autotarget Location: 66,70 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 4 Actor277: e1 Location: 78,77 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 Actor281: dog Location: 85,81 Owner: USSR - Facing: 224 + Facing: 896 SubCell: 1 Actor282: dog Location: 96,73 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 1 Actor287: e1.autotarget Location: 84,53 @@ -862,7 +862,7 @@ Actor288: e1.autotarget Location: 90,53 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 4 Actor289: e1.autotarget Location: 88,58 @@ -871,37 +871,37 @@ Actor290: e2.autotarget Location: 89,58 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 3 Actor291: e2.autotarget Location: 83,55 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 Actor292: e2.autotarget Location: 98,58 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 4 Actor293: e2.autotarget Location: 96,61 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 4 Actor294: e1.autotarget Location: 93,58 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 4 Actor295: e1.autotarget Location: 90,59 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 4 Actor296: e1.autotarget Location: 97,66 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 0 Actor297: e1.autotarget Location: 94,65 @@ -910,27 +910,27 @@ Actor298: e1.autotarget Location: 96,65 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 3 Actor299: e2.autotarget Location: 99,67 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 0 Actor300: e2.autotarget Location: 99,68 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 4 Actor301: e2.autotarget Location: 98,67 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 1 Actor302: e1.autotarget Location: 87,61 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 2 Actor309: fenc Location: 72,63 @@ -1172,12 +1172,12 @@ USSRBaseGuard1: e1 Location: 49,66 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 0 USSRBaseGuard2: e1 Location: 48,67 Owner: USSR - Facing: 224 + Facing: 896 SubCell: 0 USSRBaseGuard3: e2 Location: 48,70 @@ -1186,42 +1186,42 @@ USSRBaseGuard4: e2 Location: 49,69 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 0 USSRBaseGuard5: e1 Location: 51,69 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 USSRBaseGuard6: e2 Location: 49,72 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 2 USSRBaseGuard7: e1 Location: 53,70 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 1 USSRBaseGuard8: e1 Location: 56,69 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 2 USSRBaseGuard10: e2 Location: 77,80 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 0 USSRBaseGuard11: e1 Location: 78,77 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 4 USSRBaseGuard12: e1 Location: 79,77 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 4 USSRBaseGuard13: e2 Location: 80,76 @@ -1230,17 +1230,17 @@ USSRBaseGuard14: dog Location: 81,76 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 PGuard1: e1 Location: 58,59 Owner: USSR - Facing: 224 + Facing: 896 SubCell: 3 PGuard2: e1 Location: 57,68 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 4 PrisonedMedi1: medi Location: 58,60 @@ -1249,12 +1249,12 @@ PrisonedMedi2: medi Location: 57,67 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 0 PrisonedEngi: e6 Location: 57,67 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 2 Jail1: prison Location: 58,60 diff -Nru openra-20200503/mods/ra/maps/allies-03a/weapons.yaml openra-20210321/mods/ra/maps/allies-03a/weapons.yaml --- openra-20200503/mods/ra/maps/allies-03a/weapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-03a/weapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,3 +1,3 @@ BarrelExplode: Warhead@1Dam: SpreadDamage - ValidTargets: Ground, Prisoner + ValidTargets: Ground, GroundActor, Prisoner diff -Nru openra-20200503/mods/ra/maps/allies-03b/allies03b.lua openra-20210321/mods/ra/maps/allies-03b/allies03b.lua --- openra-20200503/mods/ra/maps/allies-03b/allies03b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-03b/allies03b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -68,7 +68,7 @@ end SetupAlliedUnits = function() - Tanya = Actor.Create(TanyaType, true, { Owner = player, Location = TanyaWaypoint.Location, Facing = 128 }) + Tanya = Actor.Create(TanyaType, true, { Owner = player, Location = TanyaWaypoint.Location, Facing = Angle.South }) if TanyaType == "e7.noautotarget" then Trigger.AfterDelay(DateTime.Seconds(2), function() @@ -89,13 +89,13 @@ player.MarkCompletedObjective(FindAllies) Media.PlaySpeechNotification(player, "AlliedReinforcementsArrived") Reinforcements.Reinforce(player, AlliedIslandReinforcements, { AlliedIslandReinforcementsEntry.Location, IslandParadropReinforcementsDropzone.Location }) - SendUSSRParadrops(128 + 52, IslandParadropReinforcementsDropzone) + SendUSSRParadrops(Angle.New(720), IslandParadropReinforcementsDropzone) end SendUSSRParadrops = function(facing, dropzone) local paraproxy = Actor.Create("powerproxy.paratroopers", false, { Owner = ussr }) - local aircraft = paraproxy.ActivateParatroopers(dropzone.CenterPosition, facing) + local aircraft = paraproxy.TargetParatroopers(dropzone.CenterPosition, facing) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) @@ -336,7 +336,7 @@ if a.Owner == player and a.Type ~= "jeep.mission" and not paradropsTriggered then paradropsTriggered = true Trigger.RemoveFootprintTrigger(id) - SendUSSRParadrops(54, ParadropReinforcementsDropzone) + SendUSSRParadrops(Angle.New(216), ParadropReinforcementsDropzone) end end) Trigger.OnEnteredFootprint(ReinforcementsTriggerArea, function(a, id) diff -Nru openra-20200503/mods/ra/maps/allies-03b/map.yaml openra-20210321/mods/ra/maps/allies-03b/map.yaml --- openra-20200503/mods/ra/maps/allies-03b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-03b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -529,12 +529,12 @@ Actor189: e2 Location: 98,91 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 0 Actor201: e1.autotarget Location: 64,91 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 4 Actor202: e1.autotarget Location: 61,99 @@ -551,22 +551,22 @@ Actor205: e2.autotarget Location: 90,92 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 0 Actor206: e1.autotarget Location: 56,45 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 1 Actor207: e1.autotarget Location: 57,44 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 3 Actor208: e2.autotarget Location: 57,43 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 0 Actor210: e1 Location: 103,96 @@ -575,7 +575,7 @@ Actor211: e1 Location: 102,95 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 4 Actor212: e1.autotarget Location: 79,94 @@ -1039,80 +1039,80 @@ Jeep: jeep.mission Location: 101,97 Owner: England - Facing: 32 + Facing: 128 Heavy1: 3tnk Location: 96,66 Owner: USSR Health: 13 - Facing: 128 + Facing: 512 Heavy2: 3tnk Location: 97,65 Owner: USSR Health: 13 - Facing: 128 + Facing: 512 Heavy3: 3tnk Location: 98,66 Owner: USSR Health: 6 - Facing: 128 + Facing: 512 USSRTruk: truk Location: 56,93 Owner: USSR - Facing: 96 + Facing: 384 MediGuard: e2 Location: 104,48 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 1 PGuard1: e1 Location: 89,85 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 3 PGuard2: e1 Location: 89,86 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 3 PGuard3: e1 Location: 89,86 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 1 PGuard4: e1 Location: 89,87 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 1 PGuard5: e1 Location: 91,84 Owner: USSR - Facing: 128 + Facing: 512 SubCell: 4 USSRBaseGuard1: e2.autotarget Location: 96,60 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 1 USSRBaseGuard2: e2.autotarget Location: 102,49 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 USSRBaseGuard3: e2.autotarget Location: 104,50 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 USSRCheckpointGuard1: e1 Location: 95,68 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 0 USSRCheckpointGuard2: e1 Location: 99,68 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 0 Jail1: prison Location: 104,47 @@ -1124,27 +1124,27 @@ Location: 104,47 Owner: Greece Health: 15 - Facing: 192 + Facing: 768 SubCell: 0 PrisonedEngi1: e6 Location: 91,86 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 0 PrisonedEngi2: e6 Location: 91,86 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 1 PrisonedEngi3: e6 Location: 91,86 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 2 PrisonedEngi4: e6 Location: 91,86 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 4 MediHideaway: v06 Location: 57,93 @@ -1152,7 +1152,7 @@ InsertionHeli: tran Location: 55,80 Owner: Greece - Facing: 32 + Facing: 128 TanyaWaypoint: waypoint Location: 54,81 Owner: Greece diff -Nru openra-20200503/mods/ra/maps/allies-03b/rules.yaml openra-20210321/mods/ra/maps/allies-03b/rules.yaml --- openra-20200503/mods/ra/maps/allies-03b/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-03b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -96,7 +96,7 @@ TRUK: -Demolishable: Targetable: - TargetTypes: Ground, Truk + TargetTypes: GroundActor, Truk Armor: Type: Truk diff -Nru openra-20200503/mods/ra/maps/allies-03b/weapons.yaml openra-20210321/mods/ra/maps/allies-03b/weapons.yaml --- openra-20200503/mods/ra/maps/allies-03b/weapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-03b/weapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,5 +1,5 @@ Colt45: - ValidTargets: Ground, Infantry, Truk + ValidTargets: Ground, GroundActor, Infantry, Truk Warhead@1Dam: SpreadDamage ValidTargets: Barrel, Infantry, Truk Versus: @@ -7,4 +7,4 @@ BarrelExplode: Warhead@1Dam: SpreadDamage - ValidTargets: Ground, Prisoner + ValidTargets: Ground, GroundActor, Prisoner diff -Nru openra-20200503/mods/ra/maps/allies-04/allies04-AI.lua openra-20210321/mods/ra/maps/allies-04/allies04-AI.lua --- openra-20200503/mods/ra/maps/allies-04/allies04-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-04/allies04-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -240,35 +240,7 @@ Trigger.AfterDelay(DateTime.Minutes(1), ProduceAircraft) end - TargetAndAttack(yak) - end) -end - -TargetAndAttack = function(yak, target) - if yak.IsDead then - return - end - - if not target or target.IsDead or (not target.IsInWorld) then - local enemies = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == player and self.HasProperty("Health") and yak.CanTarget(self) end) - - if #enemies > 0 then - target = Utils.Random(enemies) - end - end - - if target and yak.AmmoCount() > 0 and yak.CanTarget(target) then - yak.Attack(target) - else - yak.ReturnToBase() - end - - yak.CallFunc(function() - -- TODO: Replace this with an idle trigger once that works for aircraft - -- Add a delay of one tick to fix an endless recursive call - Trigger.AfterDelay(1, function() - TargetAndAttack(yak, target) - end) + InitializeAttackAircraft(yak, player) end) end diff -Nru openra-20200503/mods/ra/maps/allies-04/allies04.lua openra-20210321/mods/ra/maps/allies-04/allies04.lua --- openra-20200503/mods/ra/maps/allies-04/allies04.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-04/allies04.lua 2021-03-21 11:10:05.000000000 +0000 @@ -57,7 +57,7 @@ Paradropped = 0 Paradrop = function() Trigger.AfterDelay(Utils.RandomInteger(ParadropDelay[1], ParadropDelay[2]), function() - local aircraft = PowerProxy.ActivateParatroopers(Utils.Random(ParadropLZs)) + local aircraft = PowerProxy.TargetParatroopers(Utils.Random(ParadropLZs)) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) diff -Nru openra-20200503/mods/ra/maps/allies-04/map.yaml openra-20210321/mods/ra/maps/allies-04/map.yaml --- openra-20200503/mods/ra/maps/allies-04/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-04/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -269,59 +269,59 @@ Actor89: 3tnk Location: 42,35 Owner: USSR - Facing: 64 + Facing: 256 Actor90: 3tnk Location: 39,34 Owner: USSR - Facing: 64 + Facing: 256 Actor91: 3tnk Location: 49,31 Owner: USSR - Facing: 96 + Facing: 384 Actor93: e2 Location: 47,40 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 0 Actor94: e2 Location: 47,36 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 4 Actor95: e2 Location: 50,40 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 0 Actor96: e2 Location: 48,40 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 0 Actor97: e2 Location: 48,36 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 0 Actor98: e2 Location: 46,39 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 2 Actor99: e1 Location: 70,59 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 4 Actor100: e1 Location: 44,34 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 4 Actor101: e1 Location: 43,37 Owner: USSR - Facing: 96 + Facing: 384 SubCell: 4 waypoint17: waypoint Location: 92,68 @@ -342,7 +342,7 @@ Actor88: jeep Location: 70,60 Owner: Greece - Facing: 224 + Facing: 896 Actor132: jeep Location: 57,65 Owner: Greece @@ -413,20 +413,17 @@ Owner: USSR Location: 82,47 SubCell: 3 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor155: e1 Owner: USSR Location: 87,49 SubCell: 3 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor156: e1 Owner: USSR Location: 87,49 SubCell: 1 - Facing: 122 - TurretFacing: 122 + Facing: 488 AlliedConyard: fact Owner: Greece Location: 88,49 @@ -434,7 +431,7 @@ Harvester: harv Location: 57,24 Owner: USSR - Facing: 64 + Facing: 256 Conyard: fact Location: 49,24 Owner: USSR diff -Nru openra-20200503/mods/ra/maps/allies-04/rules.yaml openra-20210321/mods/ra/maps/allies-04/rules.yaml --- openra-20200503/mods/ra/maps/allies-04/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-04/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,7 +4,7 @@ World: LuaScript: - Scripts: allies04.lua, allies04-AI.lua + Scripts: campaign-global.lua, allies04.lua, allies04-AI.lua MissionData: Briefing: Soviet forces are trying to retake the pass you cleared for our convoys.\n\nDon't let this happen. Hold the pass and prevent the Soviets from taking this vital area.\n\nDestroy all Soviet units and buildings in this region. BriefingVideo: ally4.vqa diff -Nru openra-20200503/mods/ra/maps/allies-05a/allies05a-AI.lua openra-20210321/mods/ra/maps/allies-05a/allies05a-AI.lua --- openra-20200503/mods/ra/maps/allies-05a/allies05a-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-05a/allies05a-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -259,34 +259,7 @@ Trigger.AfterDelay(DateTime.Minutes(1), ProduceAircraft) end - TargetAndAttack(yak) - end) -end - -TargetAndAttack = function(yak, target) - if yak.IsDead then - return - end - - if not target or target.IsDead or (not target.IsInWorld) then - local enemies = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == greece and self.HasProperty("Health") and yak.CanTarget(self) end) - if #enemies > 0 then - target = Utils.Random(enemies) - end - end - - if target and yak.AmmoCount() > 0 and yak.CanTarget(target) then - yak.Attack(target) - else - yak.ReturnToBase() - end - - yak.CallFunc(function() - -- TODO: Replace this with an idle trigger once that works for aircraft - -- Add a delay of one tick to fix an endless recursive call - Trigger.AfterDelay(1, function() - TargetAndAttack(yak, target) - end) + InitializeAttackAircraft(yak, greece) end) end diff -Nru openra-20200503/mods/ra/maps/allies-05a/allies05a.lua openra-20210321/mods/ra/maps/allies-05a/allies05a.lua --- openra-20200503/mods/ra/maps/allies-05a/allies05a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-05a/allies05a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -329,7 +329,11 @@ end end) - Trigger.OnKilled(SamBarrel, Sam1.Kill) + Trigger.OnKilled(SamBarrel, function() + if not Sam1.IsDead then + Sam1.Kill() + end + end) Trigger.OnAllKilled(SamSites, function() greece.MarkCompletedObjective(KillSams) diff -Nru openra-20200503/mods/ra/maps/allies-05a/map.yaml openra-20210321/mods/ra/maps/allies-05a/map.yaml --- openra-20200503/mods/ra/maps/allies-05a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-05a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1121,11 +1121,11 @@ Actor380: v2rl Location: 48,87 Owner: USSR - Facing: 224 + Facing: 896 Actor381: v2rl Location: 51,84 Owner: USSR - Facing: 136 + Facing: 544 Actor382: v2rl Location: 45,82 Owner: USSR @@ -1145,11 +1145,11 @@ Actor387: 3tnk Location: 28,79 Owner: USSR - Facing: 160 + Facing: 640 Actor388: 3tnk Location: 42,84 Owner: USSR - Facing: 64 + Facing: 256 Actor390: 3tnk Location: 63,94 Owner: USSR @@ -1209,7 +1209,7 @@ Actor408: dog Location: 32,85 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 1 Actor409: dog Location: 46,81 @@ -1266,17 +1266,17 @@ Actor427: dog Location: 25,93 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 Actor430: e1 Location: 37,60 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 3 Actor431: e1 Location: 36,60 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 4 Actor94: brik Location: 39,79 @@ -1343,20 +1343,20 @@ Location: 65,83 Owner: USSR SubCell: 4 - Facing: 160 + Facing: 640 Mammoth: 4tnk Location: 41,57 Owner: USSR - Facing: 192 + Facing: 768 Dog1: dog Location: 24,54 Owner: USSR - Facing: 224 + Facing: 896 SubCell: 0 Dog2: dog Location: 23,55 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 0 PatrolA1: e1 Location: 28,56 @@ -1393,7 +1393,7 @@ Truk: truk.mission Location: 44,52 Owner: USSR - Facing: 160 + Facing: 640 Prison: miss Location: 25,106 Owner: USSR @@ -1428,7 +1428,7 @@ Harvester: harv Location: 59,91 Owner: USSR - Facing: 224 + Facing: 896 Sam1: sam Location: 16,107 Owner: USSR diff -Nru openra-20200503/mods/ra/maps/allies-05a/notifications.yaml openra-20210321/mods/ra/maps/allies-05a/notifications.yaml --- openra-20200503/mods/ra/maps/allies-05a/notifications.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-05a/notifications.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,9 +1,9 @@ -Sounds: - Notifications: +Sounds: + Notifications: bombit: bombit1 laugh: laugh1 gotit: gotit1 lefty: lefty1 keepem: keepem1 tuffguy: tuffguy1 - sking: sking1 \ No newline at end of file + sking: sking1 diff -Nru openra-20200503/mods/ra/maps/allies-05a/rules.yaml openra-20210321/mods/ra/maps/allies-05a/rules.yaml --- openra-20200503/mods/ra/maps/allies-05a/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-05a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,6 +1,6 @@ World: LuaScript: - Scripts: allies05a.lua, allies05a-AI.lua + Scripts: campaign-global.lua, allies05a.lua, allies05a-AI.lua MissionData: Briefing: Rescue Tanya.\n\nOnce disguised, your spy can move past any enemy unit, except dogs, without being detected. Direct him into the weapons factory located at a nearby Soviet Base where he will hijack a truck and free Tanya.\n\nWith Tanya's help, take out the air defenses on the island and a Chinook will arrive to rescue her.\n\nThen destroy all remaining Soviet buildings and units. BriefingVideo: ally5.vqa @@ -35,7 +35,7 @@ LST: -Selectable: Targetable: - TargetTypes: Ground, Water + TargetTypes: GroundActor, WaterActor Interactable: LST.IN: @@ -50,7 +50,7 @@ RevealsShroud: Range: 4c0 Targetable@GROUND: - TargetTypes: Ground + TargetTypes: GroundActor Interactable: TRAN.IN: @@ -68,7 +68,7 @@ -SpawnActorOnDeath: RevealsShroud: Range: 4c0 - ValidStances: Ally, Enemy + ValidRelationships: Ally, Enemy RequiresCondition: hijacked ExternalCondition@hijacked: Condition: hijacked @@ -82,14 +82,14 @@ WEAP: -InfiltrateForSupportPower: Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure + TargetTypes: GroundActor, C4, DetonateAttack, Structure WEAP.infiltratable: Inherits: WEAP Buildable: Prerequisites: ~disabled Targetable@Spy: - TargetTypes: Ground, C4, DetonateAttack, Structure, Mission Objectives + TargetTypes: GroundActor, C4, DetonateAttack, Structure, Mission Objectives RenderSprites: Image: WEAP ProvidesPrerequisite: @@ -99,7 +99,7 @@ Tooltip: Name: Prison Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure, Mission Objectives + TargetTypes: GroundActor, C4, DetonateAttack, Structure, Mission Objectives AttackOmni: Armament: Weapon: PrisonColt diff -Nru openra-20200503/mods/ra/maps/allies-05a/weapons.yaml openra-20210321/mods/ra/maps/allies-05a/weapons.yaml --- openra-20200503/mods/ra/maps/allies-05a/weapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-05a/weapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,6 +1,8 @@ PrisonColt: - ReloadDelay: 5 + ValidTargets: Ground, GroundActor + ReloadDelay: 7 Report: gun5.aud Projectile: InstantHit Warhead@1Dam: SpreadDamage AffectsParent: true + ValidTargets: Ground, GroundActor diff -Nru openra-20200503/mods/ra/maps/allies-06a/allies06a-AI.lua openra-20210321/mods/ra/maps/allies-06a/allies06a-AI.lua --- openra-20200503/mods/ra/maps/allies-06a/allies06a-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-06a/allies06a-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -154,34 +154,7 @@ Trigger.AfterDelay(DateTime.Seconds(BuildDelays), ProduceAircraft) end - TargetAndAttack(yak) - end) -end - -TargetAndAttack = function(yak, target) - if yak.IsDead then - return - end - - if not target or target.IsDead or (not target.IsInWorld) then - local enemies = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == player and self.HasProperty("Health") and yak.CanTarget(self) end) - if #enemies > 0 then - target = Utils.Random(enemies) - end - end - - if target and yak.AmmoCount() > 0 and yak.CanTarget(target) then - yak.Attack(target) - else - yak.ReturnToBase() - end - - yak.CallFunc(function() - -- TODO: Replace this with an idle trigger once that works for aircraft - -- Add a delay of one tick to fix an endless recursive call - Trigger.AfterDelay(1, function() - TargetAndAttack(yak, target) - end) + InitializeAttackAircraft(yak, player) end) end diff -Nru openra-20200503/mods/ra/maps/allies-06a/allies06a.lua openra-20210321/mods/ra/maps/allies-06a/allies06a.lua --- openra-20200503/mods/ra/maps/allies-06a/allies06a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-06a/allies06a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -146,7 +146,7 @@ local Proxy = Actor.Create("powerproxy.paratroopers", false, { Owner = ussr }) Utils.Do(ParadropWaypoints[Map.LobbyOption("difficulty")], function(waypoint) - Proxy.ActivateParatroopers(waypoint.CenterPosition, Facing.South) + Proxy.TargetParatroopers(waypoint.CenterPosition, Angle.South) end) Proxy.Destroy() end) diff -Nru openra-20200503/mods/ra/maps/allies-06a/map.yaml openra-20210321/mods/ra/maps/allies-06a/map.yaml --- openra-20200503/mods/ra/maps/allies-06a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-06a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -290,31 +290,31 @@ Actor105: jeep Location: 19,64 Owner: Greece - Facing: 127 + Facing: 508 Actor109: e2 Location: 13,85 Owner: USSR - Facing: 223 + Facing: 892 SubCell: 2 Actor110: e2 Location: 23,82 Owner: USSR - Facing: 31 + Facing: 124 SubCell: 3 Actor111: e1 Location: 20,64 Owner: Greece - Facing: 159 + Facing: 636 SubCell: 2 Actor112: e1 Location: 19,65 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 0 Actor113: e1 Location: 18,64 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 1 Actor114: e1 Location: 23,82 @@ -323,21 +323,21 @@ Actor115: e1 Location: 13,85 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 3 Actor117: dog Location: 79,100 Owner: USSR - Facing: 191 + Facing: 764 SubCell: 0 Actor126: ss Location: 59,102 Owner: USSR - Facing: 95 + Facing: 380 Actor130: ss Location: 74,113 Owner: USSR - Facing: 63 + Facing: 252 Actor177: mine Owner: Neutral Location: 56,94 @@ -356,38 +356,38 @@ harv: harv Location: 82,94 Owner: USSR - Facing: 31 + Facing: 124 tank1: 3tnk Location: 69,90 Owner: USSR - Facing: 95 + Facing: 380 tank2: 3tnk Location: 93,102 Owner: USSR - Facing: 31 + Facing: 124 tank3: 3tnk Location: 85,90 Owner: USSR tank4: 3tnk Location: 93,106 Owner: USSR - Facing: 63 + Facing: 252 tank5: 3tnk Location: 73,100 Owner: USSR - Facing: 63 + Facing: 252 tank6: v2rl Location: 80,90 Owner: USSR - Facing: 223 + Facing: 892 tank7: v2rl Location: 70,91 Owner: USSR - Facing: 95 + Facing: 380 tank8: v2rl Location: 74,101 Owner: USSR - Facing: 63 + Facing: 252 SubPatrol3_1: waypoint Location: 48,114 Owner: Neutral @@ -400,19 +400,19 @@ Patrol3Sub1: ss Location: 46,105 Owner: USSR - Facing: 63 + Facing: 252 Patrol3Sub2: ss Location: 77,71 Owner: USSR - Facing: 63 + Facing: 252 Patrol1Sub: ss Location: 46,71 Owner: USSR - Facing: 127 + Facing: 508 Patrol2Sub: ss Location: 52,85 Owner: USSR - Facing: 63 + Facing: 252 SubPatrol1_1: waypoint Location: 42,71 Owner: Neutral @@ -482,23 +482,23 @@ Mammoth1: 4tnk Location: 63,94 Owner: USSR - Facing: 63 + Facing: 252 Mammoth2: 4tnk Location: 82,87 Owner: USSR - Facing: 223 + Facing: 892 Mammoth3: 4tnk Location: 76,105 Owner: USSR - Facing: 31 + Facing: 124 AttackTnk1: 3tnk Location: 18,85 Owner: USSR - Facing: 31 + Facing: 124 AttackTnk2: 3tnk Location: 17,82 Owner: USSR - Facing: 223 + Facing: 892 BadGuy1: e1 Location: 20,69 Owner: USSR @@ -510,7 +510,7 @@ BadGuy3: e1 Location: 24,67 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 3 Patrol_1_e1: e1 Location: 71,84 @@ -519,7 +519,7 @@ Patrol_1_dog: dog Location: 72,84 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 1 Patrol_2_e1: e1 Location: 89,94 @@ -528,7 +528,7 @@ Patrol_2_dog: dog Location: 89,93 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Patrol_3_e1: e1 Location: 92,108 @@ -545,7 +545,7 @@ Patrol_4_dog: dog Location: 77,102 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 WaterUnloadEntry1: waypoint Location: 22,114 diff -Nru openra-20200503/mods/ra/maps/allies-06a/rules.yaml openra-20210321/mods/ra/maps/allies-06a/rules.yaml --- openra-20200503/mods/ra/maps/allies-06a/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-06a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,7 +4,7 @@ World: LuaScript: - Scripts: allies06a.lua, allies06a-AI.lua + Scripts: campaign-global.lua, allies06a.lua, allies06a-AI.lua MissionData: Briefing: Priority one is to establish a base and get your spy into one of the Soviet Tech Centers in the base across the gulf.\nData on the Iron Curtain is in there and we need it.\n\nOnce you get the data complete your mission...\nWipe out everything. BriefingVideo: ally6.vqa @@ -48,7 +48,7 @@ STEK: Targetable: - TargetTypes: Ground, Structure, C4, DetonateAttack, SpyInfiltrate + TargetTypes: GroundActor, Structure, C4, DetonateAttack, SpyInfiltrate TECH.CAM: Inherits: CAMERA @@ -91,7 +91,3 @@ MSUB: Buildable: Prerequisites: ~disabled - -SS: - AutoTarget: - InitialStanceAI: AttackAnything diff -Nru openra-20200503/mods/ra/maps/allies-06b/allies06b-AI.lua openra-20210321/mods/ra/maps/allies-06b/allies06b-AI.lua --- openra-20200503/mods/ra/maps/allies-06b/allies06b-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-06b/allies06b-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -166,34 +166,7 @@ Trigger.AfterDelay(DateTime.Seconds(BuildDelays / 2), ProduceAircraft) end - TargetAndAttack(yak) - end) -end - -TargetAndAttack = function(yak, target) - if yak.IsDead then - return - end - - if not target or target.IsDead or (not target.IsInWorld) then - local enemies = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == player and self.HasProperty("Health") and yak.CanTarget(self) end) - if #enemies > 0 then - target = Utils.Random(enemies) - end - end - - if target and yak.AmmoCount() > 0 and yak.CanTarget(target) then - yak.Attack(target) - else - yak.ReturnToBase() - end - - yak.CallFunc(function() - -- TODO: Replace this with an idle trigger once that works for aircraft - -- Add a delay of one tick to fix an endless recursive call - Trigger.AfterDelay(1, function() - TargetAndAttack(yak, target) - end) + InitializeAttackAircraft(yak, player) end) end diff -Nru openra-20200503/mods/ra/maps/allies-06b/map.yaml openra-20210321/mods/ra/maps/allies-06b/map.yaml --- openra-20200503/mods/ra/maps/allies-06b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-06b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -447,15 +447,15 @@ Actor148: 3tnk Location: 49,91 Owner: USSR - Facing: 127 + Facing: 508 Actor158: harv Location: 78,37 Owner: USSR - Facing: 223 + Facing: 892 Actor161: v2rl Location: 85,55 Owner: USSR - Facing: 63 + Facing: 252 Actor165: e1 Location: 75,93 Owner: USSR @@ -495,17 +495,17 @@ Actor183: e1 Location: 53,106 Owner: Greece - Facing: 31 + Facing: 124 SubCell: 2 Actor184: e1 Location: 55,105 Owner: Greece - Facing: 223 + Facing: 892 SubCell: 4 Actor186: ss Location: 67,62 Owner: USSR - Facing: 127 + Facing: 508 Actor236: mine Owner: Neutral Location: 88,35 @@ -530,11 +530,11 @@ AttackTank1: 3tnk Location: 71,87 Owner: USSR - Facing: 63 + Facing: 252 AttackTank2: 3tnk Location: 80,84 Owner: USSR - Facing: 95 + Facing: 380 AlliedEntry1: waypoint Location: 49,111 Owner: Neutral @@ -628,27 +628,27 @@ BadGuy1: e1 Location: 48,95 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 BadGuy2: e1 Location: 50,98 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 BadGuy3: e1 Location: 50,96 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 BadGuy4: e1 Location: 48,97 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Patrol1Sub: ss Location: 96,58 Owner: USSR - Facing: 127 + Facing: 508 SubPatrol1_1: waypoint Location: 96,58 Owner: Neutral @@ -658,7 +658,7 @@ Patrol2Sub: ss Location: 39,70 Owner: USSR - Facing: 95 + Facing: 380 SubPatrol2_1: waypoint Location: 42,63 Owner: Neutral @@ -668,7 +668,7 @@ Patrol3Sub: ss Location: 22,64 Owner: USSR - Facing: 191 + Facing: 764 SubPatrol3_1: waypoint Location: 41,75 Owner: Neutral @@ -678,7 +678,7 @@ Patrol4Sub: ss Location: 79,51 Owner: USSR - Facing: 191 + Facing: 764 SubPatrol4_1: waypoint Location: 79,51 Owner: Neutral @@ -688,7 +688,7 @@ Patrol5Sub: ss Owner: USSR Location: 94,75 - Facing: 125 + Facing: 500 SubPatrol5_1: waypoint Location: 94,94 Owner: Neutral @@ -698,15 +698,15 @@ Mammoth1: 4tnk Location: 69,43 Owner: USSR - Facing: 63 + Facing: 252 Mammoth2: 4tnk Location: 43,40 Owner: USSR - Facing: 63 + Facing: 252 Mammoth3: 4tnk Location: 54,37 Owner: USSR - Facing: 63 + Facing: 252 TnkPatrol1: waypoint Location: 69,43 Owner: Neutral @@ -740,42 +740,42 @@ Patrol_1_e1: e1 Location: 40,44 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 1 Patrol_1_dog: dog Location: 40,43 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 1 Patrol_2_e1: e1 Location: 41,37 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 1 Patrol_2_dog: dog Location: 41,37 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 3 Patrol_3_e1: e1 Location: 84,43 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 2 Patrol_3_dog: dog Location: 86,43 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 0 Patrol_4_e1: e1 Location: 67,51 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 Patrol_4_dog: dog Location: 66,50 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 3 Patrol1: waypoint Location: 85,43 @@ -804,34 +804,34 @@ tank1: 3tnk Location: 81,56 Owner: USSR - Facing: 95 + Facing: 380 tank2: 3tnk Location: 77,54 Owner: USSR - Facing: 95 + Facing: 380 tank3: 3tnk Location: 64,43 Owner: USSR - Facing: 159 + Facing: 636 tank4: 3tnk Location: 45,43 Owner: USSR - Facing: 127 + Facing: 508 tank5: 3tnk Location: 51,56 Owner: USSR tank6: v2rl Location: 46,41 Owner: USSR - Facing: 95 + Facing: 380 tank7: v2rl Location: 62,42 Owner: USSR - Facing: 159 + Facing: 636 BeachDog: dog Location: 75,54 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 BeachPatrol1: waypoint Owner: Neutral diff -Nru openra-20200503/mods/ra/maps/allies-06b/rules.yaml openra-20210321/mods/ra/maps/allies-06b/rules.yaml --- openra-20200503/mods/ra/maps/allies-06b/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-06b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,7 +4,7 @@ World: LuaScript: - Scripts: allies06b.lua, allies06b-AI.lua + Scripts: campaign-global.lua, allies06b.lua, allies06b-AI.lua MissionData: BriefingVideo: ally6.vqa WinVideo: allymorf.vqa @@ -50,7 +50,7 @@ STEK: Targetable: - TargetTypes: Ground, Structure, C4, DetonateAttack, SpyInfiltrate + TargetTypes: GroundActor, Structure, C4, DetonateAttack, SpyInfiltrate APWR: Buildable: @@ -87,7 +87,3 @@ MSUB: Buildable: Prerequisites: ~disabled - -SS: - AutoTarget: - InitialStanceAI: AttackAnything diff -Nru openra-20200503/mods/ra/maps/allies-07/allies07-AI.lua openra-20210321/mods/ra/maps/allies-07/allies07-AI.lua --- openra-20200503/mods/ra/maps/allies-07/allies07-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-07/allies07-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ SovietAircraftType = { "yak" } Yaks = { } SovietInfantry = { "e1", "e2", "e4" } -SovietVehicles = +SovietVehicles = { hard = { "3tnk", "3tnk", "v2rl" }, normal = { "3tnk" }, @@ -37,7 +37,7 @@ Paradrop = function() Trigger.AfterDelay(Utils.RandomInteger(ParadropDelay[1], ParadropDelay[2]), function() - local aircraft = PowerProxy.ActivateParatroopers(Utils.Random(ParadropLZs)) + local aircraft = PowerProxy.TargetParatroopers(Utils.Random(ParadropLZs)) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) @@ -131,34 +131,7 @@ Trigger.AfterDelay(DateTime.Seconds(ProductionInterval[Map.LobbyOption("difficulty")] / 2), ProduceAircraft) end - TargetAndAttack(yak) - end) -end - -TargetAndAttack = function(yak, target) - if yak.IsDead then - return - end - - if not target or target.IsDead or (not target.IsInWorld) then - local enemies = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == greece and self.HasProperty("Health") and yak.CanTarget(self) end) - if #enemies > 0 then - target = Utils.Random(enemies) - end - end - - if target and yak.AmmoCount() > 0 and yak.CanTarget(target) then - yak.Attack(target) - else - yak.ReturnToBase() - end - - yak.CallFunc(function() - -- TODO: Replace this with an idle trigger once that works for aircraft - -- Add a delay of one tick to fix an endless recursive call - Trigger.AfterDelay(1, function() - TargetAndAttack(yak, target) - end) + InitializeAttackAircraft(yak, greece) end) end diff -Nru openra-20200503/mods/ra/maps/allies-07/map.yaml openra-20210321/mods/ra/maps/allies-07/map.yaml --- openra-20200503/mods/ra/maps/allies-07/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-07/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -388,109 +388,109 @@ Actor107: v2rl Location: 95,60 Owner: USSR - Facing: 191 + Facing: 764 Actor108: v2rl Location: 87,56 Owner: USSR - Facing: 223 + Facing: 892 Actor109: v2rl Location: 78,54 Owner: USSR - Facing: 31 + Facing: 124 Actor110: v2rl Location: 78,67 Owner: USSR - Facing: 63 + Facing: 252 Actor111: v2rl Location: 78,62 Owner: USSR - Facing: 63 + Facing: 252 Actor112: 3tnk Location: 87,69 Owner: USSR - Facing: 31 + Facing: 124 Actor113: 3tnk Location: 84,71 Owner: USSR - Facing: 31 + Facing: 124 Actor114: v2rl Location: 94,68 Owner: USSR - Facing: 159 + Facing: 636 Actor115: jeep Location: 27,58 Owner: England Health: 7 - Facing: 159 + Facing: 636 Actor116: 3tnk Location: 72,67 Owner: USSR - Facing: 95 + Facing: 380 Actor117: 3tnk Location: 63,66 Owner: USSR - Facing: 95 + Facing: 380 Actor118: 3tnk Location: 43,79 Owner: BadGuy - Facing: 31 + Facing: 124 Actor119: 3tnk Location: 47,55 Owner: USSR - Facing: 159 + Facing: 636 Actor120: v2rl Location: 89,71 Owner: BadGuy - Facing: 31 + Facing: 124 Actor121: v2rl Location: 48,80 Owner: BadGuy - Facing: 31 + Facing: 124 Actor122: 3tnk Location: 65,69 Owner: USSR - Facing: 63 + Facing: 252 Actor123: 3tnk Location: 69,69 Owner: USSR - Facing: 63 + Facing: 252 Actor124: 3tnk Location: 53,56 Owner: USSR - Facing: 95 + Facing: 380 Actor125: 3tnk Location: 67,71 Owner: BadGuy - Facing: 31 + Facing: 124 Actor126: e1 Location: 79,64 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Actor127: e1 Location: 78,63 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 0 Actor128: e1 Location: 82,62 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 0 Actor129: e1 Location: 95,59 Owner: USSR - Facing: 223 + Facing: 892 SubCell: 2 Actor130: e1 Location: 94,60 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 2 Actor131: e1 Location: 96,61 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 1 Actor132: e2 Location: 77,66 @@ -507,27 +507,27 @@ Actor135: e2 Location: 59,70 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 2 Actor136: e2 Location: 60,71 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 4 Actor137: e2 Location: 58,71 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 4 Actor138: e2 Location: 71,62 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 0 Actor139: e2 Location: 70,63 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 4 Actor140: e1 Location: 82,74 @@ -536,140 +536,140 @@ Actor141: e1 Location: 80,72 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Actor142: e1 Location: 81,76 Owner: USSR - Facing: 223 + Facing: 892 SubCell: 3 Actor143: e1 Location: 80,77 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 1 Actor144: e2 Location: 84,74 Owner: USSR - Facing: 223 + Facing: 892 SubCell: 4 Actor145: e2 Location: 81,77 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 4 Actor146: e2 Location: 81,75 Owner: USSR - Facing: 191 + Facing: 764 SubCell: 1 Actor147: e4 Location: 30,61 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 0 Actor148: e4 Location: 30,59 Owner: USSR - Facing: 31 + Facing: 124 SubCell: 0 Actor149: e1 Location: 26,58 Owner: England Health: 61 - Facing: 191 + Facing: 764 SubCell: 0 Actor150: e1 Location: 27,57 Owner: England Health: 43 - Facing: 159 + Facing: 636 SubCell: 0 Actor151: e1 Location: 26,59 Owner: England Health: 55 - Facing: 159 + Facing: 636 SubCell: 4 BeachRifle1: e1 Location: 35,55 Owner: BadGuy - Facing: 63 + Facing: 252 SubCell: 3 BeachRifle2: e1 Location: 33,55 Owner: BadGuy - Facing: 95 + Facing: 380 SubCell: 4 BeachRifle3: e1 Location: 34,55 Owner: BadGuy - Facing: 31 + Facing: 124 SubCell: 1 BeachRifle4: e1 Location: 34,56 Owner: BadGuy - Facing: 159 + Facing: 636 SubCell: 4 Actor156: dog Location: 82,65 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 Actor157: dog Location: 86,62 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 4 Actor158: dog Location: 80,69 Owner: USSR - Facing: 223 + Facing: 892 SubCell: 3 Actor159: e2 Location: 40,74 Owner: BadGuy - Facing: 95 + Facing: 380 SubCell: 0 Actor160: e2 Location: 40,73 Owner: BadGuy - Facing: 223 + Facing: 892 SubCell: 4 Actor161: e1 Location: 46,74 Owner: BadGuy - Facing: 63 + Facing: 252 SubCell: 1 Actor162: e1 Location: 45,75 Owner: BadGuy - Facing: 95 + Facing: 380 SubCell: 2 Actor163: e1 Location: 47,74 Owner: BadGuy - Facing: 159 + Facing: 636 SubCell: 1 Actor164: e1 Location: 67,66 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Actor165: e1 Location: 68,70 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 1 Actor166: e1 Location: 66,68 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 Actor167: e1 Location: 66,66 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 1 Actor168: e1 Location: 45,81 @@ -690,22 +690,22 @@ Actor172: e4 Location: 45,77 Owner: BadGuy - Facing: 223 + Facing: 892 SubCell: 0 Actor173: e4 Location: 31,60 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 1 Actor174: dog Location: 60,80 Owner: USSR - Facing: 223 + Facing: 892 SubCell: 0 Actor175: e4 Location: 61,63 Owner: BadGuy - Facing: 127 + Facing: 508 SubCell: 3 Actor176: e4 Location: 66,72 @@ -714,47 +714,47 @@ Actor177: e4 Location: 62,67 Owner: BadGuy - Facing: 95 + Facing: 380 SubCell: 3 Actor178: pt Location: 13,51 Owner: Greece - Facing: 191 + Facing: 764 Actor179: pt Location: 13,55 Owner: Greece - Facing: 191 + Facing: 764 Sub1: ss Location: 43,52 Owner: USSR - Facing: 31 + Facing: 124 Sub2: ss Location: 39,52 Owner: USSR - Facing: 191 + Facing: 764 Sub3: ss Location: 21,53 Owner: USSR - Facing: 63 + Facing: 252 Sub4: ss Location: 13,70 Owner: USSR Sub5: ss Location: 16,75 Owner: USSR - Facing: 31 + Facing: 124 Sub6: ss Location: 66,58 Owner: USSR - Facing: 63 + Facing: 252 Sub7: ss Location: 71,54 Owner: USSR - Facing: 31 + Facing: 124 Sub8: ss Location: 65,50 Owner: USSR - Facing: 95 + Facing: 380 Sub9: ss Location: 103,75 Owner: USSR @@ -767,27 +767,27 @@ Sub12: ss Location: 95,78 Owner: USSR - Facing: 191 + Facing: 764 Sub13: ss Location: 86,46 Owner: USSR - Facing: 63 + Facing: 252 Sub14: ss Location: 93,51 Owner: USSR - Facing: 31 + Facing: 124 Sub15: ss Location: 101,50 Owner: BadGuy - Facing: 159 + Facing: 636 Sub16: ss Location: 99,51 Owner: BadGuy - Facing: 63 + Facing: 252 Sub17: ss Location: 99,48 Owner: BadGuy - Facing: 95 + Facing: 380 AlliedMCVEntry: waypoint Location: 10,53 Owner: Neutral diff -Nru openra-20200503/mods/ra/maps/allies-07/rules.yaml openra-20210321/mods/ra/maps/allies-07/rules.yaml --- openra-20200503/mods/ra/maps/allies-07/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-07/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,7 +4,7 @@ World: LuaScript: - Scripts: allies07.lua, allies07-AI.lua + Scripts: campaign-global.lua, allies07.lua, allies07-AI.lua MissionData: Briefing: LANDCOM 16 HQS.\nTOP SECRET.\nTO: FIELD COMMANDER A9\n\nINTERCEPTION OF SOVIET COMMUNIQUE INDICATES THEIR IRON CURTAIN RESEARCH WAS SET BACK BY ESPIONAGE. EXCELLENT WORK, COMMANDER!\n\nCOMMUNIQUE WAS TRACED BACK TO SECRET SOVIET BASE IN BORNHOLM. INVESTIGATE POSSIBLE CONNECTION WITH IRON CURTAIN RESEARCH. CAPTURE RADAR CENTER AND DESTROY SUB PRODUCTION CAPABILITY.\n\nCONFIRMATION CODE 1138.\n\nTRANSMISSION ENDS.\n StartVideo: shorbom1.vqa @@ -127,7 +127,3 @@ MSUB: Buildable: Prerequisites: ~disabled - -SS: - AutoTarget: - InitialStanceAI: AttackAnything diff -Nru openra-20200503/mods/ra/maps/allies-08a/allies08a-AI.lua openra-20210321/mods/ra/maps/allies-08a/allies08a-AI.lua --- openra-20200503/mods/ra/maps/allies-08a/allies08a-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-08a/allies08a-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -17,13 +17,13 @@ GroundWavesUpgradeDelay = DateTime.Minutes(12) GroundAttackUnitType = "Normal" -GroundAttackUnits = -{ +GroundAttackUnits = +{ Normal = { {"4tnk", "3tnk", "e2", "e2", "e2" }, { "3tnk", "v2rl", "e4", "e4", "e4" } }, Upgraded = { {"4tnk", "3tnk", "ftrk", "apc", "apc", "e1", "e1", "e1", "e1", "e1", "e2", "e2", "e2" }, { "3tnk", "v2rl", "ftrk", "apc", "apc", "e1", "e1", "e1", "e1", "e1", "e4", "e4", "e4" } } } -GroundAttackPaths = -{ +GroundAttackPaths = +{ { SovEntry1.Location, ParaLZ3.Location, AttackChrono.Location }, { SovEntry2.Location, ParaLZ5.Location, AttackChrono.Location }, { SovEntry3.Location, ParaLZ5.Location, AttackChrono.Location } @@ -125,36 +125,7 @@ Trigger.AfterDelay(DateTime.Seconds(ProductionInterval[Map.LobbyOption("difficulty")] / 2), ProduceAircraft) end - TargetAndAttack(mig) - end) -end - -TargetAndAttack = function(mig, target) - if mig.IsDead then - return - end - - if not target or target.IsDead or (not target.IsInWorld) then - local enemies = Utils.Where(greece.GetActors(), function(actor) - return actor.HasProperty("Health") and actor.Type ~= "brik" and mig.CanTarget(target) - end) - if #enemies > 0 then - target = Utils.Random(enemies) - end - end - - if target and mig.AmmoCount() > 0 and mig.CanTarget(target) then - mig.Attack(target) - else - mig.ReturnToBase() - end - - mig.CallFunc(function() - -- TODO: Replace this with an idle trigger once that works for aircraft - -- Add a delay of one tick to fix an endless recursive call - Trigger.AfterDelay(1, function() - TargetAndAttack(mig, target) - end) + InitializeAttackAircraft(mig, greece) end) end @@ -189,7 +160,7 @@ end Paradrop = function() - local aircraft = PowerProxy.ActivateParatroopers(Utils.Random(ParadropLZs)) + local aircraft = PowerProxy.TargetParatroopers(Utils.Random(ParadropLZs)) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) @@ -209,8 +180,8 @@ end local targets = Utils.Where(greece.GetActors(), function(actor) - return - actor.HasProperty("Sell") and + return + actor.HasProperty("Sell") and actor.Type ~= "brik" and actor.Type ~= "sbag" or actor.Type == "pdox" or @@ -218,7 +189,7 @@ end) if #targets > 0 then - airfield.SendAirstrike(Utils.Random(targets).CenterPosition, true, 0) + airfield.TargetAirstrike(Utils.Random(targets).CenterPosition) end Trigger.AfterDelay(DateTime.Minutes(BombDelays), SendParabombs) diff -Nru openra-20200503/mods/ra/maps/allies-08a/allies08a.lua openra-20210321/mods/ra/maps/allies-08a/allies08a.lua --- openra-20200503/mods/ra/maps/allies-08a/allies08a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-08a/allies08a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -74,26 +74,15 @@ end) end -FinishTimer = function() - for i = 0, 5 do - local c = TimerColor - if i % 2 == 0 then - c = HSLColor.White - end - - Trigger.AfterDelay(DateTime.Seconds(i), function() UserInterface.SetMissionText("The experiment is a success!", c) end) - end - Trigger.AfterDelay(DateTime.Seconds(6), function() UserInterface.SetMissionText("") end) -end - DefendChronosphereCompleted = function() local cells = Utils.ExpandFootprint({ ChronoshiftLocation.Location }, false) local units = { } for i = 1, #cells do - local unit = Actor.Create("2tnk", true, { Owner = greece, Facing = 0 }) + local unit = Actor.Create("2tnk", true, { Owner = greece, Facing = Angle.North }) units[unit] = cells[i] end Chronosphere.Chronoshift(units) + UserInterface.SetMissionText("The experiment is a success!", greece.Color) Trigger.AfterDelay(DateTime.Seconds(3), function() greece.MarkCompletedObjective(DefendChronosphere) diff -Nru openra-20200503/mods/ra/maps/allies-08a/map.yaml openra-20210321/mods/ra/maps/allies-08a/map.yaml --- openra-20200503/mods/ra/maps/allies-08a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-08a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -688,12 +688,12 @@ Location: 71,100 Owner: Greece Health: 99 - Facing: 191 + Facing: 764 Gun4: gun Location: 71,103 Owner: Greece Health: 99 - Facing: 191 + Facing: 764 OreRef: proc Location: 62,90 Owner: Greece @@ -813,77 +813,77 @@ Actor259: 3tnk Location: 56,64 Owner: USSR - Facing: 31 + Facing: 124 Actor260: 3tnk Location: 52,66 Owner: USSR Actor261: 2tnk Location: 28,60 Owner: Greece - Facing: 159 + Facing: 636 Actor262: 2tnk Location: 28,66 Owner: Greece - Facing: 191 + Facing: 764 Actor263: 2tnk Location: 28,64 Owner: Greece - Facing: 191 + Facing: 764 Actor264: 2tnk Location: 30,66 Owner: Greece - Facing: 223 + Facing: 892 Actor265: 1tnk Location: 30,64 Owner: Greece - Facing: 191 + Facing: 764 Actor266: 1tnk Location: 29,62 Owner: Greece - Facing: 191 + Facing: 764 Actor267: mnly Location: 27,61 Owner: Greece - Facing: 191 + Facing: 764 Actor268: mnly Location: 26,60 Owner: Greece - Facing: 191 + Facing: 764 Actor269: jeep Location: 32,61 Owner: Greece - Facing: 223 + Facing: 892 Actor270: arty Location: 24,66 Owner: Greece - Facing: 223 + Facing: 892 Actor271: arty Location: 25,67 Owner: Greece - Facing: 223 + Facing: 892 Actor272: harv Location: 65,95 Owner: Greece - Facing: 95 + Facing: 380 Actor273: e1 Location: 58,98 Owner: Greece - Facing: 31 + Facing: 124 SubCell: 4 Actor274: e1 Location: 59,98 Owner: Greece - Facing: 223 + Facing: 892 SubCell: 4 Actor275: e1 Location: 55,102 Owner: Greece - Facing: 31 + Facing: 124 SubCell: 0 Actor276: e1 Location: 62,102 Owner: Greece - Facing: 223 + Facing: 892 SubCell: 4 Actor277: e1 Location: 62,99 @@ -892,7 +892,7 @@ Actor278: e1 Location: 55,91 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 0 Actor279: e1 Location: 54,103 @@ -901,12 +901,12 @@ Actor280: e1 Location: 55,99 Owner: Greece - Facing: 31 + Facing: 124 SubCell: 0 Actor281: e1 Location: 61,91 Owner: Greece - Facing: 31 + Facing: 124 SubCell: 0 Actor282: e1 Location: 63,104 diff -Nru openra-20200503/mods/ra/maps/allies-08a/rules.yaml openra-20210321/mods/ra/maps/allies-08a/rules.yaml --- openra-20200503/mods/ra/maps/allies-08a/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-08a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,7 +4,7 @@ World: LuaScript: - Scripts: allies08a.lua, allies08a-AI.lua + Scripts: campaign-global.lua, allies08a.lua, allies08a-AI.lua MissionData: Briefing: Our latest technology, the Chronosphere, is housed in this research station. The timer represents the appointed time for the completion of a vital experiment. The Soviets have learned of this and are moving in. \n\nProtect the Chronosphere and the Advanced-Tech research center. Make sure the base is fully powered at the appointed time. If not, all will be lost! BriefingVideo: ally8.vqa diff -Nru openra-20200503/mods/ra/maps/allies-08b/allies08b-AI.lua openra-20210321/mods/ra/maps/allies-08b/allies08b-AI.lua --- openra-20200503/mods/ra/maps/allies-08b/allies08b-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-08b/allies08b-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -17,13 +17,13 @@ GroundWavesUpgradeDelay = DateTime.Minutes(12) GroundAttackUnitType = "Normal" -GroundAttackUnits = -{ +GroundAttackUnits = +{ Normal = { {"4tnk", "3tnk", "e2", "e2", "e2" }, { "3tnk", "v2rl", "e4", "e4", "e4" } }, Upgraded = { {"4tnk", "3tnk", "ftrk", "apc", "apc", "e1", "e1", "e1", "e1", "e1", "e2", "e2", "e2" }, { "3tnk", "v2rl", "ftrk", "apc", "apc", "e1", "e1", "e1", "e1", "e1", "e4", "e4", "e4" } } } -GroundAttackPaths = -{ +GroundAttackPaths = +{ { SovEntry1.Location, ParaLZ2.Location, AttackChrono.Location }, { SovEntry2.Location, ParaLZ2.Location, AttackChrono.Location }, { SovEntry3.Location, ParaLZ4.Location, AttackChrono.Location } @@ -124,36 +124,7 @@ Trigger.AfterDelay(DateTime.Seconds(ProductionInterval[Map.LobbyOption("difficulty")] / 2), ProduceAircraft) end - TargetAndAttack(mig) - end) -end - -TargetAndAttack = function(mig, target) - if mig.IsDead then - return - end - - if not target or target.IsDead or (not target.IsInWorld) then - local enemies = Utils.Where(greece.GetActors(), function(actor) - return actor.HasProperty("Health") and actor.Type ~= "brik" and mig.CanTarget(target) - end) - if #enemies > 0 then - target = Utils.Random(enemies) - end - end - - if target and mig.AmmoCount() > 0 and mig.CanTarget(target) then - mig.Attack(target) - else - mig.ReturnToBase() - end - - mig.CallFunc(function() - -- TODO: Replace this with an idle trigger once that works for aircraft - -- Add a delay of one tick to fix an endless recursive call - Trigger.AfterDelay(1, function() - TargetAndAttack(mig, target) - end) + InitializeAttackAircraft(mig, greece) end) end @@ -188,7 +159,7 @@ end Paradrop = function() - local aircraft = PowerProxy.ActivateParatroopers(Utils.Random(ParadropLZs)) + local aircraft = PowerProxy.TargetParatroopers(Utils.Random(ParadropLZs)) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) @@ -209,8 +180,8 @@ end local targets = Utils.Where(greece.GetActors(), function(actor) - return - actor.HasProperty("Sell") and + return + actor.HasProperty("Sell") and actor.Type ~= "brik" and actor.Type ~= "sbag" or actor.Type == "pdox" or @@ -218,7 +189,7 @@ end) if #targets > 0 then - airfield.SendAirstrike(Utils.Random(targets).CenterPosition, true, 0) + airfield.TargetAirstrike(Utils.Random(targets).CenterPosition) end Trigger.AfterDelay(DateTime.Minutes(BombDelays), SendParabombs) diff -Nru openra-20200503/mods/ra/maps/allies-08b/allies08b.lua openra-20210321/mods/ra/maps/allies-08b/allies08b.lua --- openra-20200503/mods/ra/maps/allies-08b/allies08b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-08b/allies08b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -74,26 +74,15 @@ end) end -FinishTimer = function() - for i = 0, 5 do - local c = TimerColor - if i % 2 == 0 then - c = HSLColor.White - end - - Trigger.AfterDelay(DateTime.Seconds(i), function() UserInterface.SetMissionText("The experiment is a success!", c) end) - end - Trigger.AfterDelay(DateTime.Seconds(6), function() UserInterface.SetMissionText("") end) -end - DefendChronosphereCompleted = function() local cells = Utils.ExpandFootprint({ ChronoshiftLocation.Location }, false) local units = { } for i = 1, #cells do - local unit = Actor.Create("2tnk", true, { Owner = greece, Facing = 0 }) + local unit = Actor.Create("2tnk", true, { Owner = greece, Facing = Angle.North }) units[unit] = cells[i] end Chronosphere.Chronoshift(units) + UserInterface.SetMissionText("The experiment is a success!", greece.Color) Trigger.AfterDelay(DateTime.Seconds(3), function() greece.MarkCompletedObjective(DefendChronosphere) diff -Nru openra-20200503/mods/ra/maps/allies-08b/map.yaml openra-20210321/mods/ra/maps/allies-08b/map.yaml --- openra-20200503/mods/ra/maps/allies-08b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-08b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -411,11 +411,11 @@ AAGun1: agun Location: 64,45 Owner: Greece - Facing: 95 + Facing: 380 AAGun2: agun Location: 71,45 Owner: Greece - Facing: 159 + Facing: 636 Gap1: gap Location: 66,44 Owner: Greece @@ -449,19 +449,19 @@ Gun1: gun Location: 51,48 Owner: Greece - Facing: 63 + Facing: 252 Gun2: gun Location: 74,56 Owner: Greece - Facing: 95 + Facing: 380 Gun3: gun Location: 70,56 Owner: Greece - Facing: 95 + Facing: 380 Gun4: gun Location: 51,52 Owner: Greece - Facing: 63 + Facing: 252 Dome: dome Location: 75,41 Owner: Greece @@ -541,167 +541,167 @@ Actor156: harv Location: 60,47 Owner: Greece - Facing: 95 + Facing: 380 Actor157: 3tnk Location: 68,81 Owner: USSR - Facing: 159 + Facing: 636 Actor158: 3tnk Location: 66,82 Owner: USSR - Facing: 159 + Facing: 636 Actor159: 3tnk Location: 64,83 Owner: USSR - Facing: 159 + Facing: 636 Actor160: 3tnk Location: 65,80 Owner: USSR - Facing: 159 + Facing: 636 Actor161: 3tnk Location: 63,81 Owner: USSR - Facing: 159 + Facing: 636 Actor162: v2rl Location: 66,78 Owner: USSR - Facing: 159 + Facing: 636 Actor163: v2rl Location: 61,81 Owner: USSR - Facing: 159 + Facing: 636 Actor164: 2tnk Location: 100,86 Owner: Greece - Facing: 63 + Facing: 252 Actor165: 2tnk Location: 98,86 Owner: Greece - Facing: 63 + Facing: 252 Actor166: 2tnk Location: 98,88 Owner: Greece - Facing: 63 + Facing: 252 Actor167: 2tnk Location: 99,87 Owner: Greece - Facing: 63 + Facing: 252 Actor168: 1tnk Location: 96,85 Owner: Greece - Facing: 63 + Facing: 252 Actor169: 1tnk Location: 96,87 Owner: Greece - Facing: 63 + Facing: 252 Actor170: jeep Location: 94,87 Owner: Greece - Facing: 63 + Facing: 252 Actor171: arty Location: 101,87 Owner: Greece - Facing: 31 + Facing: 124 Actor172: arty Location: 100,88 Owner: Greece - Facing: 31 + Facing: 124 Actor173: mnly Location: 99,89 Owner: Greece - Facing: 31 + Facing: 124 Actor174: mnly Location: 102,86 Owner: Greece - Facing: 31 + Facing: 124 Actor175: 3tnk Location: 47,82 Owner: USSR - Facing: 191 + Facing: 764 Actor176: 3tnk Location: 47,85 Owner: USSR - Facing: 191 + Facing: 764 Actor177: v2rl Location: 36,82 Owner: USSR Actor178: 3tnk Location: 38,74 Owner: USSR - Facing: 223 + Facing: 892 Actor179: 3tnk Location: 41,74 Owner: USSR - Facing: 31 + Facing: 124 Actor180: e1 Location: 67,47 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 1 Actor181: e1 Location: 68,47 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 2 Actor182: e1 Location: 70,48 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 1 Actor183: e1 Location: 67,48 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 2 Actor184: e1 Location: 64,47 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 4 Actor185: e1 Location: 71,47 Owner: Greece - Facing: 159 + Facing: 636 SubCell: 3 Actor186: e1 Location: 71,47 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 2 Actor187: e1 Location: 64,47 Owner: Greece - Facing: 63 + Facing: 252 SubCell: 1 Actor188: e1 Location: 68,48 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 1 Actor189: e1 Location: 65,48 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 2 Actor190: e1 Location: 70,53 Owner: Greece - Facing: 159 + Facing: 636 SubCell: 4 Actor191: e1 Location: 73,53 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 4 Actor192: e1 Location: 40,79 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 0 Actor193: e1 Location: 39,79 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 3 Actor194: e2 Location: 46,81 @@ -710,17 +710,17 @@ Actor195: e2 Location: 45,85 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 4 Actor196: e2 Location: 40,85 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 4 Actor197: c1 Location: 97,66 Owner: England - Facing: 95 + Facing: 380 SubCell: 3 Actor198: c2 Location: 102,56 @@ -729,7 +729,7 @@ Actor199: c1 Location: 106,53 Owner: England - Facing: 95 + Facing: 380 SubCell: 4 Actor200: c3 Location: 102,60 @@ -738,7 +738,7 @@ Actor201: c4 Location: 102,67 Owner: England - Facing: 159 + Facing: 636 SubCell: 4 Actor202: c4 Location: 90,64 @@ -747,17 +747,17 @@ Actor203: c5 Location: 104,51 Owner: England - Facing: 127 + Facing: 508 SubCell: 3 Actor204: c6 Location: 98,67 Owner: England - Facing: 95 + Facing: 380 SubCell: 1 Actor205: c8 Location: 104,68 Owner: England - Facing: 159 + Facing: 636 SubCell: 3 MCVEntry: waypoint Location: 102,89 diff -Nru openra-20200503/mods/ra/maps/allies-08b/rules.yaml openra-20210321/mods/ra/maps/allies-08b/rules.yaml --- openra-20200503/mods/ra/maps/allies-08b/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-08b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,7 +4,7 @@ World: LuaScript: - Scripts: allies08b.lua, allies08b-AI.lua + Scripts: campaign-global.lua, allies08b.lua, allies08b-AI.lua MissionData: Briefing: Our latest technology, the Chronosphere, is housed in this research station. The timer represents the appointed time for the completion of a vital experiment. The Soviets have learned of this and are moving in. \n\nProtect the Chronosphere and the Advanced-Tech research center. Make sure the base is fully powered at the appointed time. If not, all will be lost! BriefingVideo: ally8.vqa diff -Nru openra-20200503/mods/ra/maps/allies-09a/allies09a-AI.lua openra-20210321/mods/ra/maps/allies-09a/allies09a-AI.lua --- openra-20200503/mods/ra/maps/allies-09a/allies09a-AI.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-09a/allies09a-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,209 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] + +WTransWays = +{ + { USSRRFEntry.Location, USSRUnload1.Location }, + { USSRRFEntry.Location, USSRUnload2.Location } +} +WTransUnits = +{ + hard = { { "3tnk", "3tnk", "3tnk", "v2rl", "v2rl" }, { "v2rl", "v2rl", "e4", "e4", "3tnk" } }, + normal = { { "e1", "e1", "3tnk", "3tnk", "v2rl" }, { "e4", "e4", "e4", "e4", "v2rl" } }, + easy = { { "e1", "e1", "e1", "e2", "e2" }, { "e2", "3tnk", "3tnk" } } +} +WTransDelays = +{ + easy = 7, + normal = 6, + hard = 5 +} +SubAttackGroupSize = +{ + easy = 1, + normal = 2, + hard = 3 +} +InfantryUnits = +{ + hard = { "e1", "e2", "e2", "e4", "e4" }, + normal = { "e1", "e1", "e2", "e2", "e4" }, + easy = { "e1", "e1", "e1", "e2", "e2" } +} +ProductionInterval = +{ + easy = DateTime.Seconds(60), + normal = DateTime.Seconds(40), + hard = DateTime.Seconds(20) +} +ParadropDelay = +{ + easy = 7, + normal = 6, + hard = 5 +} + +InfantryAttackGroup = { } +InfantryAttackGroupSize = 5 +VehicleAttackGroup = { } +VehicleAttackGroupSize = 3 +SubAttackGroup = { } +SovietAircraftType = { "yak" } +SovietSSType = { "ss" } +VehicleUnits = { "3tnk", "3tnk", "3tnk", "v2rl" } + +IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end + +SendInfantryAttackGroup = function() + if #InfantryAttackGroup < InfantryAttackGroupSize then + return + end + Utils.Do(InfantryAttackGroup, IdleHunt) + InfantryAttackGroup = { } +end + +SendVehicleAttackGroup = function() + if #VehicleAttackGroup < VehicleAttackGroupSize then + return + end + Utils.Do(VehicleAttackGroup, IdleHunt) + VehicleAttackGroup = { } +end + +SendSubAttackGroup = function() + if #SubAttackGroup < SubAttackGroupSize then + return + end + Utils.Do(SubAttackGroup, IdleHunt) + SubAttackGroup = { } +end + +ProduceSovietInfantry = function() + if (Barracks.IsDead or Barracks.Owner ~= USSR) and (BarracksA.IsDead or BarracksA.Owner ~= USSR) then + return + end + USSR.Build({ Utils.Random(InfantryUnits) }, function(units) + table.insert(InfantryAttackGroup, units[1]) + SendInfantryAttackGroup() + Trigger.AfterDelay(ProductionInterval, ProduceSovietInfantry) + end) +end + +ProduceSovietVehicle = function() + if WarFactory.IsDead or WarFactory.Owner ~= USSR then + return + end + USSR.Build({ Utils.Random(VehicleUnits) }, function(units) + table.insert(VehicleAttackGroup, units[1]) + SendVehicleAttackGroup() + Trigger.AfterDelay(ProductionInterval, ProduceSovietVehicle) + end) +end + +ProduceSovietSub = function() + if SubPen.IsDead or SubPen.Owner ~= USSR then + return + end + USSR.Build(SovietSSType, function(units) + table.insert(SubAttackGroup, units[1]) + SendSubAttackGroup() + Trigger.AfterDelay(ProductionInterval, ProduceSovietSub) + end) +end + +ProduceAircraft = function() + if Airfield.IsDead or Airfield.Owner ~= USSR then + return + end + USSR.Build(SovietAircraftType, function(units) + local yak = units[1] + Trigger.OnKilled(yak, ProduceAircraft) + InitializeAttackAircraft(yak, Greece) + end) +end + +WTransWaves = function() + if SubPen.IsDead or SubPen.Owner ~= USSR then + return + end + local way = Utils.Random(WTransWays) + local units = Utils.Random(WTransUnits) + local attackUnits = Reinforcements.ReinforceWithTransport(USSR, "lst", units , way, { way[2], way[1] })[2] + Utils.Do(attackUnits, function(a) + Trigger.OnAddedToWorld(a, function() + a.AttackMove(KosyginExtractPoint.Location) + IdleHunt(a) + end) + end) + Trigger.AfterDelay(DateTime.Minutes(WTransDelays), WTransWaves) +end + +MMGroupGuardGate = function() + if not MM1.IsDead then + MM1.AttackMove(WP78.Location) + end + if not MM2.IsDead then + MM2.AttackMove(WP79.Location) + end + if not MM1.IsDead then + MM3.AttackMove(WP80.Location) + end +end + +TankGroupWallGuard = function() + if not WGTank01.IsDead then + WGTank01.AttackMove(WP72.Location) + end + if not WGTank02.IsDead then + WGTank02.AttackMove(WP72.Location) + end + if not WGV2.IsDead then + WGV2.AttackMove(WP72.Location) + end +end + +Paradrop = function() + if Airfield.IsDead or Airfield.Owner ~= USSR then + return + end + local aircraft = PowerProxy.TargetParatroopers(KosyginExtractPoint.CenterPosition) + Utils.Do(aircraft, function(a) + Trigger.OnPassengerExited(a, function(t, p) + IdleHunt(p) + end) + end) + Trigger.AfterDelay(DateTime.Minutes(ParadropDelay), Paradrop) +end + +ActivateAI = function() + local difficulty = Map.LobbyOption("difficulty") + WTransUnits = WTransUnits[difficulty] + WTransDelays = WTransDelays[difficulty] + SubAttackGroupSize = SubAttackGroupSize[difficulty] + InfantryUnits = InfantryUnits[difficulty] + ProductionInterval = ProductionInterval[difficulty] + ParadropDelay = ParadropDelay[difficulty] + PowerProxy = Actor.Create("powerproxy.paratroopers", false, { Owner = USSR }) + local buildings = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == USSR and self.HasProperty("StartBuildingRepairs") end) + Utils.Do(buildings, function(actor) + Trigger.OnDamaged(actor, function(building) + if building.Owner == USSR and building.Health < building.MaxHealth * 3/4 then + building.StartBuildingRepairs() + end + end) + end) + Trigger.AfterDelay(DateTime.Minutes(2), ProduceAircraft) + Trigger.AfterDelay(DateTime.Minutes(2), ProduceSovietInfantry) + Trigger.AfterDelay(DateTime.Minutes(2), ProduceSovietVehicle) + Trigger.AfterDelay(DateTime.Minutes(4), ProduceSovietSub) + Trigger.AfterDelay(DateTime.Minutes(5), MMGroupGuardGate) + Trigger.AfterDelay(DateTime.Minutes(5), TankGroupWallGuard) + Trigger.AfterDelay(DateTime.Minutes(WTransDelays), WTransWaves) + Trigger.AfterDelay(DateTime.Minutes(ParadropDelay), Paradrop) +end diff -Nru openra-20200503/mods/ra/maps/allies-09a/allies09a.lua openra-20210321/mods/ra/maps/allies-09a/allies09a.lua --- openra-20200503/mods/ra/maps/allies-09a/allies09a.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-09a/allies09a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,184 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] + +lstReinforcements = +{ + actors = { "mcv" }, + entryPath = { AlliedMCVEntry.Location, Unload1.Location }, + exitPath = { AlliedMCVEntry.Location } +} + +ExtractionHelicopterType = "tran.extraction" +ExtractionPath = { HeliWP01.Location, HeliWP02.Location, HeliWP03.Location } +Dog5PatrolPath = { WP94.Location, WP93.Location } +Dog6PatrolPath = { WP90.Location, WP91.Location, WP92.Location, WP91.Location } +TankGroup10 = { TankGroup101, TankGroup102 } +TankGroup10PatrolPath = { WP81.Location, WP82.Location, WP83.Location, WP84.Location, WP85.Location, WP84.Location, WP83.Location, WP82.Location } +HuntDogsGroup = { Dog701, Dog702, Dog703, Dog704, Dog705, Dog706 } + +KosyginType = "gnrl" +KosyginContacted = false + +MissionAccomplished = function() + Media.PlaySpeechNotification(Greece, "MissionAccomplished") +end + +MissionFailed = function() + Media.PlaySpeechNotification(Greece, "MissionFailed") +end + +InitialAlliedReinforcements = function() + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(Greece, "ReinforcementsArrived") + Reinforcements.ReinforceWithTransport(Greece, "lst.reinforcement", lstReinforcements.actors, lstReinforcements.entryPath, lstReinforcements.exitPath) + end) +end + +RescueFailed = function() + Media.PlaySpeechNotification(Greece, "ObjectiveNotMet") + Greece.MarkFailedObjective(KosyginSurviveObjective) +end + +InitialSovietPatrols = function() + Dog5.Patrol(Dog5PatrolPath, true, DateTime.Seconds(60)) + Dog6.Patrol(Dog6PatrolPath, true, DateTime.Seconds(90)) + for i = 1, 2 do + TankGroup10[i].Patrol(TankGroup10PatrolPath, true, DateTime.Seconds(30)) + end +end + +CreateKosygin = function() + Greece.MarkCompletedObjective(UseSpyObjective) + Media.PlaySpeechNotification(Greece, "ObjectiveMet") + local kosygin = Actor.Create(KosyginType, true, { Location = KosyginSpawnPoint.Location, Owner = Greece }) + Trigger.OnKilled(kosygin, RescueFailed) + ExtractObjective = Greece.AddObjective("Extract Kosygin and\nget him back to your base.") + Trigger.AfterDelay(DateTime.Seconds(1), function() Media.PlaySpeechNotification(Greece, "TargetFreed") end) +end + +DogsGuardGates = function() + if not Dog707.IsDead then + Dog707.AttackMove(WP89.Location) + end + if not Dog708.IsDead then + Dog708.AttackMove(WP81.Location) + end + if not Dog709.IsDead then + Dog709.AttackMove(WP79.Location) + end +end + +InfiltrateForwardCenter = function() + Trigger.OnInfiltrated(USSRFC, function() + if not KosyginContacted then + KosyginContacted = true + CreateKosygin() + DogsGuardGates() + end + end) + + Trigger.OnKilledOrCaptured(USSRFC, function() + if not Greece.IsObjectiveCompleted(UseSpyObjective) then + Greece.MarkFailedObjective(UseSpyObjective) + end + end) +end + +Tick = function() + USSR.Cash = 5000 + if Greece.HasNoRequiredUnits() then + USSR.MarkCompletedObjective(USSRObj) + end +end + +TriggerHuntKosygin = function() + Trigger.OnEnteredProximityTrigger(WP79.CenterPosition, WDist.FromCells(4), function(actor, triggerflee) + if actor.Type == KosyginType then + Trigger.RemoveProximityTrigger(triggerflee) + for i = 1, 6 do + if not HuntDogsGroup[i].IsDead then + HuntDogsGroup[i].Attack(actor) + end + end + end + end) + Trigger.OnEnteredProximityTrigger(WP81.CenterPosition, WDist.FromCells(4), function(actor, triggerflee) + if actor.Type == KosyginType then + Trigger.RemoveProximityTrigger(triggerflee) + for i = 1, 6 do + if not HuntDogsGroup[i].IsDead then + HuntDogsGroup[i].Attack(actor) + end + end + end + end) + Trigger.OnEnteredProximityTrigger(WP89.CenterPosition, WDist.FromCells(4), function(actor, triggerflee) + if actor.Type == KosyginType then + Trigger.RemoveProximityTrigger(triggerflee) + for i = 1, 6 do + if not HuntDogsGroup[i].IsDead then + HuntDogsGroup[i].Attack(actor) + end + end + end + end) +end + +TriggerRevealUSSRBase = function() + Trigger.OnEnteredProximityTrigger(LowerBaseWP.CenterPosition, WDist.FromCells(10), function(a, id) + if a.Owner == Greece then + Trigger.RemoveProximityTrigger(id) + local cam = Actor.Create("Camera", true, { Owner = Greece, Location = RevealLowerBase.Location }) + Trigger.AfterDelay(DateTime.Seconds(15), cam.Destroy) + end + end) +end + +TriggerRevealUSSRFC = function() + Trigger.OnEnteredProximityTrigger(UpperBaseWP.CenterPosition, WDist.FromCells(10), function(a, id) + if a.Owner == Greece then + Trigger.RemoveProximityTrigger(id) + local cam = Actor.Create("Camera", true, { Owner = Greece, Location = KosyginSpawnPoint.Location }) + Trigger.AfterDelay(DateTime.Seconds(15), cam.Destroy) + end + end) +end + +TriggerExtractKosygin = function() + Trigger.OnEnteredProximityTrigger(KosyginExtractPoint.CenterPosition, WDist.FromCells(10), function(actor, triggerflee) + if actor.Type == KosyginType then + Reinforcements.ReinforceWithTransport(Greece, ExtractionHelicopterType, nil, ExtractionPath) + Trigger.RemoveProximityTrigger(triggerflee) + Trigger.AfterDelay(DateTime.Seconds(10), function() + Greece.MarkCompletedObjective(KosyginSurviveObjective) + Greece.MarkCompletedObjective(ExtractObjective) + Media.PlaySpeechNotification(Greece, "ObjectiveMet") + end) + end + end) +end + +WorldLoaded = function() + Greece = Player.GetPlayer("Greece") + USSR = Player.GetPlayer("USSR") + Camera.Position = DefaultCameraPosition.CenterPosition + UseSpyObjective = Greece.AddObjective("Infiltrate the Soviet command center and\ncontact Kosygin.") + KosyginSurviveObjective = Greece.AddObjective("Kosygin must survive.") + USSRObj = USSR.AddObjective("Eliminate all Allied forces.") + Trigger.OnPlayerLost(Greece, MissionFailed) + Trigger.OnPlayerWon(Greece, MissionAccomplished) + InitialAlliedReinforcements() + InfiltrateForwardCenter() + InitialSovietPatrols() + TriggerRevealUSSRBase() + TriggerRevealUSSRFC() + TriggerExtractKosygin() + TriggerHuntKosygin() + ActivateAI() +end Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/allies-09a/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/allies-09a/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/allies-09a/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/allies-09a/map.png differ diff -Nru openra-20200503/mods/ra/maps/allies-09a/map.yaml openra-20210321/mods/ra/maps/allies-09a/map.yaml --- openra-20200503/mods/ra/maps/allies-09a/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-09a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,975 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: 09a: Evacuate Kosygin + +Author: Westwood Studios + +Tileset: TEMPERAT + +MapSize: 86,72 + +Bounds: 1,1,84,70 + +Visibility: MissionSelector + +Categories: Campaign + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: england + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Faction: england + PlayerReference@USSR: + Name: USSR + Bot: campaign + Faction: soviet + Color: FF1400 + Enemies: Greece + PlayerReference@Greece: + Name: Greece + Playable: True + Required: True + LockFaction: True + Faction: allies + LockColor: True + Color: E2E6F5 + Enemies: USSR + +Actors: + Actor0: t17 + Owner: Neutral + Location: 18,21 + Health: 100 + Actor1: tc02 + Owner: Neutral + Location: 7,33 + Actor2: tc04 + Owner: Neutral + Location: 1,28 + Actor3: t08 + Owner: Neutral + Location: 6,29 + Actor4: tc04 + Owner: Neutral + Location: 9,27 + Health: 100 + Actor5: tc05 + Owner: Neutral + Location: 12,27 + Actor6: tc03 + Owner: Neutral + Location: 11,29 + Actor7: tc05 + Owner: Neutral + Location: 67,11 + Actor8: t16 + Owner: Neutral + Location: 73,10 + Actor9: t12 + Owner: Neutral + Location: 67,8 + Actor10: t02 + Owner: Neutral + Location: 67,4 + Actor11: t17 + Owner: Neutral + Location: 69,1 + Actor12: t14 + Owner: Neutral + Location: 71,3 + Actor13: t03 + Owner: Neutral + Location: 72,7 + Actor14: t12 + Owner: Neutral + Location: 59,19 + Actor15: mine + Owner: Neutral + Location: 69,57 + Actor16: t08 + Owner: Neutral + Location: 65,52 + Actor17: tc02 + Owner: Neutral + Location: 61,50 + Actor18: t07 + Owner: Neutral + Location: 60,53 + Actor19: tc01 + Owner: Neutral + Location: 55,53 + Actor20: mine + Owner: Neutral + Location: 43,58 + Actor21: t10 + Owner: Neutral + Location: 29,63 + Actor22: t08 + Owner: Neutral + Location: 28,63 + Actor23: t07 + Owner: Neutral + Location: 30,62 + Actor24: tc05 + Owner: Neutral + Location: 22,49 + Actor25: tc04 + Owner: Neutral + Location: 25,49 + Actor26: tc03 + Owner: Neutral + Location: 11,58 + Actor28: tc02 + Owner: Neutral + Location: 13,60 + Actor30: t11 + Owner: Neutral + Location: 12,59 + Actor29: tc01 + Owner: Neutral + Location: 15,61 + Actor31: tc04 + Owner: Neutral + Location: 22,27 + Health: 100 + Actor32: tc04 + Owner: Neutral + Location: 19,31 + Actor33: tc03 + Owner: Neutral + Location: 24,31 + Actor34: tc04 + Owner: Neutral + Location: 26,31 + Actor35: t10 + Owner: Neutral + Location: 26,28 + Actor36: tc02 + Owner: Neutral + Location: 31,25 + Health: 100 + Actor37: tc01 + Owner: Neutral + Location: 46,36 + Actor38: t11 + Owner: Neutral + Location: 44,35 + Actor39: t16 + Owner: Neutral + Location: 48,35 + Actor40: t11 + Owner: Neutral + Location: 45,31 + Actor41: t13 + Owner: Neutral + Location: 41,27 + Actor42: tc05 + Owner: Neutral + Location: 35,38 + Actor43: tc01 + Owner: Neutral + Location: 33,39 + Actor44: tc02 + Owner: Neutral + Location: 38,37 + Actor46: t17 + Owner: Neutral + Location: 38,31 + Actor47: t15 + Owner: Neutral + Location: 35,31 + Actor48: t16 + Owner: Neutral + Location: 38,29 + Actor49: brik + Owner: USSR + Location: 1,1 + Actor50: brik + Owner: USSR + Location: 1,1 + Actor51: brik + Owner: USSR + Location: 1,2 + Actor52: brik + Owner: USSR + Location: 1,3 + Actor53: brik + Owner: USSR + Location: 1,4 + Actor54: brik + Owner: USSR + Location: 1,5 + Actor55: brik + Owner: USSR + Location: 1,6 + Actor56: brik + Owner: USSR + Location: 1,7 + Actor57: brik + Owner: USSR + Location: 1,8 + Actor58: brik + Owner: USSR + Location: 1,10 + Actor59: brik + Owner: USSR + Location: 1,9 + Actor60: brik + Owner: USSR + Location: 1,11 + Actor61: brik + Owner: USSR + Location: 1,12 + Actor62: brik + Owner: USSR + Location: 1,13 + Actor63: brik + Owner: USSR + Location: 1,14 + Actor64: brik + Owner: USSR + Location: 1,15 + Actor65: brik + Owner: USSR + Location: 1,16 + Actor66: brik + Owner: USSR + Location: 1,17 + Actor67: brik + Owner: USSR + Location: 1,18 + Actor68: brik + Owner: USSR + Location: 1,19 + Actor69: brik + Owner: USSR + Location: 2,19 + Actor76: brik + Owner: USSR + Location: 8,19 + Actor77: brik + Owner: USSR + Location: 9,19 + Actor81: brik + Owner: USSR + Location: 24,19 + Actor82: brik + Owner: USSR + Location: 23,19 + Actor83: brik + Owner: USSR + Location: 24,20 + Actor84: brik + Owner: USSR + Location: 23,20 + Actor85: brik + Owner: USSR + Location: 22,20 + Actor86: brik + Owner: USSR + Location: 21,20 + Actor87: brik + Owner: USSR + Location: 20,20 + Actor88: brik + Owner: USSR + Location: 19,20 + Actor89: brik + Owner: USSR + Location: 18,20 + Actor90: brik + Owner: USSR + Location: 17,20 + Actor91: brik + Owner: USSR + Location: 17,19 + Actor92: brik + Owner: USSR + Location: 18,19 + Actor93: brik + Owner: USSR + Location: 27,10 + Actor94: brik + Owner: USSR + Location: 27,9 + Actor95: brik + Owner: USSR + Location: 26,10 + Actor96: brik + Owner: USSR + Location: 26,9 + Actor97: brik + Owner: USSR + Location: 26,8 + Actor98: brik + Owner: USSR + Location: 27,8 + Actor99: brik + Owner: USSR + Location: 26,7 + Actor100: brik + Owner: USSR + Location: 27,7 + Actor101: brik + Owner: USSR + Location: 26,1 + Actor102: brik + Owner: USSR + Location: 26,2 + Actor103: brik + Owner: USSR + Location: 27,1 + Actor104: brik + Owner: USSR + Location: 27,2 + Actor105: brik + Owner: USSR + Location: 25,1 + Actor106: brik + Owner: USSR + Location: 24,1 + Actor107: brik + Owner: USSR + Location: 23,1 + Actor108: brik + Owner: USSR + Location: 23,1 + Actor109: brik + Owner: USSR + Location: 22,1 + Actor110: brik + Owner: USSR + Location: 21,1 + Actor111: brik + Owner: USSR + Location: 20,1 + Actor112: brik + Owner: USSR + Location: 20,1 + Actor113: brik + Owner: USSR + Location: 19,1 + Actor114: brik + Owner: USSR + Location: 18,1 + Actor115: brik + Owner: USSR + Location: 17,1 + Actor116: brik + Owner: USSR + Location: 17,1 + Actor117: brik + Owner: USSR + Location: 16,1 + Actor118: brik + Owner: USSR + Location: 15,1 + Actor119: brik + Owner: USSR + Location: 14,1 + Actor120: brik + Owner: USSR + Location: 13,1 + Actor121: brik + Owner: USSR + Location: 12,1 + Actor122: brik + Owner: USSR + Location: 11,1 + Actor123: brik + Owner: USSR + Location: 10,1 + Actor124: brik + Owner: USSR + Location: 9,1 + Actor125: brik + Owner: USSR + Location: 8,1 + Actor126: brik + Owner: USSR + Location: 7,1 + Actor127: brik + Owner: USSR + Location: 7,1 + Actor128: brik + Owner: USSR + Location: 6,1 + Actor129: brik + Owner: USSR + Location: 6,1 + Actor130: brik + Owner: USSR + Location: 4,1 + Actor131: brik + Owner: USSR + Location: 5,1 + Actor132: brik + Owner: USSR + Location: 3,1 + Actor133: brik + Owner: USSR + Location: 2,1 + Actor134: fenc + Owner: USSR + Location: 2,2 + Health: 100 + Actor135: fenc + Owner: USSR + Location: 3,2 + Actor136: fenc + Owner: USSR + Location: 4,2 + Actor137: fenc + Owner: USSR + Location: 5,2 + Actor138: fenc + Owner: USSR + Location: 5,3 + Actor139: fenc + Owner: USSR + Location: 2,3 + Actor140: fenc + Owner: USSR + Location: 2,4 + Actor141: fenc + Owner: USSR + Location: 2,4 + Actor142: fenc + Owner: USSR + Location: 2,5 + Actor143: fenc + Owner: USSR + Location: 3,5 + Dog703: dog + Location: 4,3 + SubCell: 3 + Health: 100 + Facing: 384 + Owner: USSR + Dog702: dog + Location: 3,3 + SubCell: 3 + Owner: USSR + Health: 100 + Facing: 384 + Dog706: dog + Location: 4,4 + SubCell: 3 + Owner: USSR + Health: 100 + Facing: 384 + Dog705: dog + Location: 3,4 + SubCell: 3 + Owner: USSR + Health: 100 + Facing: 384 + Dog704: dog + Location: 4,4 + SubCell: 1 + Owner: USSR + Health: 100 + Facing: 384 + Dog701: dog + SubCell: 1 + Location: 3,3 + Health: 100 + Facing: 384 + Owner: USSR + Actor150: apwr + Owner: USSR + Location: 6,2 + Actor151: apwr + Owner: USSR + Location: 9,2 + Kennel: kenn + Owner: USSR + Location: 12,2 + Actor153: apwr + Owner: USSR + Location: 22,2 + Actor154: apwr + Owner: USSR + Location: 19,2 + Actor155: stek + Owner: USSR + Location: 16,1 + Actor156: apwr + Owner: USSR + Location: 6,6 + Actor157: fact + Owner: USSR + Location: 6,9 + Airfield: afld + Owner: USSR + Location: 2,10 + Actor161: proc + Owner: USSR + Location: 23,7 + Actor171: fenc + Owner: USSR + Location: 18,18 + Actor172: fenc + Owner: USSR + Location: 17,18 + Actor173: fenc + Owner: USSR + Location: 16,18 + Actor174: fenc + Owner: USSR + Location: 16,18 + Actor175: fenc + Owner: USSR + Location: 15,18 + Actor176: fenc + Owner: USSR + Location: 15,17 + Actor177: brik + Owner: USSR + Location: 1,20 + Actor178: brik + Owner: USSR + Location: 2,20 + Actor179: brik + Owner: USSR + Location: 3,20 + Actor180: brik + Owner: USSR + Location: 4,20 + Actor181: brik + Owner: USSR + Location: 5,20 + Actor182: brik + Owner: USSR + Location: 6,20 + Actor183: brik + Owner: USSR + Location: 6,20 + Actor184: brik + Owner: USSR + Location: 7,20 + Actor185: brik + Owner: USSR + Location: 8,20 + Actor186: brik + Owner: USSR + Location: 9,20 + Actor187: tsla + Owner: USSR + Location: 9,17 + Actor188: ftur + Owner: USSR + TurretFacing: 384 + Location: 10,17 + Actor189: fenc + Owner: USSR + Location: 11,17 + Actor190: fenc + Owner: USSR + Location: 8,18 + Actor191: fenc + Owner: USSR + Location: 9,18 + Actor192: fenc + Owner: USSR + Location: 10,18 + Actor193: fenc + Owner: USSR + Location: 11,18 + Actor194: apwr + Owner: USSR + Location: 7,14 + Actor195: apwr + Owner: USSR + Location: 2,14 + Actor196: ftur + Owner: USSR + TurretFacing: 384 + Location: 16,17 + Actor197: tsla + Owner: USSR + Location: 17,17 + Actor199: fenc + Owner: USSR + Location: 24,18 + Actor200: fenc + Owner: USSR + Location: 24,17 + Actor201: fenc + Owner: USSR + Location: 24,16 + Actor202: fenc + Owner: USSR + Location: 23,18 + Actor203: fenc + Owner: USSR + Location: 22,18 + Actor204: fenc + Owner: USSR + Location: 21,18 + Actor205: fenc + Owner: USSR + Location: 21,17 + Actor206: fenc + Owner: USSR + Location: 21,16 + Dog709: dog + Location: 22,17 + SubCell: 3 + Owner: USSR + Health: 100 + Facing: 384 + Dog710: dog + Location: 23,17 + SubCell: 3 + Health: 100 + Facing: 384 + Owner: USSR + Dog708: dog + Location: 23,16 + SubCell: 3 + Owner: USSR + Health: 100 + Facing: 384 + Dog707: dog + Location: 22,16 + SubCell: 3 + Owner: USSR + Health: 100 + Facing: 384 + Actor211: tsla + Owner: USSR + Location: 37,15 + Actor212: ftur + Owner: USSR + TurretFacing: 384 + Location: 29,17 + Actor213: ftur + Owner: USSR + TurretFacing: 384 + Location: 29,13 + Actor214: kenn + Owner: USSR + Location: 26,11 + Actor215: dome + Owner: USSR + Location: 22,12 + Barracks: barr + Owner: USSR + Location: 17,12 + Health: 100 + BarracksA: barr + Owner: USSR + Location: 20,7 + Health: 100 + Actor218: tsla + Owner: USSR + Location: 30,4 + WarFactory: weap + Owner: USSR + Location: 12,9 + Health: 100 + USSRFC: fcom + Owner: USSR + Location: 13,4 + SubPen: spen + Owner: USSR + Location: 33,10 + Actor222: ss + Owner: USSR + Location: 57,13 + Facing: 612 + Actor223: ss + Owner: USSR + Location: 58,13 + Facing: 632 + Actor224: ss + Owner: USSR + Location: 60,13 + Facing: 652 + Actor225: ss + Owner: USSR + Location: 61,12 + Facing: 668 + Actor226: ss + Owner: USSR + Location: 60,11 + Facing: 632 + Actor227: harv + Owner: USSR + Location: 39,3 + Facing: 0 + TankGroup101: 3tnk + Owner: USSR + Location: 27,3 + TurretFacing: 0 + Health: 100 + Facing: 753 + TankGroup102: 3tnk + Owner: USSR + Location: 28,4 + TurretFacing: 0 + Health: 100 + Facing: 761 + Actor230: dog + Owner: USSR + SubCell: 3 + Location: 26,3 + Health: 100 + Facing: 716 + Actor231: dog + Owner: USSR + SubCell: 3 + Location: 26,5 + Health: 100 + Facing: 769 + Actor232: e1 + Owner: USSR + SubCell: 3 + Location: 25,4 + Health: 100 + Facing: 756 + TurretFacing: 756 + Actor233: v2rl + Owner: USSR + Location: 19,6 + Health: 100 + Facing: 531 + Actor234: v2rl + Owner: USSR + Location: 17,8 + Health: 100 + Facing: 515 + Actor235: 3tnk + Owner: USSR + Location: 18,7 + TurretFacing: 0 + Health: 100 + Facing: 507 + WGV2: v2rl + Owner: USSR + Location: 9,5 + Health: 100 + Facing: 504 + Actor237: v2rl + Owner: USSR + Location: 11,7 + Health: 100 + Facing: 520 + Actor238: 3tnk + Owner: USSR + Location: 10,6 + Health: 100 + Facing: 512 + TurretFacing: 0 + MM2: 4tnk + Owner: USSR + Location: 13,13 + TurretFacing: 0 + Health: 100 + Facing: 528 + MM1: 4tnk + Owner: USSR + Location: 12,15 + TurretFacing: 0 + Health: 100 + Facing: 508 + MM3: 4tnk + Owner: USSR + Location: 14,15 + TurretFacing: 0 + Health: 100 + Facing: 528 + WGTank01: 3tnk + Owner: USSR + Location: 5,12 + TurretFacing: 0 + Health: 100 + Facing: 604 + WGTank02: 3tnk + Owner: USSR + Location: 6,16 + TurretFacing: 0 + Health: 100 + Facing: 636 + Actor244: dog + Owner: USSR + SubCell: 3 + Location: 12,22 + Health: 100 + Facing: 539 + Actor245: dog + Owner: USSR + SubCell: 3 + Location: 14,22 + Health: 100 + Facing: 507 + Actor246: e1 + Owner: USSR + SubCell: 3 + Location: 13,21 + Health: 100 + Facing: 384 + TurretFacing: 384 + Actor247: 3tnk + Owner: USSR + Location: 18,16 + Health: 100 + Facing: 384 + TurretFacing: 0 + Actor248: 3tnk + Owner: USSR + Location: 15,2 + TurretFacing: 0 + Health: 100 + Facing: 523 + Actor249: e1 + Owner: Greece + SubCell: 3 + Location: 17,60 + Health: 100 + Facing: 634 + TurretFacing: 634 + Actor250: e1 + Owner: Greece + SubCell: 3 + Location: 23,62 + Health: 100 + TurretFacing: 29 + Facing: 29 + AlliedMCVEntry: waypoint + Owner: Neutral + Location: 19,70 + Unload1: waypoint + Owner: Neutral + Location: 19,63 + DefaultCameraPosition: waypoint + Owner: Neutral + Location: 21,60 + HeliLandZone: waypoint + Owner: Neutral + Location: 21,62 + KosyginSpawnPoint: waypoint + Owner: Neutral + Location: 14,6 + KosyginExtractPoint: waypoint + Owner: Neutral + Location: 25,57 + HeliWP01: waypoint + Owner: Neutral + Location: 58,70 + HeliWP02: waypoint + Owner: Neutral + Location: 58,66 + HeliWP03: waypoint + Owner: Neutral + Location: 16,55 + LowerBaseWP: waypoint + Owner: Neutral + Location: 13,25 + USSRUnload1: waypoint + Owner: Neutral + Location: 53,53 + USSRRFEntry: waypoint + Owner: Neutral + Location: 80,1 + RevealLowerBase: waypoint + Owner: Neutral + Location: 13,19 + Harbor: waypoint + Owner: Neutral + Location: 22,43 + USSRUnload2: waypoint + Owner: Neutral + Location: 55,63 + WP92: waypoint + Owner: Neutral + Location: 20,31 + WP91: waypoint + Owner: Neutral + Location: 22,27 + WP90: waypoint + Owner: Neutral + Location: 31,25 + Dog6: dog + Owner: USSR + SubCell: 3 + Location: 22,31 + Health: 100 + Facing: 384 + Dog5: dog + Owner: USSR + SubCell: 3 + Location: 10,25 + Health: 100 + Facing: 384 + WP93: waypoint + Owner: Neutral + Location: 9,27 + WP94: waypoint + Owner: Neutral + Location: 1,28 + WP88: waypoint + Owner: Neutral + Location: 13,23 + WP81: waypoint + Owner: Neutral + Location: 27,4 + WP82: waypoint + Owner: Neutral + Location: 37,4 + WP83: waypoint + Owner: Neutral + Location: 46,8 + WP84: waypoint + Owner: Neutral + Location: 52,11 + WP85: waypoint + Owner: Neutral + Location: 60,2 + WP89: waypoint + Owner: Neutral + Location: 30,15 + WP79: waypoint + Owner: Neutral + Location: 13,18 + WP78: waypoint + Owner: Neutral + Location: 12,18 + WP80: waypoint + Owner: Neutral + Location: 14,18 + WPHNTG: waypoint + Owner: Neutral + Location: 15,9 + WP4: waypoint + Owner: Neutral + Location: 19,13 + WP76: waypoint + Owner: Neutral + Location: 56,7 + WP72: waypoint + Owner: Neutral + Location: 5,18 + WP18: waypoint + Owner: Neutral + Location: 42,9 + WP17: waypoint + Owner: Neutral + Location: 47,12 + UpperBaseWP: waypoint + Owner: Neutral + Location: 13,8 + +Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml + +Weapons: weapons.yaml diff -Nru openra-20200503/mods/ra/maps/allies-09a/rules.yaml openra-20210321/mods/ra/maps/allies-09a/rules.yaml --- openra-20200503/mods/ra/maps/allies-09a/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-09a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,148 @@ +Player: + PlayerResources: + DefaultCash: 10000 + +World: + LuaScript: + Scripts: campaign-global.lua, allies09a.lua, allies09a-AI.lua + MissionData: + Briefing: One of Stalin's top atomic strategists, Vladimir Kosygin, wishes to defect. His knowledge of Stalin's atomic strategies is invaluable to us. We will extract him from the Riga compound where he is stationed.\n\nUse a spy to infiltrate the Soviet command center and contact Kosygin. Once he is out of the building, guide him back to your base any way you can. + StartVideo: + WinVideo: + LossVideo: + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Values: + easy: Easy + normal: Normal + hard: Hard + Default: normal + +LST.Reinforcement: + Inherits: LST + RejectsOrders: + -Buildable: + -Selectable: + RenderSprites: + Image: lst + Interactable: + +TRAN.Extraction: + Inherits: TRAN + RejectsOrders: + -Selectable: + RenderSprites: + Image: tran + Interactable: + +powerproxy.paratroopers: + ParatroopersPower: + DropItems: E1,E1,E1,E2,E2 + +MCV: + Buildable: + Prerequisites: ~disabled + +TRUK: + Buildable: + Prerequisites: ~disabled + +MRJ: + Buildable: + Prerequisites: ~disabled + +3TNK: + Buildable: + Prerequisites: ~vehicles.soviet + +V2RL: + Buildable: + Prerequisites: ~vehicles.soviet + +4TNK: + Buildable: + Prerequisites: ~vehicles.soviet + +QTNK: + Buildable: + Prerequisites: ~disabled + +AFLD: + Buildable: + Prerequisites: ~disabled + +HPAD: + Buildable: + Prerequisites: ~disabled + +ATEK: + Buildable: + Prerequisites: ~disabled + +STEK: + Buildable: + Prerequisites: ~disabled + +PDOX: + Buildable: + Prerequisites: ~disabled + +IRON: + Buildable: + Prerequisites: ~disabled + +MSLO: + Buildable: + Prerequisites: ~disabled + +GAP: + Buildable: + Prerequisites: ~disabled + +BRIK: + Buildable: + Prerequisites: ~disabled + +MECH: + Buildable: + Prerequisites: ~disabled + +THF: + Buildable: + Prerequisites: ~disabled + +E7: + Buildable: + Prerequisites: ~disabled + +E7.noautotarget: + Buildable: + Prerequisites: ~disabled + +MIG: + Buildable: + Prerequisites: ~disabled + +CA: + Buildable: + Prerequisites: ~disabled + +MSUB: + Buildable: + Prerequisites: ~disabled + +FCOM: + Targetable: + TargetTypes: GroundActor, Structure, C4, DetonateAttack, SpyInfiltrate + +GNRL: + Targetable: + TargetTypes: Kosygin + AutoTarget: + InitialStance: HoldFire + InitialStanceAI: HoldFire + +DOG: + AutoTargetPriority@DEFAULT: + ValidTargets: Infantry, Kosygin diff -Nru openra-20200503/mods/ra/maps/allies-09a/weapons.yaml openra-20210321/mods/ra/maps/allies-09a/weapons.yaml --- openra-20200503/mods/ra/maps/allies-09a/weapons.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/allies-09a/weapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,4 @@ +DogJaw: + ValidTargets: Infantry, Kosygin + Warhead@1Dam: TargetDamage + ValidTargets: Infantry, Kosygin Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/altercation.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/altercation.oramap differ diff -Nru openra-20200503/mods/ra/maps/ant-01/ant-01.lua openra-20210321/mods/ra/maps/ant-01/ant-01.lua --- openra-20200503/mods/ra/maps/ant-01/ant-01.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/ant-01/ant-01.lua 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,7 @@ AlliedForces = { "2tnk" , "2tnk", "mcv" } ChopperTeam = { "e1r1", "e1r1", "e2", "e2", "e1r1" } -SendTanks = function() +SendTanks = function() Media.PlaySpeechNotification(allies, "ReinforcementsArrived") Reinforcements.Reinforce(allies, AlliedForces, TankPath, DateTime.Seconds(1)) end @@ -52,7 +52,7 @@ DiscoveredAlliedBase = function(actor, discoverer) if (not baseDiscovered and discoverer.Owner == allies) then - baseDiscovered = true + baseDiscovered = true Media.PlaySpeechNotification(allies, "ObjectiveReached") Utils.Do(AlliedBase, function(building) building.Owner = allies @@ -106,7 +106,7 @@ return ticks end -Tick = function() +Tick = function() if SurviveObjective ~= nil then if ticks > 0 then if ticks == DateTime.Minutes(17) then diff -Nru openra-20200503/mods/ra/maps/ant-01/map.yaml openra-20210321/mods/ra/maps/ant-01/map.yaml --- openra-20200503/mods/ra/maps/ant-01/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/ant-01/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -502,7 +502,7 @@ Ranger: jeep Location: 43,87 Owner: Spain - Facing: 223 + Facing: 892 Steve: e1 Location: 43,86 Owner: Spain diff -Nru openra-20200503/mods/ra/maps/a-nuclear-winter/map.yaml openra-20210321/mods/ra/maps/a-nuclear-winter/map.yaml --- openra-20200503/mods/ra/maps/a-nuclear-winter/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/a-nuclear-winter/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -48,12 +48,12 @@ Actor239: c3 Owner: Neutral SubCell: 3 - Facing: 92 + Facing: 368 Location: 47,16 Actor240: c3 Owner: Neutral SubCell: 3 - Facing: 92 + Facing: 368 Location: 52,16 Actor241: v06 Owner: Neutral @@ -160,7 +160,7 @@ Actor330: c3 Owner: Neutral SubCell: 3 - Facing: 92 + Facing: 368 Location: 49,24 Actor341: t08 Owner: Neutral @@ -426,7 +426,7 @@ Actor509: c3 Owner: Neutral SubCell: 3 - Facing: 92 + Facing: 368 Location: 52,47 Actor510: t12 Owner: Neutral @@ -536,12 +536,12 @@ Actor620: c3 Owner: Neutral SubCell: 3 - Facing: 92 + Facing: 368 Location: 49,55 Actor621: c3 Owner: Neutral SubCell: 3 - Facing: 92 + Facing: 368 Location: 54,55 Actor641: wood Owner: Neutral @@ -1647,12 +1647,12 @@ Actor1219: c3 Owner: Neutral SubCell: 3 - Facing: 92 + Facing: 368 Location: 36,35 Actor1220: c3 Owner: Neutral SubCell: 3 - Facing: 92 + Facing: 368 Location: 33,37 Actor1221: v08 Owner: Neutral @@ -1687,12 +1687,12 @@ Actor1231: c3 Owner: Neutral SubCell: 3 - Facing: 92 + Facing: 368 Location: 68,35 Actor1232: c3 Owner: Neutral SubCell: 3 - Facing: 92 + Facing: 368 Location: 65,37 Actor1179: snowhut Owner: Neutral Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/archipelago.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/archipelago.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/ardennes.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/ardennes.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/ascent.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/ascent.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/barracuda.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/barracuda.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/blitz.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/blitz.oramap differ diff -Nru openra-20200503/mods/ra/maps/bomber-john/rules.yaml openra-20210321/mods/ra/maps/bomber-john/rules.yaml --- openra-20200503/mods/ra/maps/bomber-john/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/bomber-john/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -86,7 +86,8 @@ BeginChargeSound: chrochr1.aud EndChargeSound: chrordy1.aud KillCargo: true - Range: 3 + Dimensions: 7, 7 + Footprint: ___x___ __xxx__ _xxxxx_ xxxxxxx _xxxxx_ __xxx__ ___x___ GrantExternalConditionPower@IRONCURTAIN: Icon: invuln ChargeInterval: 750 @@ -96,10 +97,11 @@ SelectTargetSound: slcttgt1.aud BeginChargeSound: ironchg1.aud EndChargeSound: ironrdy1.aud - Range: 1 Condition: invulnerability Sequence: idle OnFireSound: ironcur9.aud + Dimensions: 3, 3 + Footprint: _x_ xxx _x_ Production: Produces: Building LobbyPrerequisiteCheckbox@GLOBALBOUNTY: @@ -121,7 +123,7 @@ Type: Heavy Mobile: Speed: 128 - TurnSpeed: 900 + TurnSpeed: 512 RevealsShroud: Range: 40c0 MustBeDestroyed: @@ -129,7 +131,7 @@ Transforms: IntoActor: ftur Offset: 0,0 - Facing: 96 + Facing: 384 CashTrickler: Interval: 150 Amount: 20 @@ -145,7 +147,7 @@ Transforms: IntoActor: mnlyr Offset: 0,0 - Facing: 96 + Facing: 384 MustBeDestroyed: RequiredForShortGame: true CashTrickler: @@ -173,10 +175,10 @@ WithSpriteBody: Tooltip: Name: Bomb - SelfHealing: + ChangesHealth: Step: -100 Delay: 1 - HealIfBelow: 101 + StartIfBelow: 101 Explodes: Weapon: CrateNuke EmptyWeapon: CrateNuke Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/caffeinated.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/caffeinated.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/center-of-attention-redux-2/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/center-of-attention-redux-2/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/center-of-attention-redux-2/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/center-of-attention-redux-2/map.png differ diff -Nru openra-20200503/mods/ra/maps/center-of-attention-redux-2/map.yaml openra-20210321/mods/ra/maps/center-of-attention-redux-2/map.yaml --- openra-20200503/mods/ra/maps/center-of-attention-redux-2/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/center-of-attention-redux-2/map.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,1180 +0,0 @@ -MapFormat: 11 - -RequiresMod: ra - -Title: Center of Attention Redux 2 - -Author: Buddha - -Tileset: TEMPERAT - -MapSize: 128,128 - -Bounds: 15,10,105,114 - -Visibility: Lobby - -Categories: Conquest - -Players: - PlayerReference@Neutral: - Name: Neutral - OwnsWorld: True - NonCombatant: True - Faction: allies - PlayerReference@Creeps: - Name: Creeps - NonCombatant: True - Faction: allies - Enemies: Multi0, Multi1, Multi2, Multi3, Multi4, Multi5, Multi6, Multi7 - PlayerReference@Multi0: - Name: Multi0 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi1: - Name: Multi1 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi2: - Name: Multi2 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi3: - Name: Multi3 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi4: - Name: Multi4 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi5: - Name: Multi5 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi6: - Name: Multi6 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi7: - Name: Multi7 - Playable: True - Faction: Random - Enemies: Creeps - -Actors: - Actor101: oilb.strong - Location: 69,68 - Owner: Neutral - Actor391: mine - Owner: Neutral - Location: 71,61 - Actor93: oilb.strong - Location: 69,63 - Owner: Neutral - Actor47: tc05 - Location: 67,71 - Owner: Neutral - Actor380: mine - Owner: Neutral - Location: 59,18 - Actor379: mine - Owner: Neutral - Location: 72,20 - Actor382: mine - Owner: Neutral - Location: 25,19 - Actor381: mine - Owner: Neutral - Location: 21,25 - Actor375: mine - Owner: Neutral - Location: 116,69 - Actor376: mine - Owner: Neutral - Location: 117,61 - Actor388: mine - Owner: Neutral - Location: 79,96 - Actor387: mine - Owner: Neutral - Location: 78,101 - Actor390: mine - Owner: Neutral - Location: 107,96 - Actor389: mine - Owner: Neutral - Location: 112,90 - Actor377: mine - Owner: Neutral - Location: 112,24 - Actor378: mine - Owner: Neutral - Location: 108,22 - Actor16: tc05 - Location: 109,42 - Owner: Neutral - Actor17: tc05 - Location: 105,89 - Owner: Neutral - Actor18: tc04 - Location: 93,99 - Owner: Neutral - Actor19: tc05 - Location: 68,99 - Owner: Neutral - Actor20: tc04 - Location: 19,62 - Owner: Neutral - Actor21: tc05 - Location: 38,44 - Owner: Neutral - Actor26: tc05 - Location: 77,18 - Owner: Neutral - Actor23: tc04 - Location: 108,41 - Owner: Neutral - Actor24: tc03 - Location: 93,98 - Owner: Neutral - Actor25: tc03 - Location: 20,61 - Owner: Neutral - Actor22: tc05 - Location: 72,8 - Owner: Neutral - Actor370: t06 - Owner: Neutral - Location: 108,87 - Actor29: tc02 - Location: 86,60 - Owner: Neutral - Actor30: tc02 - Location: 111,77 - Owner: Neutral - Actor31: tc02 - Location: 86,95 - Owner: Neutral - Actor32: tc04 - Location: 72,92 - Owner: Neutral - Actor33: tc02 - Location: 74,93 - Owner: Neutral - Actor34: t17 - Location: 73,93 - Owner: Neutral - Actor124: t02 - Location: 84,106 - Owner: Neutral - Actor36: tc04 - Location: 96,104 - Owner: Neutral - Actor37: tc03 - Location: 66,100 - Owner: Neutral - Actor38: tc04 - Location: 45,107 - Owner: Neutral - Actor39: tc03 - Location: 46,109 - Owner: Neutral - Actor42: tc05 - Location: 45,59 - Owner: Neutral - Actor43: tc05 - Location: 86,61 - Owner: Neutral - Actor44: tc03 - Location: 81,56 - Owner: Neutral - Actor394: mine - Owner: Neutral - Location: 56,60 - Actor97: t03 - Location: 88,64 - Owner: Neutral - Actor49: tc01 - Location: 72,37 - Owner: Neutral - Actor51: tc01 - Location: 30,38 - Owner: Neutral - Actor52: tc02 - Location: 31,39 - Owner: Neutral - Actor53: tc04 - Location: 19,34 - Owner: Neutral - Actor54: tc03 - Location: 20,36 - Owner: Neutral - Actor55: t15 - Location: 35,22 - Owner: Neutral - Actor56: t14 - Location: 47,45 - Owner: Neutral - Actor95: t06 - Location: 85,64 - Owner: Neutral - Actor58: t12 - Location: 56,97 - Owner: Neutral - Actor273: tc01 - Owner: Neutral - Location: 24,118 - Actor384: mine - Owner: Neutral - Location: 32,66 - Actor383: mine - Owner: Neutral - Location: 36,68 - Actor385: mine - Owner: Neutral - Location: 39,95 - Actor386: mine - Owner: Neutral - Location: 35,90 - Actor63: tc04 - Location: 15,23 - Owner: Neutral - Actor64: t11 - Location: 20,81 - Owner: Neutral - Actor66: t16 - Location: 21,84 - Owner: Neutral - Actor65: t11 - Location: 21,82 - Owner: Neutral - Actor67: tc04 - Location: 20,93 - Owner: Neutral - Actor69: oilb.weak - Location: 63,40 - Owner: Neutral - Actor70: oilb.weak - Location: 89,44 - Owner: Neutral - Actor71: t08 - Location: 63,44 - Owner: Neutral - Actor72: t10 - Location: 61,43 - Owner: Neutral - Actor73: t11 - Location: 94,32 - Owner: Neutral - Actor74: tc03 - Location: 109,57 - Owner: Neutral - Actor75: tc02 - Location: 108,59 - Owner: Neutral - Actor76: tc01 - Location: 65,91 - Owner: Neutral - Actor77: t13 - Location: 51,93 - Owner: Neutral - Actor78: t08 - Location: 55,102 - Owner: Neutral - Actor8: oilb.weak - Location: 39,78 - Owner: Neutral - Actor82: t11 - Location: 93,75 - Owner: Neutral - Actor369: t11 - Owner: Neutral - Location: 83,49 - Actor28: tc04 - Location: 84,80 - Owner: Neutral - Actor48: t16 - Location: 84,70 - Owner: Neutral - Actor90: t11 - Location: 104,76 - Owner: Neutral - Actor92: t14 - Location: 95,88 - Owner: Neutral - Actor57: t16 - Location: 87,72 - Owner: Neutral - Actor395: mine - Owner: Neutral - Location: 59,66 - Actor85: oilb.strong - Location: 64,63 - Owner: Neutral - Actor96: t06 - Location: 83,63 - Owner: Neutral - Actor94: oilb.strong - Location: 64,68 - Owner: Neutral - Actor392: mine - Owner: Neutral - Location: 77,63 - Actor99: tc01 - Location: 89,77 - Owner: Neutral - Actor100: t10 - Location: 86,73 - Owner: Neutral - Actor84: t06 - Location: 81,80 - Owner: Neutral - Actor393: mine - Owner: Neutral - Location: 81,71 - Actor396: mine - Owner: Neutral - Location: 57,75 - Actor104: tc02 - Location: 54,27 - Owner: Neutral - Actor35: t05 - Location: 88,108 - Owner: Neutral - Actor27: tc05 - Location: 27,115 - Owner: Neutral - Actor50: tc04 - Location: 30,116 - Owner: Neutral - Actor106: tc02 - Location: 25,115 - Owner: Neutral - Actor107: t10 - Location: 24,114 - Owner: Neutral - Actor108: t10 - Location: 32,117 - Owner: Neutral - Actor109: tc05 - Location: 32,118 - Owner: Neutral - Actor110: tc04 - Location: 25,117 - Owner: Neutral - Actor111: tc04 - Location: 29,118 - Owner: Neutral - Actor112: t15 - Location: 42,117 - Owner: Neutral - Actor113: t17 - Location: 44,117 - Owner: Neutral - Actor303: t05 - Owner: Neutral - Location: 39,123 - Actor40: tc05 - Location: 16,19 - Owner: Neutral - Actor116: tc04 - Location: 40,113 - Owner: Neutral - Actor117: tc05 - Location: 108,118 - Owner: Neutral - Actor118: tc04 - Location: 112,118 - Owner: Neutral - Actor119: tc04 - Location: 115,117 - Owner: Neutral - Actor120: tc04 - Location: 113,115 - Owner: Neutral - Actor121: tc04 - Location: 72,119 - Owner: Neutral - Actor122: tc05 - Location: 60,120 - Owner: Neutral - Actor123: t17 - Location: 56,120 - Owner: Neutral - Actor105: t02 - Location: 89,106 - Owner: Neutral - Actor125: t17 - Location: 64,94 - Owner: Neutral - Actor126: t17 - Location: 63,95 - Owner: Neutral - Actor127: t17 - Location: 30,79 - Owner: Neutral - Actor128: t17 - Location: 36,48 - Owner: Neutral - Actor129: t17 - Location: 49,18 - Owner: Neutral - Actor274: tc01 - Owner: Neutral - Location: 42,114 - Actor275: tc01 - Owner: Neutral - Location: 22,116 - Actor132: t17 - Location: 29,16 - Owner: Neutral - Actor133: t17 - Location: 45,39 - Owner: Neutral - Actor134: t17 - Location: 98,56 - Owner: Neutral - Actor135: tc05 - Location: 96,54 - Owner: Neutral - Actor136: t17 - Location: 117,114 - Owner: Neutral - Actor137: t17 - Location: 114,112 - Owner: Neutral - Actor138: tc05 - Location: 20,18 - Owner: Neutral - Actor139: t15 - Location: 100,85 - Owner: Neutral - Actor140: t03 - Location: 105,86 - Owner: Neutral - Actor141: t17 - Location: 90,107 - Owner: Neutral - Actor142: t16 - Location: 90,104 - Owner: Neutral - Actor143: t16 - Location: 91,104 - Owner: Neutral - Actor144: t16 - Location: 91,103 - Owner: Neutral - Actor145: t01 - Location: 92,105 - Owner: Neutral - Actor146: t08 - Location: 88,106 - Owner: Neutral - Actor147: t05 - Location: 87,104 - Owner: Neutral - Actor148: t05 - Location: 89,101 - Owner: Neutral - Actor149: t07 - Location: 86,107 - Owner: Neutral - Actor150: t05 - Location: 86,109 - Owner: Neutral - Actor151: tc04 - Location: 83,110 - Owner: Neutral - Actor152: t05 - Location: 84,113 - Owner: Neutral - Actor153: t05 - Location: 86,112 - Owner: Neutral - Actor154: t13 - Location: 79,11 - Owner: Neutral - Actor155: t03 - Location: 80,10 - Owner: Neutral - Actor156: t02 - Location: 55,10 - Owner: Neutral - Actor157: t08 - Location: 56,11 - Owner: Neutral - Actor158: t01 - Location: 54,11 - Owner: Neutral - Actor98: t10 - Location: 72,51 - Owner: Neutral - Actor102: t10 - Location: 50,64 - Owner: Neutral - Actor103: t01 - Location: 49,65 - Owner: Neutral - Actor115: t10 - Location: 98,75 - Owner: Neutral - Actor159: tc04 - Location: 61,61 - Owner: Neutral - Actor160: tc03 - Location: 72,63 - Owner: Neutral - Actor161: tc01 - Location: 62,70 - Owner: Neutral - Actor162: t14 - Location: 61,66 - Owner: Neutral - Actor163: t17 - Location: 74,65 - Owner: Neutral - Actor164: t14 - Location: 73,66 - Owner: Neutral - Actor173: arty - Location: 69,66 - Owner: Creeps - Actor167: arty - Location: 65,66 - Owner: Creeps - Actor178: agun - Location: 67,69 - Owner: Creeps - Actor180: v2rl - Location: 73,65 - Owner: Creeps - Actor179: arty - Location: 75,66 - Owner: Creeps - Actor166: arty - Location: 67,67 - Owner: Creeps - Actor165: arty - Location: 67,65 - Owner: Creeps - Actor182: brl3 - Location: 68,69 - Owner: Neutral - Actor184: brl3 - Location: 66,63 - Owner: Neutral - Actor185: brl3 - Location: 66,62 - Owner: Neutral - Actor186: brl3 - Location: 65,62 - Owner: Neutral - Actor187: brl3 - Location: 68,63 - Owner: Neutral - Actor188: brl3 - Location: 68,62 - Owner: Neutral - Actor189: brl3 - Location: 66,70 - Owner: Neutral - Actor190: brl3 - Location: 65,70 - Owner: Neutral - Actor191: brl3 - Location: 69,70 - Owner: Neutral - Actor192: oilb.weak - Location: 68,95 - Owner: Neutral - Actor193: oilb.weak - Location: 45,96 - Owner: Neutral - Actor408: mpspawn - Owner: Neutral - Location: 31,29 - Actor195: oilb.weak - Location: 103,87 - Owner: Neutral - Actor196: oilb.weak - Location: 104,67 - Owner: Neutral - Actor197: oilb.weak - Location: 45,44 - Owner: Neutral - Actor215: cycl - Location: 89,42 - Owner: Neutral - Actor214: cycl - Location: 88,42 - Owner: Neutral - Actor218: cycl - Location: 92,42 - Owner: Neutral - Actor219: cycl - Location: 94,40 - Owner: Neutral - Actor220: cycl - Location: 95,40 - Owner: Neutral - Actor221: cycl - Location: 95,41 - Owner: Neutral - Actor222: cycl - Location: 93,42 - Owner: Neutral - Actor223: cycl - Location: 95,42 - Owner: Neutral - Actor224: cycl - Location: 95,43 - Owner: Neutral - Actor213: cycl - Location: 88,41 - Owner: Neutral - Actor212: cycl - Location: 88,40 - Owner: Neutral - Actor211: cycl - Location: 88,39 - Owner: Neutral - Actor210: cycl - Location: 88,38 - Owner: Neutral - Actor209: cycl - Location: 88,37 - Owner: Neutral - Actor208: cycl - Location: 89,37 - Owner: Neutral - Actor207: cycl - Location: 90,39 - Owner: Neutral - Actor204: cycl - Location: 91,40 - Owner: Neutral - Actor203: cycl - Location: 92,40 - Owner: Neutral - Actor202: cycl - Location: 90,37 - Owner: Neutral - Actor201: cycl - Location: 91,37 - Owner: Neutral - Actor198: cycl - Location: 93,37 - Owner: Neutral - Actor199: cycl - Location: 93,40 - Owner: Neutral - Actor200: cycl - Location: 92,37 - Owner: Neutral - Actor216: cycl - Location: 90,42 - Owner: Neutral - Actor217: cycl - Location: 91,42 - Owner: Neutral - Actor205: cycl - Location: 92,38 - Owner: Neutral - Actor206: cycl - Location: 90,40 - Owner: Neutral - Actor169: jeep - Location: 70,62 - Owner: Creeps - Actor168: jeep - Location: 71,64 - Owner: Creeps - Actor170: jeep - Location: 62,69 - Owner: Creeps - Actor171: jeep - Location: 64,70 - Owner: Creeps - Actor172: jeep - Location: 64,61 - Owner: Creeps - Actor175: jeep - Location: 62,60 - Owner: Creeps - Actor181: v2rl - Location: 59,64 - Owner: Creeps - Actor177: jeep - Location: 71,70 - Owner: Creeps - Actor176: jeep - Location: 72,69 - Owner: Creeps - Actor234: cycl - Location: 95,44 - Owner: Neutral - Actor235: cycl - Location: 94,44 - Owner: Neutral - Actor236: cycl - Location: 93,44 - Owner: Neutral - Actor237: cycl - Location: 92,44 - Owner: Neutral - Actor238: cycl - Location: 91,44 - Owner: Neutral - Actor239: cycl - Location: 87,42 - Owner: Neutral - Actor240: cycl - Location: 87,43 - Owner: Neutral - Actor241: cycl - Location: 91,45 - Owner: Neutral - Actor242: cycl - Location: 91,46 - Owner: Neutral - Actor243: cycl - Location: 91,47 - Owner: Neutral - Actor244: brl3 - Location: 62,64 - Owner: Neutral - Actor245: brl3 - Location: 61,64 - Owner: Neutral - Actor246: brl3 - Location: 64,62 - Owner: Neutral - Actor174: agun - Location: 67,61 - Owner: Creeps - Actor248: brl3 - Location: 71,63 - Owner: Neutral - Actor249: brl3 - Location: 70,71 - Owner: Neutral - Actor250: brl3 - Location: 71,71 - Owner: Neutral - Actor251: brl3 - Location: 66,71 - Owner: Neutral - Actor252: truk - Location: 90,46 - Owner: Neutral - Actor253: truk - Location: 89,46 - Owner: Neutral - Actor254: truk - Location: 90,47 - Owner: Neutral - Actor255: tc05 - Location: 67,54 - Owner: Neutral - Actor256: tc05 - Location: 68,76 - Owner: Neutral - Actor257: t06 - Location: 68,78 - Owner: Neutral - Actor258: t11 - Location: 70,78 - Owner: Neutral - Actor259: t17 - Location: 69,79 - Owner: Neutral - Actor260: tc04 - Location: 70,79 - Owner: Neutral - Actor261: t05 - Location: 68,56 - Owner: Neutral - Actor262: tc01 - Location: 58,76 - Owner: Neutral - Actor263: t06 - Location: 57,63 - Owner: Neutral - Actor264: t17 - Location: 58,60 - Owner: Neutral - Actor265: t11 - Location: 56,61 - Owner: Neutral - Actor266: t05 - Location: 58,69 - Owner: Neutral - Actor267: t06 - Location: 80,67 - Owner: Neutral - Actor268: t12 - Location: 80,68 - Owner: Neutral - Actor269: t02 - Location: 79,66 - Owner: Neutral - Actor270: tc03 - Location: 72,77 - Owner: Neutral - Actor183: gun - Location: 52,71 - Owner: Creeps - Actor225: gun - Location: 84,69 - Owner: Creeps - Actor226: gun - Location: 73,58 - Owner: Creeps - Actor227: gun - Location: 68,74 - Owner: Creeps - Actor228: t11 - Location: 50,73 - Owner: Neutral - Actor229: arty - Location: 67,74 - Owner: Creeps - Actor230: arty - Location: 77,72 - Owner: Creeps - Actor231: arty - Location: 67,60 - Owner: Creeps - Actor233: apwr - Location: 121,91 - Owner: Creeps - Actor232: apwr - Location: 121,96 - Owner: Creeps - Actor276: tc01 - Owner: Neutral - Location: 33,121 - Actor277: tc02 - Owner: Neutral - Location: 32,117 - Actor278: t05 - Owner: Neutral - Location: 33,122 - Actor279: t05 - Owner: Neutral - Location: 21,114 - Actor280: t02 - Owner: Neutral - Location: 30,120 - Actor281: t02 - Owner: Neutral - Location: 27,113 - Actor282: t02 - Owner: Neutral - Location: 39,122 - Actor283: t02 - Owner: Neutral - Location: 31,119 - Actor284: tc01 - Owner: Neutral - Location: 115,114 - Actor285: tc01 - Owner: Neutral - Location: 111,120 - Actor286: tc02 - Owner: Neutral - Location: 116,119 - Actor287: tc02 - Owner: Neutral - Location: 112,116 - Actor288: t16 - Owner: Neutral - Location: 109,121 - Actor289: t16 - Owner: Neutral - Location: 116,111 - Actor290: t02 - Owner: Neutral - Location: 118,116 - Actor291: t02 - Owner: Neutral - Location: 106,120 - Actor292: t02 - Owner: Neutral - Location: 117,110 - Actor293: t01 - Owner: Neutral - Location: 111,123 - Actor294: t01 - Owner: Neutral - Location: 119,110 - Actor295: tc01 - Owner: Neutral - Location: 82,112 - Actor296: tc01 - Owner: Neutral - Location: 42,123 - Actor297: tc01 - Owner: Neutral - Location: 21,113 - Actor298: t16 - Owner: Neutral - Location: 17,112 - Actor299: t02 - Owner: Neutral - Location: 20,112 - Actor300: t02 - Owner: Neutral - Location: 28,118 - Actor301: t02 - Owner: Neutral - Location: 32,123 - Actor302: t02 - Owner: Neutral - Location: 44,112 - Actor304: t05 - Owner: Neutral - Location: 19,111 - Actor305: tc02 - Owner: Neutral - Location: 17,105 - Actor306: t11 - Owner: Neutral - Location: 15,103 - Actor307: t12 - Owner: Neutral - Location: 28,122 - Actor308: t12 - Owner: Neutral - Location: 25,107 - Actor309: t05 - Owner: Neutral - Location: 50,105 - Actor310: t05 - Owner: Neutral - Location: 42,115 - Actor311: t03 - Owner: Neutral - Location: 49,119 - Actor312: t10 - Owner: Neutral - Location: 84,119 - Actor313: t13 - Owner: Neutral - Location: 119,103 - Actor314: t02 - Owner: Neutral - Location: 67,87 - Actor315: t02 - Owner: Neutral - Location: 18,62 - Actor316: t05 - Owner: Neutral - Location: 15,60 - Actor317: t02 - Owner: Neutral - Location: 31,45 - Actor318: t02 - Owner: Neutral - Location: 18,32 - Actor319: t17 - Owner: Neutral - Location: 21,46 - Actor320: tc02 - Owner: Neutral - Location: 17,21 - Actor321: tc04 - Owner: Neutral - Location: 14,25 - Actor322: tc04 - Owner: Neutral - Location: 16,15 - Actor323: tc01 - Owner: Neutral - Location: 18,14 - Actor324: tc01 - Owner: Neutral - Location: 21,12 - Actor325: t16 - Owner: Neutral - Location: 15,21 - Actor326: t13 - Owner: Neutral - Location: 18,17 - Actor327: t02 - Owner: Neutral - Location: 15,14 - Actor328: t05 - Owner: Neutral - Location: 22,11 - Actor329: t02 - Owner: Neutral - Location: 16,11 - Actor330: t12 - Owner: Neutral - Location: 19,11 - Actor331: t05 - Owner: Neutral - Location: 28,10 - Actor332: tc04 - Owner: Neutral - Location: 55,11 - Actor333: t05 - Owner: Neutral - Location: 57,10 - Actor334: t05 - Owner: Neutral - Location: 47,9 - Actor335: t01 - Owner: Neutral - Location: 65,9 - Actor336: tc04 - Owner: Neutral - Location: 114,16 - Actor337: tc01 - Owner: Neutral - Location: 109,14 - Actor338: tc02 - Owner: Neutral - Location: 107,14 - Actor339: tc01 - Owner: Neutral - Location: 117,13 - Actor340: tc04 - Owner: Neutral - Location: 102,11 - Actor341: tc01 - Owner: Neutral - Location: 104,11 - Actor342: tc01 - Owner: Neutral - Location: 119,26 - Actor343: t02 - Owner: Neutral - Location: 119,28 - Actor344: t02 - Owner: Neutral - Location: 119,12 - Actor345: t02 - Owner: Neutral - Location: 100,9 - Actor347: t07 - Owner: Neutral - Location: 119,14 - Actor346: tc05 - Owner: Neutral - Location: 118,10 - Actor348: t17 - Owner: Neutral - Location: 109,11 - Actor349: t05 - Owner: Neutral - Location: 110,13 - Actor350: t08 - Owner: Neutral - Location: 117,11 - Actor351: t01 - Owner: Neutral - Location: 100,12 - Actor352: t01 - Owner: Neutral - Location: 118,30 - Actor353: t02 - Owner: Neutral - Location: 118,25 - Actor354: t02 - Owner: Neutral - Location: 115,15 - Actor355: t02 - Owner: Neutral - Location: 115,9 - Actor356: t05 - Owner: Neutral - Location: 118,12 - Actor357: t05 - Owner: Neutral - Location: 101,10 - Actor358: t02 - Owner: Neutral - Location: 106,10 - Actor359: t02 - Owner: Neutral - Location: 106,10 - Actor360: tc01 - Owner: Neutral - Location: 114,39 - Actor361: t05 - Owner: Neutral - Location: 113,39 - Actor362: t05 - Owner: Neutral - Location: 106,42 - Actor363: t02 - Owner: Neutral - Location: 119,38 - Actor364: tc04 - Owner: Neutral - Location: 118,37 - Actor365: tc01 - Owner: Neutral - Location: 119,35 - Actor366: t05 - Owner: Neutral - Location: 119,29 - Actor367: t13 - Owner: Neutral - Location: 115,35 - Actor368: t17 - Owner: Neutral - Location: 118,42 - Actor371: tc03 - Owner: Neutral - Location: 15,122 - Actor372: t08 - Owner: Neutral - Location: 17,123 - Actor373: v05 - Owner: Neutral - Location: 18,118 - Actor374: t15 - Owner: Neutral - Location: 21,122 - Actor397: mine - Owner: Neutral - Location: 16,50 - Actor398: mine - Owner: Neutral - Location: 97,122 - Actor399: mine - Owner: Neutral - Location: 85,11 - Actor407: mpspawn - Owner: Neutral - Location: 70,27 - Actor406: mpspawn - Owner: Neutral - Location: 97,27 - Actor405: mpspawn - Owner: Neutral - Location: 110,51 - Actor400: mpspawn - Owner: Neutral - Location: 20,73 - Actor401: mpspawn - Owner: Neutral - Location: 31,102 - Actor402: mpspawn - Owner: Neutral - Location: 64,109 - Actor403: mpspawn - Owner: Neutral - Location: 108,107 - -Rules: rules.yaml diff -Nru openra-20200503/mods/ra/maps/center-of-attention-redux-2/rules.yaml openra-20210321/mods/ra/maps/center-of-attention-redux-2/rules.yaml --- openra-20200503/mods/ra/maps/center-of-attention-redux-2/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/center-of-attention-redux-2/rules.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -OILB.Strong: - Inherits: OILB - Health: - HP: 600000 - RenderSprites: - Image: OILB - -OILB.Weak: - Inherits: OILB - Health: - HP: 90000 - RenderSprites: - Image: OILB Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/chernobyl/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/chernobyl/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/chernobyl/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/chernobyl/map.png differ diff -Nru openra-20200503/mods/ra/maps/chernobyl/map.yaml openra-20210321/mods/ra/maps/chernobyl/map.yaml --- openra-20200503/mods/ra/maps/chernobyl/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/chernobyl/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,1135 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: Chernobyl + +Author: Lad + +Tileset: TEMPERAT + +MapSize: 122,122 + +Bounds: 1,1,120,120 + +Visibility: Lobby + +Categories: Conquest + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: england + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Faction: england + Enemies: Multi0, Multi1, Multi2, Multi3 + PlayerReference@Multi0: + Name: Multi0 + Playable: True + Faction: Random + Enemies: Creeps + PlayerReference@Multi1: + Name: Multi1 + Playable: True + Faction: Random + Enemies: Creeps + PlayerReference@Multi2: + Name: Multi2 + Playable: True + Faction: Random + Enemies: Creeps + PlayerReference@Multi3: + Name: Multi3 + Playable: True + Faction: Random + Enemies: Creeps + +Actors: + Actor0: bio + Owner: Neutral + Location: 5,5 + Health: 22 + Actor1: mslo + Owner: Neutral + Location: 7,7 + Health: 31 + Actor2: mslo + Owner: Neutral + Location: 7,8 + Health: 25 + Actor3: oilb + Owner: Neutral + Location: 58,58 + Actor4: cycl + Owner: Neutral + Location: 58,57 + Actor5: cycl + Owner: Neutral + Location: 57,57 + Actor6: cycl + Owner: Neutral + Location: 57,58 + Actor7: cycl + Owner: Neutral + Location: 60,59 + Actor8: cycl + Owner: Neutral + Location: 60,60 + Actor9: cycl + Owner: Neutral + Location: 59,60 + Actor10: v02 + Owner: Neutral + Location: 53,59 + Actor11: v10 + Owner: Neutral + Location: 61,54 + Actor12: v16 + Owner: Neutral + Location: 61,53 + Actor13: v08 + Owner: Neutral + Location: 64,64 + Actor14: v19 + Owner: Neutral + Location: 70,59 + Actor15: v19 + Owner: Neutral + Location: 59,70 + Actor16: v01 + Owner: Neutral + Location: 51,51 + Actor17: barl + Owner: Neutral + Location: 63,63 + Actor18: brl3 + Owner: Neutral + Location: 53,53 + Actor19: hosp + Owner: Neutral + Location: 42,42 + Actor20: v04 + Owner: Neutral + Location: 49,40 + Actor21: v09 + Owner: Neutral + Location: 41,49 + Actor22: v12 + Owner: Neutral + Location: 41,50 + Actor23: v11 + Owner: Neutral + Location: 43,53 + Actor24: v08 + Owner: Neutral + Location: 53,43 + Actor25: brik + Owner: Neutral + Location: 38,52 + Actor26: brik + Owner: Neutral + Location: 37,52 + Actor27: brik + Owner: Neutral + Location: 52,38 + Actor28: brik + Owner: Neutral + Location: 52,37 + Actor29: brik + Owner: Neutral + Location: 36,52 + Actor30: brik + Owner: Neutral + Location: 36,53 + Actor31: brik + Owner: Neutral + Location: 52,36 + Actor32: brik + Owner: Neutral + Location: 53,36 + Actor33: brik + Owner: Neutral + Location: 51,38 + Actor34: brik + Owner: Neutral + Location: 38,51 + Actor35: brik + Owner: Neutral + Location: 38,50 + Actor36: brik + Owner: Neutral + Location: 39,50 + Actor37: brik + Owner: Neutral + Location: 50,38 + Actor38: brik + Owner: Neutral + Location: 50,39 + Actor39: brik + Owner: Neutral + Location: 36,58 + Actor40: brik + Owner: Neutral + Location: 58,36 + Actor41: brik + Owner: Neutral + Location: 36,59 + Actor42: brik + Owner: Neutral + Location: 59,36 + Actor43: brik + Owner: Neutral + Location: 37,59 + Actor44: brik + Owner: Neutral + Location: 38,59 + Actor45: brik + Owner: Neutral + Location: 59,37 + Actor46: brik + Owner: Neutral + Location: 59,38 + Actor47: brik + Owner: Neutral + Location: 60,38 + Actor48: brik + Owner: Neutral + Location: 61,38 + Actor49: brik + Owner: Neutral + Location: 62,38 + Actor50: brik + Owner: Neutral + Location: 38,60 + Actor51: brik + Owner: Neutral + Location: 38,61 + Actor52: brik + Owner: Neutral + Location: 38,62 + Actor53: brik + Owner: Neutral + Location: 39,62 + Actor54: brik + Owner: Neutral + Location: 40,62 + Actor55: brik + Owner: Neutral + Location: 41,62 + Actor56: brik + Owner: Neutral + Location: 62,39 + Actor57: brik + Owner: Neutral + Location: 62,40 + Actor58: brik + Owner: Neutral + Location: 62,41 + Actor59: brik + Owner: Neutral + Location: 63,41 + Actor60: brik + Owner: Neutral + Location: 41,63 + Actor61: brik + Owner: Neutral + Location: 42,63 + Actor62: brik + Owner: Neutral + Location: 63,42 + Actor63: brik + Owner: Neutral + Location: 46,63 + Actor64: brik + Owner: Neutral + Location: 47,63 + Actor65: brik + Owner: Neutral + Location: 47,62 + Actor66: brik + Owner: Neutral + Location: 46,62 + Actor67: brik + Owner: Neutral + Location: 42,62 + Actor68: brik + Owner: Neutral + Location: 62,42 + Actor69: brik + Owner: Neutral + Location: 63,46 + Actor70: brik + Owner: Neutral + Location: 62,46 + Actor71: brik + Owner: Neutral + Location: 62,47 + Actor72: brik + Owner: Neutral + Location: 63,47 + Actor73: v09 + Owner: Neutral + Location: 51,56 + Actor74: v11 + Owner: Neutral + Location: 56,51 + Actor75: v05 + Owner: Neutral + Location: 44,52 + Actor76: v11 + Owner: Neutral + Location: 52,45 + Actor77: t03 + Owner: Neutral + Location: 46,53 + Actor78: t01 + Owner: Neutral + Location: 54,45 + Actor79: t10 + Owner: Neutral + Location: 54,53 + Actor80: t08 + Owner: Neutral + Location: 56,58 + Actor81: t07 + Owner: Neutral + Location: 58,55 + Actor82: t02 + Owner: Neutral + Location: 61,60 + Actor84: t13 + Owner: Neutral + Location: 51,61 + Actor85: tc02 + Owner: Neutral + Location: 39,60 + Actor86: tc01 + Owner: Neutral + Location: 60,38 + Actor87: t01 + Owner: Neutral + Location: 61,39 + Actor88: t03 + Owner: Neutral + Location: 38,57 + Actor89: t07 + Owner: Neutral + Location: 58,37 + Actor90: t03 + Owner: Neutral + Location: 61,45 + Actor91: t08 + Owner: Neutral + Location: 46,61 + Actor92: t01 + Owner: Neutral + Location: 37,52 + Actor93: t02 + Owner: Neutral + Location: 53,36 + Actor94: rushouse + Owner: Neutral + Location: 57,47 + Actor95: rushouse + Owner: Neutral + Location: 48,56 + Actor98: asianhut + Owner: Neutral + Location: 53,66 + Actor99: oilb + Owner: Neutral + Location: 36,60 + Actor100: oilb + Owner: Neutral + Location: 60,36 + Actor101: barl + Owner: Neutral + Location: 37,62 + Actor102: barl + Owner: Neutral + Location: 38,63 + Actor103: barl + Owner: Neutral + Location: 62,37 + Actor104: barl + Owner: Neutral + Location: 63,38 + Actor105: tc03 + Owner: Neutral + Location: 40,41 + Actor106: t08 + Owner: Neutral + Location: 42,41 + Actor107: t05 + Owner: Neutral + Location: 42,39 + Actor108: t16 + Owner: Neutral + Location: 43,47 + Actor109: t07 + Owner: Neutral + Location: 48,42 + Actor110: utilpol1 + Owner: Neutral + Location: 48,49 + Actor111: utilpol1 + Owner: Neutral + Location: 59,48 + Actor112: utilpol2 + Owner: Neutral + Location: 53,58 + Actor113: utilpol1 + Owner: Neutral + Location: 42,56 + Actor114: utilpol1 + Owner: Neutral + Location: 38,49 + Actor115: utilpol1 + Owner: Neutral + Location: 50,37 + Actor116: utilpol2 + Owner: Neutral + Location: 58,41 + Actor118: v02 + Owner: Neutral + Location: 35,46 + Actor123: t13.husk + Owner: Neutral + Location: 25,37 + Actor124: tc01.husk + Owner: Neutral + Location: 29,39 + Actor125: t06.husk + Owner: Neutral + Location: 26,39 + Actor126: t14.husk + Owner: Neutral + Location: 29,35 + Actor128: tc04.husk + Owner: Neutral + Location: 20,40 + Actor132: rushouse + Owner: Neutral + Location: 47,35 + Actor127: tc05.husk + Owner: Neutral + Location: 40,20 + Actor129: t11.husk + Owner: Neutral + Location: 38,25 + Actor130: t05.husk + Owner: Neutral + Location: 40,26 + Actor131: t07.husk + Owner: Neutral + Location: 40,28 + Actor133: t06.husk + Owner: Neutral + Location: 36,29 + Actor134: gmine + Owner: Neutral + Location: 33,33 + Actor135: brik + Owner: Neutral + Location: 60,70 + Actor136: brik + Owner: Neutral + Location: 59,71 + Actor137: brik + Owner: Neutral + Location: 60,71 + Actor138: brik + Owner: Neutral + Location: 58,71 + Actor139: brik + Owner: Neutral + Location: 58,70 + Actor140: brik + Owner: Neutral + Location: 70,60 + Actor141: brik + Owner: Neutral + Location: 71,60 + Actor142: brik + Owner: Neutral + Location: 71,59 + Actor143: brik + Owner: Neutral + Location: 71,58 + Actor144: brik + Owner: Neutral + Location: 70,58 + Actor145: brik + Owner: Neutral + Location: 61,70 + Actor146: brik + Owner: Neutral + Location: 57,70 + Actor147: brik + Owner: Neutral + Location: 70,57 + Actor148: brik + Owner: Neutral + Location: 70,60 + Actor149: brik + Owner: Neutral + Location: 70,61 + Actor150: brik + Owner: Neutral + Location: 62,70 + Actor151: brik + Owner: Neutral + Location: 63,70 + Actor152: brik + Owner: Neutral + Location: 63,69 + Actor153: brik + Owner: Neutral + Location: 62,69 + Actor154: brik + Owner: Neutral + Location: 70,62 + Actor155: brik + Owner: Neutral + Location: 70,62 + Actor156: brik + Owner: Neutral + Location: 69,63 + Actor157: brik + Owner: Neutral + Location: 69,62 + Actor158: brik + Owner: Neutral + Location: 70,63 + Actor159: brik + Owner: Neutral + Location: 52,66 + Actor160: brik + Owner: Neutral + Location: 52,67 + Actor161: brik + Owner: Neutral + Location: 53,67 + Actor165: brik + Owner: Neutral + Location: 54,67 + Actor167: brik + Owner: Neutral + Location: 52,65 + Actor169: tc02 + Owner: Neutral + Location: 68,60 + Actor170: t17 + Owner: Neutral + Location: 54,65 + Actor172: tc04 + Owner: Neutral + Location: 61,70 + Actor173: tc04 + Owner: Neutral + Location: 71,60 + Actor174: t03 + Owner: Neutral + Location: 71,62 + Actor175: t16 + Owner: Neutral + Location: 62,50 + Actor163: brik + Owner: Neutral + Location: 65,52 + Actor164: brik + Owner: Neutral + Location: 66,52 + Actor166: brik + Owner: Neutral + Location: 67,52 + Actor168: windmill + Owner: Neutral + Location: 66,53 + Actor171: brik + Owner: Neutral + Location: 67,53 + Actor176: t08 + Owner: Neutral + Location: 66,54 + Actor177: brik + Owner: Neutral + Location: 67,54 + Actor178: mine + Owner: Neutral + Location: 41,59 + Actor179: mine + Owner: Neutral + Location: 60,42 + Actor180: fcom + Owner: Neutral + Location: 118,117 + Actor182: mine + Owner: Neutral + Location: 107,107 + Actor181: v06 + Owner: Neutral + Location: 119,111 + Actor183: v10 + Owner: Neutral + Location: 111,120 + Actor184: v18 + Owner: Neutral + Location: 111,119 + Actor185: wood + Owner: Neutral + Location: 110,120 + Actor186: wood + Owner: Neutral + Location: 110,119 + Actor187: wood + Owner: Neutral + Location: 112,119 + Actor188: wood + Owner: Neutral + Location: 112,120 + Actor189: wood + Owner: Neutral + Location: 120,112 + Actor190: wood + Owner: Neutral + Location: 119,112 + Actor191: wood + Owner: Neutral + Location: 119,110 + Actor192: wood + Owner: Neutral + Location: 120,110 + Actor202: wood + Owner: Neutral + Location: 118,116 + Actor203: wood + Owner: Neutral + Location: 117,116 + Actor204: wood + Owner: Neutral + Location: 117,117 + Actor196: v08 + Owner: Neutral + Location: 111,114 + Actor193: v09 + Owner: Neutral + Location: 114,111 + Actor194: t16 + Owner: Neutral + Location: 113,112 + Actor195: t12 + Owner: Neutral + Location: 114,109 + Actor197: t03 + Owner: Neutral + Location: 110,113 + Actor198: t07 + Owner: Neutral + Location: 120,119 + Actor199: t15 + Owner: Neutral + Location: 112,119 + Actor200: tc01 + Owner: Neutral + Location: 120,112 + Actor201: t16 + Owner: Neutral + Location: 119,108 + Actor205: t01 + Owner: Neutral + Location: 109,118 + Actor206: mine + Owner: Neutral + Location: 66,66 + Actor207: tc01.husk + Owner: Neutral + Location: 14,42 + Actor208: tc01.husk + Owner: Neutral + Location: 42,14 + Actor209: t11.husk + Owner: Neutral + Location: 9,44 + Actor210: t15.husk + Owner: Neutral + Location: 43,9 + Actor211: tc05.husk + Owner: Neutral + Location: 0,41 + Actor212: tc02.husk + Owner: Neutral + Location: 42,1 + Actor213: tc05.husk + Owner: Neutral + Location: 40,0 + Actor214: t17.husk + Owner: Neutral + Location: 21,33 + Actor215: t12.husk + Owner: Neutral + Location: 34,20 + Actor216: t16.husk + Owner: Neutral + Location: 17,37 + Actor217: t05.husk + Owner: Neutral + Location: 38,16 + Actor218: t03.husk + Owner: Neutral + Location: 26,45 + Actor219: t05.husk + Owner: Neutral + Location: 46,25 + Actor220: t13.husk + Owner: Neutral + Location: 3,47 + Actor221: t05.husk + Owner: Neutral + Location: 49,3 + Actor222: t17.husk + Owner: Neutral + Location: 37,8 + Actor223: t01.husk + Owner: Neutral + Location: 10,36 + Actor224: mine + Owner: Neutral + Location: 56,82 + Actor225: mine + Owner: Neutral + Location: 82,56 + Actor241: t15 + Owner: Neutral + Location: 51,85 + Actor242: tc02 + Owner: Neutral + Location: 55,87 + Actor243: tc04 + Owner: Neutral + Location: 55,88 + Actor244: t16 + Owner: Neutral + Location: 52,82 + Actor245: t03 + Owner: Neutral + Location: 51,82 + Actor246: t05 + Owner: Neutral + Location: 58,89 + Actor247: tc05 + Owner: Neutral + Location: 87,54 + Actor248: tc04 + Owner: Neutral + Location: 88,55 + Actor249: t15 + Owner: Neutral + Location: 82,51 + Actor250: tc01 + Owner: Neutral + Location: 82,50 + Actor251: t14 + Owner: Neutral + Location: 83,49 + Actor252: t10 + Owner: Neutral + Location: 89,57 + Actor253: t07 + Owner: Neutral + Location: 88,52 + Actor254: t08 + Owner: Neutral + Location: 90,54 + Actor238: t10 + Owner: Neutral + Location: 32,72 + Actor239: t16 + Owner: Neutral + Location: 31,73 + Actor255: t08 + Owner: Neutral + Location: 33,74 + Actor256: t01 + Owner: Neutral + Location: 30,74 + Actor257: mine + Owner: Neutral + Location: 27,80 + Actor258: mine + Owner: Neutral + Location: 24,85 + Actor259: mine + Owner: Neutral + Location: 23,91 + Actor260: mine + Owner: Neutral + Location: 19,97 + Actor240: mine + Owner: Neutral + Location: 97,19 + Actor261: mine + Owner: Neutral + Location: 91,23 + Actor262: mine + Owner: Neutral + Location: 85,24 + Actor263: mine + Owner: Neutral + Location: 80,27 + Actor264: t03 + Owner: Neutral + Location: 75,29 + Actor265: t16 + Owner: Neutral + Location: 74,30 + Actor266: tc01 + Owner: Neutral + Location: 73,32 + Actor267: mpspawn + Owner: Neutral + Location: 37,87 + Actor268: mpspawn + Owner: Neutral + Location: 32,98 + Actor269: mpspawn + Owner: Neutral + Location: 87,37 + Actor270: mpspawn + Owner: Neutral + Location: 98,32 + Actor271: mine + Owner: Neutral + Location: 48,96 + Actor272: mine + Owner: Neutral + Location: 44,101 + Actor273: mine + Owner: Neutral + Location: 101,44 + Actor274: mine + Owner: Neutral + Location: 96,48 + Actor275: tc05 + Owner: Neutral + Location: 59,93 + Actor276: tc04 + Owner: Neutral + Location: 57,91 + Actor277: tc02 + Owner: Neutral + Location: 54,90 + Actor278: tc01 + Owner: Neutral + Location: 59,90 + Actor279: t14 + Owner: Neutral + Location: 59,91 + Actor280: t15 + Owner: Neutral + Location: 55,90 + Actor281: tc02 + Owner: Neutral + Location: 92,60 + Actor282: t11 + Owner: Neutral + Location: 91,55 + Actor283: t12 + Owner: Neutral + Location: 95,60 + Actor284: t16 + Owner: Neutral + Location: 93,57 + Actor285: mine + Owner: Neutral + Location: 5,51 + Actor287: mine + Owner: Neutral + Location: 51,5 + Actor286: mine + Owner: Neutral + Location: 13,48 + Actor288: mine + Owner: Neutral + Location: 48,13 + Actor289: t16.husk + Owner: Neutral + Location: 15,48 + Actor290: t14.husk + Owner: Neutral + Location: 8,48 + Actor291: t06.husk + Owner: Neutral + Location: 7,51 + Actor292: t11.husk + Owner: Neutral + Location: 1,51 + Actor293: t07.husk + Owner: Neutral + Location: 7,47 + Actor294: t15.husk + Owner: Neutral + Location: 49,8 + Actor295: t03.husk + Owner: Neutral + Location: 53,5 + Actor296: t06.husk + Owner: Neutral + Location: 48,14 + Actor297: t05.husk + Owner: Neutral + Location: 46,8 + Actor298: t13.husk + Owner: Neutral + Location: 47,4 + Actor299: t11.husk + Owner: Neutral + Location: 18,45 + Actor300: t11.husk + Owner: Neutral + Location: 46,18 + Actor301: t06.husk + Owner: Neutral + Location: 6,42 + Actor302: t08.husk + Owner: Neutral + Location: 12,40 + Actor303: t08.husk + Owner: Neutral + Location: 40,11 + Actor304: t06.husk + Owner: Neutral + Location: 41,5 + Actor305: t08.husk + Owner: Neutral + Location: 44,4 + Actor306: t06.husk + Owner: Neutral + Location: 5,39 + Actor307: mine + Owner: Neutral + Location: 40,106 + Actor308: mine + Owner: Neutral + Location: 106,40 + Actor309: mine + Owner: Neutral + Location: 69,115 + Actor310: mine + Owner: Neutral + Location: 115,69 + Actor311: mine + Owner: Neutral + Location: 76,114 + Actor312: mine + Owner: Neutral + Location: 114,76 + Actor313: tc05 + Owner: Neutral + Location: 61,110 + Actor314: tc01 + Owner: Neutral + Location: 60,106 + Actor315: t16 + Owner: Neutral + Location: 58,112 + Actor316: tc04 + Owner: Neutral + Location: 111,61 + Actor317: t12 + Owner: Neutral + Location: 114,57 + Actor318: t11 + Owner: Neutral + Location: 106,60 + Actor319: tc02 + Owner: Neutral + Location: 85,113 + Actor320: tc02 + Owner: Neutral + Location: 113,85 + Actor321: t12 + Owner: Neutral + Location: 47,81 + Actor323: t12 + Owner: Neutral + Location: 81,46 + Actor322: oilb + Owner: Neutral + Location: 83,83 + Actor324: brik + Owner: Neutral + Location: 86,85 + Actor325: brik + Owner: Neutral + Location: 86,84 + Actor326: brik + Owner: Neutral + Location: 86,86 + Actor327: brik + Owner: Neutral + Location: 85,86 + Actor328: brik + Owner: Neutral + Location: 84,86 + Actor330: t01 + Owner: Neutral + Location: 80,82 + Actor331: tc03 + Owner: Neutral + Location: 86,86 + Actor332: t15 + Owner: Neutral + Location: 84,86 + Actor333: t13 + Owner: Neutral + Location: 87,84 + Actor334: t16 + Owner: Neutral + Location: 83,79 + Actor329: tc01 + Owner: Neutral + Location: 79,78 + Actor335: mine + Owner: Neutral + Location: 64,114 + Actor337: mine + Owner: Neutral + Location: 114,64 + Actor336: mine + Owner: Neutral + Location: 5,72 + Actor338: mine + Owner: Neutral + Location: 72,5 + Actor339: tc05 + Owner: Neutral + Location: 6,65 + Actor340: tc04 + Owner: Neutral + Location: 3,63 + Actor341: tc05 + Owner: Neutral + Location: 64,6 + Actor342: tc04 + Owner: Neutral + Location: 62,3 + Actor343: tc01 + Owner: Neutral + Location: 22,75 + Actor344: tc02 + Owner: Neutral + Location: 75,22 + Actor345: t17 + Owner: Neutral + Location: 70,25 + Actor346: t16 + Owner: Neutral + Location: 26,69 + Actor347: tc04 + Owner: Neutral + Location: 16,81 + Actor348: tc04 + Owner: Neutral + Location: 81,17 + Actor349: tc05 + Owner: Neutral + Location: 7,90 + Actor350: tc01 + Owner: Neutral + Location: 6,89 + Actor351: tc04 + Owner: Neutral + Location: 89,5 + Actor352: tc01 + Owner: Neutral + Location: 91,6 + Actor353: tc05 + Owner: Neutral + Location: 14,111 + Actor354: tc04 + Owner: Neutral + Location: 11,108 + Actor355: tc01 + Owner: Neutral + Location: 13,109 + Actor356: t12 + Owner: Neutral + Location: 11,106 + Actor357: t13 + Owner: Neutral + Location: 18,112 + Actor358: t15 + Owner: Neutral + Location: 42,110 + Actor359: t05 + Owner: Neutral + Location: 36,111 + Actor360: t13 + Owner: Neutral + Location: 110,41 + Actor361: t02 + Owner: Neutral + Location: 112,36 + Actor362: t12 + Owner: Neutral + Location: 6,118 + Actor363: t03 + Owner: Neutral + Location: 9,111 + Actor364: t03 + Owner: Neutral + Location: 113,10 + Actor365: t10 + Owner: Neutral + Location: 119,4 + Actor366: t16 + Owner: Neutral + Location: 100,1 + Actor368: t05 + Owner: Neutral + Location: 2,99 + Actor367: t17 + Owner: Neutral + Location: 26,108 + Actor369: t17 + Owner: Neutral + Location: 107,27 + Actor370: t01 + Owner: Neutral + Location: 97,72 + Actor371: t02 + Owner: Neutral + Location: 77,96 + Actor372: t12 + Owner: Neutral + Location: 92,93 + Actor373: t08 + Owner: Neutral + Location: 71,90 + Actor374: t08 + Owner: Neutral + Location: 88,71 + Actor375: t16 + Owner: Neutral + Location: 92,104 + Actor376: t16 + Owner: Neutral + Location: 104,92 + Actor377: t05 + Owner: Neutral + Location: 77,72 + Actor378: t01 + Owner: Neutral + Location: 73,75 + Actor379: t03 + Owner: Neutral + Location: 73,72 + +Rules: rules.yaml Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/chernobyl/plains.pal and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/chernobyl/plains.pal differ diff -Nru openra-20200503/mods/ra/maps/chernobyl/rules.yaml openra-20210321/mods/ra/maps/chernobyl/rules.yaml --- openra-20200503/mods/ra/maps/chernobyl/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/chernobyl/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,36 @@ +World: + GlobalLightingPaletteEffect: + Red: 1 + Green: 0.90 + Blue: 0.83 + Ambient: 1.00 + +^Palettes: + PaletteFromFile@terrain-temperat: + Name: terrain + Tileset: TEMPERAT + Filename: plains.pal + ShadowIndex: 3, 4 + PaletteFromFile@player: + Name: player + Filename: temperat.pal + ShadowIndex: 4 + PaletteFromFile@chrome: + Name: chrome + Filename: temperat.pal + ShadowIndex: 3 + AllowModifiers: false + PaletteFromFile@cursor: + Name: cursor + Filename: temperat.pal + AllowModifiers: false + CursorPalette: true + PaletteFromFile@effect: + Name: effect + Filename: temperat.pal + ShadowIndex: 4 + PaletteFromFile@colorpicker: + Name: colorpicker + Filename: temperat.pal + ShadowIndex: 4 + AllowModifiers: false Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/chernobyl/temperat.pal and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/chernobyl/temperat.pal differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/climax-rev15.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/climax-rev15.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/coastal-influence.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/coastal-influence.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/code-19/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/code-19/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/code-19/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/code-19/map.png differ diff -Nru openra-20200503/mods/ra/maps/code-19/map.yaml openra-20210321/mods/ra/maps/code-19/map.yaml --- openra-20200503/mods/ra/maps/code-19/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/code-19/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,3944 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: Code 19 + +Author: WhoCares + +Tileset: SNOW + +MapSize: 130,130 + +Bounds: 1,1,128,128 + +Visibility: Lobby + +Categories: Conquest + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: england + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Faction: england + Enemies: Multi0, Multi1, Multi2 + PlayerReference@Multi0: + Name: Multi0 + Playable: True + Faction: Random + Enemies: Creeps + PlayerReference@Multi1: + Name: Multi1 + Playable: True + Faction: Random + Enemies: Creeps + PlayerReference@Multi2: + Name: Multi2 + Playable: True + Faction: Random + Enemies: Creeps + +Actors: + Actor373: t03.husk + Owner: Neutral + Location: 52,3 + Actor493: t03 + Owner: Neutral + Location: 123,50 + Actor489: t06 + Owner: Neutral + Location: 28,13 + Actor753: t10.husk + Owner: Neutral + Location: 39,53 + Actor761: t15.husk + Owner: Neutral + Location: 34,65 + Actor762: tc01.husk + Owner: Neutral + Location: 91,65 + Actor767: t11.husk + Owner: Neutral + Location: 36,79 + Actor770: t03.husk + Owner: Neutral + Location: 96,82 + Actor773: t03.husk + Owner: Neutral + Location: 35,90 + Actor780: tc05.husk + Owner: Neutral + Location: 31,105 + Actor805: t11 + Owner: Neutral + Location: 94,108 + Actor813: t16 + Owner: Neutral + Location: 87,114 + Actor321: tc02 + Owner: Neutral + Location: 34,111 + Actor148: t16 + Owner: Neutral + Location: 8,17 + Actor149: tc02 + Owner: Neutral + Location: 7,19 + Actor150: ice04 + Owner: Neutral + Location: 13,10 + Actor151: ice02 + Owner: Neutral + Location: 11,13 + Actor153: ice03 + Owner: Neutral + Location: 11,10 + Actor154: ice05 + Owner: Neutral + Location: 10,10 + Actor155: ice04 + Owner: Neutral + Location: 11,8 + Actor156: ice02 + Owner: Neutral + Location: 10,8 + Actor207: ice03 + Owner: Neutral + Location: 13,11 + Actor208: ice03 + Owner: Neutral + Location: 9,14 + Actor209: ice04 + Owner: Neutral + Location: 8,13 + Actor210: ice05 + Owner: Neutral + Location: 8,14 + Actor152: ice01 + Owner: Neutral + Location: 9,11 + Actor218: tc04 + Owner: Neutral + Location: 18,6 + Actor219: t16 + Owner: Neutral + Location: 19,7 + Actor220: tc03 + Owner: Neutral + Location: 30,2 + Actor221: tc03 + Owner: Neutral + Location: 28,4 + Actor222: tc03 + Owner: Neutral + Location: 23,5 + Actor223: tc03 + Owner: Neutral + Location: 24,3 + Actor224: tc03 + Owner: Neutral + Location: 27,3 + Actor225: tc03 + Owner: Neutral + Location: 25,4 + Actor226: tc03 + Owner: Neutral + Location: 29,4 + Actor227: tc03 + Owner: Neutral + Location: 23,4 + Actor228: t08 + Owner: Neutral + Location: 22,5 + Actor229: t08 + Owner: Neutral + Location: 24,6 + Actor230: t08 + Owner: Neutral + Location: 27,5 + Actor231: tc03.husk + Owner: Neutral + Location: 24,5 + Actor232: tc03.husk + Owner: Neutral + Location: 26,4 + Actor233: tc03.husk + Owner: Neutral + Location: 28,3 + Actor234: tc03.husk + Owner: Neutral + Location: 24,3 + Actor235: tc03.husk + Owner: Neutral + Location: 25,3 + Actor236: tc02 + Owner: Neutral + Location: 20,9 + Actor237: tc03 + Owner: Neutral + Location: 18,10 + Actor238: t08 + Owner: Neutral + Location: 17,11 + Actor239: ice01 + Owner: Neutral + Location: 1,47 + Actor240: ice01 + Owner: Neutral + Location: 3,39 + Actor241: ice01 + Owner: Neutral + Location: 6,34 + Actor242: ice01 + Owner: Neutral + Location: 2,34 + Actor244: ice01 + Owner: Neutral + Location: 10,24 + Actor246: ice01 + Owner: Neutral + Location: 16,18 + Actor247: ice01 + Owner: Neutral + Location: 20,16 + Actor248: ice01 + Owner: Neutral + Location: 23,12 + Actor249: ice01 + Owner: Neutral + Location: 27,8 + Actor250: ice01 + Owner: Neutral + Location: 34,6 + Actor251: ice01 + Owner: Neutral + Location: 35,1 + Actor252: ice01 + Owner: Neutral + Location: 44,2 + Actor253: ice01 + Owner: Neutral + Location: 49,1 + Actor254: ice01 + Owner: Neutral + Location: 38,3 + Actor255: ice01 + Owner: Neutral + Location: 30,7 + Actor256: ice01 + Owner: Neutral + Location: 17,15 + Actor257: ice01 + Owner: Neutral + Location: 9,27 + Actor258: ice01 + Owner: Neutral + Location: 7,31 + Actor259: ice01 + Owner: Neutral + Location: 3,36 + Actor260: ice01 + Owner: Neutral + Location: 1,41 + Actor261: ice01 + Owner: Neutral + Location: 2,43 + Actor262: ice01 + Owner: Neutral + Location: 1,37 + Actor263: ice01 + Owner: Neutral + Location: 1,30 + Actor264: ice03 + Owner: Neutral + Location: 4,35 + Actor265: ice03 + Owner: Neutral + Location: 3,38 + Actor266: ice03 + Owner: Neutral + Location: 11,24 + Actor267: ice03 + Owner: Neutral + Location: 12,21 + Actor271: ice03 + Owner: Neutral + Location: 23,14 + Actor272: ice03 + Owner: Neutral + Location: 25,9 + Actor273: ice03 + Owner: Neutral + Location: 30,8 + Actor274: ice03 + Owner: Neutral + Location: 34,6 + Actor275: ice03 + Owner: Neutral + Location: 36,1 + Actor276: ice03 + Owner: Neutral + Location: 2,40 + Actor277: ice03 + Owner: Neutral + Location: 2,36 + Actor278: ice03 + Owner: Neutral + Location: 0,29 + Actor279: ice03 + Owner: Neutral + Location: 34,3 + Actor280: ice03 + Owner: Neutral + Location: 51,1 + Actor281: ice03 + Owner: Neutral + Location: 43,4 + Actor282: ice03 + Owner: Neutral + Location: 44,1 + Actor283: ice03 + Owner: Neutral + Location: 40,3 + Actor284: ice03 + Owner: Neutral + Location: 36,5 + Actor285: ice02 + Owner: Neutral + Location: 2,31 + Actor286: ice02 + Owner: Neutral + Location: 8,29 + Actor287: ice02 + Owner: Neutral + Location: 8,33 + Actor288: ice02 + Owner: Neutral + Location: 5,36 + Actor289: ice02 + Owner: Neutral + Location: 1,39 + Actor290: ice02 + Owner: Neutral + Location: 3,41 + Actor291: ice02 + Owner: Neutral + Location: 1,43 + Actor293: ice02 + Owner: Neutral + Location: 1,46 + Actor292: ice02 + Owner: Neutral + Location: 4,40 + Actor295: ice02 + Owner: Neutral + Location: 1,33 + Actor296: ice02 + Owner: Neutral + Location: 12,22 + Actor297: ice02 + Owner: Neutral + Location: 16,19 + Actor298: ice02 + Owner: Neutral + Location: 18,18 + Actor299: ice02 + Owner: Neutral + Location: 19,16 + Actor300: ice02 + Owner: Neutral + Location: 21,14 + Actor301: ice02 + Owner: Neutral + Location: 25,10 + Actor302: ice02 + Owner: Neutral + Location: 29,8 + Actor303: ice02 + Owner: Neutral + Location: 37,3 + Actor304: ice02 + Owner: Neutral + Location: 34,1 + Actor305: ice02 + Owner: Neutral + Location: 46,1 + Actor306: ice02 + Owner: Neutral + Location: 42,3 + Actor307: ice02 + Owner: Neutral + Location: 34,5 + Actor308: ice04 + Owner: Neutral + Location: 51,2 + Actor309: ice04 + Owner: Neutral + Location: 48,1 + Actor310: ice04 + Owner: Neutral + Location: 43,3 + Actor311: ice04 + Owner: Neutral + Location: 43,4 + Actor312: ice04 + Owner: Neutral + Location: 38,5 + Actor313: ice04 + Owner: Neutral + Location: 33,7 + Actor314: ice04 + Owner: Neutral + Location: 4,30 + Actor315: ice04 + Owner: Neutral + Location: 6,32 + Actor316: ice04 + Owner: Neutral + Location: 4,34 + Actor317: ice04 + Owner: Neutral + Location: 1,35 + Actor318: ice04 + Owner: Neutral + Location: 6,38 + Actor319: ice04 + Owner: Neutral + Location: 2,39 + Actor320: ice04 + Owner: Neutral + Location: 2,46 + Actor322: ice04 + Owner: Neutral + Location: 8,36 + Actor323: ice04 + Owner: Neutral + Location: 7,33 + Actor324: ice05 + Owner: Neutral + Location: 9,33 + Actor325: ice05 + Owner: Neutral + Location: 2,33 + Actor326: ice05 + Owner: Neutral + Location: 1,36 + Actor327: ice05 + Owner: Neutral + Location: 7,36 + Actor328: ice05 + Owner: Neutral + Location: 5,34 + Actor330: ice05 + Owner: Neutral + Location: 4,31 + Actor331: ice05 + Owner: Neutral + Location: 3,30 + Actor333: ice05 + Owner: Neutral + Location: 1,32 + Actor329: ice05 + Owner: Neutral + Location: 9,29 + Actor334: ice05 + Owner: Neutral + Location: 11,26 + Actor335: ice05 + Owner: Neutral + Location: 11,23 + Actor336: ice05 + Owner: Neutral + Location: 13,23 + Actor337: ice05 + Owner: Neutral + Location: 16,21 + Actor338: ice05 + Owner: Neutral + Location: 18,17 + Actor339: ice05 + Owner: Neutral + Location: 20,14 + Actor340: ice05 + Owner: Neutral + Location: 25,13 + Actor341: ice05 + Owner: Neutral + Location: 26,10 + Actor342: ice05 + Owner: Neutral + Location: 26,8 + Actor343: ice05 + Owner: Neutral + Location: 30,9 + Actor344: ice05 + Owner: Neutral + Location: 35,5 + Actor345: ice05 + Owner: Neutral + Location: 37,2 + Actor346: ice05 + Owner: Neutral + Location: 40,4 + Actor347: ice05 + Owner: Neutral + Location: 40,2 + Actor348: ice05 + Owner: Neutral + Location: 43,1 + Actor349: ice05 + Owner: Neutral + Location: 47,1 + Actor350: ice05 + Owner: Neutral + Location: 48,2 + Actor351: ice05 + Owner: Neutral + Location: 37,6 + Actor352: ice05 + Owner: Neutral + Location: 33,6 + Actor353: ice05 + Owner: Neutral + Location: 32,9 + Actor354: ice05 + Owner: Neutral + Location: 22,15 + Actor355: ice05 + Owner: Neutral + Location: 19,19 + Actor356: ice01 + Owner: Neutral + Location: 21,13 + Actor357: ice01 + Owner: Neutral + Location: 14,20 + Actor358: ice02 + Owner: Neutral + Location: 13,24 + Actor359: ice02 + Owner: Neutral + Location: 5,32 + Actor360: ice03 + Owner: Neutral + Location: 3,33 + Actor361: ice04 + Owner: Neutral + Location: 4,32 + Actor362: ice04 + Owner: Neutral + Location: 3,31 + Actor363: ice04 + Owner: Neutral + Location: 10,29 + Actor365: ice04 + Owner: Neutral + Location: 7,30 + Actor364: ice04 + Owner: Neutral + Location: 14,23 + Actor366: ice04 + Owner: Neutral + Location: 11,22 + Actor368: ice04 + Owner: Neutral + Location: 10,26 + Actor369: ice04 + Owner: Neutral + Location: 12,25 + Actor370: ice04 + Owner: Neutral + Location: 17,20 + Actor374: ice04 + Owner: Neutral + Location: 15,19 + Actor372: ice02 + Owner: Neutral + Location: 16,16 + Actor371: ice04 + Owner: Neutral + Location: 17,17 + Actor375: ice04 + Owner: Neutral + Location: 19,18 + Actor381: ice04 + Owner: Neutral + Location: 19,14 + Actor384: ice04 + Owner: Neutral + Location: 24,11 + Actor385: ice04 + Owner: Neutral + Location: 28,10 + Actor386: ice04 + Owner: Neutral + Location: 32,7 + Actor387: ice04 + Owner: Neutral + Location: 36,4 + Actor388: ice04 + Owner: Neutral + Location: 33,5 + Actor389: ice04 + Owner: Neutral + Location: 38,2 + Actor390: ice04 + Owner: Neutral + Location: 40,1 + Actor391: ice04 + Owner: Neutral + Location: 43,2 + Actor332: ice03 + Owner: Neutral + Location: 28,1 + Actor392: ice04 + Owner: Neutral + Location: 27,1 + Actor393: ice05 + Owner: Neutral + Location: 26,1 + Actor394: ice01 + Owner: Neutral + Location: 22,1 + Actor395: ice01 + Owner: Neutral + Location: 18,1 + Actor396: ice01 + Owner: Neutral + Location: 12,1 + Actor397: ice01 + Owner: Neutral + Location: 7,0 + Actor398: ice01 + Owner: Neutral + Location: 3,1 + Actor399: ice01 + Owner: Neutral + Location: 1,2 + Actor400: ice01 + Owner: Neutral + Location: 2,4 + Actor401: ice01 + Owner: Neutral + Location: 1,8 + Actor402: ice01 + Owner: Neutral + Location: 1,13 + Actor403: ice01 + Owner: Neutral + Location: 0,16 + Actor404: ice03 + Owner: Neutral + Location: 16,1 + Actor406: ice03 + Owner: Neutral + Location: 3,3 + Actor407: ice03 + Owner: Neutral + Location: 5,1 + Actor408: ice03 + Owner: Neutral + Location: 1,7 + Actor409: ice03 + Owner: Neutral + Location: 0,12 + Actor410: ice03 + Owner: Neutral + Location: 0,18 + Actor411: ice02 + Owner: Neutral + Location: 20,1 + Actor412: ice02 + Owner: Neutral + Location: 14,0 + Actor413: ice02 + Owner: Neutral + Location: 11,1 + Actor415: ice02 + Owner: Neutral + Location: 1,5 + Actor416: ice02 + Owner: Neutral + Location: 1,10 + Actor417: ice02 + Owner: Neutral + Location: 2,16 + Actor418: ice01 + Owner: Neutral + Location: 0,19 + Actor419: ice03 + Owner: Neutral + Location: 0,21 + Actor420: ice05 + Owner: Neutral + Location: 0,22 + Actor421: ice04 + Owner: Neutral + Location: 0,23 + Actor422: ice01 + Owner: Neutral + Location: 119,8 + Actor423: tc02 + Owner: Neutral + Location: 117,5 + Actor424: tc01 + Owner: Neutral + Location: 121,5 + Actor425: tc05 + Owner: Neutral + Location: 117,9 + Actor426: tc02 + Owner: Neutral + Location: 120,10 + Actor427: tc03 + Owner: Neutral + Location: 121,9 + Actor428: tc03 + Owner: Neutral + Location: 119,5 + Actor429: tc04 + Owner: Neutral + Location: 116,7 + Actor431: tc03 + Owner: Neutral + Location: 122,8 + Actor432: tc03 + Owner: Neutral + Location: 120,5 + Actor433: tc03 + Owner: Neutral + Location: 117,6 + Actor434: t08 + Owner: Neutral + Location: 117,8 + Actor435: t08 + Owner: Neutral + Location: 117,9 + Actor436: t08 + Owner: Neutral + Location: 118,11 + Actor437: t08 + Owner: Neutral + Location: 122,8 + Actor438: ice01 + Owner: Neutral + Location: 123,31 + Actor439: ice05 + Owner: Neutral + Location: 125,31 + Actor440: ice04 + Owner: Neutral + Location: 126,31 + Actor441: ice01 + Owner: Neutral + Location: 127,31 + Actor442: ice04 + Owner: Neutral + Location: 129,31 + Actor443: ice02 + Owner: Neutral + Location: 124,32 + Actor444: ice04 + Owner: Neutral + Location: 125,32 + Actor445: ice05 + Owner: Neutral + Location: 126,32 + Actor447: ice05 + Owner: Neutral + Location: 123,33 + Actor448: ice04 + Owner: Neutral + Location: 126,33 + Actor451: ice02 + Owner: Neutral + Location: 123,34 + Actor452: ice05 + Owner: Neutral + Location: 124,34 + Actor454: ice04 + Owner: Neutral + Location: 129,34 + Actor455: ice01 + Owner: Neutral + Location: 124,35 + Actor459: ice04 + Owner: Neutral + Location: 123,36 + Actor470: ice05 + Owner: Neutral + Location: 123,37 + Actor471: ice03 + Owner: Neutral + Location: 124,37 + Actor474: ice05 + Owner: Neutral + Location: 129,37 + Actor475: ice01 + Owner: Neutral + Location: 123,38 + Actor243: ice01 + Owner: Neutral + Location: 5,30 + Actor449: ice02 + Owner: Neutral + Location: 126,34 + Actor453: ice05 + Owner: Neutral + Location: 127,34 + Actor456: ice03 + Owner: Neutral + Location: 128,34 + Actor457: ice01 + Owner: Neutral + Location: 127,35 + Actor458: ice04 + Owner: Neutral + Location: 126,36 + Actor469: ice05 + Owner: Neutral + Location: 126,37 + Actor472: ice03 + Owner: Neutral + Location: 127,37 + Actor473: ice01 + Owner: Neutral + Location: 128,37 + Actor476: ice01 + Owner: Neutral + Location: 126,38 + Actor477: ice03 + Owner: Neutral + Location: 128,39 + Actor478: ice02 + Owner: Neutral + Location: 126,40 + Actor479: ice04 + Owner: Neutral + Location: 127,40 + Actor480: ice01 + Owner: Neutral + Location: 128,40 + Actor485: ice03 + Owner: Neutral + Location: 127,41 + Actor486: ice01 + Owner: Neutral + Location: 126,42 + Actor487: ice02 + Owner: Neutral + Location: 128,42 + Actor488: ice02 + Owner: Neutral + Location: 126,44 + Actor490: ice01 + Owner: Neutral + Location: 127,44 + Actor491: ice01 + Owner: Neutral + Location: 108,14 + Actor500: ice02 + Owner: Neutral + Location: 110,15 + Actor505: ice01 + Owner: Neutral + Location: 111,15 + Actor506: ice04 + Owner: Neutral + Location: 108,16 + Actor507: ice05 + Owner: Neutral + Location: 109,16 + Actor495: ice02 + Owner: Neutral + Location: 87,1 + Actor508: ice01 + Owner: Neutral + Location: 88,1 + Actor509: ice03 + Owner: Neutral + Location: 89,1 + Actor510: ice04 + Owner: Neutral + Location: 93,1 + Actor511: ice05 + Owner: Neutral + Location: 96,1 + Actor512: ice05 + Owner: Neutral + Location: 90,2 + Actor513: ice04 + Owner: Neutral + Location: 91,2 + Actor514: ice05 + Owner: Neutral + Location: 93,2 + Actor515: ice04 + Owner: Neutral + Location: 96,2 + Actor516: ice03 + Owner: Neutral + Location: 87,3 + Actor517: ice02 + Owner: Neutral + Location: 90,3 + Actor518: ice01 + Owner: Neutral + Location: 91,3 + Actor519: ice03 + Owner: Neutral + Location: 93,3 + Actor520: ice02 + Owner: Neutral + Location: 95,3 + Actor522: ice04 + Owner: Neutral + Location: 89,4 + Actor523: ice05 + Owner: Neutral + Location: 93,4 + Actor525: ice04 + Owner: Neutral + Location: 96,4 + Actor521: ice03 + Owner: Neutral + Location: 74,1 + Actor526: ice05 + Owner: Neutral + Location: 77,1 + Actor527: ice04 + Owner: Neutral + Location: 78,1 + Actor524: tc05 + Owner: Neutral + Location: 106,3 + Actor528: tc03 + Owner: Neutral + Location: 106,6 + Actor530: tc04 + Owner: Neutral + Location: 106,5 + Actor531: tc04 + Owner: Neutral + Location: 113,4 + Actor532: tc04 + Owner: Neutral + Location: 124,16 + Actor533: tc04 + Owner: Neutral + Location: 124,25 + Actor534: tc04 + Owner: Neutral + Location: 116,13 + Actor535: tc04 + Owner: Neutral + Location: 110,8 + Actor536: tc05 + Owner: Neutral + Location: 112,9 + Actor537: tc05 + Owner: Neutral + Location: 109,3 + Actor538: tc05 + Owner: Neutral + Location: 124,17 + Actor539: tc05 + Owner: Neutral + Location: 117,14 + Actor540: tc02 + Owner: Neutral + Location: 111,4 + Actor541: tc02 + Owner: Neutral + Location: 117,2 + Actor542: tc02 + Owner: Neutral + Location: 122,13 + Actor543: tc02 + Owner: Neutral + Location: 120,17 + Actor544: tc02 + Owner: Neutral + Location: 124,24 + Actor545: tc01 + Owner: Neutral + Location: 124,19 + Actor546: tc01 + Owner: Neutral + Location: 122,14 + Actor547: tc02 + Owner: Neutral + Location: 104,2 + Actor548: tc02 + Owner: Neutral + Location: 108,4 + Actor549: t05 + Owner: Neutral + Location: 124,5 + Actor550: t02 + Owner: Neutral + Location: 124,10 + Actor551: t07 + Owner: Neutral + Location: 123,3 + Actor552: t08 + Owner: Neutral + Location: 124,12 + Actor553: t07 + Owner: Neutral + Location: 123,12 + Actor554: t16 + Owner: Neutral + Location: 123,15 + Actor555: t16 + Owner: Neutral + Location: 115,3 + Actor556: t16 + Owner: Neutral + Location: 115,12 + Actor557: t16 + Owner: Neutral + Location: 112,10 + Actor558: t16 + Owner: Neutral + Location: 103,6 + Actor559: t05 + Owner: Neutral + Location: 99,2 + Actor560: t05 + Owner: Neutral + Location: 103,7 + Actor561: tc04.husk + Owner: Neutral + Location: 112,9 + Actor562: tc04.husk + Owner: Neutral + Location: 108,4 + Actor563: t02 + Owner: Neutral + Location: 104,8 + Actor564: t02 + Owner: Neutral + Location: 111,9 + Actor565: t02 + Owner: Neutral + Location: 115,10 + Actor566: t02 + Owner: Neutral + Location: 121,20 + Actor567: t02 + Owner: Neutral + Location: 124,22 + Actor568: t05 + Owner: Neutral + Location: 124,20 + Actor569: t05 + Owner: Neutral + Location: 121,23 + Actor570: t07 + Owner: Neutral + Location: 121,24 + Actor571: t07 + Owner: Neutral + Location: 121,18 + Actor572: t07 + Owner: Neutral + Location: 121,26 + Actor573: t08 + Owner: Neutral + Location: 122,28 + Actor574: t08 + Owner: Neutral + Location: 121,22 + Actor575: t08 + Owner: Neutral + Location: 121,20 + Actor576: t08 + Owner: Neutral + Location: 99,5 + Actor577: t07 + Owner: Neutral + Location: 101,4 + Actor578: ice01 + Owner: Neutral + Location: 126,3 + Actor579: ice01 + Owner: Neutral + Location: 127,5 + Actor580: ice01 + Owner: Neutral + Location: 128,8 + Actor581: ice01 + Owner: Neutral + Location: 127,10 + Actor582: ice01 + Owner: Neutral + Location: 128,13 + Actor583: ice01 + Owner: Neutral + Location: 128,21 + Actor584: ice01 + Owner: Neutral + Location: 121,32 + Actor585: ice01 + Owner: Neutral + Location: 124,40 + Actor586: ice01 + Owner: Neutral + Location: 117,20 + Actor587: ice01 + Owner: Neutral + Location: 113,19 + Actor588: ice01 + Owner: Neutral + Location: 115,21 + Actor589: ice01 + Owner: Neutral + Location: 117,23 + Actor590: ice01 + Owner: Neutral + Location: 112,17 + Actor591: ice01 + Owner: Neutral + Location: 106,13 + Actor592: ice01 + Owner: Neutral + Location: 104,12 + Actor593: ice01 + Owner: Neutral + Location: 82,1 + Actor529: ice01 + Owner: Neutral + Location: 92,5 + Actor594: ice01 + Owner: Neutral + Location: 95,6 + Actor595: ice01 + Owner: Neutral + Location: 110,1 + Actor596: ice01 + Owner: Neutral + Location: 125,1 + Actor597: ice02 + Owner: Neutral + Location: 128,3 + Actor598: ice02 + Owner: Neutral + Location: 127,7 + Actor599: ice02 + Owner: Neutral + Location: 126,13 + Actor600: ice02 + Owner: Neutral + Location: 128,23 + Actor601: ice04 + Owner: Neutral + Location: 127,22 + Actor602: ice05 + Owner: Neutral + Location: 127,23 + Actor603: ice04 + Owner: Neutral + Location: 128,20 + Actor604: ice05 + Owner: Neutral + Location: 128,25 + Actor605: ice05 + Owner: Neutral + Location: 127,14 + Actor606: ice04 + Owner: Neutral + Location: 126,15 + Actor607: ice04 + Owner: Neutral + Location: 127,12 + Actor608: ice05 + Owner: Neutral + Location: 128,12 + Actor609: ice04 + Owner: Neutral + Location: 127,9 + Actor610: ice04 + Owner: Neutral + Location: 128,7 + Actor611: ice03 + Owner: Neutral + Location: 127,1 + Actor612: ice03 + Owner: Neutral + Location: 120,1 + Actor613: ice03 + Owner: Neutral + Location: 113,2 + Actor614: ice03 + Owner: Neutral + Location: 114,1 + Actor615: ice03 + Owner: Neutral + Location: 107,1 + Actor616: ice04 + Owner: Neutral + Location: 109,1 + Actor617: ice05 + Owner: Neutral + Location: 112,1 + Actor618: ice04 + Owner: Neutral + Location: 116,1 + Actor619: ice05 + Owner: Neutral + Location: 123,1 + Actor620: ice04 + Owner: Neutral + Location: 124,1 + Actor621: ice04 + Owner: Neutral + Location: 122,1 + Actor622: ice04 + Owner: Neutral + Location: 119,1 + Actor623: ice04 + Owner: Neutral + Location: 113,1 + Actor624: ice04 + Owner: Neutral + Location: 106,1 + Actor625: ice05 + Owner: Neutral + Location: 105,1 + Actor626: ice04 + Owner: Neutral + Location: 80,1 + Actor627: ice05 + Owner: Neutral + Location: 81,1 + Actor628: ice04 + Owner: Neutral + Location: 83,3 + Actor630: ice05 + Owner: Neutral + Location: 86,3 + Actor632: ice04 + Owner: Neutral + Location: 86,2 + Actor629: ice03 + Owner: Neutral + Location: 85,1 + Actor631: ice05 + Owner: Neutral + Location: 84,1 + Actor633: ice05 + Owner: Neutral + Location: 91,1 + Actor634: ice02 + Owner: Neutral + Location: 92,1 + Actor635: ice03 + Owner: Neutral + Location: 89,3 + Actor636: ice03 + Owner: Neutral + Location: 94,4 + Actor637: ice01 + Owner: Neutral + Location: 94,2 + Actor638: ice01 + Owner: Neutral + Location: 94,5 + Actor639: ice05 + Owner: Neutral + Location: 96,5 + Actor640: ice03 + Owner: Neutral + Location: 94,7 + Actor641: ice05 + Owner: Neutral + Location: 96,8 + Actor642: ice05 + Owner: Neutral + Location: 100,8 + Actor643: ice04 + Owner: Neutral + Location: 99,9 + Actor644: ice04 + Owner: Neutral + Location: 100,10 + Actor645: ice04 + Owner: Neutral + Location: 101,9 + Actor646: ice03 + Owner: Neutral + Location: 108,13 + Actor647: ice03 + Owner: Neutral + Location: 110,17 + Actor648: ice03 + Owner: Neutral + Location: 115,20 + Actor649: ice03 + Owner: Neutral + Location: 113,21 + Actor650: ice03 + Owner: Neutral + Location: 115,23 + Actor651: ice03 + Owner: Neutral + Location: 117,25 + Actor652: ice02 + Owner: Neutral + Location: 112,19 + Actor653: ice02 + Owner: Neutral + Location: 110,13 + Actor654: ice05 + Owner: Neutral + Location: 113,16 + Actor655: ice04 + Owner: Neutral + Location: 114,18 + Actor656: ice05 + Owner: Neutral + Location: 111,19 + Actor657: ice04 + Owner: Neutral + Location: 117,22 + Actor658: ice05 + Owner: Neutral + Location: 118,22 + Actor659: ice04 + Owner: Neutral + Location: 118,26 + Actor660: ice01 + Owner: Neutral + Location: 128,50 + Actor661: ice01 + Owner: Neutral + Location: 128,46 + Actor662: ice04 + Owner: Neutral + Location: 128,48 + Actor663: ice05 + Owner: Neutral + Location: 125,43 + Actor664: ice04 + Owner: Neutral + Location: 125,42 + Actor665: ice02 + Owner: Neutral + Location: 125,38 + Actor666: ice02 + Owner: Neutral + Location: 128,29 + Actor667: ice02 + Owner: Neutral + Location: 122,36 + Actor668: ice05 + Owner: Neutral + Location: 122,34 + Actor669: ice05 + Owner: Neutral + Location: 121,34 + Actor670: ice02 + Owner: Neutral + Location: 119,28 + Actor671: ice05 + Owner: Neutral + Location: 119,30 + Actor672: ice03 + Owner: Neutral + Location: 120,31 + Actor673: ice04 + Owner: Neutral + Location: 119,31 + Actor674: ice04 + Owner: Neutral + Location: 122,31 + Actor675: ice01 + Owner: Neutral + Location: 127,84 + Actor676: ice01 + Owner: Neutral + Location: 126,86 + Actor677: ice01 + Owner: Neutral + Location: 127,88 + Actor678: ice01 + Owner: Neutral + Location: 120,98 + Actor679: ice01 + Owner: Neutral + Location: 119,100 + Actor680: ice01 + Owner: Neutral + Location: 118,102 + Actor681: ice01 + Owner: Neutral + Location: 127,101 + Actor682: ice01 + Owner: Neutral + Location: 127,109 + Actor683: ice01 + Owner: Neutral + Location: 122,109 + Actor684: ice01 + Owner: Neutral + Location: 120,110 + Actor685: ice01 + Owner: Neutral + Location: 118,109 + Actor686: ice01 + Owner: Neutral + Location: 119,112 + Actor687: ice01 + Owner: Neutral + Location: 127,119 + Actor688: ice01 + Owner: Neutral + Location: 121,116 + Actor689: ice01 + Owner: Neutral + Location: 119,115 + Actor690: ice01 + Owner: Neutral + Location: 119,118 + Actor691: ice01 + Owner: Neutral + Location: 118,120 + Actor692: ice01 + Owner: Neutral + Location: 112,122 + Actor693: ice01 + Owner: Neutral + Location: 108,120 + Actor694: ice01 + Owner: Neutral + Location: 107,118 + Actor695: ice01 + Owner: Neutral + Location: 109,116 + Actor696: ice01 + Owner: Neutral + Location: 107,115 + Actor697: ice01 + Owner: Neutral + Location: 108,113 + Actor698: ice01 + Owner: Neutral + Location: 110,112 + Actor699: ice01 + Owner: Neutral + Location: 112,111 + Actor700: ice01 + Owner: Neutral + Location: 115,110 + Actor701: ice01 + Owner: Neutral + Location: 113,109 + Actor702: ice01 + Owner: Neutral + Location: 122,96 + Actor703: ice01 + Owner: Neutral + Location: 82,127 + Actor704: ice01 + Owner: Neutral + Location: 86,127 + Actor705: ice01 + Owner: Neutral + Location: 88,125 + Actor706: ice01 + Owner: Neutral + Location: 108,127 + Actor707: ice01 + Owner: Neutral + Location: 100,119 + Actor708: ice01 + Owner: Neutral + Location: 102,118 + Actor709: ice01 + Owner: Neutral + Location: 117,127 + Actor710: ice01 + Owner: Neutral + Location: 121,127 + Actor711: ice01 + Owner: Neutral + Location: 127,126 + Actor712: ice01 + Owner: Neutral + Location: 125,127 + Actor713: ice01 + Owner: Neutral + Location: 128,78 + Actor714: ice02 + Owner: Neutral + Location: 128,81 + Actor715: ice02 + Owner: Neutral + Location: 128,86 + Actor716: ice02 + Owner: Neutral + Location: 126,88 + Actor717: ice02 + Owner: Neutral + Location: 128,90 + Actor718: ice02 + Owner: Neutral + Location: 124,92 + Actor719: ice02 + Owner: Neutral + Location: 123,94 + Actor720: ice02 + Owner: Neutral + Location: 121,100 + Actor721: ice02 + Owner: Neutral + Location: 117,103 + Actor722: ice02 + Owner: Neutral + Location: 128,103 + Actor723: ice02 + Owner: Neutral + Location: 128,111 + Actor724: ice02 + Owner: Neutral + Location: 118,111 + Actor725: ice02 + Owner: Neutral + Location: 114,111 + Actor726: ice02 + Owner: Neutral + Location: 111,110 + Actor728: ice02 + Owner: Neutral + Location: 109,118 + Actor729: ice02 + Owner: Neutral + Location: 111,122 + Actor730: ice02 + Owner: Neutral + Location: 114,121 + Actor731: ice02 + Owner: Neutral + Location: 120,120 + Actor732: ice02 + Owner: Neutral + Location: 123,117 + Actor733: ice02 + Owner: Neutral + Location: 126,119 + Actor734: ice02 + Owner: Neutral + Location: 118,125 + Actor735: ice02 + Owner: Neutral + Location: 107,127 + Actor736: ice02 + Owner: Neutral + Location: 101,126 + Actor737: ice02 + Owner: Neutral + Location: 79,127 + Actor738: ice02 + Owner: Neutral + Location: 88,127 + Actor739: ice02 + Owner: Neutral + Location: 90,124 + Actor740: ice02 + Owner: Neutral + Location: 92,123 + Actor741: ice02 + Owner: Neutral + Location: 97,122 + Actor742: ice02 + Owner: Neutral + Location: 98,120 + Actor743: ice02 + Owner: Neutral + Location: 101,117 + Actor744: ice02 + Owner: Neutral + Location: 106,118 + Actor745: ice02 + Owner: Neutral + Location: 106,115 + Actor746: ice02 + Owner: Neutral + Location: 116,106 + Actor747: ice03 + Owner: Neutral + Location: 128,83 + Actor748: ice03 + Owner: Neutral + Location: 126,90 + Actor749: ice03 + Owner: Neutral + Location: 120,102 + Actor750: ice03 + Owner: Neutral + Location: 115,105 + Actor774: ice03 + Owner: Neutral + Location: 116,109 + Actor810: ice03 + Owner: Neutral + Location: 124,110 + Actor811: ice03 + Owner: Neutral + Location: 124,100 + Actor816: ice03 + Owner: Neutral + Location: 128,98 + Actor817: ice03 + Owner: Neutral + Location: 124,89 + Actor818: ice03 + Owner: Neutral + Location: 124,117 + Actor819: ice03 + Owner: Neutral + Location: 116,121 + Actor820: ice03 + Owner: Neutral + Location: 119,128 + Actor821: ice03 + Owner: Neutral + Location: 123,128 + Actor822: ice03 + Owner: Neutral + Location: 127,121 + Actor823: ice03 + Owner: Neutral + Location: 105,128 + Actor824: ice03 + Owner: Neutral + Location: 102,128 + Actor825: ice03 + Owner: Neutral + Location: 95,122 + Actor826: ice03 + Owner: Neutral + Location: 104,118 + Actor827: ice03 + Owner: Neutral + Location: 107,117 + Actor828: ice03 + Owner: Neutral + Location: 80,128 + Actor829: ice03 + Owner: Neutral + Location: 84,128 + Actor830: ice03 + Owner: Neutral + Location: 93,123 + Actor831: ice03 + Owner: Neutral + Location: 112,113 + Actor832: ice05 + Owner: Neutral + Location: 126,85 + Actor833: ice05 + Owner: Neutral + Location: 128,97 + Actor834: ice05 + Owner: Neutral + Location: 126,101 + Actor835: ice05 + Owner: Neutral + Location: 123,101 + Actor836: ice05 + Owner: Neutral + Location: 120,103 + Actor837: ice05 + Owner: Neutral + Location: 115,106 + Actor838: ice05 + Owner: Neutral + Location: 115,109 + Actor839: ice05 + Owner: Neutral + Location: 117,111 + Actor840: ice05 + Owner: Neutral + Location: 119,111 + Actor841: ice05 + Owner: Neutral + Location: 120,114 + Actor842: ice05 + Owner: Neutral + Location: 120,117 + Actor843: ice05 + Owner: Neutral + Location: 117,120 + Actor844: ice05 + Owner: Neutral + Location: 110,122 + Actor845: ice05 + Owner: Neutral + Location: 94,122 + Actor846: ice05 + Owner: Neutral + Location: 91,124 + Actor847: ice05 + Owner: Neutral + Location: 102,126 + Actor848: ice05 + Owner: Neutral + Location: 98,124 + Actor849: ice05 + Owner: Neutral + Location: 110,127 + Actor850: ice05 + Owner: Neutral + Location: 126,126 + Actor851: ice05 + Owner: Neutral + Location: 118,122 + Actor852: ice05 + Owner: Neutral + Location: 125,119 + Actor853: ice05 + Owner: Neutral + Location: 128,113 + Actor854: ice04 + Owner: Neutral + Location: 123,91 + Actor855: ice04 + Owner: Neutral + Location: 121,97 + Actor856: ice04 + Owner: Neutral + Location: 122,101 + Actor857: ice04 + Owner: Neutral + Location: 126,110 + Actor858: ice04 + Owner: Neutral + Location: 116,108 + Actor859: ice04 + Owner: Neutral + Location: 110,111 + Actor860: ice04 + Owner: Neutral + Location: 115,112 + Actor861: ice04 + Owner: Neutral + Location: 115,121 + Actor862: ice04 + Owner: Neutral + Location: 127,128 + Actor863: ice05 + Owner: Neutral + Location: 128,128 + Actor864: ice04 + Owner: Neutral + Location: 104,128 + Actor865: ice04 + Owner: Neutral + Location: 87,126 + Actor866: ice04 + Owner: Neutral + Location: 100,125 + Actor867: ice04 + Owner: Neutral + Location: 111,117 + Actor869: ice04 + Owner: Neutral + Location: 111,114 + Actor727: ice02 + Owner: Neutral + Location: 110,114 + Actor868: ice04 + Owner: Neutral + Location: 107,114 + Actor870: ice04 + Owner: Neutral + Location: 109,112 + Actor871: ice04 + Owner: Neutral + Location: 112,110 + Actor872: ice04 + Owner: Neutral + Location: 115,107 + Actor873: ice04 + Owner: Neutral + Location: 122,95 + Actor874: ice04 + Owner: Neutral + Location: 125,88 + Actor875: ice04 + Owner: Neutral + Location: 128,99 + Actor877: tc05 + Owner: Neutral + Location: 124,113 + Actor878: tc05 + Owner: Neutral + Location: 118,105 + Actor879: tc05 + Owner: Neutral + Location: 100,122 + Actor880: tc05 + Owner: Neutral + Location: 113,125 + Actor881: tc05 + Owner: Neutral + Location: 93,125 + Actor882: tc05 + Owner: Neutral + Location: 105,122 + Actor883: tc05 + Owner: Neutral + Location: 111,118 + Actor884: tc05 + Owner: Neutral + Location: 123,102 + Actor885: tc04 + Owner: Neutral + Location: 123,103 + Actor886: tc04 + Owner: Neutral + Location: 119,105 + Actor887: tc04 + Owner: Neutral + Location: 122,112 + Actor888: tc04 + Owner: Neutral + Location: 123,120 + Actor889: tc04 + Owner: Neutral + Location: 115,123 + Actor890: tc04 + Owner: Neutral + Location: 101,122 + Actor891: tc04 + Owner: Neutral + Location: 103,120 + Actor892: tc04 + Owner: Neutral + Location: 113,114 + Actor893: tc04 + Owner: Neutral + Location: 91,125 + Actor894: tc04 + Owner: Neutral + Location: 95,124 + Actor895: tc04 + Owner: Neutral + Location: 124,96 + Actor896: tc04 + Owner: Neutral + Location: 126,92 + Actor897: tc03 + Owner: Neutral + Location: 126,93 + Actor898: tc03 + Owner: Neutral + Location: 125,95 + Actor899: tc03 + Owner: Neutral + Location: 126,106 + Actor900: tc03 + Owner: Neutral + Location: 125,112 + Actor901: tc03 + Owner: Neutral + Location: 116,113 + Actor902: tc03 + Owner: Neutral + Location: 116,117 + Actor903: tc03 + Owner: Neutral + Location: 121,122 + Actor904: tc03 + Owner: Neutral + Location: 102,121 + Actor905: tc03 + Owner: Neutral + Location: 105,124 + Actor906: tc03 + Owner: Neutral + Location: 112,126 + Actor907: tc03 + Owner: Neutral + Location: 109,124 + Actor908: tc03 + Owner: Neutral + Location: 115,123 + Actor909: tc03 + Owner: Neutral + Location: 97,126 + Actor910: tc03 + Owner: Neutral + Location: 94,125 + Actor911: tc02 + Owner: Neutral + Location: 103,123 + Actor912: tc02 + Owner: Neutral + Location: 122,123 + Actor913: tc01 + Owner: Neutral + Location: 124,123 + Actor914: tc03 + Owner: Neutral + Location: 123,124 + Actor915: tc03 + Owner: Neutral + Location: 126,122 + Actor916: tc01 + Owner: Neutral + Location: 127,115 + Actor917: tc03 + Owner: Neutral + Location: 124,114 + Actor918: tc02 + Owner: Neutral + Location: 122,105 + Actor919: tc01 + Owner: Neutral + Location: 124,104 + Actor920: tc04 + Owner: Neutral + Location: 124,105 + Actor921: t16 + Owner: Neutral + Location: 111,125 + Actor922: t05 + Owner: Neutral + Location: 108,123 + Actor923: t16 + Owner: Neutral + Location: 104,124 + Actor924: t13 + Owner: Neutral + Location: 103,121 + Actor925: t10 + Owner: Neutral + Location: 115,113 + Actor926: t13 + Owner: Neutral + Location: 122,122 + Actor927: t14 + Owner: Neutral + Location: 126,114 + Actor928: t15 + Owner: Neutral + Location: 120,105 + Actor929: t10 + Owner: Neutral + Location: 124,104 + Actor930: t10 + Owner: Neutral + Location: 125,94 + Actor931: t15 + Owner: Neutral + Location: 124,96 + Actor932: t15 + Owner: Neutral + Location: 96,125 + Actor933: t16 + Owner: Neutral + Location: 4,110 + Actor934: tc05 + Owner: Neutral + Location: 3,111 + Actor935: tc03 + Owner: Neutral + Location: 4,111 + Actor936: tc01 + Owner: Neutral + Location: 4,110 + Actor937: tc02 + Owner: Neutral + Location: 2,112 + Actor938: tc02 + Owner: Neutral + Location: 1,116 + Actor939: tc02 + Owner: Neutral + Location: 0,120 + Actor940: tc02 + Owner: Neutral + Location: 3,122 + Actor941: tc02 + Owner: Neutral + Location: 5,125 + Actor942: tc03 + Owner: Neutral + Location: 5,126 + Actor943: tc03 + Owner: Neutral + Location: 1,121 + Actor944: tc03 + Owner: Neutral + Location: 3,123 + Actor945: tc03 + Owner: Neutral + Location: 2,113 + Actor946: tc03 + Owner: Neutral + Location: 1,117 + Actor947: tc03 + Owner: Neutral + Location: 4,114 + Actor948: tc05 + Owner: Neutral + Location: 2,123 + Actor949: tc05 + Owner: Neutral + Location: 0,118 + Actor950: tc01 + Owner: Neutral + Location: 3,113 + Actor951: tc01 + Owner: Neutral + Location: 2,121 + Actor952: tc01 + Owner: Neutral + Location: 2,114 + Actor953: t13 + Owner: Neutral + Location: 2,120 + Actor954: t14 + Owner: Neutral + Location: 1,115 + Actor955: t10 + Owner: Neutral + Location: 2,122 + Actor956: ice01 + Owner: Neutral + Location: 0,77 + Actor957: ice01 + Owner: Neutral + Location: 0,81 + Actor958: ice01 + Owner: Neutral + Location: 3,89 + Actor959: ice01 + Owner: Neutral + Location: 5,96 + Actor960: ice01 + Owner: Neutral + Location: 7,97 + Actor961: ice01 + Owner: Neutral + Location: 1,108 + Actor962: ice01 + Owner: Neutral + Location: 5,108 + Actor963: ice01 + Owner: Neutral + Location: 8,105 + Actor964: ice01 + Owner: Neutral + Location: 10,102 + Actor965: ice01 + Owner: Neutral + Location: 11,105 + Actor966: ice01 + Owner: Neutral + Location: 15,107 + Actor967: ice01 + Owner: Neutral + Location: 17,110 + Actor968: ice01 + Owner: Neutral + Location: 18,112 + Actor969: ice01 + Owner: Neutral + Location: 16,113 + Actor970: ice01 + Owner: Neutral + Location: 19,114 + Actor971: ice01 + Owner: Neutral + Location: 24,116 + Actor972: ice01 + Owner: Neutral + Location: 13,116 + Actor973: ice01 + Owner: Neutral + Location: 7,115 + Actor974: ice01 + Owner: Neutral + Location: 8,124 + Actor975: ice01 + Owner: Neutral + Location: 11,122 + Actor976: ice01 + Owner: Neutral + Location: 9,127 + Actor977: ice01 + Owner: Neutral + Location: 2,127 + Actor978: ice01 + Owner: Neutral + Location: 19,125 + Actor979: ice01 + Owner: Neutral + Location: 24,123 + Actor980: ice01 + Owner: Neutral + Location: 23,125 + Actor981: ice01 + Owner: Neutral + Location: 26,127 + Actor982: ice01 + Owner: Neutral + Location: 41,127 + Actor983: ice01 + Owner: Neutral + Location: 32,121 + Actor984: ice01 + Owner: Neutral + Location: 27,118 + Actor985: ice01 + Owner: Neutral + Location: 29,119 + Actor986: ice01 + Owner: Neutral + Location: 0,96 + Actor987: ice01 + Owner: Neutral + Location: 0,91 + Actor988: ice01 + Owner: Neutral + Location: 14,128 + Actor989: ice01 + Owner: Neutral + Location: 43,128 + Actor990: ice01 + Owner: Neutral + Location: 48,128 + Actor991: ice03 + Owner: Neutral + Location: 42,126 + Actor992: ice03 + Owner: Neutral + Location: 28,128 + Actor993: ice03 + Owner: Neutral + Location: 24,128 + Actor994: ice03 + Owner: Neutral + Location: 21,126 + Actor995: ice03 + Owner: Neutral + Location: 8,126 + Actor996: ice03 + Owner: Neutral + Location: 6,123 + Actor997: ice03 + Owner: Neutral + Location: 12,121 + Actor998: ice03 + Owner: Neutral + Location: 30,121 + Actor999: ice03 + Owner: Neutral + Location: 27,120 + Actor1000: ice03 + Owner: Neutral + Location: 0,79 + Actor1001: ice03 + Owner: Neutral + Location: 2,83 + Actor1002: ice03 + Owner: Neutral + Location: 1,89 + Actor1003: ice03 + Owner: Neutral + Location: 5,91 + Actor1004: ice03 + Owner: Neutral + Location: 2,95 + Actor1005: ice03 + Owner: Neutral + Location: 9,101 + Actor1006: ice03 + Owner: Neutral + Location: 11,107 + Actor1007: ice03 + Owner: Neutral + Location: 6,107 + Actor1008: ice03 + Owner: Neutral + Location: 4,117 + Actor1009: ice03 + Owner: Neutral + Location: 11,116 + Actor1010: ice03 + Owner: Neutral + Location: 22,117 + Actor1011: ice03 + Owner: Neutral + Location: 20,113 + Actor1012: ice03 + Owner: Neutral + Location: 16,109 + Actor1013: ice02 + Owner: Neutral + Location: 13,118 + Actor1014: ice02 + Owner: Neutral + Location: 4,118 + Actor1015: ice02 + Owner: Neutral + Location: 8,113 + Actor1016: ice02 + Owner: Neutral + Location: 3,108 + Actor1017: ice02 + Owner: Neutral + Location: 6,93 + Actor1018: ice02 + Owner: Neutral + Location: 3,87 + Actor1019: ice02 + Owner: Neutral + Location: 2,81 + Actor1020: ice02 + Owner: Neutral + Location: 10,104 + Actor1021: ice02 + Owner: Neutral + Location: 21,115 + Actor1022: ice02 + Owner: Neutral + Location: 37,123 + Actor1023: ice02 + Owner: Neutral + Location: 46,128 + Actor1024: ice02 + Owner: Neutral + Location: 8,127 + Actor1025: ice02 + Owner: Neutral + Location: 1,127 + Actor1026: ice01 + Owner: Neutral + Location: 3,102 + Actor1027: ice04 + Owner: Neutral + Location: 1,80 + Actor1028: ice04 + Owner: Neutral + Location: 3,84 + Actor1029: ice04 + Owner: Neutral + Location: 3,86 + Actor1030: ice05 + Owner: Neutral + Location: 3,85 + Actor1031: ice05 + Owner: Neutral + Location: 0,80 + Actor1032: ice05 + Owner: Neutral + Location: 0,76 + Actor1033: ice05 + Owner: Neutral + Location: 5,90 + Actor1034: ice05 + Owner: Neutral + Location: 4,95 + Actor1035: ice05 + Owner: Neutral + Location: 7,96 + Actor1036: ice05 + Owner: Neutral + Location: 8,99 + Actor1037: ice05 + Owner: Neutral + Location: 9,104 + Actor1038: ice05 + Owner: Neutral + Location: 11,104 + Actor1039: ice05 + Owner: Neutral + Location: 10,106 + Actor1040: ice05 + Owner: Neutral + Location: 4,108 + Actor1041: ice05 + Owner: Neutral + Location: 2,110 + Actor1042: ice05 + Owner: Neutral + Location: 2,96 + Actor1043: ice05 + Owner: Neutral + Location: 15,114 + Actor1044: ice05 + Owner: Neutral + Location: 18,114 + Actor1045: ice05 + Owner: Neutral + Location: 10,123 + Actor1046: ice05 + Owner: Neutral + Location: 1,126 + Actor1047: ice05 + Owner: Neutral + Location: 5,120 + Actor1048: ice05 + Owner: Neutral + Location: 6,116 + Actor1049: ice05 + Owner: Neutral + Location: 6,110 + Actor1050: ice05 + Owner: Neutral + Location: 11,128 + Actor1051: ice05 + Owner: Neutral + Location: 18,126 + Actor1052: ice05 + Owner: Neutral + Location: 21,125 + Actor1053: ice05 + Owner: Neutral + Location: 23,127 + Actor1054: ice05 + Owner: Neutral + Location: 26,123 + Actor1055: ice05 + Owner: Neutral + Location: 28,121 + Actor1056: ice05 + Owner: Neutral + Location: 31,122 + Actor1057: ice05 + Owner: Neutral + Location: 36,123 + Actor1058: ice05 + Owner: Neutral + Location: 30,128 + Actor1059: ice05 + Owner: Neutral + Location: 39,125 + Actor1060: ice05 + Owner: Neutral + Location: 41,126 + Actor1061: ice05 + Owner: Neutral + Location: 41,129 + Actor1062: ice05 + Owner: Neutral + Location: 45,128 + Actor1063: ice05 + Owner: Neutral + Location: 50,129 + Actor1064: ice05 + Owner: Neutral + Location: 53,129 + Actor1065: ice04 + Owner: Neutral + Location: 55,129 + Actor1066: ice04 + Owner: Neutral + Location: 54,129 + Actor1067: ice04 + Owner: Neutral + Location: 52,129 + Actor1068: ice04 + Owner: Neutral + Location: 51,129 + Actor1069: ice04 + Owner: Neutral + Location: 47,129 + Actor1070: ice04 + Owner: Neutral + Location: 47,128 + Actor1071: ice04 + Owner: Neutral + Location: 45,129 + Actor1072: ice04 + Owner: Neutral + Location: 40,129 + Actor1073: ice04 + Owner: Neutral + Location: 40,126 + Actor1074: ice04 + Owner: Neutral + Location: 38,125 + Actor1075: ice04 + Owner: Neutral + Location: 28,122 + Actor1076: ice04 + Owner: Neutral + Location: 22,125 + Actor1077: ice04 + Owner: Neutral + Location: 24,127 + Actor1078: ice04 + Owner: Neutral + Location: 7,124 + Actor1079: ice04 + Owner: Neutral + Location: 6,122 + Actor1080: ice04 + Owner: Neutral + Location: 6,121 + Actor1081: ice04 + Owner: Neutral + Location: 26,118 + Actor1082: ice04 + Owner: Neutral + Location: 19,111 + Actor1083: ice04 + Owner: Neutral + Location: 12,108 + Actor1084: ice04 + Owner: Neutral + Location: 9,103 + Actor1085: ice04 + Owner: Neutral + Location: 4,96 + Actor1086: ice04 + Owner: Neutral + Location: 6,92 + Actor1087: ice04 + Owner: Neutral + Location: 0,93 + Actor1088: ice04 + Owner: Neutral + Location: 14,108 + Actor1089: ice04 + Owner: Neutral + Location: 17,112 + Actor1090: ice04 + Owner: Neutral + Location: 16,115 + Actor1091: ice04 + Owner: Neutral + Location: 14,118 + Actor1092: ice04 + Owner: Neutral + Location: 13,120 + Actor1093: ice04 + Owner: Neutral + Location: 25,122 + Actor1094: ice04 + Owner: Neutral + Location: 35,123 + Actor1095: ice04 + Owner: Neutral + Location: 12,104 + Actor1096: ice04 + Owner: Neutral + Location: 9,100 + Actor1097: ice04 + Owner: Neutral + Location: 7,106 + Actor1098: ice04 + Owner: Neutral + Location: 7,112 + Actor1099: ice04 + Owner: Neutral + Location: 10,116 + Actor1100: ice04 + Owner: Neutral + Location: 14,115 + Actor1101: tc05 + Owner: Neutral + Location: 2,98 + Actor1102: tc04 + Owner: Neutral + Location: 2,104 + Actor1103: tc03 + Owner: Neutral + Location: 5,103 + Actor1104: tc02 + Owner: Neutral + Location: 4,99 + Actor1105: tc01 + Owner: Neutral + Location: 6,100 + Actor1106: tc01 + Owner: Neutral + Location: 1,99 + Actor1107: tc02 + Owner: Neutral + Location: 0,101 + Actor1108: t06 + Owner: Neutral + Location: 7,101 + Actor1109: t05 + Owner: Neutral + Location: 6,102 + Actor1110: t07 + Owner: Neutral + Location: 5,104 + Actor1111: t06 + Owner: Neutral + Location: 6,103 + Actor1112: t06 + Owner: Neutral + Location: 7,102 + Actor1113: t05 + Owner: Neutral + Location: 7,102 + Actor1114: t13 + Owner: Neutral + Location: 6,101 + Actor1115: t10 + Owner: Neutral + Location: 5,103 + Actor1118: tc03 + Owner: Neutral + Location: 0,85 + Actor1119: tc01 + Owner: Neutral + Location: 0,86 + Actor1116: tc03 + Owner: Neutral + Location: 3,92 + Actor1117: tc01 + Owner: Neutral + Location: 3,91 + Actor1120: tc05 + Owner: Neutral + Location: 9,109 + Actor1122: tc05 + Owner: Neutral + Location: 12,124 + Actor1125: tc05 + Owner: Neutral + Location: 28,124 + Actor1126: tc05 + Owner: Neutral + Location: 34,126 + Actor1127: tc04 + Owner: Neutral + Location: 30,124 + Actor1128: tc04 + Owner: Neutral + Location: 33,125 + Actor1129: tc04 + Owner: Neutral + Location: 13,123 + Actor1131: tc04 + Owner: Neutral + Location: 22,119 + Actor1132: tc04 + Owner: Neutral + Location: 16,121 + Actor1134: tc04 + Owner: Neutral + Location: 11,111 + Actor1135: tc04 + Owner: Neutral + Location: 8,108 + Actor1136: tc04 + Owner: Neutral + Location: 0,102 + Actor1137: tc04 + Owner: Neutral + Location: 13,110 + Actor1138: tc05 + Owner: Neutral + Location: 12,110 + Actor1139: tc03 + Owner: Neutral + Location: 10,110 + Actor1140: tc03 + Owner: Neutral + Location: 11,112 + Actor1142: tc03 + Owner: Neutral + Location: 20,120 + Actor1143: tc03 + Owner: Neutral + Location: 16,123 + Actor1144: tc03 + Owner: Neutral + Location: 15,120 + Actor1145: tc03 + Owner: Neutral + Location: 14,122 + Actor1146: tc03 + Owner: Neutral + Location: 20,128 + Actor1147: tc03 + Owner: Neutral + Location: 17,128 + Actor1148: tc02 + Owner: Neutral + Location: 20,128 + Actor1149: tc03 + Owner: Neutral + Location: 32,126 + Actor1150: tc03 + Owner: Neutral + Location: 38,127 + Actor1151: tc03 + Owner: Neutral + Location: 33,124 + Actor1152: tc03 + Owner: Neutral + Location: 28,124 + Actor1153: tc03 + Owner: Neutral + Location: 31,125 + Actor1154: tc03 + Owner: Neutral + Location: 23,119 + Actor1156: tc03 + Owner: Neutral + Location: 10,118 + Actor1158: t08 + Owner: Neutral + Location: 12,113 + Actor1159: t08 + Owner: Neutral + Location: 9,121 + Actor1160: t08 + Owner: Neutral + Location: 15,125 + Actor1161: t08 + Owner: Neutral + Location: 17,120 + Actor1162: t08 + Owner: Neutral + Location: 21,119 + Actor1163: t08 + Owner: Neutral + Location: 17,121 + Actor1164: t08 + Owner: Neutral + Location: 37,127 + Actor1167: t05 + Owner: Neutral + Location: 99,12 + Actor1168: t06 + Owner: Neutral + Location: 102,13 + Actor1169: t02 + Owner: Neutral + Location: 106,16 + Actor1170: t03 + Owner: Neutral + Location: 109,20 + Actor1172: tc03 + Owner: Neutral + Location: 89,7 + Actor1173: t05 + Owner: Neutral + Location: 115,26 + Actor1174: t07 + Owner: Neutral + Location: 117,29 + Actor1175: t02 + Owner: Neutral + Location: 118,32 + Actor1176: t07 + Owner: Neutral + Location: 120,34 + Actor1177: t10 + Owner: Neutral + Location: 120,37 + Actor1178: tc02 + Owner: Neutral + Location: 121,40 + Actor1179: tc05 + Owner: Neutral + Location: 93,8 + Actor1181: tc05 + Owner: Neutral + Location: 13,26 + Actor1182: tc04 + Owner: Neutral + Location: 22,18 + Actor1183: tc03 + Owner: Neutral + Location: 17,22 + Actor1184: tc01 + Owner: Neutral + Location: 26,14 + Actor1185: tc04 + Owner: Neutral + Location: 35,7 + Actor1186: tc05.husk + Owner: Neutral + Location: 6,39 + Actor1187: tc02 + Owner: Neutral + Location: 9,34 + Actor1188: tc01 + Owner: Neutral + Location: 20,20 + Actor1189: t05 + Owner: Neutral + Location: 26,11 + Actor1190: t17 + Owner: Neutral + Location: 5,38 + Actor1191: tc02 + Owner: Neutral + Location: 104,14 + Actor1192: tc02 + Owner: Neutral + Location: 115,27 + Actor1193: tc02 + Owner: Neutral + Location: 125,46 + Actor1194: tc05 + Owner: Neutral + Location: 125,53 + Actor1195: tc04 + Owner: Neutral + Location: 85,4 + Actor1197: tc05 + Owner: Neutral + Location: 55,0 + Actor1198: tc01 + Owner: Neutral + Location: 61,0 + Actor1200: tc03 + Owner: Neutral + Location: 49,3 + Actor1201: tc05 + Owner: Neutral + Location: 39,5 + Actor1202: tc01 + Owner: Neutral + Location: 44,4 + Actor1203: tc02 + Owner: Neutral + Location: 30,10 + Actor1205: tc05 + Owner: Neutral + Location: 1,49 + Actor1206: tc04 + Owner: Neutral + Location: 0,54 + Actor1207: tc03 + Owner: Neutral + Location: 0,59 + Actor1208: tc01 + Owner: Neutral + Location: 1,63 + Actor1209: tc02 + Owner: Neutral + Location: 0,68 + Actor1210: tc03 + Owner: Neutral + Location: 1,72 + Actor1214: tc05 + Owner: Neutral + Location: 44,124 + Actor1215: tc05 + Owner: Neutral + Location: 28,115 + Actor1216: tc04 + Owner: Neutral + Location: 57,127 + Actor1218: tc04 + Owner: Neutral + Location: 23,112 + Actor1220: t02 + Owner: Neutral + Location: 13,104 + Actor1221: t05 + Owner: Neutral + Location: 14,104 + Actor1222: tc01 + Owner: Neutral + Location: 40,122 + Actor1223: tc03 + Owner: Neutral + Location: 84,125 + Actor1224: tc04 + Owner: Neutral + Location: 104,112 + Actor1227: tc03 + Owner: Neutral + Location: 108,109 + Actor1228: tc05 + Owner: Neutral + Location: 122,84 + Actor1230: tc04 + Owner: Neutral + Location: 127,69 + Actor1232: tc05 + Owner: Neutral + Location: 95,116 + Actor1233: tc05 + Owner: Neutral + Location: 70,127 + Actor1235: tc03 + Owner: Neutral + Location: 96,118 + Actor1236: tc03 + Owner: Neutral + Location: 103,113 + Actor1238: tc03 + Owner: Neutral + Location: 125,80 + Actor1239: tc02 + Owner: Neutral + Location: 126,74 + Actor1240: tc02 + Owner: Neutral + Location: 83,124 + Actor1241: tc02 + Owner: Neutral + Location: 19,107 + Actor1243: t07 + Owner: Neutral + Location: 2,73 + Actor1244: t02 + Owner: Neutral + Location: 3,77 + Actor1246: t02 + Owner: Neutral + Location: 17,105 + Actor1247: t02 + Owner: Neutral + Location: 33,117 + Actor1248: t02 + Owner: Neutral + Location: 48,124 + Actor1249: t02 + Owner: Neutral + Location: 65,127 + Actor1250: t02 + Owner: Neutral + Location: 86,122 + Actor1251: t02 + Owner: Neutral + Location: 95,118 + Actor1252: t02 + Owner: Neutral + Location: 106,111 + Actor1253: t02 + Owner: Neutral + Location: 110,107 + Actor1256: t02 + Owner: Neutral + Location: 123,83 + Actor1257: t02 + Owner: Neutral + Location: 126,77 + Actor1258: t02 + Owner: Neutral + Location: 128,67 + Actor1259: t02 + Owner: Neutral + Location: 127,59 + Actor1260: t02 + Owner: Neutral + Location: 126,51 + Actor1261: t02 + Owner: Neutral + Location: 123,43 + Actor1262: t02 + Owner: Neutral + Location: 114,24 + Actor1263: t02 + Owner: Neutral + Location: 97,9 + Actor1264: t02 + Owner: Neutral + Location: 47,3 + Actor1266: t02 + Owner: Neutral + Location: 25,15 + Actor1267: t02 + Owner: Neutral + Location: 11,30 + Actor1268: t06 + Owner: Neutral + Location: 22,110 + Actor1270: t06 + Owner: Neutral + Location: 5,82 + Actor1271: t06 + Owner: Neutral + Location: 2,74 + Actor1272: t06 + Owner: Neutral + Location: 1,62 + Actor1273: t06 + Owner: Neutral + Location: 2,58 + Actor1274: t06 + Owner: Neutral + Location: 4,45 + Actor1275: t06 + Owner: Neutral + Location: 7,40 + Actor1276: t06 + Owner: Neutral + Location: 8,39 + Actor1277: t06 + Owner: Neutral + Location: 11,34 + Actor1278: t07 + Owner: Neutral + Location: 13,28 + Actor1279: t07 + Owner: Neutral + Location: 21,19 + Actor1280: t07 + Owner: Neutral + Location: 24,17 + Actor1281: t07 + Owner: Neutral + Location: 29,11 + Actor1282: t07 + Owner: Neutral + Location: 36,9 + Actor1283: t07 + Owner: Neutral + Location: 43,5 + Actor1285: t07 + Owner: Neutral + Location: 82,4 + Actor1286: t07 + Owner: Neutral + Location: 88,6 + Actor1287: t07 + Owner: Neutral + Location: 98,10 + Actor1288: t07 + Owner: Neutral + Location: 105,15 + Actor1289: t07 + Owner: Neutral + Location: 108,19 + Actor1290: t07 + Owner: Neutral + Location: 124,44 + Actor1291: t07 + Owner: Neutral + Location: 128,55 + Actor1292: t07 + Owner: Neutral + Location: 127,63 + Actor1293: t07 + Owner: Neutral + Location: 126,76 + Actor1294: t07 + Owner: Neutral + Location: 122,86 + Actor1295: t07 + Owner: Neutral + Location: 121,91 + Actor1296: t07 + Owner: Neutral + Location: 116,100 + Actor1297: t07 + Owner: Neutral + Location: 112,105 + Actor1299: t07 + Owner: Neutral + Location: 102,114 + Actor1300: t07 + Owner: Neutral + Location: 94,119 + Actor1301: t07 + Owner: Neutral + Location: 87,121 + Actor1304: t07 + Owner: Neutral + Location: 67,127 + Actor1305: t07 + Owner: Neutral + Location: 59,126 + Actor1306: t07 + Owner: Neutral + Location: 52,125 + Actor1307: t07 + Owner: Neutral + Location: 42,123 + Actor1308: t07 + Owner: Neutral + Location: 34,118 + Actor1309: t07 + Owner: Neutral + Location: 23,111 + Actor1310: t07 + Owner: Neutral + Location: 18,106 + Actor1311: t07 + Owner: Neutral + Location: 12,98 + Actor1312: t07 + Owner: Neutral + Location: 8,91 + Actor1313: t07 + Owner: Neutral + Location: 6,87 + Actor1315: t07 + Owner: Neutral + Location: 1,70 + Actor1316: t07 + Owner: Neutral + Location: 2,56 + Actor1329: gmine + Owner: Neutral + Location: 64,64 + Actor1330: gmine + Owner: Neutral + Location: 65,64 + Actor1360: tc05 + Owner: Neutral + Location: 5,7 + Actor1361: tc05 + Owner: Neutral + Location: 6,15 + Actor1362: tc05 + Owner: Neutral + Location: 2,25 + Actor1363: tc05 + Owner: Neutral + Location: 11,15 + Actor1364: tc02 + Owner: Neutral + Location: 2,24 + Actor1365: tc03 + Owner: Neutral + Location: 3,23 + Actor1366: tc01 + Owner: Neutral + Location: 3,22 + Actor1367: t16 + Owner: Neutral + Location: 4,21 + Actor1368: t02 + Owner: Neutral + Location: 4,18 + Actor1369: t06 + Owner: Neutral + Location: 4,17 + Actor1370: t08 + Owner: Neutral + Location: 4,18 + Actor1371: t01 + Owner: Neutral + Location: 3,19 + Actor1372: tc02 + Owner: Neutral + Location: 6,16 + Actor1373: tc01 + Owner: Neutral + Location: 5,16 + Actor1374: tc03 + Owner: Neutral + Location: 5,15 + Actor1375: tc01 + Owner: Neutral + Location: 5,14 + Actor1376: t05 + Owner: Neutral + Location: 5,13 + Actor1377: tc04 + Owner: Neutral + Location: 4,11 + Actor1378: tc04 + Owner: Neutral + Location: 11,16 + Actor1379: tc04 + Owner: Neutral + Location: 16,10 + Actor1380: tc04 + Owner: Neutral + Location: 15,3 + Actor1381: tc04 + Owner: Neutral + Location: 8,4 + Actor1382: tc04 + Owner: Neutral + Location: 5,6 + Actor1383: tc03 + Owner: Neutral + Location: 7,21 + Actor1384: tc01 + Owner: Neutral + Location: 7,20 + Actor1385: t05 + Owner: Neutral + Location: 7,22 + Actor1386: t06 + Owner: Neutral + Location: 7,23 + Actor1389: t15 + Owner: Neutral + Location: 6,23 + Actor1390: t08 + Owner: Neutral + Location: 7,26 + Actor1391: t02 + Owner: Neutral + Location: 6,24 + Actor1392: t07 + Owner: Neutral + Location: 7,25 + Actor1393: t01 + Owner: Neutral + Location: 9,18 + Actor1394: t02 + Owner: Neutral + Location: 10,18 + Actor1395: t03 + Owner: Neutral + Location: 10,16 + Actor1396: t10 + Owner: Neutral + Location: 4,14 + Actor1397: t13 + Owner: Neutral + Location: 13,13 + Actor1398: tc02 + Owner: Neutral + Location: 13,13 + Actor1399: tc01 + Owner: Neutral + Location: 13,14 + Actor1400: tc03 + Owner: Neutral + Location: 14,12 + Actor1401: tc01 + Owner: Neutral + Location: 16,8 + Actor1402: tc02 + Owner: Neutral + Location: 5,8 + Actor1403: tc03 + Owner: Neutral + Location: 4,9 + Actor1404: tc03 + Owner: Neutral + Location: 7,6 + Actor1405: tc03 + Owner: Neutral + Location: 10,4 + Actor1406: tc03 + Owner: Neutral + Location: 14,4 + Actor1407: tc03 + Owner: Neutral + Location: 19,10 + Actor1408: tc03 + Owner: Neutral + Location: 11,17 + Actor1387: t06 + Owner: Neutral + Location: 7,24 + Actor1388: t01 + Owner: Neutral + Location: 8,24 + Actor1409: tc03 + Owner: Neutral + Location: 15,7 + Actor1410: tc03 + Owner: Neutral + Location: 12,5 + Actor1411: tc03 + Owner: Neutral + Location: 8,5 + Actor1412: tc03 + Owner: Neutral + Location: 5,10 + Actor1413: tc02 + Owner: Neutral + Location: 4,10 + Actor1414: tc01 + Owner: Neutral + Location: 5,9 + Actor1415: tc02 + Owner: Neutral + Location: 6,5 + Actor1416: t07 + Owner: Neutral + Location: 8,7 + Actor1417: t05 + Owner: Neutral + Location: 8,8 + Actor1418: t05 + Owner: Neutral + Location: 13,6 + Actor1419: t06 + Owner: Neutral + Location: 13,7 + Actor1420: t07 + Owner: Neutral + Location: 14,7 + Actor1422: tc01 + Owner: Neutral + Location: 12,4 + Actor1423: tc03 + Owner: Neutral + Location: 13,4 + Actor1424: t16 + Owner: Neutral + Location: 20,4 + Actor1425: t05 + Owner: Neutral + Location: 17,4 + Actor1426: t08 + Owner: Neutral + Location: 19,4 + Actor1427: t08 + Owner: Neutral + Location: 22,8 + Actor1428: t08 + Owner: Neutral + Location: 6,27 + Actor1429: t08 + Owner: Neutral + Location: 22,4 + Actor1430: tc01 + Owner: Neutral + Location: 22,4 + Actor1431: tc01 + Owner: Neutral + Location: 11,4 + Actor1432: ca + Owner: Neutral + Facing: 96 + TurretFacing: 96 + Location: 8,2 + Actor1433: ice04 + Owner: Neutral + Location: 9,2 + Actor1435: ice04 + Owner: Neutral + Location: 7,2 + Actor1434: ice05 + Owner: Neutral + Location: 7,3 + Actor1436: ice03 + Owner: Neutral + Location: 9,1 + Actor1437: pt + Owner: Neutral + Facing: 96 + TurretFacing: 96 + Location: 21,1 + Actor1438: c3 + Owner: Neutral + Facing: 96 + Location: 10,12 + SubCell: 1 + Actor1440: dog + Owner: Neutral + Facing: 96 + SubCell: 1 + Location: 27,5 + Actor1441: dog + Owner: Neutral + Facing: 96 + SubCell: 1 + Location: 14,4 + Actor1442: dog + Owner: Neutral + Facing: 96 + Location: 15,9 + SubCell: 3 + Actor1443: dog + Owner: Neutral + Facing: 96 + Location: 8,8 + SubCell: 1 + Actor1444: dog + Owner: Neutral + Facing: 96 + SubCell: 1 + Location: 11,18 + Actor1445: dog + Owner: Neutral + Facing: 96 + Location: 5,16 + SubCell: 1 + Actor1446: dog + Owner: Neutral + Facing: 96 + SubCell: 1 + Location: 30,4 + Actor1447: dog + Owner: Neutral + Facing: 96 + SubCell: 1 + Location: 107,5 + Actor1448: dog + Owner: Neutral + Facing: 96 + SubCell: 1 + Location: 114,11 + Actor1449: dog + Owner: Neutral + Facing: 96 + Location: 114,6 + SubCell: 3 + Actor1450: dog + Owner: Neutral + Facing: 96 + SubCell: 1 + Location: 118,3 + Actor1451: dog + Owner: Neutral + Facing: 96 + Location: 123,4 + SubCell: 1 + Actor1452: dog + Owner: Neutral + Facing: 96 + SubCell: 1 + Location: 123,14 + Actor1453: dd + Owner: Neutral + Location: 112,14 + Facing: 37 + TurretFacing: 232 + Stance: HoldFire + Actor245: ice01 + Owner: Neutral + Location: 13,21 + Actor1121: tc05 + Owner: Neutral + Location: 7,118 + Actor1157: tc03 + Owner: Neutral + Location: 8,120 + Actor1454: dtrk + Owner: Neutral + Location: 8,119 + Facing: 0 + Actor1455: tc04 + Owner: Neutral + Location: 8,119 + Actor1456: dtrk + Owner: Neutral + Location: 123,121 + Facing: 0 + Actor1457: tc05 + Owner: Neutral + Location: 123,121 + Actor1458: dtrk + Owner: Neutral + Location: 121,6 + Facing: 0 + Actor1459: tc04 + Owner: Neutral + Location: 121,6 + Actor1460: dtrk + Owner: Neutral + Location: 13,5 + Facing: 0 + Actor1421: tc01 + Owner: Neutral + Location: 14,6 + Actor1359: tc04 + Owner: Neutral + Location: 13,5 + Actor1461: msub + Owner: Neutral + Location: 121,120 + Facing: 236 + Health: 11 + Actor1462: ss + Owner: Neutral + Location: 96,3 + Facing: 110 + Health: 16 + Actor1463: ca + Owner: Neutral + Location: 128,33 + Facing: 68 + TurretFacing: 104 + Actor1464: dd + Owner: Neutral + Location: 34,4 + Facing: 174 + TurretFacing: 146 + Actor1439: t16 + Owner: Neutral + Location: 21,79 + Actor1465: t07 + Owner: Neutral + Location: 22,77 + Actor1466: t01 + Owner: Neutral + Location: 21,75 + Actor1467: t02 + Owner: Neutral + Location: 21,72 + Actor1468: t07 + Owner: Neutral + Location: 21,74 + Actor1469: t08 + Owner: Neutral + Location: 22,76 + Actor1470: tc01 + Owner: Neutral + Location: 22,69 + Actor1471: tc02 + Owner: Neutral + Location: 23,64 + Actor1472: t06 + Owner: Neutral + Location: 23,66 + Actor1473: t05 + Owner: Neutral + Location: 22,70 + Actor1474: t07 + Owner: Neutral + Location: 21,71 + Actor1475: t08 + Owner: Neutral + Location: 22,71 + Actor1476: t08 + Owner: Neutral + Location: 23,67 + Actor1477: t08 + Owner: Neutral + Location: 24,63 + Actor1478: t06 + Owner: Neutral + Location: 107,79 + Actor1479: tc01 + Owner: Neutral + Location: 107,72 + Actor1480: t07 + Owner: Neutral + Location: 105,64 + Actor1481: t06 + Owner: Neutral + Location: 106,65 + Actor1482: t02 + Owner: Neutral + Location: 106,66 + Actor1483: t07 + Owner: Neutral + Location: 106,67 + Actor1484: t02 + Owner: Neutral + Location: 107,70 + Actor1485: t06 + Owner: Neutral + Location: 106,69 + Actor1486: t07 + Owner: Neutral + Location: 107,69 + Actor1487: t01 + Owner: Neutral + Location: 107,74 + Actor1488: t02 + Owner: Neutral + Location: 107,75 + Actor1489: t03 + Owner: Neutral + Location: 108,76 + Actor1490: tc01 + Owner: Neutral + Location: 98,95 + Actor1491: tc03 + Owner: Neutral + Location: 95,96 + Actor1493: t08 + Owner: Neutral + Location: 100,95 + Actor1492: tc02 + Owner: Neutral + Location: 34,96 + Actor1494: tc01 + Owner: Neutral + Location: 30,95 + Actor1495: t07 + Owner: Neutral + Location: 33,96 + Actor1496: t06 + Owner: Neutral + Location: 32,96 + Actor1497: t08 + Owner: Neutral + Location: 29,95 + Actor1528: tc03 + Owner: Neutral + Location: 47,22 + Actor1529: t06 + Owner: Neutral + Location: 48,21 + Actor1530: t06 + Owner: Neutral + Location: 44,26 + Actor1531: t07 + Owner: Neutral + Location: 47,25 + Actor1532: t05 + Owner: Neutral + Location: 47,23 + Actor1533: t02 + Owner: Neutral + Location: 47,24 + Actor1534: t15 + Owner: Neutral + Location: 46,24 + Actor1535: t11 + Owner: Neutral + Location: 81,22 + Actor1536: t02 + Owner: Neutral + Location: 80,21 + Actor1537: t08 + Owner: Neutral + Location: 80,20 + Actor1538: t08 + Owner: Neutral + Location: 82,25 + Actor1539: tc03 + Owner: Neutral + Location: 81,25 + Actor1540: t16 + Owner: Neutral + Location: 82,26 + Actor1541: t06 + Owner: Neutral + Location: 82,25 + Actor1542: t07 + Owner: Neutral + Location: 82,24 + Actor1543: t02 + Owner: Neutral + Location: 82,23 + Actor1544: t07 + Owner: Neutral + Location: 81,21 + Actor1545: t05 + Owner: Neutral + Location: 81,24 + Actor1546: t08 + Owner: Neutral + Location: 81,23 + Actor1547: t07 + Owner: Neutral + Location: 81,23 + Actor1551: miss + Owner: Neutral + Location: 18,118 + Actor1552: tc04 + Owner: Neutral + Location: 17,119 + Actor1553: tc05 + Owner: Neutral + Location: 19,119 + Actor1554: tc02 + Owner: Neutral + Location: 17,118 + Actor1555: tc02 + Owner: Neutral + Location: 20,118 + Actor1556: tc04 + Owner: Neutral + Location: 17,117 + Actor1557: tc02 + Owner: Neutral + Location: 19,117 + Actor1558: tc03 + Owner: Neutral + Location: 18,120 + Actor1559: tc04 + Owner: Neutral + Location: 16,118 + Actor1560: tc03 + Owner: Neutral + Location: 16,117 + Actor1561: tc04 + Owner: Neutral + Location: 21,120 + Actor1562: tc02 + Owner: Neutral + Location: 19,120 + Actor1563: tc03 + Owner: Neutral + Location: 16,120 + Actor1564: tc03 + Owner: Neutral + Location: 20,121 + Actor1565: tc03 + Owner: Neutral + Location: 15,119 + Actor1566: tc03 + Owner: Neutral + Location: 21,119 + Actor1567: tc03 + Owner: Neutral + Location: 15,122 + Actor1337: t02 + Owner: Neutral + Location: 30,12 + Actor1334: t07 + Owner: Neutral + Location: 93,24 + Actor1605: t06 + Owner: Neutral + Location: 93,32 + Actor1606: t08 + Owner: Neutral + Location: 88,15 + Actor1609: t08 + Owner: Neutral + Location: 35,33 + Actor1610: t06 + Owner: Neutral + Location: 23,26 + Actor1638: tc01 + Owner: Neutral + Location: 98,112 + Actor1637: t07 + Owner: Neutral + Location: 21,82 + Actor1641: t07 + Owner: Neutral + Location: 108,82 + Actor1611: t06 + Owner: Neutral + Location: 37,20 + Actor1499: tc02 + Owner: Neutral + Location: 68,93 + Actor1500: tc01 + Owner: Neutral + Location: 60,93 + Actor1314: tc01 + Owner: Neutral + Location: 51,16 + Actor1317: tc02 + Owner: Neutral + Location: 53,15 + Actor1318: t08 + Owner: Neutral + Location: 56,15 + Actor1319: tc01 + Owner: Neutral + Location: 77,16 + Actor1320: tc02 + Owner: Neutral + Location: 73,14 + Actor1321: oilb + Owner: Neutral + Location: 102,61 + Actor1323: oilb + Owner: Neutral + Location: 44,33 + Actor1322: oilb + Owner: Neutral + Location: 84,33 + Actor1324: oilb + Owner: Neutral + Location: 26,61 + Actor1325: oilb + Owner: Neutral + Location: 81,97 + Actor1326: oilb + Owner: Neutral + Location: 47,97 + Actor1331: mpspawn + Owner: Neutral + Location: 64,8 + Actor1332: mpspawn + Owner: Neutral + Location: 112,92 + Actor1335: tc04 + Owner: Neutral + Location: 83,96 + Actor1336: tc04 + Owner: Neutral + Location: 88,96 + Actor1338: tc05 + Owner: Neutral + Location: 85,96 + Actor1339: tc03 + Owner: Neutral + Location: 88,97 + Actor1340: tc02 + Owner: Neutral + Location: 84,97 + Actor1341: tc01 + Owner: Neutral + Location: 91,96 + Actor1342: t16 + Owner: Neutral + Location: 93,96 + Actor1343: tc05 + Owner: Neutral + Location: 44,96 + Actor1344: tc05 + Owner: Neutral + Location: 38,96 + Actor1345: tc04 + Owner: Neutral + Location: 41,96 + Actor1346: tc03 + Owner: Neutral + Location: 43,97 + Actor1347: tc03 + Owner: Neutral + Location: 36,96 + Actor1349: t16 + Owner: Neutral + Location: 45,97 + Actor1350: t06 + Owner: Neutral + Location: 44,97 + Actor1351: tc03 + Owner: Neutral + Location: 104,60 + Actor1498: tc01 + Owner: Neutral + Location: 104,61 + Actor1501: t05 + Owner: Neutral + Location: 105,63 + Actor1503: t07 + Owner: Neutral + Location: 105,62 + Actor1502: tc02 + Owner: Neutral + Location: 24,61 + Actor1504: t16 + Owner: Neutral + Location: 25,60 + Actor1505: tc05 + Owner: Neutral + Location: 82,26 + Actor1506: tc04 + Owner: Neutral + Location: 83,28 + Actor1507: tc05 + Owner: Neutral + Location: 84,30 + Actor1508: tc04 + Owner: Neutral + Location: 45,26 + Actor1509: tc05 + Owner: Neutral + Location: 44,28 + Actor1510: tc04 + Owner: Neutral + Location: 43,30 + Actor1511: t02 + Owner: Neutral + Location: 80,18 + Actor1512: t06 + Owner: Neutral + Location: 49,19 + Actor1513: t07 + Owner: Neutral + Location: 79,17 + Actor1514: t08 + Owner: Neutral + Location: 81,20 + Actor1515: t05 + Owner: Neutral + Location: 49,20 + Actor1517: t08 + Owner: Neutral + Location: 50,17 + Actor1519: t01 + Owner: Neutral + Location: 75,15 + Actor1520: t02 + Owner: Neutral + Location: 76,15 + Actor1327: hosp + Owner: Neutral + Location: 64,94 + Actor1328: hosp + Owner: Neutral + Location: 89,49 + Actor1521: hosp + Owner: Neutral + Location: 39,49 + Actor1526: mpspawn + Owner: Neutral + Location: 17,92 + Actor1333: mine + Owner: Neutral + Location: 19,102 + Actor1527: oilb + Owner: Neutral + Location: 64,70 + Actor1548: oilb + Owner: Neutral + Location: 59,61 + Actor1522: oilb + Owner: Neutral + Location: 69,61 + Actor1549: mine + Owner: Neutral + Location: 11,41 + Actor1577: mine + Owner: Neutral + Location: 75,6 + Actor1578: mine + Owner: Neutral + Location: 75,10 + Actor1573: mine + Owner: Neutral + Location: 111,26 + Actor1574: mine + Owner: Neutral + Location: 107,22 + Actor1586: mine + Owner: Neutral + Location: 104,105 + Actor1587: mine + Owner: Neutral + Location: 101,102 + Actor1590: gmine + Owner: Neutral + Location: 65,88 + Actor1592: gmine + Owner: Neutral + Location: 44,53 + Actor1593: gmine + Owner: Neutral + Location: 85,53 + Actor1595: mine + Owner: Neutral + Location: 36,47 + Actor1596: mine + Owner: Neutral + Location: 93,47 + Actor1591: mine + Owner: Neutral + Location: 82,75 + Actor1597: mine + Owner: Neutral + Location: 84,72 + Actor1355: mine + Owner: Neutral + Location: 47,76 + Actor1357: mine + Owner: Neutral + Location: 45,73 + Actor1358: mine + Owner: Neutral + Location: 62,43 + Actor1516: mine + Owner: Neutral + Location: 66,43 + Actor1354: mine + Owner: Neutral + Location: 119,85 + Actor1571: mine + Owner: Neutral + Location: 55,7 + Actor1356: mine + Owner: Neutral + Location: 11,81 + Actor1284: mine + Owner: Neutral + Location: 64,99 + Actor1298: mine + Owner: Neutral + Location: 78,123 + Actor1352: mine + Owner: Neutral + Location: 73,125 + Actor1269: mine + Owner: Neutral + Location: 8,45 + Actor1265: mine + Owner: Neutral + Location: 29,17 + Actor1217: tc04 + Owner: Neutral + Location: 35,119 + Actor1302: mine + Owner: Neutral + Location: 41,119 + Actor1303: mine + Owner: Neutral + Location: 124,58 + Actor1348: perma.burn.mcv.husk + Owner: Neutral + Facing: 96 + Location: 61,113 + Actor1523: tc04 + Owner: Neutral + Location: 59,111 + Actor1525: tc02 + Owner: Neutral + Location: 61,114 + Actor1550: tc05 + Owner: Neutral + Location: 105,44 + Actor1569: perma.burn.4tnk.husk + Owner: Neutral + Facing: 96 + Location: 107,44 + Actor1568: tc01 + Owner: Neutral + Location: 107,42 + Actor1570: perma.burn.chk1.husk + Owner: Neutral + Facing: 96 + Location: 27,37 + Actor1575: tc05 + Owner: Neutral + Location: 28,35 + Actor1576: tc01 + Owner: Neutral + Location: 26,37 + Actor1579: tc01 + Owner: Neutral + Location: 114,67 + Actor1580: tc04.husk + Owner: Neutral + Location: 120,73 + Actor1581: tc04.husk + Owner: Neutral + Location: 44,9 + Actor1582: t02 + Owner: Neutral + Location: 15,58 + Actor1583: t06 + Owner: Neutral + Location: 10,70 + Actor1585: t03 + Owner: Neutral + Location: 58,24 + Actor1588: t13 + Owner: Neutral + Location: 71,31 + Actor1589: t11 + Owner: Neutral + Location: 86,88 + Actor1594: t11 + Owner: Neutral + Location: 55,34 + Actor1598: t03 + Owner: Neutral + Location: 76,107 + Actor1599: t03 + Owner: Neutral + Location: 24,46 + Actor1600: t03 + Owner: Neutral + Location: 101,33 + Actor1601: t01 + Owner: Neutral + Location: 82,101 + Actor1602: t01 + Owner: Neutral + Location: 111,55 + Actor1603: t01 + Owner: Neutral + Location: 51,107 + Actor1353: mine + Owner: Neutral + Location: 23,100 + +Rules: rules.yaml diff -Nru openra-20200503/mods/ra/maps/code-19/rules.yaml openra-20210321/mods/ra/maps/code-19/rules.yaml --- openra-20200503/mods/ra/maps/code-19/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/code-19/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,14 @@ +PERMA.BURN.MCV.HUSK: + Inherits: MCV.Husk + -Targetable: + -ChangesHealth: + +PERMA.BURN.4TNK.HUSK: + Inherits: 4TNK.Husk + -Targetable: + -ChangesHealth: + +PERMA.BURN.CHK1.HUSK: + Inherits: TRAN.Husk1 + -Targetable: + -ChangesHealth: Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/cold-front.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/cold-front.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/collaboration.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/collaboration.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/decrepit-isles.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/decrepit-isles.oramap differ diff -Nru openra-20200503/mods/ra/maps/desert-rats/map.yaml openra-20210321/mods/ra/maps/desert-rats/map.yaml --- openra-20200503/mods/ra/maps/desert-rats/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/desert-rats/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -229,7 +229,7 @@ Owner: Neutral Location: 23,58 SubCell: 3 - Facing: 92 + Facing: 368 Actor124: wood Owner: Neutral Location: 49,10 @@ -273,17 +273,17 @@ Owner: Neutral Location: 48,13 SubCell: 3 - Facing: 92 + Facing: 368 Actor132: c9 Owner: Neutral Location: 22,60 SubCell: 3 - Facing: 92 + Facing: 368 Actor133: c5 Owner: Neutral Location: 49,11 SubCell: 3 - Facing: 92 + Facing: 368 Actor135: tc01 Owner: Neutral Location: 46,10 diff -Nru openra-20200503/mods/ra/maps/desert-shellmap/desert-shellmap.lua openra-20210321/mods/ra/maps/desert-shellmap/desert-shellmap.lua --- openra-20200503/mods/ra/maps/desert-shellmap/desert-shellmap.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/desert-shellmap/desert-shellmap.lua 2021-03-21 11:10:05.000000000 +0000 @@ -119,7 +119,7 @@ ParadropSovietUnits = function() local lz = Utils.Random(ParadropWaypoints) - local aircraft = powerproxy.ActivateParatroopers(lz.CenterPosition) + local aircraft = powerproxy.TargetParatroopers(lz.CenterPosition) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) @@ -159,7 +159,7 @@ local cells = Utils.ExpandFootprint({ ChronoshiftLocation.Location }, false) local units = { } for i = 1, #cells do - local unit = Actor.Create("2tnk", true, { Owner = allies, Facing = 0 }) + local unit = Actor.Create("2tnk", true, { Owner = allies, Facing = Angle.North }) BindActorTriggers(unit) units[unit] = cells[i] end diff -Nru openra-20200503/mods/ra/maps/desert-shellmap/map.yaml openra-20210321/mods/ra/maps/desert-shellmap/map.yaml --- openra-20200503/mods/ra/maps/desert-shellmap/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/desert-shellmap/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -113,7 +113,7 @@ Actor27: barl Location: 42,45 Owner: Neutral - Actor333: syrf + Actor333: syrd Location: 67,95 Owner: Allies Actor53: brik @@ -251,11 +251,11 @@ Actor93: ca Location: 20,86 Owner: Allies - Facing: 64 + Facing: 256 Actor94: ca Location: 40,90 Owner: Allies - Facing: 64 + Facing: 256 Actor95: rock6 Location: 10,76 Owner: Neutral @@ -325,7 +325,7 @@ Actor136: v2rl Location: 91,40 Owner: Soviets - Facing: 90 + Facing: 360 Actor122: afld Location: 116,49 Owner: Soviets @@ -371,7 +371,7 @@ Actor137: 4tnk Location: 105,33 Owner: Soviets - Facing: 100 + Facing: 400 Actor123: afld Location: 119,49 Owner: Soviets @@ -381,11 +381,11 @@ Actor139: 3tnk Location: 89,32 Owner: Soviets - Facing: 64 + Facing: 256 Actor140: 3tnk Location: 92,29 Owner: Soviets - Facing: 20 + Facing: 80 Actor141: 3tnk Location: 36,23 Owner: Soviets @@ -416,7 +416,7 @@ Actor152: 1tnk Location: 69,85 Owner: Allies - Facing: 110 + Facing: 440 Actor150: apwr Location: 94,91 Owner: Allies @@ -432,7 +432,7 @@ Actor186: 3tnk Location: 107,50 Owner: Soviets - Facing: 80 + Facing: 320 Actor174: tc01 Location: 98,37 Owner: Neutral @@ -478,7 +478,7 @@ Actor54: agun Location: 76,93 Owner: Allies - Facing: 150 + Facing: 600 Actor155: apwr Location: 90,88 Owner: Allies @@ -488,7 +488,7 @@ Actor196: pt Location: 55,92 Owner: Allies - Facing: 160 + Facing: 640 Actor183: rock2 Location: 93,41 Owner: Neutral @@ -498,7 +498,7 @@ Actor197: dd Location: 30,88 Owner: Allies - Facing: 64 + Facing: 256 Actor199: e1 Location: 72,83 Owner: Allies @@ -559,7 +559,7 @@ Actor208: e7 Location: 39,81 Owner: Allies - Facing: 64 + Facing: 256 Actor209: e1 Location: 41,79 Owner: Allies @@ -569,7 +569,7 @@ Actor211: jeep Location: 41,82 Owner: Allies - Facing: 90 + Facing: 360 Actor36: brik Location: 72,66 Owner: Allies @@ -624,11 +624,11 @@ Actor295: jeep Location: 37,67 Owner: Allies - Facing: 64 + Facing: 256 Actor296: 1tnk Location: 58,65 Owner: Allies - Facing: 192 + Facing: 768 Actor215: brik Location: 58,80 Owner: Allies @@ -656,11 +656,11 @@ Actor249: arty Location: 57,63 Owner: Allies - Facing: 240 + Facing: 960 Actor248: arty Location: 54,63 Owner: Allies - Facing: 16 + Facing: 64 Actor250: sbag Location: 44,67 Owner: Allies @@ -769,22 +769,22 @@ Actor226: 2tnk Location: 62,60 Owner: Allies - Facing: 240 + Facing: 960 Actor225: 2tnk Location: 47,61 Owner: Allies Actor239: 1tnk Location: 44,65 Owner: Allies - Facing: 30 + Facing: 120 Actor236: jeep Location: 45,62 Owner: Allies - Facing: 16 + Facing: 64 Actor238: 2tnk Location: 36,65 Owner: Allies - Facing: 40 + Facing: 160 Actor224: 2tnk Location: 41,62 Owner: Allies @@ -1139,7 +1139,7 @@ Actor118: agun Location: 47,70 Owner: Allies - Facing: 64 + Facing: 256 SovietWarFactory1: weap Location: 106,29 Owner: Soviets diff -Nru openra-20200503/mods/ra/maps/desert-shellmap/rules.yaml openra-20210321/mods/ra/maps/desert-shellmap/rules.yaml --- openra-20200503/mods/ra/maps/desert-shellmap/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/desert-shellmap/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -27,42 +27,6 @@ ^ExistsInWorld: GivesExperience: ActorExperienceModifier: 0 - -^Vehicle: - DamageMultiplier@UNKILLABLE: - RequiresCondition: unkillable - Modifier: 0 - ExternalCondition@UNKILLABLE: - Condition: unkillable - -^Infantry: - DeathSounds@NORMAL: - VolumeMultiplier: 0.1 - DeathSounds@BURNED: - VolumeMultiplier: 0.1 - DeathSounds@ZAPPED: - VolumeMultiplier: 0.1 - DamageMultiplier@UNKILLABLE: - RequiresCondition: unkillable - Modifier: 0 - ExternalCondition@UNKILLABLE: - Condition: unkillable - -^Ship: - DamageMultiplier@UNKILLABLE: - RequiresCondition: unkillable - Modifier: 0 - ExternalCondition@UNKILLABLE: - Condition: unkillable - -^Plane: - DamageMultiplier@UNKILLABLE: - RequiresCondition: unkillable - Modifier: 0 - ExternalCondition@UNKILLABLE: - Condition: unkillable - -^Building: DamageMultiplier@UNKILLABLE: RequiresCondition: unkillable Modifier: 0 @@ -82,8 +46,10 @@ ShowTicks: false TRAN.Husk2: - Burns: - Damage: 0 + WithIdleOverlay@Burns: + Image: fire + Sequence: 1 + IsDecoration: True MISS: DamageMultiplier@INVULNERABLE: @@ -99,9 +65,6 @@ Health: HP: 20000 -E7: - -AnnounceOnKill: - powerproxy.paratroopers: ParatroopersPower: DisplayBeacon: false Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/discovery.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/discovery.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/doublestep.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/doublestep.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/dusttown-battle.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/dusttown-battle.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/east-vs-west.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/east-vs-west.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/encounter.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/encounter.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/engagement.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/engagement.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/europe.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/europe.oramap differ diff -Nru openra-20200503/mods/ra/maps/evacuation/evacuation.lua openra-20210321/mods/ra/maps/evacuation/evacuation.lua --- openra-20200503/mods/ra/maps/evacuation/evacuation.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/evacuation/evacuation.lua 2021-03-21 11:10:05.000000000 +0000 @@ -115,8 +115,8 @@ SendParabombs = function() local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = soviets }) - proxy.SendAirstrikeFrom(BadgerEntryPoint2.Location, ParabombPoint1.Location) - proxy.SendAirstrikeFrom(BadgerEntryPoint2.Location + CVec.New(0, 3), ParabombPoint2.Location) + proxy.TargetAirstrike(ParabombPoint1.CenterPosition, (BadgerEntryPoint2.CenterPosition - ParabombPoint1.CenterPosition).Facing) + proxy.TargetAirstrike(ParabombPoint2.CenterPosition, (Map.CenterOfCell(BadgerEntryPoint2.Location + CVec.New(0, 3)) - ParabombPoint2.CenterPosition).Facing) proxy.Destroy() end @@ -125,8 +125,8 @@ local proxy = Actor.Create(para.proxy, false, { Owner = soviets }) local target = Map.CenterOfCell(para.drop) local dir = target - Map.CenterOfCell(para.entry) - - local aircraft = proxy.ActivateParatroopers(target, dir.facing) + + local aircraft = proxy.TargetParatroopers(target, dir.Facing) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) diff -Nru openra-20200503/mods/ra/maps/evacuation/map.yaml openra-20210321/mods/ra/maps/evacuation/map.yaml --- openra-20200503/mods/ra/maps/evacuation/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/evacuation/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1509,15 +1509,15 @@ Actor357: 3tnk Location: 43,59 Owner: Soviets - Facing: 90 + Facing: 360 Actor537: harv Location: 25,94 Owner: Allies - Facing: 96 + Facing: 384 Actor358: 3tnk Location: 38,55 Owner: Soviets - Facing: 110 + Facing: 440 Actor359: v2rl Location: 44,53 Owner: Soviets diff -Nru openra-20200503/mods/ra/maps/evacuation/rules.yaml openra-20210321/mods/ra/maps/evacuation/rules.yaml --- openra-20200503/mods/ra/maps/evacuation/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/evacuation/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -40,12 +40,16 @@ ScriptTags: TRAN.Husk1: - Burns: - Damage: 0 + WithIdleOverlay@Burns: + Image: fire + Sequence: 1 + IsDecoration: True TRAN.Husk2: - Burns: - Damage: 0 + WithIdleOverlay@Burns: + Image: fire + Sequence: 1 + IsDecoration: True E7: Passenger: diff -Nru openra-20200503/mods/ra/maps/exodus/exodus.lua openra-20210321/mods/ra/maps/exodus/exodus.lua --- openra-20200503/mods/ra/maps/exodus/exodus.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/exodus/exodus.lua 2021-03-21 11:10:05.000000000 +0000 @@ -73,16 +73,9 @@ SovietAirfield5, SovietAirfield6, SovietAirfield7, SovietAirfield8 } -MountainEntry = -{ - MountainEntry1.Location, MountainEntry2.Location, MountainEntry3.Location, MountainEntry4.Location, - MountainEntry5.Location, MountainEntry6.Location, MountainEntry7.Location, MountainEntry8.Location -} +MountainEntry = { CPos.New(25, 45), CPos.New(25, 46), CPos.New(25, 47), CPos.New(25, 48), CPos.New(25, 49) } -BridgeEntry = -{ - BridgeEntry1.Location, BridgeEntry2.Location, BridgeEntry3.Location, BridgeEntry4.Location -} +BridgeEntry = { CPos.New(25, 29), CPos.New(26, 29), CPos.New(27, 29), CPos.New(28, 29) } MobileConstructionVehicle = { "mcv" } Yak = { "yak" } @@ -185,7 +178,7 @@ local lz = Map.CenterOfCell(randomParadropCell) local powerproxy = Actor.Create("powerproxy.paratroopers", false, { Owner = soviets }) - powerproxy.ActivateParatroopers(lz) + powerproxy.TargetParatroopers(lz) powerproxy.Destroy() Trigger.AfterDelay(sovietParadropTicks, SendSovietParadrop) Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/exodus/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/exodus/map.bin differ diff -Nru openra-20200503/mods/ra/maps/exodus/map.yaml openra-20210321/mods/ra/maps/exodus/map.yaml --- openra-20200503/mods/ra/maps/exodus/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/exodus/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -51,17 +51,17 @@ Enemies: Soviets PlayerReference@Allies: Name: Allies + Bot: campaign Faction: allies Color: 5CC1A3 Allies: Allies1, Allies2 Enemies: Soviets - Bot: campaign PlayerReference@Soviets: Name: Soviets + Bot: campaign Faction: soviet Color: FE1100 Enemies: Allies1, Allies2 - Bot: campaign Actors: Actor239: dog @@ -871,9 +871,6 @@ Actor6: gun Location: 28,44 Owner: Allies - Actor47: powr - Location: 3,37 - Owner: Allies Actor45: 2tnk Location: 28,28 Owner: Allies @@ -892,9 +889,6 @@ Actor40: e1 Location: 24,30 Owner: Allies - Actor46: powr - Location: 1,37 - Owner: Allies Actor49: fenc Location: 28,27 Owner: Allies @@ -991,12 +985,6 @@ Actor167: barl Location: 173,24 Owner: Neutral - Actor168: powr - Location: 1,34 - Owner: Allies - Actor183: powr - Location: 3,34 - Owner: Allies Actor185: apwr Location: 154,72 Owner: Soviets @@ -1390,44 +1378,8 @@ ParadropBoxTopLeft: waypoint Location: 78,27 Owner: Neutral - MountainEntry1: waypoint - Location: 25,44 - Owner: Neutral - MountainEntry2: waypoint - Owner: Neutral - Location: 25,45 - MountainEntry3: waypoint - Owner: Neutral - Location: 25,46 - MountainEntry4: waypoint - Owner: Neutral - Location: 25,47 - MountainEntry5: waypoint - Owner: Neutral - Location: 25,48 - MountainEntry6: waypoint - Owner: Neutral - Location: 25,49 - MountainEntry7: waypoint - Location: 25,50 - Owner: Neutral - MountainEntry8: waypoint - Owner: Neutral - Location: 25,51 - BridgeEntry1: waypoint - Owner: Neutral - Location: 28,29 - BridgeEntry2: waypoint - Owner: Neutral - Location: 27,29 - BridgeEntry3: waypoint - Owner: Neutral - Location: 26,29 - BridgeEntry4: waypoint - Owner: Neutral - Location: 25,29 SovietIntel: camera.large Owner: Soviets - Location: 130, 45 + Location: 130,45 Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/fall-of-greece-1-personal-war/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/fall-of-greece-1-personal-war/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/fall-of-greece-1-personal-war/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/fall-of-greece-1-personal-war/map.png differ diff -Nru openra-20200503/mods/ra/maps/fall-of-greece-1-personal-war/map.yaml openra-20210321/mods/ra/maps/fall-of-greece-1-personal-war/map.yaml --- openra-20200503/mods/ra/maps/fall-of-greece-1-personal-war/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/fall-of-greece-1-personal-war/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,1310 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: Fall of Greece 1: Personal War + +Author: Westwood Studios + +Tileset: TEMPERAT + +MapSize: 128,128 + +Bounds: 20,39,85,52 + +Visibility: MissionSelector + +Categories: Mission + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: allies + PlayerReference@England: + Name: England + Faction: allies + Color: A0F08C + Allies: GreekCivilians, Allies + Enemies: USSR, BadGuy + PlayerReference@Allies: + Name: Allies + AllowBots: False + Playable: True + Required: True + LockFaction: True + Faction: allies + LockColor: True + Color: ABB7E4 + LockSpawn: True + LockTeam: True + Allies: England + Enemies: USSR, BadGuy + PlayerReference@GreekCivilians: + Name: GreekCivilians + NonCombatant: True + Faction: allies + Allies: England + PlayerReference@USSR: + Name: USSR + Faction: soviet + Color: FF1400 + Allies: BadGuy + Enemies: England, GreekCivilians, Allies + PlayerReference@BadGuy: + Name: BadGuy + Faction: soviet + Color: FF1400 + Allies: USSR + Enemies: England, GreekCivilians, Allies + +Actors: + Actor0: brik + Location: 97,44 + Owner: England + Actor1: brik + Location: 98,44 + Owner: England + Actor2: brik + Location: 101,44 + Owner: England + Actor3: brik + Location: 102,44 + Owner: England + Actor4: brik + Location: 97,45 + Owner: England + Actor5: brik + Location: 98,45 + Owner: England + Actor6: brik + Location: 99,45 + Owner: England + Actor7: brik + Location: 100,45 + Owner: England + Actor8: brik + Location: 101,45 + Owner: England + Actor9: brik + Location: 102,45 + Owner: England + Actor10: brik + Location: 82,49 + Owner: England + Actor11: brik + Location: 83,49 + Owner: England + Actor12: brik + Location: 86,49 + Owner: England + Actor13: brik + Location: 87,49 + Owner: England + Actor16: brik + Location: 82,50 + Owner: England + Actor17: brik + Location: 83,50 + Owner: England + Actor18: brik + Location: 84,50 + Owner: England + Actor19: brik + Location: 85,50 + Owner: England + Actor20: brik + Location: 86,50 + Owner: England + Actor21: brik + Location: 87,50 + Owner: England + Actor14: brik + Location: 27,50 + Owner: USSR + Actor15: brik + Location: 28,50 + Owner: USSR + Actor22: brik + Location: 27,51 + Owner: USSR + Actor23: brik + Location: 28,51 + Owner: USSR + Actor24: brik + Location: 28,52 + Owner: USSR + Actor25: brik + Location: 29,52 + Owner: USSR + Actor26: brik + Location: 30,52 + Owner: USSR + Actor27: brik + Location: 31,52 + Owner: USSR + Actor28: brik + Location: 32,52 + Owner: USSR + Actor29: brik + Location: 33,52 + Owner: USSR + Actor30: brik + Location: 34,52 + Owner: USSR + Actor31: brik + Location: 35,52 + Owner: USSR + Actor32: brik + Location: 36,52 + Owner: USSR + Actor33: brik + Location: 35,53 + Owner: USSR + Actor34: brik + Location: 36,53 + Owner: USSR + Actor35: brik + Location: 35,54 + Owner: USSR + Actor36: brik + Location: 36,54 + Owner: USSR + Actor37: brik + Location: 35,55 + Owner: USSR + Actor38: brik + Location: 36,55 + Owner: USSR + Actor39: brik + Location: 35,59 + Owner: USSR + Actor40: brik + Location: 36,59 + Owner: USSR + Actor41: brik + Location: 35,60 + Owner: USSR + Actor42: brik + Location: 36,60 + Owner: USSR + Actor43: brik + Location: 35,61 + Owner: USSR + Actor44: brik + Location: 36,61 + Owner: USSR + Actor45: brik + Location: 24,62 + Owner: USSR + Actor46: brik + Location: 25,62 + Owner: USSR + Actor47: brik + Location: 35,62 + Owner: USSR + Actor48: brik + Location: 36,62 + Owner: USSR + Actor49: brik + Location: 24,63 + Owner: USSR + Actor50: brik + Location: 25,63 + Owner: USSR + Actor51: brik + Location: 26,63 + Owner: USSR + Actor52: brik + Location: 27,63 + Owner: USSR + Actor53: brik + Location: 28,63 + Owner: USSR + Actor54: brik + Location: 29,63 + Owner: USSR + Actor55: brik + Location: 30,63 + Owner: USSR + Actor56: brik + Location: 31,63 + Owner: USSR + Actor57: brik + Location: 32,63 + Owner: USSR + Actor58: brik + Location: 33,63 + Owner: USSR + Actor59: brik + Location: 34,63 + Owner: USSR + Actor60: brik + Location: 35,63 + Owner: USSR + Actor61: brik + Location: 36,63 + Owner: USSR + Actor69: brik + Location: 40,83 + Owner: USSR + Actor70: brik + Location: 41,83 + Owner: USSR + Actor71: brik + Location: 41,84 + Owner: USSR + Actor72: brik + Location: 41,85 + Owner: USSR + Actor73: brik + Location: 41,86 + Owner: USSR + Actor74: brik + Location: 40,87 + Owner: USSR + Actor75: brik + Location: 41,87 + Owner: USSR + Actor62: wood + Location: 95,72 + Owner: GreekCivilians + Actor63: wood + Location: 90,73 + Owner: GreekCivilians + Actor64: wood + Location: 91,73 + Owner: GreekCivilians + Actor65: wood + Location: 92,73 + Owner: GreekCivilians + Actor66: wood + Location: 93,73 + Owner: GreekCivilians + Actor67: wood + Location: 94,73 + Owner: GreekCivilians + Actor68: wood + Location: 95,73 + Owner: GreekCivilians + Actor76: tc04 + Location: 26,38 + Owner: Neutral + Actor77: tc03 + Location: 20,39 + Owner: Neutral + Actor78: tc02 + Location: 32,45 + Owner: Neutral + Actor79: tc05 + Location: 87,59 + Owner: Neutral + Actor80: tc02 + Location: 87,70 + Owner: Neutral + Actor81: tc04 + Location: 100,45 + Owner: Neutral + Actor82: tc04 + Location: 88,54 + Owner: Neutral + Actor83: tc04 + Location: 58,46 + Owner: Neutral + Actor84: tc03 + Location: 55,43 + Owner: Neutral + Actor85: t16 + Location: 62,55 + Owner: Neutral + Actor86: tc04 + Location: 84,79 + Owner: Neutral + Actor87: tc01 + Location: 77,83 + Owner: Neutral + Actor88: t08 + Location: 68,85 + Owner: Neutral + Actor89: tc04 + Location: 72,52 + Owner: Neutral + Actor90: tc02 + Location: 88,81 + Owner: Neutral + Actor91: tc05 + Location: 100,88 + Owner: Neutral + Actor92: t16 + Location: 86,84 + Owner: Neutral + Actor93: tc02 + Location: 91,68 + Owner: Neutral + Actor94: tc04 + Location: 93,58 + Owner: Neutral + Actor95: tc01 + Location: 84,63 + Owner: Neutral + Actor96: t11 + Location: 100,81 + Owner: Neutral + Actor97: tc02 + Location: 89,74 + Owner: Neutral + Actor98: tc03 + Location: 92,86 + Owner: Neutral + Actor99: tc05 + Location: 96,51 + Owner: Neutral + Actor100: tc02 + Location: 91,62 + Owner: Neutral + Actor101: t16 + Location: 83,74 + Owner: Neutral + Actor102: t01 + Location: 97,60 + Owner: Neutral + Actor103: t05 + Location: 102,72 + Owner: Neutral + Actor104: t13 + Location: 101,63 + Owner: Neutral + Actor105: t01 + Location: 89,89 + Owner: Neutral + Actor106: t02 + Location: 93,78 + Owner: Neutral + Actor107: t10 + Location: 93,73 + Owner: Neutral + Actor108: t11 + Location: 93,65 + Owner: Neutral + Actor109: tc05 + Location: 79,54 + Owner: Neutral + Actor110: tc03 + Location: 81,77 + Owner: Neutral + Actor111: t01 + Location: 71,54 + Owner: Neutral + Actor112: tc02 + Location: 80,79 + Owner: Neutral + Actor113: tc01 + Location: 28,63 + Owner: Neutral + Actor114: tc02 + Location: 42,64 + Owner: Neutral + Actor115: t07 + Location: 43,65 + Owner: Neutral + Actor116: tc01 + Location: 43,61 + Owner: Neutral + Actor117: tc04 + Location: 20,48 + Owner: Neutral + Actor118: tc03 + Location: 42,40 + Owner: Neutral + Actor119: tc02 + Location: 41,56 + Owner: Neutral + Actor120: tc04 + Location: 77,38 + Owner: Neutral + Actor121: tc01 + Location: 85,38 + Owner: Neutral + Actor122: tc05 + Location: 63,86 + Owner: Neutral + Actor123: tc01 + Location: 67,82 + Owner: Neutral + Actor124: t15 + Location: 72,82 + Owner: Neutral + Actor125: tc02 + Location: 73,89 + Owner: Neutral + Actor126: tc02 + Location: 77,62 + Owner: Neutral + Actor127: tc05 + Location: 75,64 + Owner: Neutral + Actor128: t01 + Location: 76,55 + Owner: Neutral + Actor129: t02 + Location: 79,59 + Owner: Neutral + Actor130: t01 + Location: 91,71 + Owner: Neutral + Actor131: tc04 + Location: 64,38 + Owner: Neutral + Actor132: tc02 + Location: 60,41 + Owner: Neutral + Actor133: tc02 + Location: 34,50 + Owner: Neutral + Actor134: tc03 + Location: 44,49 + Owner: Neutral + Actor135: tc02 + Location: 71,72 + Owner: Neutral + Actor136: tc04 + Location: 55,72 + Owner: Neutral + Actor137: tc03 + Location: 78,68 + Owner: Neutral + Actor138: t16 + Location: 63,70 + Owner: Neutral + Actor139: t07 + Location: 76,51 + Owner: Neutral + Actor140: t15 + Location: 61,77 + Owner: Neutral + Actor141: t14 + Location: 63,81 + Owner: Neutral + Actor142: t15 + Location: 57,83 + Owner: Neutral + Actor143: tc05 + Location: 56,89 + Owner: Neutral + Actor144: tc01 + Location: 63,75 + Owner: Neutral + Actor145: tc05 + Location: 42,78 + Owner: Neutral + Actor146: tc04 + Location: 25,73 + Owner: Neutral + Actor147: tc01 + Location: 23,73 + Owner: Neutral + Actor148: tc05 + Location: 26,87 + Owner: Neutral + Actor149: tc02 + Location: 25,79 + Owner: Neutral + Actor150: tc03 + Location: 30,75 + Owner: Neutral + Actor151: tc04 + Location: 39,76 + Owner: Neutral + Actor152: t01 + Location: 24,63 + Owner: Neutral + Actor153: tc04 + Location: 30,89 + Owner: Neutral + Actor154: tc04 + Location: 59,80 + Owner: Neutral + Actor155: tc01 + Location: 55,77 + Owner: Neutral + Actor156: t16 + Location: 61,84 + Owner: Neutral + Actor391: flare + Location: 81,41 + Owner: England + Actor157: apwr + Location: 89,40 + Owner: England + Actor158: tent + Location: 89,43 + Owner: England + Actor159: pbox + Location: 88,50 + Owner: England + Actor160: pbox + Location: 96,45 + Owner: England + Actor161: gun + Location: 92,47 + Owner: England + Facing: 636 + Actor162: v19 + Location: 101,42 + Owner: England + Actor163: brl3 + Location: 102,41 + Owner: England + Actor164: brl3 + Location: 101,41 + Owner: England + Actor165: barl + Location: 100,40 + Owner: England + Actor166: brl3 + Location: 99,39 + Owner: England + Actor167: barl + Location: 98,39 + Owner: England + Actor168: v19 + Location: 97,39 + Owner: England + Actor169: brl3 + Location: 96,39 + Owner: England + Actor170: barl + Location: 95,40 + Owner: England + Actor171: barl + Location: 102,43 + Owner: England + Actor172: brl3 + Location: 100,44 + Owner: England + Actor173: brl3 + Location: 97,40 + Owner: England + Actor174: brl3 + Location: 98,40 + Owner: England + Actor175: barl + Location: 102,42 + Owner: England + Church: v01 + Location: 93,70 + Owner: GreekCivilians + Trig3House: v02 + Location: 97,67 + Owner: Neutral + Health: 51 + Trig4House: v09 + Location: 100,61 + Owner: Neutral + Health: 56 + Actor179: v10 + Location: 98,87 + Owner: GreekCivilians + Health: 37 + Actor180: v05 + Location: 88,84 + Owner: GreekCivilians + Health: 45 + Actor181: v04 + Location: 92,81 + Owner: GreekCivilians + Health: 41 + Actor182: v03 + Location: 99,80 + Owner: GreekCivilians + Health: 76 + Actor183: v07 + Location: 98,57 + Owner: GreekCivilians + Health: 33 + GuideHut: v09 + Location: 95,77 + Owner: GreekCivilians + Health: 78 + Actor185: v02 + Location: 100,84 + Owner: GreekCivilians + Health: 70 + Actor186: v19 + Location: 82,84 + Owner: Neutral + Actor187: brl3 + Location: 81,84 + Owner: USSR + Actor188: brl3 + Location: 83,84 + Owner: USSR + Actor189: barl + Location: 82,83 + Owner: USSR + Actor190: brl3 + Location: 83,85 + Owner: USSR + Actor191: barl + Location: 80,85 + Owner: USSR + Actor192: barl + Location: 81,85 + Owner: USSR + Actor193: brl3 + Location: 99,43 + Owner: England + Actor194: barl + Location: 98,43 + Owner: England + CivBarrel: barl + Location: 94,40 + Owner: England + Actor196: brl3 + Location: 101,43 + Owner: England + SovFact: fact + Location: 31,59 + Owner: USSR + SovPower1: apwr + Location: 27,60 + Owner: USSR + SovPower2: apwr + Location: 25,52 + Owner: USSR + SovRax: barr + Location: 32,53 + Owner: USSR + SovWarFactory: weap + Location: 28,53 + Owner: USSR + SovFlame1: ftur + Location: 27,59 + Owner: USSR + SovFlame2: ftur + Location: 27,55 + Owner: USSR + SovTesla: tsla + Location: 37,59 + Owner: USSR + Actor203: v19 + Location: 21,52 + Owner: USSR + Actor204: v19 + Location: 22,50 + Owner: USSR + Actor205: v19 + Location: 24,50 + Owner: USSR + Actor206: brl3 + Location: 25,50 + Owner: USSR + Actor207: barl + Location: 26,50 + Owner: USSR + Actor208: barl + Location: 24,51 + Owner: USSR + Actor209: brl3 + Location: 23,50 + Owner: USSR + Actor210: brl3 + Location: 21,51 + Owner: USSR + Actor211: barl + Location: 22,51 + Owner: USSR + Actor212: brl3 + Location: 20,52 + Owner: USSR + Actor213: barl + Location: 21,53 + Owner: USSR + Actor214: barl + Location: 20,54 + Owner: USSR + Actor215: barl + Location: 20,53 + Owner: USSR + Actor217: brl3 + Location: 26,51 + Owner: USSR + Actor218: apwr + Location: 80,46 + Owner: England + Actor219: dome + Location: 84,47 + Owner: England + BridgeBarrel1: brl3 + Location: 85,42 + Owner: England + Actor221: barl + Location: 85,41 + Owner: England + Actor222: v19 + Location: 68,57 + Owner: Neutral + Actor223: v19 + Location: 66,57 + Owner: Neutral + Actor224: brl3 + Location: 69,56 + Owner: USSR + Actor225: barl + Location: 67,57 + Owner: USSR + Actor226: barl + Location: 68,56 + Owner: USSR + Actor227: brl3 + Location: 69,58 + Owner: USSR + Actor228: barl + Location: 69,57 + Owner: USSR + Actor229: brl3 + Location: 66,56 + Owner: USSR + Actor230: barl + Location: 65,57 + Owner: USSR + Actor231: barl + Location: 64,57 + Owner: USSR + Actor232: brl3 + Location: 65,58 + Owner: USSR + Actor233: v02 + Location: 76,74 + Owner: Neutral + Health: 51 + Actor234: v03 + Location: 74,79 + Owner: Neutral + Health: 35 + Actor235: v04 + Location: 68,79 + Owner: Neutral + Actor236: v05 + Location: 70,76 + Owner: Neutral + Actor237: tsla + Location: 40,85 + Owner: BadGuy + Actor238: apwr + Location: 36,84 + Owner: BadGuy + Actor239: v19 + Location: 37,74 + Owner: Neutral + Actor240: v19 + Location: 35,74 + Owner: Neutral + BridgeBarrel2: brl3 + Location: 35,72 + Owner: USSR + Actor242: barl + Location: 36,72 + Owner: USSR + Actor243: brl3 + Location: 35,73 + Owner: USSR + Actor244: barl + Location: 37,73 + Owner: USSR + Actor245: brl3 + Location: 38,73 + Owner: USSR + Actor246: barl + Location: 34,73 + Owner: USSR + Actor247: brl3 + Location: 35,84 + Owner: USSR + Actor248: barl + Location: 35,85 + Owner: USSR + Actor249: brl3 + Location: 34,84 + Owner: USSR + Actor250: barl + Location: 34,83 + Owner: USSR + Actor251: brl3 + Location: 35,86 + Owner: USSR + Actor253: brl3 + Location: 23,78 + Owner: USSR + Actor254: barl + Location: 23,75 + Owner: USSR + Actor255: brl3 + Location: 23,76 + Owner: USSR + Actor256: barl + Location: 22,79 + Owner: USSR + Actor257: v19 + Location: 23,77 + Owner: Neutral + Actor258: brl3 + Location: 22,77 + Owner: USSR + Actor259: barl + Location: 22,75 + Owner: USSR + VillageMammoth: 4tnk + Location: 97,65 + Owner: USSR + Facing: 508 + Actor261: 4tnk + Location: 67,70 + Owner: BadGuy + Actor262: 4tnk + Location: 73,68 + Owner: USSR + Facing: 124 + BridgeMammoth1: 4tnk + Location: 37,67 + Owner: USSR + Facing: 380 + BridgeMammoth2: 4tnk + Location: 36,67 + Owner: USSR + Facing: 380 + HealCrateTruck: truk + Location: 21,66 + Owner: USSR + Facing: 508 + FlareBoy: e1 + Location: 75,87 + Owner: England + Facing: 380 + SubCell: 2 + Actor268: e1 + Location: 82,86 + Owner: USSR + Facing: 252 + SubCell: 3 + Actor269: e1 + Location: 82,88 + Owner: USSR + Facing: 252 + SubCell: 1 + Rifle1: e1 + Location: 88,87 + Owner: USSR + SubCell: 2 + Rifle2: e1 + Location: 89,86 + Owner: USSR + SubCell: 3 + Rifle3: e1 + Location: 89,88 + Owner: USSR + SubCell: 2 + Rifle4: e1 + Location: 90,86 + Owner: USSR + SubCell: 3 + Actor274: e4 + Location: 91,84 + Owner: USSR + SubCell: 3 + Actor275: e2 + Location: 89,89 + Owner: USSR + Facing: 380 + SubCell: 0 + Actor276: e1 + Location: 98,83 + Owner: USSR + SubCell: 4 + Actor277: e1 + Location: 96,86 + Owner: USSR + Facing: 636 + SubCell: 4 + Actor278: c3 + Location: 91,83 + Owner: GreekCivilians + SubCell: 0 + Actor279: c4 + Location: 98,85 + Owner: GreekCivilians + SubCell: 0 + Actor280: c5 + Location: 96,80 + Owner: GreekCivilians + SubCell: 4 + Actor281: c6 + Location: 92,80 + Owner: GreekCivilians + SubCell: 3 + Actor282: c7 + Location: 97,88 + Owner: GreekCivilians + SubCell: 3 + Actor283: c8 + Location: 94,82 + Owner: GreekCivilians + SubCell: 2 + Actor284: c9 + Location: 99,82 + Owner: GreekCivilians + SubCell: 2 + Gren1: e2 + Location: 95,65 + Owner: USSR + SubCell: 2 + Gren2: e2 + Location: 96,64 + Owner: USSR + SubCell: 4 + Gren3: e2 + Location: 98,64 + Owner: USSR + SubCell: 3 + Gren4: e2 + Location: 96,63 + Owner: USSR + SubCell: 4 + Gren5: e2 + Location: 98,63 + Owner: USSR + SubCell: 4 + TeamFive1: e1 + Location: 81,58 + Owner: USSR + SubCell: 0 + TeamFive2: e1 + Location: 83,59 + Owner: USSR + SubCell: 0 + TeamFive3: e2 + Location: 82,59 + Owner: USSR + SubCell: 1 + TeamFive4: e2 + Location: 82,60 + Owner: USSR + SubCell: 2 + TeamFive5: e2 + Location: 81,60 + Owner: USSR + SubCell: 0 + TeamFive6: e4 + Location: 82,60 + Owner: USSR + SubCell: 3 + TeamFive7: e4 + Location: 80,59 + Owner: USSR + SubCell: 2 + Actor299: e1 + Location: 38,60 + Owner: USSR + Facing: 380 + SubCell: 3 + Actor300: e1 + Location: 39,59 + Owner: USSR + Facing: 764 + SubCell: 4 + Actor301: e1 + Location: 41,60 + Owner: USSR + Facing: 508 + SubCell: 3 + Actor302: dog + Location: 95,84 + Owner: USSR + Facing: 380 + SubCell: 0 + SovBaseTeam1: e1 + Location: 33,56 + Owner: USSR + Facing: 636 + SubCell: 1 + SovBaseTeam2: e1 + Location: 32,55 + Owner: USSR + Facing: 252 + SubCell: 4 + SovBaseTeam3: e2 + Location: 33,55 + Owner: USSR + Facing: 764 + SubCell: 4 + SovBaseTeam4: dog + Location: 37,56 + Owner: USSR + Facing: 636 + SubCell: 3 + SovBaseTeam5: dog + Location: 37,58 + Owner: USSR + Facing: 380 + SubCell: 1 + SovBaseTeam6: 3tnk + Location: 35,57 + Owner: USSR + Facing: 636 + Actor306: e4 + Location: 38,59 + Owner: USSR + Facing: 636 + SubCell: 4 + Actor307: e2 + Location: 77,57 + Owner: USSR + Facing: 636 + SubCell: 4 + Actor308: e1 + Location: 78,59 + Owner: USSR + Facing: 636 + SubCell: 0 + Actor309: e2 + Location: 57,83 + Owner: USSR + SubCell: 4 + Actor310: e2 + Location: 60,80 + Owner: USSR + SubCell: 3 + Actor311: e2 + Location: 63,81 + Owner: USSR + SubCell: 4 + Actor312: e1 + Location: 61,84 + Owner: USSR + SubCell: 4 + Actor313: e1 + Location: 61,77 + Owner: USSR + SubCell: 4 + Actor314: e1 + Location: 55,77 + Owner: USSR + SubCell: 4 + Actor315: e2 + Location: 56,77 + Owner: USSR + SubCell: 3 + Actor316: e1 + Location: 25,83 + Owner: USSR + Facing: 764 + SubCell: 3 + Actor317: e1 + Location: 24,84 + Owner: USSR + Facing: 892 + SubCell: 0 + Actor318: e1 + Location: 25,85 + Owner: USSR + Facing: 636 + SubCell: 1 + Actor319: dog + Location: 25,84 + Owner: USSR + Facing: 636 + SubCell: 0 + Actor320: e1 + Location: 37,75 + Owner: USSR + Facing: 636 + SubCell: 4 + Actor321: e1 + Location: 35,75 + Owner: USSR + Facing: 380 + SubCell: 3 + Actor322: e2 + Location: 36,74 + Owner: USSR + Facing: 892 + SubCell: 4 + Sub1: ss + Location: 53,60 + Owner: USSR + Facing: 892 + Sub2: ss + Location: 51,57 + Owner: USSR + Facing: 764 + Sub3: ss + Location: 51,53 + Owner: USSR + Facing: 636 + Sub4: ss + Location: 56,51 + Owner: USSR + Facing: 636 + Actor380: v03 + Owner: Neutral + Location: 59,43 + Actor381: v02 + Owner: Neutral + Location: 63,44 + Actor382: v16 + Owner: Neutral + Location: 62,42 + Actor383: v16 + Owner: Neutral + Location: 63,42 + Actor384: v19 + Owner: Neutral + Location: 61,47 + Actor385: v19 + Owner: Neutral + Location: 62,47 + Actor386: lhus + Owner: Neutral + Location: 57,46 + Actor408: healcrate + Owner: Neutral + Location: 88,44 + Actor409: healcrate + Owner: Neutral + Location: 55,90 + LightFlare: waypoint + Location: 72,87 + Owner: Neutral + InsertionPoint: waypoint + Location: 71,86 + Owner: Neutral + FlareBoyAttack: waypoint + Location: 89,87 + Owner: Neutral + Trigger1Cam: waypoint + Location: 82,87 + Owner: Neutral + Trigger1Move: waypoint + Location: 83,86 + Owner: Neutral + DoomedHeli: waypoint + Location: 83,41 + Owner: Neutral + VillageParadrop: waypoint + Location: 94,88 + Owner: Neutral + GrenEntry: waypoint + Location: 104,78 + Owner: Neutral + ChurchSpawn: waypoint + Location: 93,71 + Owner: Neutral + GuideSpawn: waypoint + Location: 95,77 + Owner: Neutral + SafePath1: waypoint + Location: 85,76 + Owner: Neutral + SafePath2: waypoint + Location: 85,65 + Owner: Neutral + Trigger3Cam: waypoint + Location: 97,64 + Owner: Neutral + CivFlee1: waypoint + Location: 100,61 + Owner: Neutral + CivFlee2: waypoint + Location: 99,57 + Owner: Neutral + CivilianRally: waypoint + Location: 97,41 + Owner: Neutral + Tent: waypoint + Location: 90,44 + Owner: Neutral + TentMove: waypoint + Location: 91,46 + Owner: Neutral + SovietAttack: waypoint + Location: 97,50 + Owner: Neutral + BaseAttackersSpawn: waypoint + Location: 96,90 + Owner: Neutral + DoomedHeliEntry: waypoint + Location: 78,39 + Owner: Neutral + TacticalNuke1: waypoint + Owner: Neutral + Location: 92,43 + TacticalNuke2: waypoint + Owner: Neutral + Location: 84,44 + BoatSpawn: waypoint + Location: 49,39 + Owner: Neutral + BoatUnload1: waypoint + Location: 59,59 + Owner: Neutral + MammothCam: waypoint + Location: 70,70 + Owner: Neutral + House1: waypoint + Location: 70,76 + Owner: Neutral + House2: waypoint + Location: 68,80 + Owner: Neutral + House3: waypoint + Location: 74,79 + Owner: Neutral + House4: waypoint + Location: 76,75 + Owner: Neutral + TacticalNuke3: waypoint + Location: 72,78 + Owner: Neutral + TeslaCam: waypoint + Location: 39,85 + Owner: Neutral + TeslaDrop: waypoint + Location: 43,85 + Owner: Neutral + BridgeCam: waypoint + Location: 35,69 + Owner: Neutral + MammysGo: waypoint + Location: 31,74 + Owner: Neutral + TruckCam: waypoint + Location: 21,76 + Owner: Neutral + TruckGo: waypoint + Location: 20,84 + Owner: Neutral + SovBaseCam: waypoint + Location: 35,57 + Owner: Neutral + SovBaseDrop: waypoint + Location: 29,57 + Owner: Neutral + SovRaxSpawn: waypoint + Location: 33,54 + Owner: Neutral + BoatUnload2: waypoint + Location: 43,47 + Owner: Neutral + ExtractionPoint: waypoint + Location: 26,44 + Owner: Neutral + ChinookEntry: waypoint + Owner: Neutral + Location: 22,39 + +Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml + +Weapons: weapons.yaml diff -Nru openra-20200503/mods/ra/maps/fall-of-greece-1-personal-war/personal-war.lua openra-20210321/mods/ra/maps/fall-of-greece-1-personal-war/personal-war.lua --- openra-20200503/mods/ra/maps/fall-of-greece-1-personal-war/personal-war.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/fall-of-greece-1-personal-war/personal-war.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,534 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +FootprintTrigger1 = { CPos.New(77, 85), CPos.New(77, 86), CPos.New(77, 87), CPos.New(77, 88) } +Trigger1Rifles = { Rifle1, Rifle2, Rifle3, Rifle4 } +DoomedHeliPath = { DoomedHeliEntry.Location, DoomedHeli.Location } +FootprintTrigger2 = { CPos.New(90, 82), CPos.New(91, 82), CPos.New(93, 82), CPos.New(94, 82), CPos.New(95, 82), CPos.New(96, 82), CPos.New(97, 82), CPos.New(98, 82), CPos.New(99, 82), CPos.New(102, 82) } +Grenadiers = { "e2", "e2", "e2", "e2", "e2" } +FootprintTrigger3 = { CPos.New(88, 77), CPos.New(88, 76), CPos.New(91, 75), CPos.New(92, 75), CPos.New(93, 75), CPos.New(94, 75), CPos.New(95, 75), CPos.New(96, 75), CPos.New(97, 75), CPos.New(98, 75), CPos.New(99, 75), CPos.New(100, 75) } +Trigger3Team = { Gren1, Gren2, Gren3, Gren4, Gren5, VillageMammoth } +FootprintTrigger4 = { CPos.New(94, 60), CPos.New(95, 60), CPos.New(96, 60), CPos.New(97, 60), CPos.New(98, 60), CPos.New(99, 60), CPos.New(100, 60), CPos.New(101, 60), CPos.New(102, 60), CPos.New(103, 60), CPos.New(104, 60) } +CivilianSquad1 = { "c1", "c2", "c3", "c4", "c5" } +CivilianSquad2 = { "c6", "c7", "c8", "c9", "c10" } +FootprintTrigger5 = { CPos.New(99, 53), CPos.New(100, 53), CPos.New(101, 53), CPos.New(102, 53), CPos.New(103, 53), CPos.New(104, 53) } +Trigger5Team = { TeamFive1, TeamFive2, TeamFive3, TeamFive4, TeamFive5, TeamFive6, TeamFive7 } +TentTeam = { "e1", "e1", "e1", "e1", "e3", "e3" } +Doggos = { "dog", "dog", "dog" } +SovietAttackers = { "3tnk", "e2", "e2", "e2", "v2rl" } +MigEntryPath = { BaseAttackersSpawn, GuideSpawn } +FootprintTrigger6 = { CPos.New(81, 57), CPos.New(81, 58), CPos.New(81, 59), CPos.New(81, 60), CPos.New(81, 61) } +FootprintTrigger7 = { CPos.New(73, 58), CPos.New(73, 59), CPos.New(73, 60), CPos.New(73, 61) } +FootprintTrigger8 = { CPos.New(51, 83), CPos.New(51, 84), CPos.New(51, 85), CPos.New(51, 86), CPos.New(51, 87), CPos.New(51, 88) } +FootprintTrigger9 = { CPos.New(28, 77), CPos.New(29, 77), CPos.New(30, 77), CPos.New(31, 77), CPos.New(32, 77), CPos.New(33, 77), CPos.New(34, 77), CPos.New(35, 77), CPos.New(36, 77), CPos.New(37, 77), CPos.New(38, 77) } +BridgeMammoths = { BridgeMammoth1, BridgeMammoth2 } +FootprintTrigger10 = { CPos.New(24, 83), CPos.New(24, 84), CPos.New(24, 85) } +FootprintTrigger11 = { CPos.New(20, 65), CPos.New(21, 65), CPos.New(22, 65) } +SovBase = { SovFact, SovPower1, SovPower2, SovRax, SovWarFactory, SovFlame1, SovFlame2, SovTesla } +SovBaseTeam = { SovBaseTeam1, SovBaseTeam2, SovBaseTeam3, SovBaseTeam4, SovBaseTeam5, SovBaseTeam6 } +RaxTeam = { "e1", "e2", "e2", "e4", "e4", "shok" } +FootprintTrigger12 = { CPos.New(35, 39), CPos.New(35, 40), CPos.New(35, 41), CPos.New(35, 42) } +ExtractionHelicopterType = "tran" +ExtractionPath = { ChinookEntry.Location, ExtractionPoint.Location } + +lstReinforcements = +{ + first = + { + actors = { "2tnk", "2tnk", "2tnk", "2tnk", "2tnk" }, + entryPath = { BoatSpawn.Location, BoatUnload1.Location }, + exitPath = { BoatSpawn.Location } + }, + second = + { + actors = { "1tnk", "1tnk", "2tnk", "2tnk", "2tnk" }, + entryPath = { BoatSpawn.Location, BoatUnload2.Location }, + exitPath = { BoatSpawn.Location } + } +} + +IdleHunt = function(actor) if not actor.IsDead then Trigger.OnIdle(actor, actor.Hunt) end end + +VIPs = { } +MissionStart = function() + FlareBoy.Move(LightFlare.Location) + + Trigger.OnEnteredFootprint({ LightFlare.Location }, function(actor, id) + if actor.Owner == England then + Trigger.RemoveFootprintTrigger(id) + local insertionFlare = Actor.Create("flare", true, { Owner = Allies, Location = LightFlare.Location }) + Trigger.AfterDelay(DateTime.Seconds(2), function() + FlareBoy.AttackMove(FlareBoyAttack.Location) + if Map.LobbyOption("difficulty") == "normal" then + local normalDrop = InsertionDrop.TargetParatroopers(InsertionPoint.CenterPosition, Angle.New(892)) + Utils.Do(normalDrop, function(a) + Trigger.OnPassengerExited(a, function(t,p) + VIPs[#VIPs + 1] = p + FailTrigger() + end) + end) + else + local hardDrop = InsertionDropHard.TargetParatroopers(InsertionPoint.CenterPosition, Angle.New(892)) + Utils.Do(hardDrop, function(a) + Trigger.OnPassengerExited(a, function(t,p) + VIPs[#VIPs + 1] = p + FailTrigger() + end) + end) + Trigger.AfterDelay(DateTime.Seconds(6), function() + Media.DisplayMessage("Commander, there are several civilians in the area.\nWe'll need you to call out targets.", "Tanya") + end) + end + end) + + Trigger.AfterDelay(DateTime.Seconds(20), function() + insertionFlare.Destroy() + end) + end + end) +end + +FailTrigger = function() + Trigger.OnAnyKilled(VIPs, function() + Allies.MarkFailedObjective(ProtectVIPs) + end) +end + +FootprintTriggers = function() + local foot1Triggered + Trigger.OnEnteredFootprint(FootprintTrigger1, function(actor, id) + if actor.Owner == Allies and not foot1Triggered then + Trigger.RemoveFootprintTrigger(id) + foot1Triggered = true + + local trig1cam = Actor.Create("camera", true, { Owner = Allies, Location = Trigger1Cam.Location }) + Trigger.AfterDelay(DateTime.Seconds(10), function() + trig1cam.Destroy() + end) + + Utils.Do(Trigger1Rifles, function(actor) + if not actor.IsDead then + actor.AttackMove(Trigger1Move.Location) + end + end) + + DoomedHeli = Reinforcements.ReinforceWithTransport(England, ExtractionHelicopterType, nil, DoomedHeliPath)[1] + end + end) + + local foot2Triggered + Trigger.OnEnteredFootprint(FootprintTrigger2, function(actor, id) + if actor.Owner == Allies and not foot2Triggered then + Trigger.RemoveFootprintTrigger(id) + foot2Triggered = true + + local drop1 = RifleDropS.TargetParatroopers(VillageParadrop.CenterPosition, Angle.SouthWest) + Utils.Do(drop1, function(a) + Trigger.OnPassengerExited(a, function(t, p) + IdleHunt(p) + end) + end) + + local grens = Reinforcements.Reinforce(USSR, Grenadiers, { GrenEntry.Location }, 0) + Utils.Do(grens, IdleHunt) + end + end) + + local foot3Triggered + Trigger.OnEnteredFootprint(FootprintTrigger3, function(actor, id) + if actor.Owner == Allies and not foot3Triggered then + Trigger.RemoveFootprintTrigger(id) + foot3Triggered = true + + Trig3House.Owner = Civilians + local camera3 = Actor.Create("camera", true, { Owner = Allies, Location = Trigger3Cam.Location }) + Trigger.AfterDelay(DateTime.Seconds(10), function() + camera3.Destroy() + end) + + if not GuideHut.IsDead then + local guide = Actor.Create("c6", true, { Owner = England, Location = GuideSpawn.Location }) + guide.Move(SafePath1.Location) + guide.Move(SafePath2.Location) + guide.Move(CivilianRally.Location) + end + + Utils.Do(Trigger3Team, function(actor) + if not actor.IsDead then + actor.AttackMove(GuideSpawn.Location) + IdleHunt(actor) + end + end) + end + end) + + local foot4Triggered + Trigger.OnEnteredFootprint(FootprintTrigger4, function(actor, id) + if actor.Owner == Allies and not foot4Triggered then + Trigger.RemoveFootprintTrigger(id) + foot4Triggered = true + + Trig4House.Owner = Civilians + Reinforcements.Reinforce(England, CivilianSquad1, { CivFlee1.Location, CivilianRally.Location }, 0) + Reinforcements.Reinforce(England, CivilianSquad2, { CivFlee2.Location, CivilianRally.Location }, 0) + end + end) + + local foot5Triggered + Trigger.OnEnteredFootprint(FootprintTrigger5, function(actor, id) + if actor.Owner == Allies and not foot5Triggered then + Trigger.RemoveFootprintTrigger(id) + foot5Triggered = true + + Media.PlaySoundNotification(Allies, "AlertBleep") + Media.DisplayMessage("Alfa Niner this is Lima One Six. Be advised, Soviet aircraft and armor moving into your AO.", "Headquarters") + Utils.Do(Trigger5Team, function(actor) + if not actor.IsDead then + actor.AttackMove(TacticalNuke1.Location) + end + end) + + SendMig(MigEntryPath) + local barrelcam1 = Actor.Create("camera", true, { Owner = USSR, Location = TacticalNuke1.Location }) + local barrelcam2 = Actor.Create("camera", true, { Owner = USSR, Location = TacticalNuke2.Location }) + local wave1 = Reinforcements.Reinforce(USSR, SovietAttackers, { BaseAttackersSpawn.Location, SovietAttack.Location }) + Utils.Do(wave1, IdleHunt) + local drop2 = RifleDropS.TargetParatroopers(SovietAttack.CenterPosition, Angle.East) + Utils.Do(drop2, function(a) + Trigger.OnPassengerExited(a, function(t, p) + IdleHunt(p) + end) + end) + + Trigger.AfterDelay(DateTime.Seconds(20), function() + Media.PlaySoundNotification(Allies, "AlertBuzzer") + Media.DisplayMessage("Extraction point is compromised. Evacuate the base!", "Headquarters") + local defenders = Reinforcements.Reinforce(England, TentTeam, { Tent.Location, TentMove.Location }, 0) + Utils.Do(defenders, IdleHunt) + if Map.LobbyOption("difficulty") == "hard" then + Trigger.AfterDelay(DateTime.Seconds(30), function() + local wave2 = Reinforcements.Reinforce(USSR, SovietAttackers, { BaseAttackersSpawn.Location, SovietAttack.Location }) + Utils.Do(wave2, IdleHunt) + end) + end + end) + + Trigger.AfterDelay(DateTime.Seconds(35), function() + local dogs = Reinforcements.Reinforce(USSR, Doggos, { GrenEntry.Location }, 0) + Utils.Do(dogs, IdleHunt) + Media.PlaySpeechNotification(Allies, "AbombLaunchDetected") + local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = USSR }) + proxy.TargetAirstrike(TacticalNuke1.CenterPosition, Angle.NorthWest) + Trigger.AfterDelay(DateTime.Seconds(5), function() + Media.PlaySpeechNotification(Allies, "AbombLaunchDetected") + proxy.TargetAirstrike(TacticalNuke2.CenterPosition, Angle.NorthWest) + end) + proxy.Destroy() + end) + + Trigger.AfterDelay(DateTime.Seconds(50), function() + Media.DisplayMessage("We've set up a new extraction point to the Northwest.", "Headquarters") + end) + end + end) + + local foot6Triggered + Trigger.OnEnteredFootprint(FootprintTrigger6, function(actor, id) + if actor.Owner == Allies and not foot6Triggered then + Trigger.RemoveFootprintTrigger(id) + foot6Triggered = true + + local reinforcement = lstReinforcements.first + Media.PlaySpeechNotification(Allies, "ReinforcementsArrived") + Reinforcements.ReinforceWithTransport(Allies, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) + end + end) + + local foot7Triggered + Trigger.OnEnteredFootprint(FootprintTrigger7, function(actor, id) + if actor.Owner == Allies and not foot7Triggered then + Trigger.RemoveFootprintTrigger(id) + foot7Triggered = true + + local drop3 = RifleDropS.TargetParatroopers(TacticalNuke3.CenterPosition, Angle.West) + Utils.Do(drop3, function(a) + Trigger.OnPassengerExited(a, function(t, p) + IdleHunt(p) + end) + end) + + local trig7camera1 = Actor.Create("camera", true, { Owner = Allies, Location = MammothCam.Location }) + local trig7camera2 = Actor.Create("camera", true, { Owner = Allies, Location = TacticalNuke3.Location }) + Trigger.AfterDelay(DateTime.Seconds(30), function() + trig7camera1.Destroy() + end) + + Trigger.AfterDelay(DateTime.Seconds(20), function() + Media.PlaySpeechNotification(Allies, "AbombLaunchDetected") + local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = USSR }) + proxy.TargetAirstrike(TacticalNuke3.CenterPosition, Angle.SouthWest) + proxy.Destroy() + end) + + Trigger.AfterDelay(DateTime.Seconds(26), function() + Reinforcements.Reinforce(England, CivilianSquad1, { House1.Location, TacticalNuke3.Location }, 0) + Reinforcements.Reinforce(England, CivilianSquad2, { House2.Location, TacticalNuke3.Location }, 0) + Reinforcements.Reinforce(England, CivilianSquad1, { House3.Location, TacticalNuke3.Location }, 0) + Reinforcements.Reinforce(England, CivilianSquad2, { House4.Location, TacticalNuke3.Location }, 0) + end) + + Trigger.AfterDelay(DateTime.Seconds(15), function() + trig7camera2.Destroy() + end) + end + end) + + local foot8Triggered + Trigger.OnEnteredFootprint(FootprintTrigger8, function(actor, id) + if actor.Owner == Allies and not foot8Triggered then + Trigger.RemoveFootprintTrigger(id) + foot8Triggered = true + + local trig8camera = Actor.Create("camera", true, { Owner = Allies, Location = TeslaCam.Location }) + Trigger.AfterDelay(DateTime.Seconds(10), function() + trig8camera.Destroy() + end) + + Media.PlaySpeechNotification(Allies, "ReinforcementsArrived") + RifleDropA.TargetParatroopers(TeslaDrop.CenterPosition, Angle.New(124)) + end + end) + + local foot9Triggered + Trigger.OnEnteredFootprint(FootprintTrigger9, function(actor, id) + if actor.Owner == Allies and not foot9Triggered then + Trigger.RemoveFootprintTrigger(id) + foot9Triggered = true + + local trig9camera = Actor.Create("camera", true, { Owner = Allies, Location = BridgeCam.Location }) + Trigger.AfterDelay(DateTime.Seconds(10), function() + trig9camera.Destroy() + end) + + Utils.Do(BridgeMammoths, function(actor) + actor.AttackMove(MammysGo.Location) + end) + end + end) + + local foot10Triggered + Trigger.OnEnteredFootprint(FootprintTrigger10, function(actor, id) + if actor.Owner == Allies and not foot10Triggered then + Trigger.RemoveFootprintTrigger(id) + foot10Triggered = true + + local trig10camera = Actor.Create("camera", true, { Owner = Allies, Location = TruckCam.Location }) + Trigger.AfterDelay(DateTime.Seconds(10), function() + trig10camera.Destroy() + end) + + Media.PlaySpeechNotification(Allies, "SignalFlareNorth") + Actor.Create("camera", true, { Owner = Allies, Location = ExtractionPoint.Location }) + SendExtractionHelicopter() + + HealCrateTruck.Move(TruckGo.Location) + end + end) + + local foot11Triggered + Trigger.OnEnteredFootprint(FootprintTrigger11, function(actor, id) + if actor.Owner == Allies and not foot11Triggered then + Trigger.RemoveFootprintTrigger(id) + foot11Triggered = true + + local trig11camera = Actor.Create("camera", true, { Owner = Allies, Location = SovBaseCam.Location }) + Trigger.AfterDelay(DateTime.Seconds(10), function() + trig11camera.Destroy() + end) + + local reinforcement = lstReinforcements.second + Media.PlaySpeechNotification(Allies, "ReinforcementsArrived") + Reinforcements.ReinforceWithTransport(Allies, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) + end + end) + + local foot12Triggered + Trigger.OnEnteredFootprint(FootprintTrigger12, function(actor, id) + if (actor.Type == "gnrl" or actor.Type == "gnrl.noautotarget") and not foot12Triggered then + Trigger.RemoveFootprintTrigger(id) + foot12Triggered = true + + Media.PlaySoundNotification(Allies, "AlertBleep") + Media.DisplayMessage("Stalin will pay for what he has done today!\nI will bury him with my own hands!", "Stavros") + end + end) +end + +SetupTriggers = function() + Utils.Do(USSR.GetGroundAttackers(), function(unit) + Trigger.OnDamaged(unit, function() IdleHunt(unit) end) + end) + + Trigger.OnKilled(BridgeBarrel1, function() + local bridge = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "bridge2" end)[1] + if not bridge.IsDead then + bridge.Kill() + end + end) + + Trigger.OnKilled(BridgeBarrel2, function() + local bridgepart1 = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "br2" end)[1] + local bridgepart2 = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "br3" end)[1] + if not bridgepart1.IsDead then + bridgepart1.Kill() + end + if not bridgepart2.IsDead then + bridgepart2.Kill() + end + end) + + local trukEscaped + Trigger.OnEnteredFootprint({ TruckGo.Location }, function(actor, id) + if actor.Type == "truk" and not trukEscaped then + Trigger.RemoveFootprintTrigger(id) + trukEscaped = true + actor.Destroy() + end + end) +end + +ChurchAttack = function() + if not ChurchDamaged then + local churchPanicTeam = Reinforcements.Reinforce(England, CivilianSquad1, { ChurchSpawn.Location }, 0) + Utils.Do(churchPanicTeam, function(a) + a.Move(a.Location + CVec.New(-1,-1)) + a.Panic() + end) + end + ChurchDamaged = true +end + +SendMig = function(waypoints) + local MigEntryPath = { waypoints[1].Location, waypoints[2].Location } + local Mig1 = Reinforcements.Reinforce(USSR, { "mig" }, MigEntryPath) + if not BridgeBarrel1.IsDead then + Utils.Do(Mig1, function(mig) + mig.Attack(BridgeBarrel1) + end) + end + + Trigger.AfterDelay(DateTime.Seconds(5), function() + local Mig2 = Reinforcements.Reinforce(USSR, { "mig" }, MigEntryPath) + local Mig3 = Reinforcements.Reinforce(USSR, { "mig" }, MigEntryPath) + if not CivBarrel.IsDead then + Utils.Do(Mig2, function(mig) + mig.Attack(CivBarrel) + end) + end + if not DoomedHeli.IsDead then + Utils.Do(Mig3, function(mig) + mig.Attack(DoomedHeli) + end) + end + end) +end + +SovBaseAttack = function() + if not BaseDamaged then + local drop4 = RifleDropS.TargetParatroopers(SovBaseDrop.CenterPosition, Angle.East) + Utils.Do(drop4, function(a) + Trigger.OnPassengerExited(a, function(t, p) + IdleHunt(p) + end) + end) + + Utils.Do(SovBaseTeam, function(actor) + if not actor.IsDead then + IdleHunt(actor) + end + end) + + if Map.LobbyOption("difficulty") == "hard" then + local barracksTeam = Reinforcements.Reinforce(USSR, RaxTeam, { SovRaxSpawn.Location, SovBaseCam.Location }, 0) + Utils.Do(barracksTeam, IdleHunt) + end + end + BaseDamaged = true +end + +ExtractUnits = function(extractionUnit, pos, after) + if extractionUnit.IsDead or not extractionUnit.HasPassengers then + return + end + + extractionUnit.Move(pos) + extractionUnit.Destroy() + + Trigger.OnRemovedFromWorld(extractionUnit, after) +end + +SendExtractionHelicopter = function() + ExtractionHeli = Reinforcements.ReinforceWithTransport(Allies, ExtractionHelicopterType, nil, ExtractionPath)[1] + local exitPos = CPos.New(ExtractionPath[1].X, ExtractionPath[2].Y) + + Trigger.OnKilled(ExtractionHeli, function() USSR.MarkCompletedObjective(SovietObj) end) + Trigger.OnAllRemovedFromWorld(VIPs, function() + ExtractUnits(ExtractionHeli, exitPos, function() + Allies.MarkCompletedObjective(ProtectVIPs) + Allies.MarkCompletedObjective(ExtractStavros) + end) + end) +end + +WorldLoaded = function() + Allies = Player.GetPlayer("Allies") + USSR = Player.GetPlayer("USSR") + BadGuy = Player.GetPlayer("BadGuy") + England = Player.GetPlayer("England") + Civilians = Player.GetPlayer("GreekCivilians") + + Trigger.OnObjectiveAdded(Allies, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") + end) + + SovietObj = USSR.AddObjective("Kill Stavros.") + ProtectVIPs = Allies.AddObjective("Keep Stavros and Tanya alive.") + ExtractStavros = Allies.AddObjective("Get Stavros and Tanya to the extraction helicopter.") + + Trigger.OnObjectiveCompleted(Allies, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") + end) + Trigger.OnObjectiveFailed(Allies, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") + end) + + Trigger.OnPlayerLost(Allies, function() + Media.PlaySpeechNotification(Allies, "Lose") + end) + Trigger.OnPlayerWon(Allies, function() + Media.PlaySpeechNotification(Allies, "Win") + end) + + InsertionDrop = Actor.Create("insertiondrop", false, { Owner = Allies }) + InsertionDropHard = Actor.Create("insertiondrophard", false, { Owner = Allies }) + RifleDropA = Actor.Create("rifledrop", false, { Owner = Allies }) + RifleDropS = Actor.Create("rifledrop", false, { Owner = USSR }) + Camera.Position = LightFlare.CenterPosition + + MissionStart() + FootprintTriggers() + SetupTriggers() + Trigger.OnDamaged(Church, ChurchAttack) + OnAnyDamaged(SovBase, SovBaseAttack) +end + +OnAnyDamaged = function(actors, func) + Utils.Do(actors, function(actor) + Trigger.OnDamaged(actor, func) + end) +end diff -Nru openra-20200503/mods/ra/maps/fall-of-greece-1-personal-war/rules.yaml openra-20210321/mods/ra/maps/fall-of-greece-1-personal-war/rules.yaml --- openra-20200503/mods/ra/maps/fall-of-greece-1-personal-war/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/fall-of-greece-1-personal-war/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,98 @@ +World: + LuaScript: + Scripts: personal-war.lua + MissionData: + WinVideo: toofar.vqa + LossVideo: bmap.vqa + Briefing: With the fighting fast approaching Athens, Stavros has insisted that he be allowed to survey the damage in his own hometown in Greece.\n\nYou must escort Stavros through the town and to a nearby friendly outpost. Once you reach it, evacuate Stavros to safety.\n\nIf anything should happen, get Stavros to safety any way possible. He must be kept alive. + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Values: + normal: Normal + hard: Hard + Default: normal + +INSERTIONDROP: + ParatroopersPower: + DisplayBeacon: False + DropItems: E7, GNRL + AlwaysVisible: + +INSERTIONDROPHARD: + ParatroopersPower: + DisplayBeacon: False + DropItems: E7.noautotarget, GNRL.noautotarget + AlwaysVisible: + +RIFLEDROP: + ParatroopersPower: + DisplayBeacon: False + DropItems: E1, E1, E1, E1, E1 + AlwaysVisible: + +LST.Reinforcement: + Inherits: LST + RejectsOrders: + -Buildable: + -Selectable: + RenderSprites: + Image: lst + Interactable: + +GNRL: + Valued: + Cost: 1000 + Tooltip: + Name: Stavros + Armament: + Weapon: SilencedPPK + Passenger: + CargoType: VIP + +GNRL.noautotarget: + Inherits: GNRL + -AutoTarget: + -AutoTargetPriority@DEFAULT: + -AutoTargetPriority@ATTACKANYTHING: + AttackMove: + -AssaultMoveCondition: + RenderSprites: + Image: GNRL + +E7: + Passenger: + CargoType: VIP + +TRUK: + SpawnActorOnDeath: + Actor: healcrate + +HEALCRATE: + Crate: + Lifetime: 0 + +TRAN: + -Selectable: + RevealsShroud: + Range: 4c0 + Targetable@GROUND: + TargetTypes: GroundActor + Interactable: + Health: + HP: 5000 + Cargo: + Types: VIP + MaxWeight: 2 + +BADR.Bomber: + Aircraft: + Speed: 373 + Tooltip: + Name: Strategic Bomber + RenderSprites: + Image: U2 + +MIG: + Aircraft: + IdleBehavior: LeaveMap diff -Nru openra-20200503/mods/ra/maps/fall-of-greece-1-personal-war/weapons.yaml openra-20210321/mods/ra/maps/fall-of-greece-1-personal-war/weapons.yaml --- openra-20200503/mods/ra/maps/fall-of-greece-1-personal-war/weapons.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/fall-of-greece-1-personal-war/weapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,62 @@ +SilencedPPK: + Range: 4c0 + +ParaBomb: + ReloadDelay: 50 + ValidTargets: Ground, Water, GroundActor, WaterActor, Underwater, AirborneActor, Trees + Warhead@1Dam_impact: SpreadDamage + Spread: 1c0 + Damage: 15000 + Falloff: 1000, 368, 135, 50, 18, 7, 0 + ValidTargets: GroundActor, WaterActor, Underwater, AirborneActor, Trees + Versus: + Wood: 1000 + Concrete: 25 + DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary + Warhead@3Smu_impact: LeaveSmudge + SmudgeType: Scorch + ValidTargets: Ground, Infantry + Size: 1 + Warhead@4Eff_impact: CreateEffect + Explosions: nuke + ImpactSounds: kaboom1.aud + ImpactActors: false + ValidTargets: Ground, Water, Air + Warhead@5Dam_areanuke1: SpreadDamage + Spread: 2c0 + Damage: 6000 + Falloff: 1000, 368, 135, 50, 18, 7, 0 + Delay: 5 + ValidTargets: GroundActor, WaterActor, Underwater, AirborneActor, Trees + Versus: + Wood: 1000 + Concrete: 25 + DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary + Warhead@7Smu_areanuke1: LeaveSmudge + SmudgeType: Scorch + ValidTargets: Ground, Infantry + Size: 2 + Delay: 5 + Warhead@8Eff_areanuke1: CreateEffect + ImpactSounds: kaboom22.aud + Delay: 5 + ImpactActors: false + Warhead@9Dam_areanuke2: SpreadDamage + Spread: 3c0 + Damage: 6000 + Falloff: 1000, 368, 135, 50, 18, 7, 0 + Delay: 10 + ValidTargets: GroundActor, Trees, WaterActor, Underwater, AirborneActor + Versus: + Wood: 50 + Tree: 200 + Concrete: 25 + DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary + Warhead@12Smu_areanuke2: LeaveSmudge + SmudgeType: Scorch + ValidTargets: Ground, Infantry + Size: 3 + Delay: 10 + Warhead@13FlashEffect: FlashPaletteEffect + Duration: 20 + FlashType: Nuke Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/forgotten-plains.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/forgotten-plains.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/fortified.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/fortified.oramap differ diff -Nru openra-20200503/mods/ra/maps/fort-lonestar/fort-lonestar.lua openra-20210321/mods/ra/maps/fort-lonestar/fort-lonestar.lua --- openra-20200503/mods/ra/maps/fort-lonestar/fort-lonestar.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/fort-lonestar/fort-lonestar.lua 2021-03-21 11:10:05.000000000 +0000 @@ -146,7 +146,7 @@ if (Wave < #Waves) then if Utils.RandomInteger(1, 100) < ParaChance then - local aircraft = ParaProxy.ActivateParatroopers(Utils.Random(ParadropWaypoints).CenterPosition) + local aircraft = ParaProxy.TargetParatroopers(Utils.Random(ParadropWaypoints).CenterPosition) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) diff -Nru openra-20200503/mods/ra/maps/fort-lonestar/rules.yaml openra-20210321/mods/ra/maps/fort-lonestar/rules.yaml --- openra-20200503/mods/ra/maps/fort-lonestar/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/fort-lonestar/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -67,7 +67,7 @@ SelectionShares: 30 Proxy: powerproxy.parabombs Sequence: parabombs - HealUnitsCrateAction: + HealActorsCrateAction: SelectionShares: 30 Sound: heal2.aud Sequence: heal @@ -161,7 +161,7 @@ Transforms: IntoActor: tent Offset: 0,0 - Facing: 96 + Facing: 384 TransformSounds: placbldg.aud, build5.aud NoTransformNotification: BuildingCannotPlaceAudio RenderSprites: @@ -328,7 +328,7 @@ RevealsShroud: Range: 14c0 Turreted: - TurnSpeed: 1 + TurnSpeed: 4 Armament@PRIMARY: Recoil: 8 RecoilRecovery: 0c7 @@ -337,10 +337,10 @@ Explodes: Weapon: napalm EmptyWeapon: napalm - SelfHealing: + ChangesHealth: Step: 200 Delay: 1 - HealIfBelow: 40 + StartIfBelow: 40 powerproxy.parabombs: AirstrikePower: diff -Nru openra-20200503/mods/ra/maps/fort-lonestar/weapons.yaml openra-20210321/mods/ra/maps/fort-lonestar/weapons.yaml --- openra-20200503/mods/ra/maps/fort-lonestar/weapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/fort-lonestar/weapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -23,18 +23,18 @@ MammothTusk: ReloadDelay: 300 Range: 10c0 - ValidTargets: Ground, Air + ValidTargets: Ground, GroundActor, AirborneActor Projectile: Missile Blockable: false Speed: 128 TrailImage: smokey ContrailLength: 150 Inaccuracy: 0c853 - HorizontalRateOfTurn: 10 + HorizontalRateOfTurn: 40 RangeLimit: 12c0 Warhead@1Dam: SpreadDamage Spread: 640 - ValidTargets: Ground, Air + ValidTargets: GroundActor, AirborneActor Versus: None: 125 Wood: 110 @@ -49,7 +49,7 @@ ReloadDelay: 40 Range: 8c0 Report: aacanon3.aud - ValidTargets: Ground + ValidTargets: Ground, GroundActor Burst: 6 BurstDelays: 1 Projectile: Bullet @@ -61,7 +61,7 @@ Blockable: false Warhead: SpreadDamage Spread: 341 - ValidTargets: Ground + ValidTargets: GroundActor Versus: None: 65 Wood: 125 @@ -124,13 +124,13 @@ ReloadDelay: 10 Range: 8c0 Report: aacanon3.aud - ValidTargets: Air, Ground + ValidTargets: AirborneActor, Ground, GroundActor Projectile: Bullet Speed: 1c682 Blockable: false Warhead: SpreadDamage Spread: 213 - ValidTargets: Air, Ground + ValidTargets: AirborneActor, GroundActor Versus: None: 32 Wood: 28 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/forward-progress.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/forward-progress.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/icy-ridge.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/icy-ridge.oramap differ diff -Nru openra-20200503/mods/ra/maps/infiltration/map.yaml openra-20210321/mods/ra/maps/infiltration/map.yaml --- openra-20200503/mods/ra/maps/infiltration/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/infiltration/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -285,7 +285,7 @@ Actor59: sam Location: 47,60 Owner: Soviets - TurretFacing: 160 + TurretFacing: 640 Actor61: apwr Location: 45,49 Owner: Soviets @@ -310,7 +310,7 @@ Actor65: sam Location: 50,37 Owner: Soviets - TurretFacing: 192 + TurretFacing: 768 Actor70: spen Location: 39,71 Owner: Soviets @@ -320,7 +320,7 @@ Actor64: sam Location: 28,43 Owner: Soviets - TurretFacing: 48 + TurretFacing: 192 Actor72: spen Location: 23,76 Owner: Soviets @@ -492,7 +492,7 @@ Actor304: 3tnk Location: 106,38 Owner: Soviets - Facing: 96 + Facing: 384 Actor488: t02 Location: 110,28 Owner: Neutral @@ -583,7 +583,7 @@ Actor175: sam Location: 30,58 Owner: Soviets - TurretFacing: 96 + TurretFacing: 384 Actor181: t12 Location: 27,54 Owner: Neutral @@ -744,7 +744,7 @@ Actor229: v2rl Location: 96,19 Owner: Soviets - Facing: 64 + Facing: 256 Actor137: e1 Location: 66,34 Owner: Soviets @@ -829,7 +829,7 @@ Actor264: v2rl Location: 50,36 Owner: Soviets - Facing: 192 + Facing: 768 Actor266: 3tnk Location: 88,70 Owner: Soviets @@ -866,7 +866,7 @@ Actor272: 3tnk Location: 102,37 Owner: Soviets - Facing: 160 + Facing: 640 Actor280: t16 Location: 87,41 Owner: Neutral @@ -1215,7 +1215,7 @@ Actor328: v2rl Location: 27,37 Owner: Soviets - Facing: 64 + Facing: 256 Actor366: powr Location: 35,54 Owner: Soviets @@ -1348,7 +1348,7 @@ HijackTruck: truk.hijackable Location: 99,34 Owner: Soviets - Facing: 160 + Facing: 640 BaseGuard: e1 Location: 63,36 Owner: Soviets @@ -1496,7 +1496,7 @@ Actor415: sam Location: 77,102 Owner: Soviets - TurretFacing: 128 + TurretFacing: 512 Actor475: brl3 Location: 79,97 Owner: Soviets diff -Nru openra-20200503/mods/ra/maps/infiltration/rules.yaml openra-20210321/mods/ra/maps/infiltration/rules.yaml --- openra-20200503/mods/ra/maps/infiltration/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/infiltration/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -33,7 +33,7 @@ MISS: Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure, MissionObjective, NoAutoTarget + TargetTypes: GroundActor, C4, DetonateAttack, Structure, MissionObjective, NoAutoTarget LST.Unselectable.UnloadOnly: Inherits: LST @@ -44,9 +44,8 @@ Prerequisites: ~disabled Cargo: MaxWeight: 0 - PipCount: 0 Targetable: - TargetTypes: Ground, Water, Repair, NoAutoTarget + TargetTypes: GroundActor, Water, Repair, NoAutoTarget Interactable: SPY.Strong: @@ -80,6 +79,7 @@ TRUK.Hijackable: Inherits: TRUK + Inherits@CARGOPIPS: ^CargoPips Buildable: Prerequisites: ~disabled Mobile: @@ -87,11 +87,10 @@ Cargo: Types: Infantry MaxWeight: 5 - PipCount: 5 PassengerConditions: spy.strong: mobile Targetable: - TargetTypes: Ground, Repair, Vehicle, NoAutoTarget + TargetTypes: GroundActor, Repair, Vehicle, NoAutoTarget -Huntable: Capturable: Types: MissionObjective @@ -104,11 +103,6 @@ Voiced: VoiceSet: SpyVoice -HARV: - Harvester: - SearchFromProcRadius: 25 - SearchFromHarvesterRadius: 25 - E7: Buildable: Prerequisites: ~disabled diff -Nru openra-20200503/mods/ra/maps/intervention/intervention.lua openra-20210321/mods/ra/maps/intervention/intervention.lua --- openra-20200503/mods/ra/maps/intervention/intervention.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/intervention/intervention.lua 2021-03-21 11:10:05.000000000 +0000 @@ -72,7 +72,7 @@ ParadropSovietUnits = function() local powerproxy = Actor.Create("powerproxy.paratroopers", false, { Owner = soviets }) - local aircraft = powerproxy.ActivateParatroopers(MCVDeployLocation.CenterPosition, 256 - 53) + local aircraft = powerproxy.TargetParatroopers(MCVDeployLocation.CenterPosition, Angle.New(812)) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) diff -Nru openra-20200503/mods/ra/maps/intervention/map.yaml openra-20210321/mods/ra/maps/intervention/map.yaml --- openra-20200503/mods/ra/maps/intervention/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/intervention/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -93,15 +93,15 @@ Actor15: gun Location: 18,116 Owner: Soviets - Facing: 192 + Facing: 768 Actor16: gun Location: 19,119 Owner: Soviets - Facing: 192 + Facing: 768 Actor17: sam Location: 16,118 Owner: Soviets - Facing: 192 + Facing: 768 Actor18: t10 Location: 18,117 Owner: Neutral @@ -123,19 +123,19 @@ Actor24: gun Location: 23,110 Owner: Soviets - Facing: 92 + Facing: 368 Actor25: gun Location: 25,115 Owner: Soviets - Facing: 92 + Facing: 368 Actor26: gun Location: 24,113 Owner: Soviets - Facing: 92 + Facing: 368 Actor27: sam Location: 26,113 Owner: Soviets - Facing: 160 + Facing: 640 Actor28: tc02 Location: 26,114 Owner: Neutral @@ -163,7 +163,7 @@ Actor43: sam Location: 54,103 Owner: Soviets - Facing: 192 + Facing: 768 Actor44: tc02 Location: 51,98 Owner: Neutral @@ -182,14 +182,14 @@ Actor51: gun Location: 58,104 Owner: Soviets - Facing: 160 + Facing: 640 Actor50: tc02 Location: 112,108 Owner: Neutral Actor49: gun Location: 54,107 Owner: Soviets - Facing: 160 + Facing: 640 Actor52: tc05 Location: 113,107 Owner: Neutral @@ -214,7 +214,7 @@ Actor59: sam Location: 80,87 Owner: Soviets - Facing: 192 + Facing: 768 Actor60: tc01 Location: 84,90 Owner: Neutral @@ -275,15 +275,15 @@ Actor79: sam Location: 80,100 Owner: Soviets - Facing: 192 + Facing: 768 Actor80: gun Location: 80,106 Owner: Soviets - Facing: 160 + Facing: 640 Actor81: gun Location: 85,105 Owner: Soviets - Facing: 160 + Facing: 640 Actor209: tc05 Location: 141,47 Owner: Neutral @@ -512,7 +512,7 @@ Actor175: sam Location: 45,88 Owner: Soviets - Facing: 224 + Facing: 896 Actor173: brik Location: 45,85 Owner: Soviets @@ -631,7 +631,7 @@ Actor206: sam Location: 40,101 Owner: Soviets - Facing: 160 + Facing: 640 Actor193: t13 Location: 130,63 Owner: Neutral @@ -647,7 +647,7 @@ Actor211: sam Location: 35,111 Owner: Soviets - Facing: 160 + Facing: 640 Actor212: tc03 Location: 142,52 Owner: Neutral @@ -939,7 +939,7 @@ Actor309: sam Location: 72,77 Owner: Soviets - Facing: 192 + Facing: 768 Actor246: tc02 Location: 24,47 Owner: Neutral @@ -1227,11 +1227,11 @@ Actor407: sam Location: 77,61 Owner: Soviets - Facing: 192 + Facing: 768 Actor408: sam Location: 77,69 Owner: Soviets - Facing: 192 + Facing: 768 Actor409: brik Location: 59,59 Owner: Soviets @@ -1427,18 +1427,18 @@ Actor456: sam Location: 87,35 Owner: Soviets - Facing: 160 + Facing: 640 Actor457: sam Location: 85,26 Owner: Soviets - Facing: 160 + Facing: 640 Actor87: t11 Location: 63,31 Owner: Neutral Actor459: sam Location: 68,39 Owner: Soviets - Facing: 96 + Facing: 384 Actor460: tc05 Location: 88,33 Owner: Neutral @@ -1580,7 +1580,7 @@ Actor506: sam Location: 82,44 Owner: Soviets - Facing: 160 + Facing: 640 Actor507: t11 Location: 86,42 Owner: Neutral @@ -1656,11 +1656,11 @@ Actor531: gun Location: 68,30 Owner: Soviets - Facing: 160 + Facing: 640 Actor532: gun Location: 87,32 Owner: Soviets - Facing: 192 + Facing: 768 Actor533: gun Location: 83,24 Owner: Soviets @@ -1808,14 +1808,14 @@ Actor84: sam Location: 63,28 Owner: Soviets - Facing: 64 + Facing: 256 Actor88: t17 Location: 64,26 Owner: Neutral Actor90: sam Location: 79,53 Owner: Soviets - Facing: 160 + Facing: 640 Actor91: tc02 Location: 81,52 Owner: Neutral @@ -1831,14 +1831,14 @@ Actor482: 3tnk Location: 24,43 Owner: Soviets - Facing: 160 + Facing: 640 Actor641: 3tnk Location: 23,48 Owner: Soviets Actor642: v2rl Location: 20,45 Owner: Soviets - Facing: 160 + Facing: 640 Actor593: tc01 Location: 97,64 Owner: Neutral @@ -2040,32 +2040,32 @@ Uboat1: ss Location: 17,92 Owner: Soviets - Facing: 128 + Facing: 512 Stance: Defend Uboat2: ss Location: 20,91 Owner: Soviets - Facing: 128 + Facing: 512 Stance: Defend Uboat3: ss Location: 17,112 Owner: Soviets - Facing: 192 + Facing: 768 Stance: Defend Uboat4: ss Location: 34,120 Owner: Soviets - Facing: 160 + Facing: 640 Stance: Defend Uboat5: ss Location: 24,126 Owner: Soviets - Facing: 160 + Facing: 640 Stance: Defend Uboat6: ss Location: 29,131 Owner: Soviets - Facing: 192 + Facing: 768 Stance: Defend WarFactory: weap Location: 70,72 diff -Nru openra-20200503/mods/ra/maps/intervention/rules.yaml openra-20210321/mods/ra/maps/intervention/rules.yaml --- openra-20200503/mods/ra/maps/intervention/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/intervention/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -32,7 +32,7 @@ Name: Soviet Air Force HQ Capturable: Types: building - ValidStances: Enemy + ValidRelationships: Enemy CaptureManager: TENT: @@ -80,7 +80,7 @@ AmmoPool: Ammo: 2 Aircraft: - IdleBehavior: LeaveMap + IdleBehavior: LeaveMapAtClosestEdge HELI: Buildable: Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/jungle-law.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/jungle-law.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/marigold-town.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/marigold-town.oramap differ diff -Nru openra-20200503/mods/ra/maps/monster-tank-madness/map.yaml openra-20210321/mods/ra/maps/monster-tank-madness/map.yaml --- openra-20200503/mods/ra/maps/monster-tank-madness/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/monster-tank-madness/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1374,17 +1374,17 @@ Location: 45,25 Owner: Outpost Health: 31 - Facing: 96 + Facing: 384 Actor430: gun Location: 29,30 Owner: Outpost Health: 19 - Facing: 32 + Facing: 128 Actor431: gun Location: 38,29 Owner: Outpost Health: 39 - Facing: 96 + Facing: 384 Actor432: tent Location: 33,22 Owner: Outpost @@ -1816,26 +1816,26 @@ Actor588: v2rl Location: 91,75 Owner: USSR - Facing: 32 + Facing: 128 Actor589: v2rl Location: 91,89 Owner: USSR - Facing: 32 + Facing: 128 Actor590: badtruk Location: 89,34 Owner: BadGuy - Facing: 32 + Facing: 128 Actor591: badtruk Location: 90,35 Owner: BadGuy - Facing: 96 + Facing: 384 Actor592: badtruk Location: 89,36 Owner: BadGuy Actor593: v2rl Location: 32,48 Owner: BadGuy - Facing: 160 + Facing: 640 Actor594: 3tnk Location: 85,86 Owner: USSR @@ -1854,24 +1854,24 @@ Actor599: bad3tnk Location: 76,27 Owner: BadGuy - Facing: 224 + Facing: 896 Actor600: dtrk Location: 86,83 Owner: USSR Actor601: e1 Location: 24,71 Owner: BadGuy - Facing: 96 + Facing: 384 SubCell: 2 Actor602: e1 Location: 25,71 Owner: BadGuy - Facing: 96 + Facing: 384 SubCell: 2 Actor603: e1 Location: 28,72 Owner: BadGuy - Facing: 192 + Facing: 768 SubCell: 1 Actor604: e1 Location: 29,72 @@ -1880,12 +1880,12 @@ Actor605: e2 Location: 29,70 Owner: BadGuy - Facing: 160 + Facing: 640 SubCell: 4 Actor606: e2 Location: 24,69 Owner: BadGuy - Facing: 160 + Facing: 640 SubCell: 4 Actor607: e1 Location: 81,88 @@ -1934,7 +1934,7 @@ Actor618: e1 Location: 61,23 Owner: BadGuy - Facing: 160 + Facing: 640 SubCell: 0 Actor619: e1 Location: 74,26 @@ -1947,27 +1947,27 @@ Actor621: e2 Location: 78,19 Owner: BadGuy - Facing: 192 + Facing: 768 SubCell: 0 Actor622: e2 Location: 79,19 Owner: BadGuy - Facing: 192 + Facing: 768 SubCell: 3 Actor623: dog Location: 61,24 Owner: BadGuy - Facing: 160 + Facing: 640 SubCell: 2 Actor624: dog Location: 60,24 Owner: BadGuy - Facing: 160 + Facing: 640 SubCell: 2 Actor625: dog Location: 74,25 Owner: BadGuy - Facing: 224 + Facing: 896 SubCell: 2 Actor507: v11.exploding Location: 97,56 @@ -2026,15 +2026,15 @@ stnk1: 5tnk Location: 89,59 Owner: Turkey - TurretFacing: 192 + TurretFacing: 768 stnk2: 5tnk Location: 77,57 Owner: Turkey - TurretFacing: 92 + TurretFacing: 368 stnk3: 5tnk Location: 94,53 Owner: Turkey - TurretFacing: 192 + TurretFacing: 768 DemitriLZ: waypoint Location: 30,21 Owner: Neutral diff -Nru openra-20200503/mods/ra/maps/monster-tank-madness/monster-tank-madness.lua openra-20210321/mods/ra/maps/monster-tank-madness/monster-tank-madness.lua --- openra-20200503/mods/ra/maps/monster-tank-madness/monster-tank-madness.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/monster-tank-madness/monster-tank-madness.lua 2021-03-21 11:10:05.000000000 +0000 @@ -121,7 +121,11 @@ if unit.Type == "e6" then Engineer = unit Trigger.OnKilled(unit, LandingPossible) - end + elseif unit.Type == "thf" then + Trigger.OnKilled(unit, function() + player.MarkFailedObjective(StealMoney) + end) + end end) end) end) @@ -297,6 +301,7 @@ end) EliminateSuperTanks = player.AddPrimaryObjective("Eliminate these super tanks.") + StealMoney = player.AddPrimaryObjective("Steal money from the nearby outpost with the Thief.") CrossRiver = player.AddPrimaryObjective("Secure transport to the mainland.") FindOutpost = player.AddPrimaryObjective("Find our outpost and start repairs on it.") RescueCivilians = player.AddSecondaryObjective("Evacuate all civilians from the hospital.") @@ -377,6 +382,17 @@ end end) + Trigger.OnInfiltrated(USSROutpostSilo, function() + MoneyStolen = true + player.MarkCompletedObjective(StealMoney) + end) + + Trigger.OnKilledOrCaptured(USSROutpostSilo, function() + if not MoneyStolen then + player.MarkFailedObjective(StealMoney) + end + end) + beachReached = false Trigger.OnEnteredFootprint(BeachTrigger, function(a, id) if not beachReached and a.Owner == player then diff -Nru openra-20200503/mods/ra/maps/monster-tank-madness/rules.yaml openra-20210321/mods/ra/maps/monster-tank-madness/rules.yaml --- openra-20200503/mods/ra/maps/monster-tank-madness/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/monster-tank-madness/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -26,9 +26,6 @@ Explodes: Weapon: BarrelExplode EmptyWeapon: BarrelExplode - -SpawnActorOnDeath@1: - -SpawnActorOnDeath@2: - -SpawnActorOnDeath@3: V01.exploding: Inherits: ^ExplodingCivBuilding @@ -137,11 +134,11 @@ RevealsShroud@friendly: Range: 6c0 RequiresCondition: friendly - ValidStances: Ally, Enemy + ValidRelationships: Ally, Enemy ExternalCondition@friendly: Condition: friendly Turreted: - TurnSpeed: 1 + TurnSpeed: 4 Armament@PRIMARY: Weapon: SuperTankPrimary LocalOffset: 900,180,340, 900,-180,340 @@ -163,10 +160,10 @@ EmptyWeapon: MiniNuke SpawnActorOnDeath: Actor: 5TNK.Husk - SelfHealing: + ChangesHealth: Step: 100 Delay: 1 - HealIfBelow: 100 + StartIfBelow: 100 DamageCooldown: 150 Selectable: Bounds: 44,38,0,-4 @@ -195,7 +192,7 @@ Image: DOME -InfiltrateForExploration: Targetable: - TargetTypes: Ground, Structure, C4, DetonateAttack, MissionObjective + TargetTypes: GroundActor, Structure, C4, DetonateAttack, MissionObjective ProvidesPrerequisite: Prerequisite: dome diff -Nru openra-20200503/mods/ra/maps/monster-tank-madness/voices.yaml openra-20210321/mods/ra/maps/monster-tank-madness/voices.yaml --- openra-20200503/mods/ra/maps/monster-tank-madness/voices.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/monster-tank-madness/voices.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,5 +1,5 @@ -DemitriVoice: - Variants: +DemitriVoice: + Variants: allies: .r01,.r03 england: .r01,.r03 france: .r01,.r03 @@ -7,10 +7,10 @@ soviet: .r01,.r03 russia: .r01,.r03 ukraine: .r01,.r03 - Voices: + Voices: Select: await1,ready,report1,yessir1 Action: ackno,affirm1,noprob,overout,ritaway,roger,ugotit Die: dedman1,dedman2,dedman3,dedman4,dedman5,dedman7,dedman8 Burned: dedman10 Zapped: dedman6 - DisableVariants: Die, Burned, Zapped \ No newline at end of file + DisableVariants: Die, Burned, Zapped Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/north-by-northwest.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/north-by-northwest.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/northwestpassage.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/northwestpassage.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/oil-spill/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/oil-spill/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/oil-spill/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/oil-spill/map.png differ diff -Nru openra-20200503/mods/ra/maps/oil-spill/map.yaml openra-20210321/mods/ra/maps/oil-spill/map.yaml --- openra-20200503/mods/ra/maps/oil-spill/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/oil-spill/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,309 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: Oil Spill + +Author: Super Newbie + +Tileset: DESERT + +MapSize: 120,120 + +Bounds: 1,1,118,118 + +Visibility: Lobby + +Categories: Minigame + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: england + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Faction: england + Enemies: Multi0, Multi1, Multi2, Multi3 + PlayerReference@Multi0: + Name: Multi0 + Playable: True + AllowBots: False + LockFaction: True + Faction: allies + Enemies: Creeps + PlayerReference@Multi1: + Name: Multi1 + Playable: True + AllowBots: False + LockFaction: True + Faction: allies + Enemies: Creeps + PlayerReference@Multi2: + Name: Multi2 + Playable: True + AllowBots: False + LockFaction: True + Faction: allies + Enemies: Creeps + PlayerReference@Multi3: + Name: Multi3 + Playable: True + AllowBots: False + LockFaction: True + Faction: allies + Enemies: Creeps + +Actors: + Actor1: rock1 + Owner: Neutral + Location: 112,21 + Actor2: tc01 + Owner: Neutral + Location: 50,4 + Actor3: tc01 + Owner: Neutral + Location: 117,23 + Actor4: tc01 + Owner: Neutral + Location: 115,31 + Actor5: tc01 + Owner: Neutral + Location: 113,13 + Actor6: tc01 + Owner: Neutral + Location: 108,3 + Actor7: v37 + Owner: Neutral + Location: 66,3 + Actor8: v30 + Owner: Neutral + Location: 69,2 + Actor9: v31 + Owner: Neutral + Location: 48,3 + Actor10: v24 + Owner: Neutral + Location: 46,3 + Actor12: v24 + Owner: Neutral + Location: 117,102 + Actor13: tc01 + Owner: Neutral + Location: 94,116 + Actor14: tc01 + Owner: Neutral + Location: 102,111 + Actor15: t08 + Owner: Neutral + Location: 105,4 + Actor18: rock6 + Owner: Neutral + Location: 15,114 + Actor19: rock7 + Owner: Neutral + Location: 41,112 + Actor20: rock6 + Owner: Neutral + Location: 74,113 + Actor21: tc01 + Owner: Neutral + Location: 31,113 + Actor22: tc01 + Owner: Neutral + Location: 62,113 + Actor23: t08 + Owner: Neutral + Location: 74,112 + Actor24: v25 + Owner: Neutral + Location: 116,99 + Actor26: tc01 + Owner: Neutral + Location: 3,30 + Actor25: tc01 + Owner: Neutral + Location: 4,36 + Actor27: rock2 + Owner: Neutral + Location: 5,81 + Actor28: v21 + Owner: Neutral + Location: 3,88 + Actor29: v30 + Owner: Neutral + Location: 2,91 + Actor30: t08 + Owner: Neutral + Location: 5,41 + Actor31: tc01 + Owner: Neutral + Location: 72,34 + Actor32: t08 + Owner: Neutral + Location: 71,34 + Actor33: tc01 + Owner: Neutral + Location: 82,44 + Actor36: oilb + Owner: Neutral + Location: 51,51 + Actor37: oilb + Owner: Neutral + Location: 67,51 + Actor38: oilb + Owner: Neutral + Location: 51,67 + Actor39: oilb + Owner: Neutral + Location: 67,67 + Actor44: oilb + Owner: Neutral + Location: 46,82 + Actor45: oilb + Owner: Neutral + Location: 36,72 + Actor46: oilb + Owner: Neutral + Location: 72,82 + Actor47: oilb + Owner: Neutral + Location: 36,46 + Actor48: oilb + Owner: Neutral + Location: 46,36 + Actor49: oilb + Owner: Neutral + Location: 82,46 + Actor50: oilb + Owner: Neutral + Location: 72,36 + Actor53: oilb + Owner: Neutral + Location: 59,34 + Actor54: oilb + Owner: Neutral + Location: 34,59 + Actor55: oilb + Owner: Neutral + Location: 59,84 + Actor56: oilb + Owner: Neutral + Location: 84,59 + OilBottomLeft2: oilb + Location: 18,96 + Owner: Neutral + OilBottomLeft1: oilb + Location: 22,100 + Owner: Neutral + OilBottomRight2: oilb + Owner: Neutral + Location: 96,100 + OilBottomRight1: oilb + Owner: Neutral + Location: 100,96 + OilTopLeft2: oilb + Owner: Neutral + Location: 22,18 + OilTopLeft1: oilb + Owner: Neutral + Location: 18,22 + OilTopRight2: oilb + Location: 100,22 + Owner: Neutral + OilTopRight1: oilb + Location: 96,18 + Owner: Neutral + Actor65: fcom + Owner: Neutral + Location: 48,96 + Actor69: fcom + Owner: Neutral + Location: 70,96 + Actor70: fcom + Owner: Neutral + Location: 22,70 + Actor72: fcom + Owner: Neutral + Location: 22,48 + Actor73: fcom + Owner: Neutral + Location: 48,22 + Actor71: fcom + Owner: Neutral + Location: 70,22 + Actor74: fcom + Owner: Neutral + Location: 96,48 + Actor75: fcom + Owner: Neutral + Location: 96,70 + Actor77: oilb + Owner: Neutral + Location: 82,72 + Actor80: oilb + Owner: Neutral + Location: 46,20 + Actor81: oilb + Owner: Neutral + Location: 72,20 + Actor82: oilb + Owner: Neutral + Location: 46,98 + Actor83: oilb + Owner: Neutral + Location: 72,98 + Actor84: oilb + Owner: Neutral + Location: 20,72 + Actor85: oilb + Owner: Neutral + Location: 20,46 + Actor86: oilb + Owner: Neutral + Location: 98,46 + Actor87: oilb + Owner: Neutral + Location: 98,72 + OilTopLeft3: oilb + Owner: Neutral + Location: 29,29 + OilBottomLeft3: oilb + Location: 29,89 + Owner: Neutral + OilTopRight3: oilb + Location: 89,29 + Owner: Neutral + OilBottomRight3: oilb + Owner: Neutral + Location: 89,89 + Spawn0: mpspawn + Owner: Neutral + Location: 31,31 + Spawn1: mpspawn + Owner: Neutral + Location: 87,31 + Spawn2: mpspawn + Owner: Neutral + Location: 31,87 + Spawn3: mpspawn + Owner: Neutral + Location: 87,87 + FCOMTopLeft: fcom + Owner: Neutral + Location: 31,31 + FCOMTopRight: fcom + Owner: Neutral + Location: 87,31 + FCOMBottomLeft: fcom + Owner: Neutral + Location: 31,87 + FCOMBottomRight: fcom + Owner: Neutral + Location: 87,87 + +Rules: rules.yaml + +Sequences: sequences.yaml diff -Nru openra-20200503/mods/ra/maps/oil-spill/oil-spill.lua openra-20210321/mods/ra/maps/oil-spill/oil-spill.lua --- openra-20200503/mods/ra/maps/oil-spill/oil-spill.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/oil-spill/oil-spill.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,27 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] + +SpawnBuildings = +{ + { FCOMTopLeft, OilTopLeft1, OilTopLeft2, OilTopLeft3 }, + { FCOMTopRight, OilTopRight1, OilTopRight2, OilTopRight3 }, + { FCOMBottomLeft, OilBottomLeft1, OilBottomLeft2, OilBottomLeft3 }, + { FCOMBottomRight, OilBottomRight1, OilBottomRight2, OilBottomRight3 }, +} + +WorldLoaded = function() + for i = 0, 4 do + local player = Player.GetPlayer("Multi" .. i) + if player then + Utils.Do(SpawnBuildings[player.Spawn], function(actor) + actor.Owner = player + end) + end + end +end diff -Nru openra-20200503/mods/ra/maps/oil-spill/rules.yaml openra-20210321/mods/ra/maps/oil-spill/rules.yaml --- openra-20200503/mods/ra/maps/oil-spill/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/oil-spill/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,215 @@ +World: + LuaScript: + Scripts: oil-spill.lua + SpawnMPUnits: + DropdownVisible: False + MPStartUnits@mcvonly: + BaseActor: fcom + +FCOM: + MustBeDestroyed: + RequiredForShortGame: true + Power: + Amount: 50 + Health: + HP: 110000 + Production: + Produces: Building, Defense + RepairableBuilding: + RepairStep: 700 + PlayerExperience: 25 + RepairingNotification: Repairing + WithBuildingRepairDecoration: + Image: allyrepair + Sequence: repair + Position: Center + Palette: player + IsPlayerPalette: True + ProductionBar@Building: + ProductionType: Building + ProductionBar@Defense: + ProductionType: Defense + Color: 8A8A8A + BaseBuilding: + ProvidesPrerequisite@buildingname: + +OILB: + CashTrickler: + Interval: 250 + Amount: 100 + SpawnActorOnDeath: + Actor: OILB.Husk + OwnerType: InternalName + +OILB.Husk: + Inherits: ^TechBuilding + Inherits@shape: ^2x2Shape + Selectable: + Priority: 0 + Bounds: 48,48 + CapturableProgressBar: + CapturableProgressBlink: + Building: + Footprint: xx xx + Dimensions: 2,2 + Tooltip: + Name: Husk (Oil Derrick) + CaptureManager: + Capturable: + Types: building-husk + TransformOnCapture: + IntoActor: OILB + ForceHealthPercentage: 50 + Targetable: + TargetTypes: building-husk + +E6: + Captures@husk: + RequiresCondition: !global-reusable-engineers + CaptureTypes: building-husk + PlayerExperience: 25 + CaptureDelay: 200 + EnterCursor: goldwrench + Captures@husk-reusable: + RequiresCondition: global-reusable-engineers + CaptureTypes: building-husk + PlayerExperience: 25 + CaptureDelay: 375 + EnterCursor: goldwrench + ConsumedByCapture: False + +WEAP: + Buildable: + Prerequisites: ~disabled + +PROC: + Buildable: + Prerequisites: ~disabled + +SILO: + Buildable: + Prerequisites: ~disabled + +BRIK: + Buildable: + Prerequisites: ~disabled + +POWR: + Power: + Amount: 125 + -SpawnActorsOnSell: + -MustBeDestroyed: + +APWR: + Power: + Amount: 250 + -SpawnActorsOnSell: + -MustBeDestroyed: + +TENT: + Buildable: + Prerequisites: fcom + -SpawnActorsOnSell: + -MustBeDestroyed: + +DOME: + Buildable: + Prerequisites: anypower + -SpawnActorsOnSell: + -MustBeDestroyed: + +SYRD: + Buildable: + Prerequisites: fcom + -MustBeDestroyed: + +SPEN: + Buildable: + Prerequisites: fcom + -MustBeDestroyed: + +STEK: + Buildable: + Prerequisites: dome, tent + -SpawnActorsOnSell: + -MustBeDestroyed: + +AFLD: + Buildable: + Prerequisites: dome + -SpawnActorsOnSell: + -MustBeDestroyed: + AirstrikePower@spyplane: + Prerequisites: afld + AirstrikePower@parabombs: + Prerequisites: afld + +HPAD: + Buildable: + Prerequisites: dome + -SpawnActorsOnSell: + -MustBeDestroyed: + +FIX: + Buildable: + Prerequisites: dome + -SpawnActorsOnSell: + -MustBeDestroyed: + +IRON: + Buildable: + Prerequisites: stek + +PDOX: + Buildable: + Prerequisites: atek + ChronoshiftPower@chronoshift: + -Prerequisites: + -ChronoshiftPower@advancedchronoshift: + +ATEK: + Buildable: + Prerequisites: dome, tent + -SpawnActorsOnSell: + -MustBeDestroyed: + +FTUR: + Buildable: + Prerequisites: tent + -SpawnActorsOnSell: + +GUN: + Buildable: + Prerequisites: tent + -SpawnActorsOnSell: + +GAP: + Buildable: + Prerequisites: atek + -SpawnActorsOnSell: + +AGUN: + Buildable: + Prerequisites: dome + -SpawnActorsOnSell: + +TSLA: + Buildable: + Prerequisites: dome + -SpawnActorsOnSell: + +MECH: + Buildable: + Prerequisites: dome + +E1: + Buildable: + Prerequisites: ~disabled + +E3: + Buildable: + Prerequisites: ~disabled + +E7: + Buildable: + Prerequisites: ~disabled diff -Nru openra-20200503/mods/ra/maps/oil-spill/sequences.yaml openra-20210321/mods/ra/maps/oil-spill/sequences.yaml --- openra-20200503/mods/ra/maps/oil-spill/sequences.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/oil-spill/sequences.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,4 @@ +oilb.husk: oilb + idle: oilb + Start: 1 + Offset: 0,-6 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/operation-goldmine.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/operation-goldmine.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/opposite-force.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/opposite-force.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/ore-gardens.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/ore-gardens.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/outdoor-trails.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/outdoor-trails.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/pitfight.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/pitfight.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/poland-raid/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/poland-raid/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/poland-raid/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/poland-raid/map.png differ diff -Nru openra-20200503/mods/ra/maps/poland-raid/map.yaml openra-20210321/mods/ra/maps/poland-raid/map.yaml --- openra-20200503/mods/ra/maps/poland-raid/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/poland-raid/map.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,796 +0,0 @@ -MapFormat: 11 - -RequiresMod: ra - -Title: Poland Raid - -Author: s1w - -Tileset: TEMPERAT - -MapSize: 128,128 - -Bounds: 16,16,96,96 - -Visibility: Lobby - -Categories: Conquest - -Players: - PlayerReference@Neutral: - Name: Neutral - OwnsWorld: True - NonCombatant: True - Faction: allies - PlayerReference@Multi0: - Name: Multi0 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Creeps: - Name: Creeps - NonCombatant: True - Faction: allies - Enemies: Multi0, Multi1, Multi2, Multi3, Multi4 - PlayerReference@Multi1: - Name: Multi1 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi2: - Name: Multi2 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi3: - Name: Multi3 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi4: - Name: Multi4 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - -Actors: - Actor1: v16 - Location: 26,55 - Owner: Neutral - Actor2: v18 - Location: 27,54 - Owner: Neutral - Actor14: tc05 - Location: 94,32 - Owner: Neutral - Actor15: tc05 - Location: 95,35 - Owner: Neutral - Actor16: tc02 - Location: 33,20 - Owner: Neutral - Actor17: tc04 - Location: 32,17 - Owner: Neutral - Actor18: tc05 - Location: 34,18 - Owner: Neutral - Actor19: tc05 - Location: 86,53 - Owner: Neutral - Actor20: tc02 - Location: 86,34 - Owner: Neutral - Actor21: tc02 - Location: 55,35 - Owner: Neutral - Actor22: t17 - Location: 58,36 - Owner: Neutral - Actor23: t07 - Location: 16,89 - Owner: Neutral - Actor24: tc04 - Location: 19,90 - Owner: Neutral - Actor25: tc04 - Location: 17,51 - Owner: Neutral - Actor26: tc04 - Location: 22,52 - Owner: Neutral - Actor27: tc04 - Location: 25,49 - Owner: Neutral - Actor28: tc04 - Location: 18,56 - Owner: Neutral - Actor29: tc05 - Location: 18,53 - Owner: Neutral - Actor30: tc05 - Location: 23,47 - Owner: Neutral - Actor31: tc03 - Location: 16,55 - Owner: Neutral - Actor32: tc03 - Location: 21,55 - Owner: Neutral - Actor34: tc01 - Location: 21,49 - Owner: Neutral - Actor35: t17 - Location: 26,52 - Owner: Neutral - Actor36: t17 - Location: 17,56 - Owner: Neutral - Actor37: t14 - Location: 23,51 - Owner: Neutral - Actor38: t14 - Location: 16,53 - Owner: Neutral - Actor39: tc04 - Location: 29,109 - Owner: Neutral - Actor41: tc01 - Location: 53,98 - Owner: Neutral - Actor42: tc04 - Location: 37,86 - Owner: Neutral - Actor43: tc02 - Location: 16,83 - Owner: Neutral - Actor44: tc05 - Location: 40,109 - Owner: Neutral - Actor45: tc04 - Location: 30,106 - Owner: Neutral - Actor46: tc04 - Location: 27,107 - Owner: Neutral - Actor47: tc02 - Location: 34,108 - Owner: Neutral - Actor48: tc02 - Location: 32,108 - Owner: Neutral - Actor49: tc02 - Location: 32,110 - Owner: Neutral - Actor50: t03 - Location: 33,106 - Owner: Neutral - Actor51: t03 - Location: 30,108 - Owner: Neutral - Actor52: t16 - Location: 41,95 - Owner: Neutral - Actor53: tc05 - Location: 109,109 - Owner: Neutral - Actor54: tc05 - Location: 37,109 - Owner: Neutral - Actor55: tc01 - Location: 35,109 - Owner: Neutral - Actor62: tc01 - Location: 57,37 - Owner: Neutral - Actor63: tc03 - Location: 59,37 - Owner: Neutral - Actor64: tc03 - Location: 53,35 - Owner: Neutral - Actor66: tc02 - Location: 41,51 - Owner: Neutral - Actor67: tc01 - Location: 97,32 - Owner: Neutral - Actor68: tc01 - Location: 97,33 - Owner: Neutral - Actor69: tc03 - Location: 98,31 - Owner: Neutral - Actor70: tc02 - Location: 77,88 - Owner: Neutral - Actor71: tc04 - Location: 103,73 - Owner: Neutral - Actor72: t12 - Location: 102,74 - Owner: Neutral - Actor73: t03 - Location: 99,74 - Owner: Neutral - Actor74: t08 - Location: 84,90 - Owner: Neutral - Actor76: tc04 - Location: 94,75 - Owner: Neutral - Actor77: tc05 - Location: 91,76 - Owner: Neutral - Actor79: tc03 - Location: 85,76 - Owner: Neutral - Actor81: tc01 - Location: 71,88 - Owner: Neutral - Actor82: tc01 - Location: 77,99 - Owner: Neutral - Actor83: t07 - Location: 26,89 - Owner: Neutral - Actor84: t08 - Location: 23,91 - Owner: Neutral - Actor85: v12 - Location: 41,94 - Owner: Neutral - Actor88: t11 - Location: 38,32 - Owner: Neutral - Actor89: t08 - Location: 95,44 - Owner: Neutral - Actor90: t12 - Location: 23,48 - Owner: Neutral - Actor94: t16 - Location: 29,106 - Owner: Neutral - Actor95: tc04 - Location: 54,74 - Owner: Neutral - Actor96: tc05 - Location: 48,72 - Owner: Neutral - Actor98: t12 - Location: 47,72 - Owner: Neutral - Actor100: tc02 - Location: 39,78 - Owner: Neutral - Actor101: tc02 - Location: 33,90 - Owner: Neutral - Actor102: tc03 - Location: 41,76 - Owner: Neutral - Actor103: t06 - Location: 47,73 - Owner: Neutral - Actor104: t08 - Location: 33,78 - Owner: Neutral - Actor105: t02 - Location: 32,89 - Owner: Neutral - Actor107: t07 - Location: 28,89 - Owner: Neutral - Actor108: tc04 - Location: 34,75 - Owner: Neutral - Actor109: t16 - Location: 35,74 - Owner: Neutral - Actor110: tc02 - Location: 38,73 - Owner: Neutral - Actor111: t11 - Location: 37,74 - Owner: Neutral - Actor112: t11 - Location: 16,84 - Owner: Neutral - Actor113: t05 - Location: 37,78 - Owner: Neutral - Actor114: t17 - Location: 71,43 - Owner: Neutral - Actor115: tc01 - Location: 76,32 - Owner: Neutral - Actor116: t16 - Location: 75,31 - Owner: Neutral - Actor117: t16 - Location: 87,48 - Owner: Neutral - Actor118: t17 - Location: 85,44 - Owner: Neutral - Actor119: t11 - Location: 79,46 - Owner: Neutral - Actor120: t08 - Location: 72,40 - Owner: Neutral - Actor121: t02 - Location: 69,21 - Owner: Neutral - Actor122: t08 - Location: 70,22 - Owner: Neutral - Actor123: tc01 - Location: 66,23 - Owner: Neutral - Actor124: t16 - Location: 66,21 - Owner: Neutral - Actor125: t05 - Location: 69,18 - Owner: Neutral - Actor126: t13 - Location: 66,18 - Owner: Neutral - Actor127: t01 - Location: 68,21 - Owner: Neutral - Actor0: tc01 - Location: 94,24 - Owner: Neutral - Actor132: tc04 - Location: 63,18 - Owner: Neutral - Actor133: tc04 - Location: 40,49 - Owner: Neutral - Actor138: tc01 - Location: 38,50 - Owner: Neutral - Actor176: t16 - Location: 100,75 - Owner: Neutral - Actor137: tc01 - Location: 42,96 - Owner: Neutral - Actor190: t05 - Location: 28,50 - Owner: Neutral - Actor139: tc01 - Location: 49,32 - Owner: Neutral - Actor140: t05 - Location: 48,33 - Owner: Neutral - Actor141: t01 - Location: 46,35 - Owner: Neutral - Actor144: tc01 - Location: 65,35 - Owner: Neutral - Actor145: tc02 - Location: 65,37 - Owner: Neutral - Actor146: t08 - Location: 56,37 - Owner: Neutral - Actor147: tc05 - Location: 53,32 - Owner: Neutral - Actor148: tc01 - Location: 56,33 - Owner: Neutral - Actor149: t12 - Location: 57,34 - Owner: Neutral - Actor150: tc04 - Location: 62,28 - Owner: Neutral - Actor151: tc04 - Location: 59,34 - Owner: Neutral - Actor152: t07 - Location: 61,28 - Owner: Neutral - Actor153: t05 - Location: 60,27 - Owner: Neutral - Actor154: tc01 - Location: 42,34 - Owner: Neutral - Actor155: t07 - Location: 43,33 - Owner: Neutral - Actor156: t08 - Location: 44,34 - Owner: Neutral - Actor157: t16 - Location: 41,34 - Owner: Neutral - Actor159: t11 - Location: 79,29 - Owner: Neutral - Actor8: t06 - Location: 89,30 - Owner: Neutral - Actor128: t06 - Location: 95,25 - Owner: Neutral - Actor164: t08 - Location: 57,53 - Owner: Neutral - Actor165: t08 - Location: 30,89 - Owner: Neutral - Actor166: tc01 - Location: 28,88 - Owner: Neutral - Actor167: t11 - Location: 26,88 - Owner: Neutral - Actor168: t07 - Location: 55,99 - Owner: Neutral - Actor169: t13 - Location: 20,86 - Owner: Neutral - Actor170: t11 - Location: 33,86 - Owner: Neutral - Actor171: tc05 - Location: 16,90 - Owner: Neutral - Actor172: tc02 - Location: 22,89 - Owner: Neutral - Actor173: t02 - Location: 17,69 - Owner: Neutral - Actor174: t11 - Location: 29,72 - Owner: Neutral - Actor175: t11 - Location: 86,95 - Owner: Neutral - Actor177: tc01 - Location: 36,16 - Owner: Neutral - Actor178: tc02 - Location: 33,16 - Owner: Neutral - Actor179: t15 - Location: 31,16 - Owner: Neutral - Actor180: t11 - Location: 54,19 - Owner: Neutral - Actor186: tc04 - Location: 109,77 - Owner: Neutral - Actor187: tc01 - Location: 105,72 - Owner: Neutral - Actor188: t10 - Location: 107,73 - Owner: Neutral - Actor191: tc03 - Location: 27,110 - Owner: Neutral - Actor192: t08 - Location: 24,51 - Owner: Neutral - Actor193: t08 - Location: 21,51 - Owner: Neutral - Actor194: t08 - Location: 22,49 - Owner: Neutral - Actor134: tc04 - Location: 32,50 - Owner: Neutral - Actor198: tc04 - Location: 18,71 - Owner: Neutral - Actor199: t16 - Location: 16,70 - Owner: Neutral - Actor200: tc02 - Location: 20,74 - Owner: Neutral - Actor201: tc05 - Location: 17,77 - Owner: Neutral - Actor202: tc03 - Location: 19,73 - Owner: Neutral - Actor203: tc05 - Location: 16,67 - Owner: Neutral - Actor204: t12 - Location: 19,66 - Owner: Neutral - Actor205: t11 - Location: 107,83 - Owner: Neutral - Actor206: t05 - Location: 108,110 - Owner: Neutral - Actor207: t15 - Location: 65,59 - Owner: Neutral - Actor208: tc03 - Location: 57,64 - Owner: Neutral - Actor209: t17 - Location: 63,68 - Owner: Neutral - Actor210: t16 - Location: 68,70 - Owner: Neutral - Actor211: tc04 - Location: 62,66 - Owner: Neutral - Actor213: t16 - Location: 21,46 - Owner: Neutral - Actor214: t17 - Location: 20,48 - Owner: Neutral - Actor215: t08 - Location: 25,38 - Owner: Neutral - Actor216: t08 - Location: 21,58 - Owner: Neutral - Actor197: tc02 - Location: 69,66 - Owner: Neutral - Actor219: tc01 - Location: 72,67 - Owner: Neutral - Actor224: tc01 - Location: 87,76 - Owner: Neutral - Actor225: oilb - Location: 68,68 - Owner: Neutral - Actor99: brl3 - Location: 59,64 - Owner: Neutral - Actor227: barl - Location: 67,70 - Owner: Neutral - Actor228: brl3 - Location: 66,68 - Owner: Neutral - Actor226: oilb - Location: 59,62 - Owner: Neutral - Actor230: barl - Location: 60,65 - Owner: Neutral - Actor231: v15 - Location: 66,70 - Owner: Neutral - Actor232: dog - Location: 63,65 - Owner: Creeps - Actor233: oilb - Location: 23,34 - Owner: Neutral - Actor229: barl - Location: 61,65 - Owner: Neutral - Actor235: brl3 - Location: 26,36 - Owner: Neutral - Actor33: v07 - Location: 61,63 - Owner: Neutral - Actor234: t05 - Location: 27,84 - Owner: Neutral - Actor218: t05 - Location: 71,67 - Owner: Neutral - Actor217: t16 - Location: 21,34 - Owner: Neutral - Actor238: t08 - Location: 16,79 - Owner: Neutral - Actor239: t02 - Location: 81,77 - Owner: Neutral - Actor136: t16 - Location: 61,102 - Owner: Neutral - Actor185: fenc - Location: 49,84 - Owner: Neutral - Actor3: t08 - Location: 53,75 - Owner: Neutral - Actor78: t16 - Location: 111,42 - Owner: Neutral - Actor61: tc01 - Location: 109,23 - Owner: Neutral - Actor161: t08 - Location: 107,23 - Owner: Neutral - Actor162: t07 - Location: 98,28 - Owner: Neutral - Actor221: t08 - Location: 91,86 - Owner: Neutral - Actor222: mine - Owner: Neutral - Location: 109,46 - Actor237: mine - Owner: Neutral - Location: 108,49 - Actor241: mine - Owner: Neutral - Location: 86,27 - Actor242: mine - Owner: Neutral - Location: 82,22 - Actor243: mine - Owner: Neutral - Location: 79,25 - Actor244: mine - Owner: Neutral - Location: 74,24 - Actor245: mine - Owner: Neutral - Location: 92,17 - Actor246: mine - Owner: Neutral - Location: 60,17 - Actor247: mine - Owner: Neutral - Location: 62,21 - Actor248: mine - Owner: Neutral - Location: 42,31 - Actor249: mine - Owner: Neutral - Location: 37,29 - Actor250: mine - Owner: Neutral - Location: 65,46 - Actor251: mine - Owner: Neutral - Location: 60,45 - Actor252: mine - Owner: Neutral - Location: 59,49 - Actor253: mine - Owner: Neutral - Location: 78,52 - Actor254: mine - Owner: Neutral - Location: 40,62 - Actor255: mine - Owner: Neutral - Location: 22,83 - Actor256: mine - Owner: Neutral - Location: 27,82 - Actor257: mine - Owner: Neutral - Location: 22,93 - Actor258: mine - Owner: Neutral - Location: 29,92 - Actor259: mine - Owner: Neutral - Location: 50,78 - Actor260: mine - Owner: Neutral - Location: 52,84 - Actor261: mine - Owner: Neutral - Location: 57,80 - Actor262: mine - Owner: Neutral - Location: 46,88 - Actor263: mine - Owner: Neutral - Location: 43,82 - Actor264: mine - Owner: Neutral - Location: 58,91 - Actor265: mine - Owner: Neutral - Location: 56,103 - Actor266: mine - Owner: Neutral - Location: 52,105 - Actor267: mine - Owner: Neutral - Location: 93,109 - Actor268: mine - Owner: Neutral - Location: 88,107 - Actor269: mine - Owner: Neutral - Location: 82,109 - Actor270: mine - Owner: Neutral - Location: 78,103 - Actor271: mine - Owner: Neutral - Location: 109,102 - Actor272: mine - Owner: Neutral - Location: 110,97 - Actor273: mine - Owner: Neutral - Location: 86,79 - Actor279: mpspawn - Owner: Neutral - Location: 46,24 - Actor280: mpspawn - Owner: Neutral - Location: 103,32 - Actor274: mpspawn - Owner: Neutral - Location: 26,66 - Actor275: mpspawn - Owner: Neutral - Location: 34,101 - Actor276: mpspawn - Owner: Neutral - Location: 99,85 - Actor240: t11 - Owner: Neutral - Location: 40,75 - Actor277: t10 - Owner: Neutral - Location: 40,75 - Actor278: t13 - Owner: Neutral - Location: 46,72 - Actor281: t07 - Owner: Neutral - Location: 43,74 - Actor282: t14 - Owner: Neutral - Location: 43,74 - Actor283: tc02 - Owner: Neutral - Location: 80,30 - Actor284: tc01 - Owner: Neutral - Location: 29,89 - Actor285: t03 - Owner: Neutral - Location: 71,34 - Actor286: tc02 - Owner: Neutral - Location: 65,34 - Actor287: t11 - Owner: Neutral - Location: 80,89 - Actor288: tc04 - Owner: Neutral - Location: 73,88 - Actor289: t06 - Owner: Neutral - Location: 16,49 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/polar-disorder.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/polar-disorder.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/production-disruption/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/production-disruption/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/production-disruption/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/production-disruption/map.png differ diff -Nru openra-20200503/mods/ra/maps/production-disruption/map.yaml openra-20210321/mods/ra/maps/production-disruption/map.yaml --- openra-20200503/mods/ra/maps/production-disruption/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/production-disruption/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,650 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: Production Disruption + +Author: Westwood Studios + +Tileset: TEMPERAT + +MapSize: 128,128 + +Bounds: 41,7,47,94 + +Visibility: MissionSelector + +Categories: Mission + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: england + PlayerReference@BadGuy: + Name: BadGuy + Faction: soviet + Color: FF1400 + Allies: USSR + Enemies: Greece + PlayerReference@USSR: + Name: USSR + Faction: soviet + Color: FF1400 + Allies: BadGuy + Enemies: Greece + PlayerReference@Greece: + Name: Greece + AllowBots: False + Playable: True + Required: True + LockFaction: True + Faction: allies + LockColor: True + Color: ABB7E4 + LockSpawn: True + LockTeam: True + Enemies: USSR, BadGuy + +Actors: + Actor0: brik + Location: 49,37 + Owner: USSR + Actor1: brik + Location: 50,37 + Owner: USSR + Actor2: brik + Location: 74,37 + Owner: USSR + Actor3: brik + Location: 75,37 + Owner: USSR + Actor4: brik + Location: 49,38 + Owner: USSR + Actor5: brik + Location: 50,38 + Owner: USSR + Actor6: brik + Location: 74,38 + Owner: USSR + Actor7: brik + Location: 75,38 + Owner: USSR + Actor8: brik + Location: 49,39 + Owner: USSR + Actor9: brik + Location: 75,39 + Owner: USSR + Actor10: brik + Location: 49,40 + Owner: USSR + Actor11: brik + Location: 75,40 + Owner: USSR + Actor12: brik + Location: 49,41 + Owner: USSR + Actor13: brik + Location: 75,41 + Owner: USSR + Actor14: brik + Location: 49,42 + Owner: USSR + Actor15: brik + Location: 75,42 + Owner: USSR + Actor16: brik + Location: 49,43 + Owner: USSR + Actor17: brik + Location: 75,43 + Owner: USSR + Actor18: brik + Location: 49,44 + Owner: USSR + Actor19: brik + Location: 75,44 + Owner: USSR + Actor20: brik + Location: 49,45 + Owner: USSR + Actor21: brik + Location: 75,45 + Owner: USSR + Actor22: brik + Location: 49,46 + Owner: USSR + Actor23: brik + Location: 75,46 + Owner: USSR + Actor24: brik + Location: 49,47 + Owner: USSR + Actor25: brik + Location: 75,47 + Owner: USSR + Actor26: brik + Location: 49,48 + Owner: USSR + Actor27: brik + Location: 75,48 + Owner: USSR + Actor28: brik + Location: 49,49 + Owner: USSR + Actor29: brik + Location: 75,49 + Owner: USSR + Actor30: brik + Location: 49,50 + Owner: USSR + Actor31: brik + Location: 50,50 + Owner: USSR + Actor32: brik + Location: 51,50 + Owner: USSR + Actor33: brik + Location: 52,50 + Owner: USSR + Actor34: brik + Location: 53,50 + Owner: USSR + Actor35: brik + Location: 54,50 + Owner: USSR + Actor36: brik + Location: 55,50 + Owner: USSR + Actor37: brik + Location: 56,50 + Owner: USSR + Actor38: brik + Location: 57,50 + Owner: USSR + Actor39: brik + Location: 61,50 + Owner: USSR + Actor40: brik + Location: 62,50 + Owner: USSR + Actor41: brik + Location: 75,50 + Owner: USSR + Actor42: brik + Location: 56,51 + Owner: USSR + Actor43: brik + Location: 57,51 + Owner: USSR + Actor44: brik + Location: 61,51 + Owner: USSR + Actor45: brik + Location: 62,51 + Owner: USSR + Actor46: brik + Location: 63,51 + Owner: USSR + Actor47: brik + Location: 64,51 + Owner: USSR + Actor48: brik + Location: 65,51 + Owner: USSR + Actor49: brik + Location: 66,51 + Owner: USSR + Actor50: brik + Location: 67,51 + Owner: USSR + Actor51: brik + Location: 68,51 + Owner: USSR + Actor52: brik + Location: 69,51 + Owner: USSR + Actor53: brik + Location: 70,51 + Owner: USSR + Actor54: brik + Location: 71,51 + Owner: USSR + Actor55: brik + Location: 72,51 + Owner: USSR + Actor56: brik + Location: 73,51 + Owner: USSR + Actor57: brik + Location: 74,51 + Owner: USSR + Actor58: brik + Location: 75,51 + Owner: USSR + Actor60: brik + Location: 67,73 + Owner: BadGuy + Actor61: brik + Location: 68,73 + Owner: BadGuy + Actor62: brik + Location: 69,73 + Owner: BadGuy + Actor63: brik + Location: 70,73 + Owner: BadGuy + Actor64: brik + Location: 71,73 + Owner: BadGuy + Actor65: brik + Location: 72,73 + Owner: BadGuy + Actor66: brik + Location: 73,73 + Owner: BadGuy + Actor67: brik + Location: 74,73 + Owner: BadGuy + Actor68: brik + Location: 75,73 + Owner: BadGuy + Actor69: brik + Location: 76,73 + Owner: BadGuy + Actor70: brik + Location: 67,74 + Owner: BadGuy + Actor71: brik + Location: 68,74 + Owner: BadGuy + Actor72: brik + Location: 76,74 + Owner: BadGuy + Actor73: brik + Location: 76,75 + Owner: BadGuy + Actor74: brik + Location: 76,76 + Owner: BadGuy + Actor75: brik + Location: 67,77 + Owner: BadGuy + Actor76: brik + Location: 68,77 + Owner: BadGuy + Actor77: brik + Location: 76,77 + Owner: BadGuy + Actor78: brik + Location: 67,78 + Owner: BadGuy + Actor79: brik + Location: 68,78 + Owner: BadGuy + Actor80: brik + Location: 69,78 + Owner: BadGuy + Actor81: brik + Location: 70,78 + Owner: BadGuy + Actor82: brik + Location: 71,78 + Owner: BadGuy + Actor83: brik + Location: 72,78 + Owner: BadGuy + Actor84: brik + Location: 73,78 + Owner: BadGuy + Actor85: brik + Location: 74,78 + Owner: BadGuy + Actor86: brik + Location: 75,78 + Owner: BadGuy + Actor87: brik + Location: 76,78 + Owner: BadGuy + Actor88: t01 + Location: 46,67 + Owner: Neutral + Actor89: tc04 + Location: 46,63 + Owner: Neutral + Actor90: tc05 + Location: 50,71 + Owner: Neutral + Actor91: tc05 + Location: 80,92 + Owner: Neutral + Actor92: tc04 + Location: 67,69 + Owner: Neutral + Actor93: tc02 + Location: 66,79 + Owner: Neutral + Actor94: tc04 + Location: 49,86 + Owner: Neutral + Actor95: tc03 + Location: 50,88 + Owner: Neutral + Actor96: tc01 + Location: 54,77 + Owner: Neutral + Actor97: t17 + Location: 64,73 + Owner: Neutral + Actor98: t16 + Location: 61,86 + Owner: Neutral + Actor99: t15 + Location: 57,89 + Owner: Neutral + Actor100: t13 + Location: 71,93 + Owner: Neutral + Actor101: t14 + Location: 80,84 + Owner: Neutral + Actor102: tc04 + Location: 47,58 + Owner: Neutral + Actor103: tc05 + Location: 78,57 + Owner: Neutral + Actor104: tc03 + Location: 79,60 + Owner: Neutral + Actor105: tc02 + Location: 49,59 + Owner: Neutral + Actor106: tc03 + Location: 45,46 + Owner: Neutral + Actor107: tc04 + Location: 53,50 + Owner: Neutral + Actor108: tc05 + Location: 78,37 + Owner: Neutral + Actor109: tc02 + Location: 75,51 + Owner: Neutral + Actor110: tc01 + Location: 71,58 + Owner: Neutral + Actor111: tc02 + Location: 80,68 + Owner: Neutral + Actor112: tsla + Location: 70,94 + Owner: BadGuy + SubPen: spen + Location: 67,37 + Owner: BadGuy + Actor114: kenn + Location: 61,45 + Owner: USSR + Actor115: barr + Location: 56,46 + Owner: USSR + Actor116: apwr + Location: 53,44 + Owner: USSR + Actor117: apwr + Location: 51,47 + Owner: USSR + Actor118: apwr + Location: 62,47 + Owner: USSR + Actor119: dome + Location: 70,47 + Owner: USSR + Actor120: apwr + Location: 71,41 + Owner: USSR + Actor121: fcom + Location: 51,40 + Owner: USSR + Actor122: apwr + Location: 73,74 + Owner: BadGuy + Actor123: apwr + Location: 69,74 + Owner: BadGuy + FlameTower1: ftur + Location: 62,66 + Owner: USSR + FlameTower2: ftur + Location: 65,66 + Owner: USSR + Actor126: ftur + Location: 57,52 + Owner: USSR + Actor127: ftur + Location: 61,52 + Owner: USSR + Actor128: sam + Location: 55,49 + Owner: USSR + Actor129: sam + Location: 63,50 + Owner: USSR + Actor130: tsla + Location: 63,92 + Owner: BadGuy + Actor131: weap + Location: 66,45 + Owner: USSR + ObjectiveDome: dome + Location: 77,61 + Owner: BadGuy + Church: v01 + Location: 51,58 + Owner: USSR + Actor134: v02 + Location: 49,60 + Owner: USSR + Actor135: v03 + Location: 53,61 + Owner: USSR + Actor136: v05 + Location: 50,63 + Owner: USSR + Actor137: v06 + Location: 55,64 + Owner: USSR + Actor138: v07 + Location: 51,65 + Owner: USSR + Actor139: v08 + Location: 47,63 + Owner: USSR + Actor140: apwr + Location: 85,8 + Owner: BadGuy + Heavy1: 3tnk + Location: 70,45 + Owner: USSR + Facing: 380 + Heavy2: 3tnk + Location: 58,45 + Owner: USSR + Facing: 636 + Actor143: e2 + Location: 67,49 + Owner: USSR + SubCell: 1 + Actor144: dog + Location: 61,47 + Owner: USSR + Facing: 380 + SubCell: 2 + Actor145: e1 + Location: 68,59 + Owner: USSR + Facing: 508 + SubCell: 0 + Actor146: e1 + Location: 67,75 + Owner: BadGuy + Facing: 124 + SubCell: 1 + Actor147: e1 + Location: 67,76 + Owner: BadGuy + Facing: 380 + SubCell: 3 + Actor148: e1 + Location: 71,77 + Owner: BadGuy + Facing: 124 + SubCell: 4 + Actor149: e1 + Location: 74,76 + Owner: BadGuy + Facing: 508 + SubCell: 1 + Actor150: e1 + Location: 72,75 + Owner: BadGuy + Facing: 380 + SubCell: 0 + Actor151: e1 + Location: 77,64 + Owner: USSR + Facing: 636 + SubCell: 1 + Actor152: e1 + Location: 76,62 + Owner: USSR + Facing: 380 + SubCell: 4 + Actor153: e1 + Location: 54,40 + Owner: USSR + SubCell: 3 + Actor154: e1 + Location: 69,40 + Owner: USSR + SubCell: 0 + Actor155: e1 + Location: 68,43 + Owner: USSR + SubCell: 1 + Actor156: e1 + Location: 61,49 + Owner: USSR + SubCell: 1 + Actor157: e1 + Location: 51,44 + Owner: USSR + SubCell: 1 + Actor158: e2 + Location: 54,48 + Owner: USSR + SubCell: 0 + Actor159: e2 + Location: 60,44 + Owner: USSR + SubCell: 2 + Actor160: e2 + Location: 71,39 + Owner: USSR + SubCell: 4 + Rifle1: e1 + Location: 78,81 + Owner: USSR + SubCell: 2 + Rifle2: e1 + Location: 78,79 + Owner: USSR + SubCell: 3 + Rifle3: e1 + Location: 77,80 + Owner: USSR + SubCell: 4 + Rifle4: e1 + Location: 47,71 + Owner: USSR + SubCell: 4 + Rifle5: e1 + Location: 49,71 + Owner: USSR + SubCell: 3 + Rifle6: e1 + Location: 49,70 + Owner: USSR + SubCell: 3 + DefaultCameraPosition: waypoint + Location: 58,86 + Owner: Neutral + TeslaCam: waypoint + Location: 66,94 + Owner: Neutral + LZ: waypoint + Location: 54,85 + Owner: Neutral + Beach1: waypoint + Location: 65,90 + Owner: Neutral + WaterEntry1: waypoint + Location: 66,100 + Owner: Neutral + FlameCam: waypoint + Location: 64,66 + Owner: Neutral + RadarCam: waypoint + Location: 77,63 + Owner: Neutral + ChurchCrate: waypoint + Location: 51,59 + Owner: Neutral + ChronoSpawn1: waypoint + Location: 62,59 + Owner: Neutral + ChronoSpawn2: waypoint + Location: 61,59 + Owner: Neutral + ChronoSpawn3: waypoint + Location: 62,60 + Owner: Neutral + Beach2: waypoint + Location: 83,59 + Owner: Neutral + Beach3: waypoint + Location: 84,64 + Owner: Neutral + WaterEntry2: waypoint + Location: 87,61 + Owner: Neutral + EasyCamera: waypoint + Location: 62,36 + Owner: Neutral + MissileSubSpawn: waypoint + Location: 66,38 + Owner: Neutral + SubPath1: waypoint + Location: 66,33 + Owner: Neutral + SubPath2: waypoint + Location: 63,28 + Owner: Neutral + SubPath3: waypoint + Location: 63,13 + Owner: Neutral + Mammoth: waypoint + Location: 77,39 + Owner: Neutral + V2: waypoint + Location: 66,43 + Owner: Neutral + +Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/ra/maps/production-disruption/production-disruption.lua openra-20210321/mods/ra/maps/production-disruption/production-disruption.lua --- openra-20200503/mods/ra/maps/production-disruption/production-disruption.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/production-disruption/production-disruption.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,268 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +TimerTicks = DateTime.Minutes(12) +LSTType = "lst.reinforcement" +RifleSquad1 = { Rifle1, Rifle2, Rifle3 } +RifleSquad2 = { Rifle4, Rifle5, Rifle6 } +Heavys = { Heavy1, Heavy2 } +FlameTowerWall = { FlameTower1, FlameTower2 } +DemoEngiPath = { WaterEntry1.Location, Beach1.Location } +DemoEngiTeam = { "dtrk", "dtrk", "e6", "e6", "e6" } +SovietWaterEntry1 = { WaterEntry2.Location, Beach2.Location } +SovietWaterEntry2 = { WaterEntry2.Location, Beach3.Location } +SovietSquad = { "e1", "e1", "e1", "e4", "e4" } +V2Squad = { "v2rl", "v2rl" } +SubEscapePath = { SubPath1, SubPath2, SubPath3 } + +IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end + +MissionStart = function() + LZCamera = Actor.Create("camera", true, { Owner = Greece, Location = LZ.Location }) + Chalk1.TargetParatroopers(LZ.CenterPosition, Angle.New(740)) + if Map.LobbyOption("difficulty") == "normal" then + Actor.Create("tsla", true, { Owner = USSR, Location = EasyCamera.Location }) + Actor.Create("4tnk", true, { Owner = USSR, Facing = Angle.South, Location = Mammoth.Location }) + Actor.Create("4tnk", true, { Owner = USSR, Facing = Angle.South, Location = Mammoth.Location + CVec.New(1,0) }) + Actor.Create("v2rl", true, { Owner = USSR, Facing = Angle.South, Location = V2.Location }) + end + + Trigger.AfterDelay(DateTime.Seconds(1), function() + Chalk2.TargetParatroopers(LZ.CenterPosition, Angle.New(780)) + end) + + Trigger.AfterDelay(DateTime.Seconds(5), function() + UnitsArrived = true + TeslaCamera = Actor.Create("camera", true, { Owner = Greece, Location = TeslaCam.Location }) + end) + + Trigger.AfterDelay(DateTime.Seconds(10), function() + LZCamera.Destroy() + Utils.Do(RifleSquad1, function(actor) + if not actor.IsDead then + actor.AttackMove(LZ.Location) + IdleHunt(actor) + end + end) + end) + + Trigger.AfterDelay(DateTime.Seconds(15), function() + TeslaCamera.Destroy() + Utils.Do(RifleSquad2, function(actor) + if not actor.IsDead then + actor.AttackMove(LZ.Location) + IdleHunt(actor) + end + end) + end) +end + +SetupTriggers = function() + Trigger.OnDamaged(SubPen, function() + Utils.Do(Heavys, function(actor) + if not actor.IsDead then + IdleHunt(actor) + end + end) + end) + + Trigger.OnKilled(Church, function() + Actor.Create("healcrate", true, { Owner = Greece, Location = ChurchCrate.Location }) + end) + + Trigger.OnKilled(ObjectiveDome, function() + if not DomeCaptured == true then + Greece.MarkFailedObjective(CaptureDome) + end + end) + + Trigger.OnAllKilled(FlameTowerWall, function() + DomeCam = Actor.Create("camera", true, { Owner = Greece, Location = RadarCam.Location }) + Trigger.AfterDelay(DateTime.Seconds(5), function() + DomeCam.Destroy() + end) + end) + + Trigger.OnKilledOrCaptured(SubPen, function() + Greece.MarkCompletedObjective(StopProduction) + end) +end + +PowerDown = false +PowerDownTeslas = function() + if not PowerDown then + CaptureDome = Greece.AddObjective("Capture the enemy radar dome.", "Secondary", false) + Greece.MarkCompletedObjective(PowerDownTeslaCoils) + Media.PlaySpeechNotification(Greece, "ReinforcementsArrived") + PowerDown = true + + local bridge = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "bridge1" end)[1] + if not bridge.IsDead then + bridge.Kill() + end + + local demoEngis = Reinforcements.ReinforceWithTransport(Greece, LSTType, DemoEngiTeam, DemoEngiPath, { DemoEngiPath[1] })[2] + Trigger.OnAllRemovedFromWorld(Utils.Where(demoEngis, function(a) return a.Type == "e6" end), function() + if not DomeCaptured then + Greece.MarkFailedObjective(CaptureDome) + end + if not DomeCaptured and bridge.IsDead then + Greece.MarkFailedObjective(StopProduction) + end + end) + + Trigger.OnCapture(ObjectiveDome, function() + DomeCaptured = true + Greece.MarkCompletedObjective(CaptureDome) + SendChronos() + end) + + FlameTowersCam = Actor.Create("camera", true, { Owner = Greece, Location = FlameCam.Location }) + Trigger.AfterDelay(DateTime.Seconds(10), function() + FlameTowersCam.Destroy() + end) + end +end + +SendChronos = function() + Trigger.AfterDelay(DateTime.Seconds(3), function() + local sovietWaterSquad1 = Reinforcements.ReinforceWithTransport(USSR, "lst", SovietSquad, { WaterEntry2.Location, Beach2.Location }, { WaterEntry2.Location })[2] + Utils.Do(sovietWaterSquad1, function(a) + Trigger.OnAddedToWorld(a, function() + IdleHunt(a) + end) + end) + + Actor.Create("ctnk", true, { Owner = Greece, Location = ChronoSpawn1.Location }) + Actor.Create("ctnk", true, { Owner = Greece, Location = ChronoSpawn2.Location }) + Actor.Create("ctnk", true, { Owner = Greece, Location = ChronoSpawn3.Location }) + Actor.Create("camera", true, { Owner = Greece, Location = EasyCamera.Location }) + Media.PlaySound("chrono2.aud") + end) + + Trigger.AfterDelay(DateTime.Seconds(5), function() + local sovietWaterSquad2 = Reinforcements.ReinforceWithTransport(USSR, "lst", SovietSquad, { WaterEntry2.Location, Beach3.Location }, { WaterEntry2.Location })[2] + Utils.Do(sovietWaterSquad2, function(a) + Trigger.OnAddedToWorld(a, function() + a.AttackMove(FlameCam.Location) + IdleHunt(a) + end) + end) + end) + + Trigger.AfterDelay(DateTime.Seconds(13), function() + local sovietWaterSquad2 = Reinforcements.ReinforceWithTransport(USSR, "lst", V2Squad, { WaterEntry2.Location, Beach2.Location }, { WaterEntry2.Location })[2] + Utils.Do(sovietWaterSquad2, function(a) + Trigger.OnAddedToWorld(a, function() + a.AttackMove(FlameCam.Location) + IdleHunt(a) + end) + end) + end) +end + +MissileSubEscape = function() + local missileSub = Actor.Create("msub", true, { Owner = USSR, Location = MissileSubSpawn.Location }) + Actor.Create("camera", true, { Owner = Greece, Location = SubPath2.Location }) + DestroySub = Greece.AddPrimaryObjective("Destroy the submarine before it escapes!.") + + Utils.Do(SubEscapePath, function(waypoint) + missileSub.Move(waypoint.Location) + end) + + Trigger.OnEnteredFootprint({ SubPath3.Location }, function(a, id) + if a.Owner == USSR and a.Type == "msub" then + Trigger.RemoveFootprintTrigger(id) + USSR.MarkCompletedObjective(EscapeWithSub) + end + end) + + Trigger.OnKilled(missileSub, function() + Greece.MarkCompletedObjective(DestroySub) + end) +end + +FinishTimer = function() + for i = 0, 5 do + local c = TimerColor + if i % 2 == 0 then + c = HSLColor.White + end + + Trigger.AfterDelay(DateTime.Seconds(i), function() UserInterface.SetMissionText("The sub is heading for open sea!", c) end) + end + Trigger.AfterDelay(DateTime.Seconds(6), function() UserInterface.SetMissionText("") end) +end + +UnitsArrived = false +TimerFinished = false +ticked = TimerTicks +Tick = function() + if BadGuy.PowerState ~= "Normal" then + PowerDownTeslas() + end + + if Greece.HasNoRequiredUnits() and UnitsArrived then + USSR.MarkCompletedObjective(EscapeWithSub) + end + + if ticked > 0 then + UserInterface.SetMissionText("Submarine completes in " .. Utils.FormatTime(ticked), TimerColor) + ticked = ticked - 1 + elseif ticked == 0 and not TimerFinished then + MissileSubEscape() + TimerFinished = true + end +end + +WorldLoaded = function() + Greece = Player.GetPlayer("Greece") + USSR = Player.GetPlayer("USSR") + BadGuy = Player.GetPlayer("BadGuy") + + EscapeWithSub = USSR.AddObjective("Get a missile sub to open waters.") + StopProduction = Greece.AddObjective("Destroy the Soviet sub pen.") + PowerDownTeslaCoils = Greece.AddObjective("Take down power to the tesla coils.") + + Trigger.OnObjectiveAdded(Greece, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") + end) + + Trigger.OnObjectiveCompleted(Greece, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") + end) + Trigger.OnObjectiveFailed(Greece, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") + end) + Trigger.OnPlayerLost(Greece, function() + Media.PlaySpeechNotification(Greece, "Lose") + end) + Trigger.OnPlayerWon(Greece, function() + Media.PlaySpeechNotification(Greece, "Win") + end) + + Trigger.AfterDelay(DateTime.Minutes(2), function() + Media.PlaySpeechNotification(Greece, "TenMinutesRemaining") + end) + Trigger.AfterDelay(DateTime.Minutes(7), function() + Media.PlaySpeechNotification(Greece, "WarningFiveMinutesRemaining") + end) + Trigger.AfterDelay(DateTime.Minutes(9), function() + Media.PlaySpeechNotification(Greece, "WarningThreeMinutesRemaining") + end) + Trigger.AfterDelay(DateTime.Minutes(11), function() + Media.PlaySpeechNotification(Greece, "WarningOneMinuteRemaining") + end) + + Camera.Position = DefaultCameraPosition.CenterPosition + TimerColor = USSR.Color + Chalk1 = Actor.Create("chalk1", false, { Owner = Greece }) + Chalk2 = Actor.Create("chalk2", false, { Owner = Greece }) + MissionStart() + SetupTriggers() +end diff -Nru openra-20200503/mods/ra/maps/production-disruption/rules.yaml openra-20210321/mods/ra/maps/production-disruption/rules.yaml --- openra-20200503/mods/ra/maps/production-disruption/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/production-disruption/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,42 @@ +World: + LuaScript: + Scripts: production-disruption.lua + MissionData: + WinVideo: battle.vqa + LossVideo: slntsrvc.vqa + Briefing: The Soviets are beginning construction of a new class of submarine capable of launching sea-to-ground missiles. We don't have to tell you the amount of devestation these could cause.\n\nTake a small squad of troops and infiltrate their power grid. When it is down, additional reinforcements will be sent in. When ready, head north and destroy their Sub pen, preventing further construction of these subs.\n\nIf any are built, they must not be allowed to escape! + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Values: + easy: Easy + normal: Normal + Default: easy + +CHALK1: + ParatroopersPower: + DisplayBeacon: False + DropItems: E1, E1, E1, E1, E1 + AlwaysVisible: + +CHALK2: + ParatroopersPower: + DisplayBeacon: False + DropItems: E3, E3, E3, E3, MEDI + AlwaysVisible: + +LST.Reinforcement: + Inherits: LST + RejectsOrders: + -Buildable: + -Selectable: + RenderSprites: + Image: lst + Interactable: + +MSUB: + -Cloak: + -GrantConditionOnDamageState@UNCLOAK: + -Targetable@UNDERWATER: + Targetable: + -RequiresCondition: Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/progress.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/progress.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/puddles-redux.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/puddles-redux.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/rapa-nui/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/rapa-nui/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/rapa-nui/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/rapa-nui/map.png differ diff -Nru openra-20200503/mods/ra/maps/rapa-nui/map.yaml openra-20210321/mods/ra/maps/rapa-nui/map.yaml --- openra-20200503/mods/ra/maps/rapa-nui/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/rapa-nui/map.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,1618 +0,0 @@ -MapFormat: 11 - -RequiresMod: ra - -Title: Rapa Nui - -Author: American Blunt - -Tileset: TEMPERAT - -MapSize: 302,202 - -Bounds: 1,1,300,200 - -Visibility: Lobby - -Categories: Conquest - -Players: - PlayerReference@Neutral: - Name: Neutral - OwnsWorld: True - NonCombatant: True - Faction: england - PlayerReference@Creeps: - Name: Creeps - NonCombatant: True - Faction: england - Enemies: Multi0, Multi1, Multi2, Multi3, Multi4, Multi5, Multi6 - PlayerReference@Multi0: - Name: Multi0 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi1: - Name: Multi1 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi2: - Name: Multi2 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi3: - Name: Multi3 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi4: - Name: Multi4 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi5: - Name: Multi5 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi6: - Name: Multi6 - AllowBots: False - Playable: True - Faction: Random - Enemies: Creeps - -Actors: - Actor210: tc01 - Owner: Neutral - Location: 37,163 - Actor22: v19 - Owner: Neutral - Location: 225,192 - Actor25: v19 - Owner: Neutral - Location: 210,189 - Actor26: v19 - Owner: Neutral - Location: 208,192 - Actor209: tc04 - Owner: Neutral - Location: 32,162 - Actor61: t02 - Owner: Neutral - Location: 9,65 - Actor62: t02 - Owner: Neutral - Location: 16,55 - Actor57: tc04 - Owner: Neutral - Location: 65,150 - Actor48: v19 - Owner: Neutral - Location: 14,57 - Actor49: v19 - Owner: Neutral - Location: 8,68 - Actor50: v19 - Owner: Neutral - Location: 10,70 - Actor51: v19 - Owner: Neutral - Location: 234,7 - Actor52: v19 - Owner: Neutral - Location: 233,10 - Actor53: v19 - Owner: Neutral - Location: 219,13 - Actor65: v05 - Owner: Neutral - Location: 50,133 - Actor597: wood - Owner: Neutral - Location: 42,142 - Actor594: wood - Owner: Neutral - Location: 41,142 - Actor68: v04 - Owner: Neutral - Location: 57,111 - Actor69: v11 - Owner: Neutral - Location: 44,134 - Actor151: tc03 - Owner: Neutral - Location: 159,99 - Actor155: tc02 - Owner: Neutral - Location: 75,128 - Actor113: tc04 - Owner: Neutral - Location: 158,90 - Actor114: tc01 - Owner: Neutral - Location: 168,87 - Actor116: tc01 - Owner: Neutral - Location: 156,94 - Actor121: mine - Owner: Neutral - Location: 254,85 - Actor123: mine - Owner: Neutral - Location: 281,83 - Actor124: mine - Owner: Neutral - Location: 265,104 - Actor125: gmine - Owner: Neutral - Location: 288,92 - Actor127: t16 - Owner: Neutral - Location: 287,88 - Actor156: mine - Owner: Neutral - Location: 55,157 - Actor656: c3 - Owner: Neutral - Location: 48,132 - SubCell: 3 - Facing: 28 - Actor159: t01 - Owner: Neutral - Location: 71,97 - Actor160: t01 - Owner: Neutral - Location: 31,159 - Actor161: t01 - Owner: Neutral - Location: 34,160 - Actor162: t01 - Owner: Neutral - Location: 37,162 - Actor164: tc01 - Owner: Neutral - Location: 150,131 - Actor165: t16 - Owner: Neutral - Location: 131,137 - Actor168: mine - Owner: Neutral - Location: 129,79 - Actor174: t16 - Owner: Neutral - Location: 111,111 - Actor175: t16 - Owner: Neutral - Location: 104,108 - Actor631: t06 - Owner: Neutral - Location: 89,104 - Actor182: wood - Owner: Neutral - Location: 45,147 - Actor183: wood - Owner: Neutral - Location: 46,147 - Actor184: wood - Owner: Neutral - Location: 47,147 - Actor185: wood - Owner: Neutral - Location: 48,147 - Actor186: wood - Owner: Neutral - Location: 48,146 - Actor187: wood - Owner: Neutral - Location: 48,145 - Actor188: wood - Owner: Neutral - Location: 57,130 - Actor189: wood - Owner: Neutral - Location: 56,130 - Actor190: wood - Owner: Neutral - Location: 55,130 - Actor621: wood - Owner: Neutral - Location: 44,142 - Actor600: wood - Owner: Neutral - Location: 43,142 - Actor198: t16 - Owner: Neutral - Location: 203,85 - Actor200: t06 - Owner: Neutral - Location: 216,86 - Actor575: t02 - Owner: Neutral - Location: 78,76 - Actor576: gmine - Owner: Neutral - Location: 127,40 - Actor577: t05 - Owner: Neutral - Location: 78,88 - Actor211: t16 - Owner: Neutral - Location: 35,163 - Actor214: t16 - Owner: Neutral - Location: 39,165 - Actor215: t16 - Owner: Neutral - Location: 41,165 - Actor216: tc01 - Owner: Neutral - Location: 29,162 - Actor217: tc01 - Owner: Neutral - Location: 36,165 - Actor218: tc04 - Owner: Neutral - Location: 26,160 - Actor219: tc04 - Owner: Neutral - Location: 54,171 - Actor220: tc01 - Owner: Neutral - Location: 58,173 - Actor221: t16 - Owner: Neutral - Location: 55,169 - Actor222: t16 - Owner: Neutral - Location: 58,171 - Actor225: tc01 - Owner: Neutral - Location: 74,153 - Actor230: v15 - Owner: Neutral - Location: 135,141 - Actor231: v15 - Owner: Neutral - Location: 138,141 - Actor232: v15 - Owner: Neutral - Location: 137,139 - Actor233: t06 - Owner: Neutral - Location: 124,116 - Actor234: t06 - Owner: Neutral - Location: 128,115 - Actor235: tc01 - Owner: Neutral - Location: 133,114 - Actor236: tc04 - Owner: Neutral - Location: 120,115 - Actor237: tc04 - Owner: Neutral - Location: 130,115 - Actor238: tc01 - Owner: Neutral - Location: 128,110 - Actor239: tc01 - Owner: Neutral - Location: 118,112 - Actor240: tc04 - Owner: Neutral - Location: 122,111 - Actor241: tc04 - Owner: Neutral - Location: 131,110 - Actor242: tc04 - Owner: Neutral - Location: 135,108 - Actor243: tc03 - Owner: Neutral - Location: 126,115 - Actor244: tc01 - Owner: Neutral - Location: 130,108 - Actor245: tc04 - Owner: Neutral - Location: 138,91 - Actor246: tc04 - Owner: Neutral - Location: 134,96 - Actor247: tc04 - Owner: Neutral - Location: 141,99 - Actor248: tc04 - Owner: Neutral - Location: 136,103 - Actor249: tc01 - Owner: Neutral - Location: 139,97 - Actor250: tc01 - Owner: Neutral - Location: 136,93 - Actor251: tc01 - Owner: Neutral - Location: 134,100 - Actor252: tc01 - Owner: Neutral - Location: 139,105 - Actor253: t16 - Owner: Neutral - Location: 141,97 - Actor254: t16 - Owner: Neutral - Location: 138,95 - Actor255: t16 - Owner: Neutral - Location: 138,99 - Actor256: t16 - Owner: Neutral - Location: 133,105 - Actor257: t16 - Owner: Neutral - Location: 131,102 - Actor258: t16 - Owner: Neutral - Location: 131,97 - Actor259: t16 - Owner: Neutral - Location: 131,100 - Actor260: t16 - Owner: Neutral - Location: 133,103 - Actor261: tc04 - Owner: Neutral - Location: 131,104 - Actor263: t05 - Owner: Neutral - Location: 138,101 - Actor264: t05 - Owner: Neutral - Location: 140,103 - Actor265: t05 - Owner: Neutral - Location: 136,106 - Actor266: t05 - Owner: Neutral - Location: 133,106 - Actor268: tc04 - Owner: Neutral - Location: 130,98 - Actor610: v15 - Owner: Neutral - Location: 131,147 - Actor270: v15 - Owner: Neutral - Location: 137,141 - Actor554: v15 - Owner: Neutral - Location: 133,144 - Actor555: v15 - Owner: Neutral - Location: 134,144 - Actor273: v15 - Owner: Neutral - Location: 133,141 - Actor274: v15 - Owner: Neutral - Location: 134,139 - Actor275: v15 - Owner: Neutral - Location: 134,140 - Actor276: v15 - Owner: Neutral - Location: 136,140 - Actor277: v15 - Owner: Neutral - Location: 135,139 - Actor430: v15 - Owner: Neutral - Location: 153,138 - Actor280: v15 - Owner: Neutral - Location: 132,141 - Actor428: v15 - Owner: Neutral - Location: 154,136 - Actor282: v15 - Owner: Neutral - Location: 133,140 - Actor283: v15 - Owner: Neutral - Location: 142,143 - Actor285: v15 - Owner: Neutral - Location: 141,145 - Actor286: v15 - Owner: Neutral - Location: 141,144 - Actor287: v15 - Owner: Neutral - Location: 141,143 - Actor288: v15 - Owner: Neutral - Location: 139,144 - Actor393: v15 - Owner: Neutral - Location: 152,137 - Actor291: v15 - Owner: Neutral - Location: 126,142 - Actor292: v15 - Owner: Neutral - Location: 127,143 - Actor293: v15 - Owner: Neutral - Location: 128,144 - Actor294: v15 - Owner: Neutral - Location: 127,146 - Actor295: v15 - Owner: Neutral - Location: 125,145 - Actor296: v15 - Owner: Neutral - Location: 123,144 - Actor435: v15 - Owner: Neutral - Location: 150,135 - Actor298: v15 - Owner: Neutral - Location: 128,146 - Actor299: v15 - Owner: Neutral - Location: 130,146 - Actor305: v16 - Owner: Neutral - Location: 136,139 - Actor306: v16 - Owner: Neutral - Location: 138,140 - Actor307: v16 - Owner: Neutral - Location: 133,140 - Actor308: v16 - Owner: Neutral - Location: 135,140 - Actor309: v16 - Owner: Neutral - Location: 134,141 - Actor310: v16 - Owner: Neutral - Location: 136,141 - Actor311: v16 - Owner: Neutral - Location: 137,140 - Actor312: v16 - Owner: Neutral - Location: 133,142 - Actor313: v16 - Owner: Neutral - Location: 135,143 - Actor319: v15 - Owner: Neutral - Location: 125,144 - Actor320: v15 - Owner: Neutral - Location: 126,144 - Actor321: v15 - Owner: Neutral - Location: 127,144 - Actor322: v15 - Owner: Neutral - Location: 127,145 - Actor323: v15 - Owner: Neutral - Location: 126,145 - Actor324: v16 - Owner: Neutral - Location: 127,142 - Actor325: v16 - Owner: Neutral - Location: 128,142 - Actor326: v16 - Owner: Neutral - Location: 128,143 - Actor327: v16 - Owner: Neutral - Location: 129,143 - Actor328: v16 - Owner: Neutral - Location: 129,145 - Actor329: v16 - Owner: Neutral - Location: 129,146 - Actor330: v16 - Owner: Neutral - Location: 129,144 - Actor331: v16 - Owner: Neutral - Location: 128,145 - Actor332: v16 - Owner: Neutral - Location: 126,143 - Actor333: v16 - Owner: Neutral - Location: 125,143 - Actor399: v15 - Owner: Neutral - Location: 154,134 - Actor335: v16 - Owner: Neutral - Location: 123,145 - Actor438: v16 - Owner: Neutral - Location: 154,135 - Actor434: v15 - Owner: Neutral - Location: 148,136 - Actor338: v16 - Owner: Neutral - Location: 126,147 - Actor339: v16 - Owner: Neutral - Location: 128,147 - Actor340: v16 - Owner: Neutral - Location: 127,147 - Actor341: v17 - Owner: Neutral - Location: 127,146 - Actor342: v17 - Owner: Neutral - Location: 126,146 - Actor437: v16 - Owner: Neutral - Location: 153,135 - Actor344: v17 - Owner: Neutral - Location: 124,145 - Actor345: v17 - Owner: Neutral - Location: 125,146 - Actor436: v16 - Owner: Neutral - Location: 152,136 - Actor347: v17 - Owner: Neutral - Location: 124,144 - Actor348: v17 - Owner: Neutral - Location: 124,143 - Actor394: v15 - Owner: Neutral - Location: 152,135 - Actor350: v17 - Owner: Neutral - Location: 123,143 - Actor351: v17 - Owner: Neutral - Location: 134,142 - Actor352: v17 - Owner: Neutral - Location: 135,142 - Actor353: v17 - Owner: Neutral - Location: 137,142 - Actor354: v17 - Owner: Neutral - Location: 138,142 - Actor355: v17 - Owner: Neutral - Location: 136,143 - Actor356: v17 - Owner: Neutral - Location: 136,143 - Actor357: v17 - Owner: Neutral - Location: 136,142 - Actor358: v17 - Owner: Neutral - Location: 132,142 - Actor359: v17 - Owner: Neutral - Location: 132,143 - Actor360: v17 - Owner: Neutral - Location: 133,143 - Actor361: v17 - Owner: Neutral - Location: 137,143 - Actor363: v17 - Owner: Neutral - Location: 134,143 - Actor364: v17 - Owner: Neutral - Location: 138,139 - Actor365: v14 - Owner: Neutral - Location: 139,146 - Actor366: v14 - Owner: Neutral - Location: 141,146 - Actor367: v15 - Owner: Neutral - Location: 140,145 - Actor368: v15 - Owner: Neutral - Location: 140,146 - Actor369: v15 - Owner: Neutral - Location: 140,147 - Actor370: v15 - Owner: Neutral - Location: 138,147 - Actor371: v15 - Owner: Neutral - Location: 138,145 - Actor372: v15 - Owner: Neutral - Location: 139,147 - Actor431: v15 - Owner: Neutral - Location: 151,137 - Actor376: v15 - Owner: Neutral - Location: 143,144 - Actor377: v15 - Owner: Neutral - Location: 142,144 - Actor378: v15 - Owner: Neutral - Location: 142,145 - Actor379: v16 - Owner: Neutral - Location: 143,145 - Actor432: v15 - Owner: Neutral - Location: 149,137 - Actor433: v15 - Owner: Neutral - Location: 149,136 - Actor382: v16 - Owner: Neutral - Location: 138,146 - Actor383: v16 - Owner: Neutral - Location: 139,145 - Actor384: v16 - Owner: Neutral - Location: 140,144 - Actor385: v17 - Owner: Neutral - Location: 143,143 - Actor386: v17 - Owner: Neutral - Location: 141,143 - Actor387: v17 - Owner: Neutral - Location: 140,143 - Actor388: v15 - Owner: Neutral - Location: 116,145 - Actor389: v15 - Owner: Neutral - Location: 118,145 - Actor390: v15 - Owner: Neutral - Location: 120,145 - Actor391: v15 - Owner: Neutral - Location: 120,144 - Actor392: v15 - Owner: Neutral - Location: 119,144 - Actor381: v15 - Owner: Neutral - Location: 151,138 - Actor380: v15 - Owner: Neutral - Location: 150,136 - Actor395: v16 - Owner: Neutral - Location: 117,145 - Actor396: v16 - Owner: Neutral - Location: 117,146 - Actor397: v16 - Owner: Neutral - Location: 119,146 - Actor398: v16 - Owner: Neutral - Location: 119,145 - Actor374: v15 - Owner: Neutral - Location: 148,137 - Actor400: v16 - Owner: Neutral - Location: 120,146 - Actor415: v15 - Owner: Neutral - Location: 114,134 - Actor416: v15 - Owner: Neutral - Location: 111,136 - Actor417: v15 - Owner: Neutral - Location: 113,135 - Actor418: v15 - Owner: Neutral - Location: 114,135 - Actor419: v15 - Owner: Neutral - Location: 113,136 - Actor420: v15 - Owner: Neutral - Location: 112,136 - Actor421: v15 - Owner: Neutral - Location: 114,136 - Actor422: v14 - Owner: Neutral - Location: 114,136 - Actor423: v14 - Owner: Neutral - Location: 115,134 - Actor424: v16 - Owner: Neutral - Location: 112,135 - Actor425: v16 - Owner: Neutral - Location: 112,137 - Actor426: v16 - Owner: Neutral - Location: 114,137 - Actor427: v16 - Owner: Neutral - Location: 113,137 - Actor439: v16 - Owner: Neutral - Location: 153,137 - Actor440: v16 - Owner: Neutral - Location: 153,136 - Actor441: v16 - Owner: Neutral - Location: 151,136 - Actor442: v16 - Owner: Neutral - Location: 150,137 - Actor443: v16 - Owner: Neutral - Location: 149,138 - Actor444: v16 - Owner: Neutral - Location: 148,139 - Actor445: v16 - Owner: Neutral - Location: 150,138 - Actor446: v16 - Owner: Neutral - Location: 150,139 - Actor447: v16 - Owner: Neutral - Location: 147,138 - Actor448: v16 - Owner: Neutral - Location: 146,139 - Actor449: v17 - Owner: Neutral - Location: 149,139 - Actor450: v17 - Owner: Neutral - Location: 149,140 - Actor451: v17 - Owner: Neutral - Location: 148,140 - Actor452: v17 - Owner: Neutral - Location: 147,140 - Actor453: v17 - Owner: Neutral - Location: 147,140 - Actor454: v17 - Owner: Neutral - Location: 148,138 - Actor455: v17 - Owner: Neutral - Location: 146,137 - Actor456: v17 - Owner: Neutral - Location: 146,138 - Actor457: v17 - Owner: Neutral - Location: 147,137 - Actor458: v17 - Owner: Neutral - Location: 151,135 - Actor459: v17 - Owner: Neutral - Location: 152,134 - Actor460: v17 - Owner: Neutral - Location: 153,133 - Actor461: v17 - Owner: Neutral - Location: 151,134 - Actor485: v16 - Owner: Neutral - Location: 134,133 - Actor527: tc04 - Owner: Neutral - Location: 136,86 - Actor528: tc04 - Owner: Neutral - Location: 132,86 - Actor529: tc01 - Owner: Neutral - Location: 128,83 - Actor530: tc04 - Owner: Neutral - Location: 126,90 - Actor532: tc01 - Owner: Neutral - Location: 123,84 - Actor533: tc01 - Owner: Neutral - Location: 122,87 - Actor534: tc04 - Owner: Neutral - Location: 120,85 - Actor536: tc01 - Owner: Neutral - Location: 132,82 - Actor537: t07 - Owner: Neutral - Location: 124,77 - Actor538: t07 - Owner: Neutral - Location: 128,86 - Actor539: t07 - Owner: Neutral - Location: 125,85 - Actor540: t07 - Owner: Neutral - Location: 135,92 - Actor541: t07 - Owner: Neutral - Location: 123,90 - Actor542: t07 - Owner: Neutral - Location: 125,92 - Actor543: t06 - Owner: Neutral - Location: 134,82 - Actor544: t06 - Owner: Neutral - Location: 133,84 - Actor545: t06 - Owner: Neutral - Location: 128,89 - Actor546: t06 - Owner: Neutral - Location: 125,87 - Actor547: t06 - Owner: Neutral - Location: 123,82 - Actor548: t06 - Owner: Neutral - Location: 121,83 - Actor549: t06 - Owner: Neutral - Location: 119,77 - Actor550: t06 - Owner: Neutral - Location: 120,77 - Actor552: tc04 - Owner: Neutral - Location: 117,80 - Actor553: tc01 - Owner: Neutral - Location: 125,76 - Actor551: tc01 - Owner: Neutral - Location: 122,79 - Actor558: t02 - Owner: Neutral - Location: 156,105 - Actor559: t01 - Owner: Neutral - Location: 150,107 - Actor560: t05 - Owner: Neutral - Location: 235,9 - Actor561: t07 - Owner: Neutral - Location: 223,192 - Actor634: tc04 - Owner: Neutral - Location: 194,82 - Actor567: t01 - Owner: Neutral - Location: 72,93 - Actor652: tc01 - Owner: Neutral - Location: 209,91 - Actor572: t16 - Owner: Neutral - Location: 229,82 - Actor574: t01 - Owner: Neutral - Location: 223,83 - Actor582: t07 - Owner: Neutral - Location: 219,118 - Actor583: t07 - Owner: Neutral - Location: 188,117 - Actor584: t07 - Owner: Neutral - Location: 287,100 - Actor585: t07 - Owner: Neutral - Location: 286,104 - Actor586: t05 - Owner: Neutral - Location: 287,102 - Actor587: tc01 - Owner: Neutral - Location: 285,107 - Actor588: t16 - Owner: Neutral - Location: 284,96 - Actor592: v10 - Owner: Neutral - Location: 56,118 - Actor593: wood - Owner: Neutral - Location: 40,142 - Actor595: t11 - Owner: Neutral - Location: 48,129 - Actor596: t15 - Owner: Neutral - Location: 54,132 - Actor632: t06 - Owner: Neutral - Location: 108,118 - Actor598: t10 - Owner: Neutral - Location: 54,113 - Actor566: tc04 - Owner: Neutral - Location: 180,82 - Actor601: t10 - Owner: Neutral - Location: 59,125 - Actor602: t10 - Owner: Neutral - Location: 57,109 - Actor603: v08 - Owner: Neutral - Location: 50,123 - Actor604: v08 - Owner: Neutral - Location: 52,137 - Actor606: t16 - Owner: Neutral - Location: 71,113 - Actor608: tc01 - Owner: Neutral - Location: 75,111 - Actor611: tc01 - Owner: Neutral - Location: 79,112 - Actor614: tc01 - Owner: Neutral - Location: 70,110 - Actor612: t06 - Owner: Neutral - Location: 120,64 - Actor620: t16 - Owner: Neutral - Location: 80,56 - Actor635: v15 - Owner: Neutral - Location: 133,147 - Actor636: v15 - Owner: Neutral - Location: 132,148 - Actor639: v15 - Owner: Neutral - Location: 134,148 - Actor640: v15 - Owner: Neutral - Location: 135,148 - Actor641: v16 - Owner: Neutral - Location: 134,147 - Actor642: v16 - Owner: Neutral - Location: 133,148 - Actor644: v16 - Owner: Neutral - Location: 131,148 - Actor645: v17 - Owner: Neutral - Location: 132,147 - Actor646: v17 - Owner: Neutral - Location: 130,148 - Actor654: t06 - Owner: Neutral - Location: 166,51 - Actor657: gmine - Owner: Neutral - Location: 37,193 - Actor658: c3 - Owner: Neutral - Location: 53,118 - SubCell: 3 - Facing: 124 - Actor659: c3 - Owner: Creeps - Location: 55,123 - SubCell: 3 - Facing: 156 - Actor660: c3 - Owner: Neutral - Location: 58,121 - SubCell: 3 - Facing: 92 - Actor661: c3 - Owner: Neutral - Location: 61,113 - SubCell: 3 - Facing: 220 - Actor675: v15 - Owner: Creeps - Location: 147,141 - Actor676: v15 - Owner: Creeps - Location: 149,141 - Actor677: v15 - Owner: Creeps - Location: 151,141 - Actor678: v15 - Owner: Creeps - Location: 150,141 - Actor679: v15 - Owner: Creeps - Location: 149,142 - Actor684: v14 - Owner: Creeps - Location: 148,141 - Actor685: v14 - Owner: Creeps - Location: 148,142 - Actor686: v14 - Owner: Creeps - Location: 146,142 - Actor687: v14 - Owner: Creeps - Location: 150,142 - Actor688: v16 - Owner: Creeps - Location: 148,141 - Actor689: v16 - Owner: Creeps - Location: 148,142 - Actor690: v16 - Owner: Creeps - Location: 146,142 - Actor691: v17 - Owner: Creeps - Location: 150,142 - Actor692: v17 - Owner: Creeps - Location: 147,142 - Actor680: c3 - Owner: Creeps - Location: 51,127 - SubCell: 3 - Facing: 92 - Actor710: gmine - Owner: Neutral - Location: 152,94 - Actor718: gmine - Owner: Neutral - Location: 148,80 - Actor696: mine - Owner: Neutral - Location: 28,168 - Actor599: tc01 - Owner: Neutral - Location: 91,125 - Actor568: tc04 - Owner: Neutral - Location: 68,107 - Actor564: t05 - Owner: Neutral - Location: 150,117 - Actor569: mine - Owner: Neutral - Location: 157,110 - Actor571: tc01 - Owner: Neutral - Location: 176,92 - Actor618: mine - Owner: Neutral - Location: 190,120 - Actor613: mine - Owner: Neutral - Location: 62,128 - Actor579: mine - Owner: Neutral - Location: 68,98 - Actor581: tc01 - Owner: Neutral - Location: 85,115 - Actor609: tc01 - Owner: Neutral - Location: 89,121 - Actor619: t05 - Owner: Neutral - Location: 81,70 - Actor590: mine - Owner: Neutral - Location: 175,56 - Actor605: mine - Owner: Neutral - Location: 170,75 - Actor573: tc04 - Owner: Neutral - Location: 77,151 - Actor625: tc01 - Owner: Neutral - Location: 82,150 - Actor627: mine - Owner: Neutral - Location: 75,147 - Actor629: mine - Owner: Neutral - Location: 101,156 - Actor616: mine - Owner: Neutral - Location: 96,133 - Actor565: mine - Owner: Neutral - Location: 115,129 - Actor607: mine - Owner: Neutral - Location: 141,118 - Actor570: tc03 - Owner: Neutral - Location: 142,138 - Actor556: t16 - Owner: Neutral - Location: 169,124 - Actor622: v18 - Owner: Neutral - Location: 104,138 - Actor638: v18 - Owner: Neutral - Location: 107,138 - Actor643: v15 - Owner: Neutral - Location: 108,138 - Actor649: v17 - Owner: Neutral - Location: 109,138 - Actor650: v17 - Owner: Neutral - Location: 109,138 - Actor651: v17 - Owner: Neutral - Location: 110,138 - Actor653: v15 - Owner: Neutral - Location: 111,138 - Actor655: v15 - Owner: Neutral - Location: 102,139 - Actor663: v18 - Owner: Neutral - Location: 103,139 - Actor664: v15 - Owner: Neutral - Location: 104,139 - Actor665: v18 - Owner: Neutral - Location: 105,139 - Actor668: v17 - Owner: Neutral - Location: 108,139 - Actor669: v17 - Owner: Neutral - Location: 109,139 - Actor670: v18 - Owner: Neutral - Location: 103,140 - Actor671: v18 - Owner: Neutral - Location: 104,140 - Actor672: v18 - Owner: Neutral - Location: 105,140 - Actor673: v18 - Owner: Neutral - Location: 106,140 - Actor674: v15 - Owner: Neutral - Location: 109,141 - Actor681: v16 - Owner: Neutral - Location: 110,141 - Actor695: v15 - Owner: Neutral - Location: 111,141 - Actor697: v16 - Owner: Neutral - Location: 104,142 - Actor699: v15 - Owner: Neutral - Location: 105,142 - Actor700: v15 - Owner: Neutral - Location: 107,142 - Actor701: v16 - Owner: Neutral - Location: 108,142 - Actor702: v16 - Owner: Neutral - Location: 109,142 - Actor703: v15 - Owner: Neutral - Location: 110,142 - Actor704: v16 - Owner: Neutral - Location: 102,143 - Actor705: v15 - Owner: Neutral - Location: 103,143 - Actor706: v16 - Owner: Neutral - Location: 104,143 - Actor707: v15 - Owner: Neutral - Location: 105,143 - Actor708: v15 - Owner: Neutral - Location: 105,143 - Actor709: v16 - Owner: Neutral - Location: 107,143 - Actor711: v16 - Owner: Neutral - Location: 108,143 - Actor712: v16 - Owner: Neutral - Location: 109,143 - Actor713: v16 - Owner: Neutral - Location: 102,144 - Actor714: v16 - Owner: Neutral - Location: 103,144 - Actor715: v16 - Owner: Neutral - Location: 104,144 - Actor637: mine - Owner: Neutral - Location: 141,134 - Actor666: v16 - Owner: Neutral - Location: 121,135 - Actor667: v15 - Owner: Neutral - Location: 122,135 - Actor716: v15 - Owner: Neutral - Location: 123,135 - Actor717: v17 - Owner: Neutral - Location: 124,135 - Actor719: v16 - Owner: Neutral - Location: 120,136 - Actor720: v16 - Owner: Neutral - Location: 121,136 - Actor721: v16 - Owner: Neutral - Location: 122,136 - Actor722: v16 - Owner: Neutral - Location: 123,136 - Actor723: v16 - Owner: Neutral - Location: 124,136 - Actor724: v15 - Owner: Neutral - Location: 119,137 - Actor725: v15 - Owner: Neutral - Location: 120,137 - Actor726: v15 - Owner: Neutral - Location: 121,137 - Actor727: v15 - Owner: Neutral - Location: 122,137 - Actor728: v17 - Owner: Neutral - Location: 123,137 - Actor729: v17 - Owner: Neutral - Location: 124,137 - Actor730: v15 - Owner: Neutral - Location: 119,138 - Actor731: v17 - Owner: Neutral - Location: 120,138 - Actor732: v17 - Owner: Neutral - Location: 121,138 - Actor733: v17 - Owner: Neutral - Location: 122,138 - Actor734: v17 - Owner: Neutral - Location: 123,138 - Actor735: v15 - Owner: Neutral - Location: 124,138 - Actor742: v16 - Owner: Neutral - Location: 128,133 - Actor743: v15 - Owner: Neutral - Location: 129,133 - Actor744: v15 - Owner: Neutral - Location: 131,133 - Actor745: v16 - Owner: Neutral - Location: 132,133 - Actor746: v16 - Owner: Neutral - Location: 126,134 - Actor747: v15 - Owner: Neutral - Location: 127,134 - Actor748: v16 - Owner: Neutral - Location: 128,134 - Actor749: v15 - Owner: Neutral - Location: 129,134 - Actor750: v15 - Owner: Neutral - Location: 129,134 - Actor751: v16 - Owner: Neutral - Location: 131,134 - Actor752: v16 - Owner: Neutral - Location: 132,134 - Actor753: v16 - Owner: Neutral - Location: 133,134 - Actor754: v16 - Owner: Neutral - Location: 126,135 - Actor755: v16 - Owner: Neutral - Location: 127,135 - Actor756: v16 - Owner: Neutral - Location: 128,135 - Actor736: v18 - Owner: Neutral - Location: 156,123 - Actor737: v18 - Owner: Neutral - Location: 157,123 - Actor738: v17 - Owner: Neutral - Location: 153,124 - Actor739: v15 - Owner: Neutral - Location: 156,124 - Actor740: v18 - Owner: Neutral - Location: 157,124 - Actor741: v18 - Owner: Neutral - Location: 158,124 - Actor757: v15 - Owner: Neutral - Location: 149,125 - Actor758: v17 - Owner: Neutral - Location: 150,125 - Actor759: v17 - Owner: Neutral - Location: 151,125 - Actor760: v17 - Owner: Neutral - Location: 152,125 - Actor761: v17 - Owner: Neutral - Location: 153,125 - Actor762: v18 - Owner: Neutral - Location: 155,125 - Actor763: v18 - Owner: Neutral - Location: 156,125 - Actor764: v15 - Owner: Neutral - Location: 150,126 - Actor765: v17 - Owner: Neutral - Location: 151,126 - Actor766: v17 - Owner: Neutral - Location: 152,126 - Actor767: v15 - Owner: Neutral - Location: 153,126 - Actor768: v18 - Owner: Neutral - Location: 155,126 - Actor769: v15 - Owner: Neutral - Location: 156,126 - Actor770: v15 - Owner: Neutral - Location: 151,127 - Actor771: v15 - Owner: Neutral - Location: 152,127 - Actor772: v15 - Owner: Neutral - Location: 155,127 - Actor773: v15 - Owner: Neutral - Location: 156,127 - Actor633: mine - Owner: Neutral - Location: 166,128 - Actor563: tc04 - Owner: Neutral - Location: 180,108 - Actor591: mine - Owner: Neutral - Location: 143,52 - Actor615: mine - Owner: Neutral - Location: 228,126 - Actor578: mine - Owner: Neutral - Location: 105,28 - Actor580: lhus - Owner: Neutral - Location: 112,18 - Actor683: mine - Owner: Neutral - Location: 75,73 - Actor693: mine - Owner: Neutral - Location: 196,79 - Actor782: mine - Owner: Neutral - Location: 218,91 - Actor557: mine - Owner: Neutral - Location: 194,100 - Actor623: tc04 - Owner: Neutral - Location: 189,101 - Actor562: t16 - Owner: Neutral - Location: 46,179 - Actor662: mine - Owner: Neutral - Location: 96,111 - Actor617: tc02 - Owner: Neutral - Location: 79,116 - Actor682: mine - Owner: Neutral - Location: 215,70 - Actor779: mine - Owner: Neutral - Location: 282,173 - Actor792: mine - Owner: Neutral - Location: 281,175 - Actor624: tc04 - Owner: Neutral - Location: 134,184 - Actor783: mine - Owner: Neutral - Location: 139,190 - Actor787: mine - Owner: Neutral - Location: 141,192 - Actor694: mine - Owner: Neutral - Location: 204,158 - Actor785: mine - Owner: Neutral - Location: 203,160 - Actor628: mpspawn - Owner: Neutral - Location: 194,156 - Actor698: tc01 - Owner: Neutral - Location: 195,151 - Actor786: tc04 - Owner: Neutral - Location: 19,105 - Actor789: mine - Owner: Neutral - Location: 16,109 - Actor790: mine - Owner: Neutral - Location: 14,112 - Actor784: mpspawn - Owner: Neutral - Location: 16,101 - Actor774: mpspawn - Owner: Neutral - Location: 184,14 - Actor776: tc04 - Owner: Neutral - Location: 20,10 - Actor778: mine - Owner: Neutral - Location: 25,16 - Actor795: mine - Owner: Neutral - Location: 27,18 - Actor589: mine - Owner: Neutral - Location: 285,18 - Actor647: mine - Owner: Neutral - Location: 282,19 - Actor648: tc01 - Owner: Neutral - Location: 275,24 - Actor780: mpspawn - Owner: Neutral - Location: 279,24 - Actor777: mpspawn - Owner: Neutral - Location: 278,181 - Actor791: mine - Owner: Neutral - Location: 176,7 - Actor630: mine - Owner: Neutral - Location: 177,10 - Actor781: mpspawn - Owner: Neutral - Location: 18,16 - Actor775: mpspawn - Owner: Neutral - Location: 131,190 - Actor626: tc01 - Owner: Neutral - Location: 134,194 - Actor788: tc04 - Owner: Neutral - Location: 176,13 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/regeneration-basin.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/regeneration-basin.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/ridges.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/ridges.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/ritual-circle.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/ritual-circle.oramap differ diff -Nru openra-20200503/mods/ra/maps/sarin-gas-1-crackdown/crackdown-AI.lua openra-20210321/mods/ra/maps/sarin-gas-1-crackdown/crackdown-AI.lua --- openra-20200503/mods/ra/maps/sarin-gas-1-crackdown/crackdown-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-1-crackdown/crackdown-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -21,8 +21,8 @@ } GroundAttackUnits = { { "ttnk", "ttnk", "e2", "e2", "e2" }, { "3tnk", "v2rl", "e4", "e4", "e4" } } -GroundAttackPaths = -{ +GroundAttackPaths = +{ { EscapeSouth5.Location, Patrol1.Location }, { EscapeNorth10.Location, EscapeNorth7.Location } } diff -Nru openra-20200503/mods/ra/maps/sarin-gas-1-crackdown/crackdown.lua openra-20210321/mods/ra/maps/sarin-gas-1-crackdown/crackdown.lua --- openra-20200503/mods/ra/maps/sarin-gas-1-crackdown/crackdown.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-1-crackdown/crackdown.lua 2021-03-21 11:10:05.000000000 +0000 @@ -108,7 +108,7 @@ Utils.Do(route, function(waypoint) truck.Move(waypoint.Location) end) - + Trigger.OnIdle(truck, function() if truck.Location == route[#route].Location then truck.Destroy() diff -Nru openra-20200503/mods/ra/maps/sarin-gas-1-crackdown/map.yaml openra-20210321/mods/ra/maps/sarin-gas-1-crackdown/map.yaml --- openra-20200503/mods/ra/maps/sarin-gas-1-crackdown/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-1-crackdown/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -568,82 +568,82 @@ Truck4: truk Location: 67,59 Owner: USSR - Facing: 223 + Facing: 892 Truck2: truk Location: 65,58 Owner: USSR - Facing: 31 + Facing: 124 IntroTruck1: truk Location: 33,57 Owner: USSR - Facing: 63 + Facing: 252 Truck1: truk Location: 62,59 Owner: USSR - Facing: 31 + Facing: 124 IntroTruck2: truk Location: 33,59 Owner: USSR - Facing: 63 + Facing: 252 Truck3: truk Location: 62,83 Owner: USSR - Facing: 223 + Facing: 892 Actor171: v2rl Location: 55,61 Owner: USSR - Facing: 63 + Facing: 252 Actor172: v2rl Location: 70,68 Owner: USSR - Facing: 159 + Facing: 636 Actor173: 3tnk Location: 58,54 Owner: USSR - Facing: 159 + Facing: 636 Actor174: 3tnk Location: 60,47 Owner: USSR - Facing: 31 + Facing: 124 Actor175: 3tnk Location: 63,68 Owner: USSR - Facing: 127 + Facing: 508 Actor176: 3tnk Location: 52,53 Owner: USSR - Facing: 63 + Facing: 252 Actor177: 3tnk Location: 45,70 Owner: USSR - Facing: 95 + Facing: 380 Actor178: 3tnk Location: 59,69 Owner: USSR - Facing: 127 + Facing: 508 Actor179: v2rl Location: 48,59 Owner: BadGuy - Facing: 63 + Facing: 252 Actor180: v2rl Location: 55,81 Owner: USSR - Facing: 31 + Facing: 124 PatrolMammoth: 4tnk Location: 20,86 Owner: BadGuy Actor182: ttnk Location: 64,55 Owner: USSR - Facing: 95 + Facing: 380 Actor183: 3tnk Location: 75,43 Owner: USSR - Facing: 31 + Facing: 124 StartTank: 3tnk Location: 31,58 Owner: BadGuy - Facing: 63 + Facing: 252 StartRifle1: e1 Location: 33,58 Owner: BadGuy @@ -663,7 +663,7 @@ StartRifle5: e1 Location: 23,44 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 4 StartRifle6: e1 Location: 24,73 @@ -676,7 +676,7 @@ Truck5: truk Location: 59,83 Owner: USSR - Facing: 31 + Facing: 124 Actor186: e1 Location: 57,60 Owner: USSR @@ -732,7 +732,7 @@ Actor199: e2 Location: 63,82 Owner: BadGuy - Facing: 159 + Facing: 636 SubCell: 1 Actor200: e4 Location: 58,78 @@ -741,12 +741,12 @@ Actor201: e1 Location: 56,77 Owner: BadGuy - Facing: 95 + Facing: 380 SubCell: 0 Actor202: e1 Location: 57,76 Owner: BadGuy - Facing: 191 + Facing: 764 SubCell: 2 Actor203: e2 Location: 60,77 @@ -759,12 +759,12 @@ Actor207: e2 Location: 45,60 Owner: BadGuy - Facing: 95 + Facing: 380 SubCell: 2 Actor208: e2 Location: 46,57 Owner: BadGuy - Facing: 63 + Facing: 252 SubCell: 3 Actor209: e1 Location: 52,60 @@ -773,12 +773,12 @@ Actor210: e1 Location: 44,82 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 0 Actor211: e1 Location: 46,83 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 2 Actor212: c1 Location: 43,41 @@ -823,79 +823,79 @@ Actor224: dog Location: 49,55 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 3 Actor225: e2 Location: 48,57 Owner: USSR - Facing: 31 + Facing: 124 SubCell: 2 Actor226: e2 Location: 50,58 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 2 Actor227: e2 Location: 50,55 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 Actor231: e1 Location: 72,36 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 3 Actor232: e1 Location: 72,37 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 3 Actor233: dog Location: 73,38 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 Actor234: dog Location: 75,41 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 3 Actor235: ss Location: 72,56 Owner: Turkey - Facing: 191 + Facing: 764 Actor236: ss Location: 74,52 Owner: Turkey - Facing: 159 + Facing: 636 Actor237: ss Location: 74,89 Owner: Turkey - Facing: 63 + Facing: 252 Actor238: ss Location: 70,93 Owner: Turkey - Facing: 31 + Facing: 124 Actor239: ss Location: 47,92 Owner: Turkey - Facing: 191 + Facing: 764 Actor240: ss Location: 70,81 Owner: Turkey - Facing: 159 + Facing: 636 Actor241: ss Location: 55,94 Owner: Turkey - Facing: 159 + Facing: 636 Actor242: ss Location: 78,48 Owner: Turkey - Facing: 95 + Facing: 380 Actor243: ss Location: 75,60 Owner: Turkey - Facing: 159 + Facing: 636 Actor320: apwr Owner: Turkey Location: 86,41 @@ -903,27 +903,27 @@ Owner: Greece Location: 16,57 SubCell: 3 - Facing: 191 + Facing: 764 GreeceRifle2: e1 Owner: Greece Location: 16,57 SubCell: 1 - Facing: 191 + Facing: 764 GreeceRifle3: e1 Owner: Greece Location: 16,57 SubCell: 2 - Facing: 191 + Facing: 764 GreeceRifle4: e1 Owner: Greece Location: 16,57 SubCell: 4 - Facing: 191 + Facing: 764 GreeceRifle5: e1 Owner: Greece Location: 16,57 SubCell: 5 - Facing: 191 + Facing: 764 AttackSouth1: waypoint Location: 61,75 Owner: Neutral diff -Nru openra-20200503/mods/ra/maps/sarin-gas-1-crackdown/rules.yaml openra-20210321/mods/ra/maps/sarin-gas-1-crackdown/rules.yaml --- openra-20200503/mods/ra/maps/sarin-gas-1-crackdown/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-1-crackdown/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -113,7 +113,3 @@ E7: Buildable: Prerequisites: ~disabled - -SS: - AutoTarget: - InitialStanceAI: AttackAnything diff -Nru openra-20200503/mods/ra/maps/sarin-gas-2-down-under/downunder.lua openra-20210321/mods/ra/maps/sarin-gas-2-down-under/downunder.lua --- openra-20200503/mods/ra/maps/sarin-gas-2-down-under/downunder.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-2-down-under/downunder.lua 2021-03-21 11:10:05.000000000 +0000 @@ -113,7 +113,7 @@ Trigger.AfterDelay(DateTime.Seconds(4), function() Utils.Do(SarinVictims, function(actor) if not actor.IsDead then - actor.Kill() + actor.Kill("ExplosionDeath") end end) end) diff -Nru openra-20200503/mods/ra/maps/sarin-gas-2-down-under/map.yaml openra-20210321/mods/ra/maps/sarin-gas-2-down-under/map.yaml --- openra-20200503/mods/ra/maps/sarin-gas-2-down-under/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-2-down-under/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -618,83 +618,83 @@ Mammoth1: 4tnk Location: 67,44 Owner: USSR - Facing: 127 + Facing: 508 Mammoth2: 4tnk Location: 73,58 Owner: BadGuy StealMammoth: 4tnk Location: 99,40 Owner: USSR - Facing: 127 + Facing: 508 StartSpy: spy Location: 4,62 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 0 Actor162: e1 Location: 6,61 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 4 Actor163: e1 Location: 6,62 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 2 Actor164: e1 Location: 6,62 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 4 Actor165: e1 Location: 6,64 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 1 Actor166: e1 Location: 6,63 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 2 Actor167: e1 Location: 6,60 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 3 Actor168: e1 Location: 5,61 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 1 Actor169: e1 Location: 5,63 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 3 Actor170: e1 Location: 5,63 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 2 Actor171: e1 Location: 5,61 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 4 Actor172: medi Location: 3,62 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 0 Actor173: dog Location: 37,62 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 2 Actor174: dog Location: 33,64 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 2 Actor175: e1 Location: 23,61 @@ -711,117 +711,117 @@ Actor178: e1 Location: 25,74 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 2 Actor179: e1 Location: 25,75 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 4 Actor180: e1 Location: 25,74 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 3 DogCrew3: e1 Location: 45,68 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 2 DogCrew2: e1 Location: 47,68 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 3 DogCrew1: dog Location: 46,69 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 1 SarinVictim12: e2 Location: 48,59 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 0 SarinVictim3: e2 Location: 45,65 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 1 SarinVictim6: e2 Location: 44,62 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 0 SarinVictim9: e2 Location: 45,59 Owner: USSR - Facing: 223 + Facing: 892 SubCell: 2 SarinVictim11: e2 Location: 50,59 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 1 SarinVictim2: e2 Location: 48,65 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 0 SarinVictim5: e2 Location: 44,63 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 2 SarinVictim8: e2 Location: 44,59 Owner: USSR - Facing: 31 + Facing: 124 SubCell: 4 SarinVictim1: e2 Location: 50,65 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 0 Camera2Rifle1: e1 Location: 38,61 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Camera2Rifle2: e1 Location: 38,63 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 2 Camera2Rifle3: e1 Location: 39,61 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 0 Camera2Gren1: e2 Location: 40,62 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 0 Camera2Gren2: e2 Location: 39,63 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 2 Actor198: e1 Location: 22,51 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 2 Actor199: e1 Location: 23,50 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 2 Actor200: e1 Location: 28,47 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 0 Scientist2: chan Location: 24,47 @@ -838,7 +838,7 @@ SarinVictim13: e2 Location: 49,65 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 0 SarinVictim10: e2 Location: 49,59 @@ -847,148 +847,148 @@ Actor206: medi Location: 53,81 Owner: Greece - Facing: 159 + Facing: 636 SubCell: 2 Actor207: spy Location: 62,81 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 2 Civ1: c6 Location: 53,74 Owner: Greece - Facing: 223 + Facing: 892 SubCell: 4 Civ2: c5 Location: 54,78 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 1 Civ3: c6 Location: 54,84 Owner: Greece - Facing: 159 + Facing: 636 SubCell: 1 Civ4: c5 Location: 62,84 Owner: Greece - Facing: 191 + Facing: 764 SubCell: 1 Civ5: c6 Location: 62,78 Owner: Greece - Facing: 159 + Facing: 636 SubCell: 3 Officer3: gnrl Location: 61,72 Owner: USSR - Facing: 223 + Facing: 892 SubCell: 3 Actor218: e1 Location: 67,72 Owner: USSR - Facing: 31 + Facing: 124 SubCell: 3 Actor219: e2 Location: 68,73 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 3 Actor220: e1 Location: 66,73 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 0 Actor221: e1 Location: 96,60 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 3 Actor222: e1 Location: 96,63 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 3 Actor223: e1 Location: 95,62 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 2 Actor224: e1 Location: 97,60 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 1 Actor225: e1 Location: 97,64 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 2 Actor226: e1 Location: 98,61 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 3 Actor227: e1 Location: 96,64 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 4 Actor228: e1 Location: 96,62 Owner: USSR - Facing: 191 + Facing: 764 SubCell: 2 Actor229: e1 Location: 66,47 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 3 Actor230: e1 Location: 68,47 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 3 Actor231: e1 Location: 96,50 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 2 Actor232: e1 Location: 94,49 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Actor233: e1 Location: 95,50 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 2 Actor234: e1 Location: 67,53 Owner: USSR SubCell: 4 - Facing: 147 - TurretFacing: -12 + Facing: 588 + TurretFacing: 388 Actor235: e1 Location: 95,51 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 Actor237: e1 Location: 82,76 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Actor238: e1 Location: 80,75 Owner: USSR - Facing: 191 + Facing: 764 SubCell: 3 Actor239: e1 Location: 78,75 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 3 Actor240: e1 Location: 79,76 @@ -1009,12 +1009,12 @@ Actor245: e1 Location: 82,51 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 1 Scientist1: chan Location: 88,50 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Actor247: e1 Location: 98,63 @@ -1028,33 +1028,32 @@ Owner: USSR Location: 99,75 SubCell: 3 - Facing: 92 + Facing: 368 DemoRifle1: e1 Location: 99,76 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 2 DemoRifle2: e1 Location: 100,75 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 DemoRifle3: e1 Location: 101,76 Owner: USSR - Facing: 191 + Facing: 764 SubCell: 1 DemoRifle4: e1 Location: 100,77 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 2 DemoFlame: e4 Owner: USSR Location: 100,75 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 ScientistMan: chan Location: 94,82 Owner: England @@ -1062,77 +1061,77 @@ Actor254: e1 Location: 92,68 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 1 Actor255: e1 Location: 92,69 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 0 Actor256: e1 Location: 93,68 Owner: USSR - Facing: 191 + Facing: 764 SubCell: 3 FiringSquad1: e1 Location: 93,79 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 5 FiringSquad2: e1 Location: 94,79 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 4 FiringSquad3: e1 Location: 94,79 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 5 FiringSquad4: e1 Location: 95,79 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 4 FiringSquad5: e1 Location: 95,79 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 5 Officer2: gnrl Location: 92,80 Owner: USSR - Facing: 127 + Facing: 508 SubCell: 2 Actor263: e2 Location: 92,49 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 3 Actor264: dog Location: 96,48 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Actor265: dog Location: 97,61 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Actor266: dog Location: 67,51 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 2 Actor267: dog Location: 42,59 Owner: USSR - Facing: 159 + Facing: 636 SubCell: 3 Actor268: dog Location: 63,46 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 1 Actor269: e1 Location: 21,61 @@ -1152,118 +1151,105 @@ Owner: USSR Location: 62,73 SubCell: 3 - Facing: 115 + Facing: 460 PrisonDog2: dog Owner: USSR Location: 60,71 SubCell: 3 - Facing: 58 + Facing: 232 PrisonDog3: dog Owner: USSR Location: 63,72 SubCell: 3 - Facing: 44 + Facing: 176 PrisonDog4: dog Owner: USSR Location: 61,70 SubCell: 3 - Facing: 92 + Facing: 368 Actor328: e1 Owner: USSR Location: 59,72 SubCell: 3 - Facing: 12 - TurretFacing: 12 + Facing: 48 Actor329: e4 Owner: USSR Location: 94,48 SubCell: 3 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor332: e4 Owner: USSR Location: 82,76 SubCell: 1 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor333: dog Owner: USSR Location: 82,76 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 DemoTruck: dtrk Owner: England Location: 106,76 - Facing: 63 + Facing: 252 Tanya: e7 Owner: Germany Location: 71,82 SubCell: 3 - Facing: 182 - TurretFacing: 182 + Facing: 728 Officer1: gnrl Owner: USSR Location: 23,47 SubCell: 3 - Facing: 92 + Facing: 368 StealTruck: truk Owner: USSR Location: 23,82 - Facing: 194 + Facing: 776 StartAttacker1: e1 Owner: USSR Location: 11,64 SubCell: 3 - Facing: 92 - TurretFacing: 92 + Facing: 368 StartAttacker2: e1 Owner: USSR Location: 13,60 SubCell: 3 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor337: e1 Owner: USSR Location: 81,51 SubCell: 3 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor338: dog Owner: USSR Location: 81,51 SubCell: 1 - Facing: 92 + Facing: 368 Actor350: e1 Owner: USSR Location: 60,62 SubCell: 3 - Facing: -20 - TurretFacing: -20 + Facing: 944 Actor351: e1 Owner: USSR Location: 61,64 SubCell: 3 - Facing: 181 - TurretFacing: 181 + Facing: 724 Actor352: e1 Owner: USSR Location: 61,60 SubCell: 3 - Facing: 177 - TurretFacing: 177 + Facing: 708 Actor353: e1 Owner: USSR Location: 61,60 SubCell: 1 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor354: spy Owner: Greece Location: 62,84 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 DoggyCam: waypoint Location: 46,72 Owner: Neutral diff -Nru openra-20200503/mods/ra/maps/sarin-gas-2-down-under/rules.yaml openra-20210321/mods/ra/maps/sarin-gas-2-down-under/rules.yaml --- openra-20200503/mods/ra/maps/sarin-gas-2-down-under/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-2-down-under/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -48,7 +48,7 @@ MaxWeight: 1 RevealsShroud: Range: 4c0 - ValidStances: Neutral + ValidRelationships: Neutral RequiresCondition: mission ExternalCondition@mission: Condition: mission diff -Nru openra-20200503/mods/ra/maps/sarin-gas-3-controlled-burn/controlledburn-AI.lua openra-20210321/mods/ra/maps/sarin-gas-3-controlled-burn/controlledburn-AI.lua --- openra-20200503/mods/ra/maps/sarin-gas-3-controlled-burn/controlledburn-AI.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-3-controlled-burn/controlledburn-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,152 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +AttackGroup = { } +AttackGroupSize = 10 +BGAttackGroup = { } +BGAttackGroupSize = 8 +SovietInfantry = { "e1", "e2", "e4" } +SovietVehicles = { "3tnk", "3tnk", "v2rl" } +SovietAircraftType = { "mig", "yak" } +Planes = { } + +ProductionInterval = +{ + easy = DateTime.Seconds(30), + normal = DateTime.Seconds(20), + hard = DateTime.Seconds(10) +} + +SendBGAttackGroup = function() + if #BGAttackGroup < BGAttackGroupSize then + return + end + + Utils.Do(BGAttackGroup, function(unit) + if not unit.IsDead then + IdleHunt(unit) + end + end) + + BGAttackGroup = { } +end + +ProduceBadGuyInfantry = function() + if BadGuyRax.IsDead or BadGuyRax.Owner ~= BadGuy then + return + end + + BadGuy.Build({ Utils.Random(SovietInfantry) }, function(units) + table.insert(BGAttackGroup, units[1]) + SendBGAttackGroup() + Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceBadGuyInfantry) + end) +end + +SendAttackGroup = function() + if #AttackGroup < AttackGroupSize then + return + end + + Utils.Do(AttackGroup, function(unit) + if not unit.IsDead then + IdleHunt(unit) + end + end) + + AttackGroup = { } +end + +ProduceUSSRInfantry = function() + if (USSRRax1.IsDead or USSRRax1.Owner ~= USSR) and (USSRRax2.IsDead or USSRRax2.Owner ~= USSR) then + return + end + + USSR.Build({ Utils.Random(SovietInfantry) }, function(units) + table.insert(AttackGroup, units[1]) + SendAttackGroup() + Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceUSSRInfantry) + end) +end + +ProduceVehicles = function() + if USSRWarFactory.IsDead or USSRWarFactory.Owner ~= USSR then + return + end + + USSR.Build({ Utils.Random(SovietVehicles) }, function(units) + table.insert(AttackGroup, units[1]) + SendAttackGroup() + Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceVehicles) + end) +end + +GroundAttackUnits = { {"4tnk", "3tnk", "e2", "e2", "e2", "e2" }, { "3tnk", "3tnk", "v2rl", "e4", "e4", "e4" }, {"ttnk", "ttnk", "ttnk", "shok", "shok", "shok" } } + +GroundAttackPaths = +{ + { SovietGroundEntry1.Location }, + { SovietGroundEntry2.Location }, + { SovietGroundEntry3.Location } +} +GroundWavesDelays = +{ + easy = 4, + normal = 3, + hard = 2 +} + +GroundWaves = function() + if not ForwardCommand.IsDead then + local path = Utils.Random(GroundAttackPaths) + local units = Reinforcements.Reinforce(BadGuy, Utils.Random(GroundAttackUnits), path) + Utils.Do(units, IdleHunt) + + Trigger.AfterDelay(DateTime.Minutes(GroundWavesDelays), GroundWaves) + end +end + +ProduceAircraft = function() + if Airfield.IsDead or Airfield.Owner ~= USSR then + return + end + + USSR.Build({ Utils.Random(SovietAircraftType) }, function(units) + local plane = units[1] + Planes[#Planes + 1] = plane + + Trigger.OnKilled(plane, ProduceAircraft) + + local alive = Utils.Where(Planes, function(y) return not y.IsDead end) + if #alive < 2 then + Trigger.AfterDelay(DateTime.Seconds(ProductionInterval[Map.LobbyOption("difficulty")] / 2), ProduceAircraft) + end + + InitializeAttackAircraft(plane, Greece) + end) +end + +ActivateAI = function() + local difficulty = Map.LobbyOption("difficulty") + GroundWavesDelays = GroundWavesDelays[difficulty] + + local buildings = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == USSR and self.HasProperty("StartBuildingRepairs") end) + Utils.Do(buildings, function(actor) + Trigger.OnDamaged(actor, function(building) + if building.Owner == USSR and building.Health < building.MaxHealth * 3/4 then + building.StartBuildingRepairs() + end + end) + end) + + ProduceBadGuyInfantry() + ProduceUSSRInfantry() + ProduceVehicles() + Trigger.AfterDelay(DateTime.Minutes(GroundWavesDelays), GroundWaves) + Trigger.AfterDelay(DateTime.Minutes(5), ProduceAircraft) +end diff -Nru openra-20200503/mods/ra/maps/sarin-gas-3-controlled-burn/controlledburn.lua openra-20210321/mods/ra/maps/sarin-gas-3-controlled-burn/controlledburn.lua --- openra-20200503/mods/ra/maps/sarin-gas-3-controlled-burn/controlledburn.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-3-controlled-burn/controlledburn.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,149 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +StartUnits = { APC, StartSpy, Rifle1, Rifle2, Rifle3, Rifle4, Rocket1, Rocket2, Rocket3, Rocket4, Rocket5 } +SarinPlants = { SarinLab1, SarinLab2, SarinLab3, SarinLab4, SarinLab5 } +MammothStart = { CPos.New(37, 46), CPos.New(37, 47), CPos.New(37, 48), CPos.New(37, 49), CPos.New(37,50) } +NorthPatrol = { NorthPatrol1.Location, NorthPatrol2.Location, NorthPatrol3.Location, NorthPatrol4.Location, NorthPatrol5.Location } +BarrerlInvestigators = { Alert1, Alert2, Alert3, Alert4, Alert5 } +RaxTeam = { "e1", "e2", "e2", "e4", "e4", "shok" } +SouthPatrol = { SouthPatrol1.Location, SouthPatrol2.Location, SouthPatrol3.Location } +MCVReinforcements = +{ + easy = { "1tnk", "1tnk", "2tnk", "2tnk", "2tnk", "2tnk", "arty", "mcv" }, + normal = { "1tnk", "1tnk", "2tnk", "2tnk", "mcv" }, + hard = { "1tnk", "1tnk", "mcv" } +} + +IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end + +SetupTriggers = function() + Trigger.OnEnteredFootprint(MammothStart, function(actor, mammothcam) + if actor.Owner == Greece then + Trigger.RemoveFootprintTrigger(mammothcam) + NorthMammoth.Patrol(NorthPatrol, true, 20) + local mammothCamera = Actor.Create("camera", true, { Owner = Greece, Location = NorthPatrol1.Location }) + Trigger.AfterDelay(DateTime.Seconds(10), function() + mammothCamera.Destroy() + end) + end + end) + + Trigger.OnEnteredProximityTrigger(NorthPatrol3.CenterPosition, WDist.FromCells(8), function(actor, trigger1) + if actor.Owner == Greece then + Trigger.RemoveProximityTrigger(trigger1) + local baseCamera = Actor.Create("camera", true, { Owner = Greece, Location = BaseCam.Location }) + if Map.LobbyOption("difficulty") == "hard" then + Reinforcements.Reinforce(BadGuy, RaxTeam, { BadGuyRaxSpawn.Location, BaseCam.Location }, 0) + end + Trigger.AfterDelay(DateTime.Seconds(10), function() + baseCamera.Destroy() + end) + end + end) + + Trigger.OnAllRemovedFromWorld(StartUnits, function() + if not MCVArrived then + USSR.MarkCompletedObjective(SovietObj) + end + end) + + Trigger.OnKilled(VeryImportantBarrel, function() + Utils.Do(BarrerlInvestigators, function(actor) + if not actor.IsDead then + actor.AttackMove(AlertGo.Location) + end + end) + end) + + Trigger.OnAnyKilled(SarinPlants, function() + Greece.MarkFailedObjective(CaptureSarin) + end) + + Trigger.OnAllKilledOrCaptured(SarinPlants, function() + Greece.MarkCompletedObjective(CaptureSarin) + end) +end + +MCVArrived = false +MCVArrivedTick = false +PowerDownTeslas = function() + if not MCVArrived then + CaptureSarin = Greece.AddObjective("Capture all Sarin processing plants intact.") + KillBase = Greece.AddObjective("Destroy the enemy compound.") + Greece.MarkCompletedObjective(TakeOutPower) + Media.PlaySpeechNotification(Greece, "ReinforcementsArrived") + Reinforcements.Reinforce(Greece, MCVReinforcements[Map.LobbyOption("difficulty")], { AlliesSpawn.Location, AlliesMove.Location }) + local baseFlare = Actor.Create("flare", true, { Owner = Greece, Location = AlliedBase.Location }) + Actor.Create("proc", true, { Owner = USSR, Location = Proc1.Location }) + Actor.Create("proc", true, { Owner = USSR, Location = Proc2.Location }) + SouthMammoth.Patrol(SouthPatrol, true, 20) + MCVArrived = true + + Trigger.AfterDelay(DateTime.Seconds(1), function() + MCVArrivedTick = true + end) + + Trigger.AfterDelay(DateTime.Seconds(60), function() + local attackers = Reinforcements.Reinforce(USSR, { "e1", "e1", "e1", "e2", "e4" }, { SovietGroundEntry3.Location }, 5) + Utils.Do(attackers, IdleHunt) + end) + + Trigger.AfterDelay(DateTime.Seconds(100), function() + baseFlare.Destroy() + ActivateAI() + end) + end +end + +Tick = function() + USSR.Cash = 10000 + BadGuy.Cash = 10000 + + if BadGuy.PowerState ~= "Normal" then + PowerDownTeslas() + end + + if Greece.HasNoRequiredUnits() and MCVArrivedTick then + USSR.MarkCompletedObjective(SovietObj) + end + + if USSR.HasNoRequiredUnits() then + Greece.MarkCompletedObjective(KillBase) + end +end + +WorldLoaded = function() + Greece = Player.GetPlayer("Greece") + USSR = Player.GetPlayer("USSR") + BadGuy = Player.GetPlayer("BadGuy") + + SovietObj = USSR.AddObjective("Defeat the Allies.") + TakeOutPower = Greece.AddObjective("Bring down the power of the base to the east.") + + Trigger.OnObjectiveAdded(Greece, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") + end) + + Trigger.OnObjectiveCompleted(Greece, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") + end) + Trigger.OnObjectiveFailed(Greece, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") + end) + Trigger.OnPlayerLost(Greece, function() + Media.PlaySpeechNotification(Greece, "Lose") + end) + Trigger.OnPlayerWon(Greece, function() + Media.PlaySpeechNotification(Greece, "Win") + end) + + StartSpy.DisguiseAsType("e1", BadGuy) + Camera.Position = DefaultCameraPosition.CenterPosition + SetupTriggers() +end Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/sarin-gas-3-controlled-burn/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/sarin-gas-3-controlled-burn/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/sarin-gas-3-controlled-burn/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/sarin-gas-3-controlled-burn/map.png differ diff -Nru openra-20200503/mods/ra/maps/sarin-gas-3-controlled-burn/map.yaml openra-20210321/mods/ra/maps/sarin-gas-3-controlled-burn/map.yaml --- openra-20200503/mods/ra/maps/sarin-gas-3-controlled-burn/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-3-controlled-burn/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,1244 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: Sarin Gas 3: Controlled Burn + +Author: Westwood Studios + +Tileset: TEMPERAT + +MapSize: 128,128 + +Bounds: 30,27,70,66 + +Visibility: MissionSelector + +Categories: Mission + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: allies + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Faction: england + PlayerReference@BadGuy: + Name: BadGuy + Faction: soviet + Color: FF1400 + Allies: USSR + Enemies: Greece + PlayerReference@USSR: + Name: USSR + Faction: soviet + Color: FF1400 + Allies: BadGuy + Enemies: Greece + PlayerReference@Greece: + Name: Greece + AllowBots: False + Playable: True + Required: True + LockFaction: True + Faction: allies + LockColor: True + Color: ABB7E4 + LockSpawn: True + LockTeam: True + Enemies: USSR, BadGuy + +Actors: + Actor0: brik + Location: 48,52 + Owner: USSR + Actor1: brik + Location: 49,52 + Owner: USSR + Actor2: brik + Location: 55,52 + Owner: USSR + Actor3: brik + Location: 56,52 + Owner: USSR + Actor4: brik + Location: 57,52 + Owner: USSR + Actor5: brik + Location: 58,52 + Owner: USSR + Actor6: brik + Location: 59,52 + Owner: USSR + Actor7: brik + Location: 48,53 + Owner: USSR + Actor8: brik + Location: 49,53 + Owner: USSR + Actor9: brik + Location: 55,53 + Owner: USSR + Actor10: brik + Location: 56,53 + Owner: USSR + Actor11: brik + Location: 58,53 + Owner: USSR + Actor12: brik + Location: 59,53 + Owner: USSR + Actor13: brik + Location: 59,54 + Owner: USSR + Actor14: brik + Location: 59,55 + Owner: USSR + Actor15: brik + Location: 60,55 + Owner: USSR + Actor16: brik + Location: 59,56 + Owner: USSR + Actor17: brik + Location: 60,56 + Owner: USSR + Actor18: brik + Location: 60,57 + Owner: USSR + Actor19: brik + Location: 60,58 + Owner: USSR + Actor20: brik + Location: 60,59 + Owner: USSR + Actor21: brik + Location: 51,60 + Owner: USSR + Actor22: brik + Location: 52,60 + Owner: USSR + Actor23: brik + Location: 53,60 + Owner: USSR + Actor24: brik + Location: 59,60 + Owner: USSR + Actor25: brik + Location: 60,60 + Owner: USSR + Actor26: brik + Location: 51,61 + Owner: USSR + Actor27: brik + Location: 53,61 + Owner: USSR + Actor28: brik + Location: 59,61 + Owner: USSR + Actor29: brik + Location: 60,61 + Owner: USSR + Actor30: brik + Location: 51,62 + Owner: USSR + Actor31: brik + Location: 52,62 + Owner: USSR + Actor32: brik + Location: 53,62 + Owner: USSR + Actor33: brik + Location: 59,67 + Owner: USSR + Actor34: brik + Location: 60,67 + Owner: USSR + Actor35: brik + Location: 51,68 + Owner: USSR + Actor36: brik + Location: 52,68 + Owner: USSR + Actor37: brik + Location: 53,68 + Owner: USSR + Actor38: brik + Location: 59,68 + Owner: USSR + Actor39: brik + Location: 60,68 + Owner: USSR + Actor40: brik + Location: 51,69 + Owner: USSR + Actor41: brik + Location: 53,69 + Owner: USSR + Actor42: brik + Location: 60,69 + Owner: USSR + Actor43: brik + Location: 51,70 + Owner: USSR + Actor44: brik + Location: 52,70 + Owner: USSR + Actor45: brik + Location: 53,70 + Owner: USSR + Actor46: brik + Location: 60,70 + Owner: USSR + Actor47: brik + Location: 60,71 + Owner: USSR + Actor48: brik + Location: 42,72 + Owner: USSR + Actor49: brik + Location: 43,72 + Owner: USSR + Actor50: brik + Location: 60,72 + Owner: USSR + Actor51: brik + Location: 42,73 + Owner: USSR + Actor52: brik + Location: 43,73 + Owner: USSR + Actor53: brik + Location: 44,73 + Owner: USSR + Actor54: brik + Location: 45,73 + Owner: USSR + Actor55: brik + Location: 46,73 + Owner: USSR + Actor56: brik + Location: 47,73 + Owner: USSR + Actor57: brik + Location: 48,73 + Owner: USSR + Actor58: brik + Location: 60,73 + Owner: USSR + Actor59: brik + Location: 47,74 + Owner: USSR + Actor60: brik + Location: 48,74 + Owner: USSR + Actor61: brik + Location: 54,74 + Owner: USSR + Actor62: brik + Location: 55,74 + Owner: USSR + Actor63: brik + Location: 59,74 + Owner: USSR + Actor64: brik + Location: 60,74 + Owner: USSR + Actor65: brik + Location: 54,75 + Owner: USSR + Actor66: brik + Location: 55,75 + Owner: USSR + Actor67: brik + Location: 56,75 + Owner: USSR + Actor68: brik + Location: 57,75 + Owner: USSR + Actor69: brik + Location: 58,75 + Owner: USSR + Actor70: brik + Location: 59,75 + Owner: USSR + Actor71: brik + Location: 60,75 + Owner: USSR + Actor72: tc04 + Location: 35,40 + Owner: Neutral + Actor73: tc03 + Location: 30,42 + Owner: Neutral + Actor74: tc02 + Location: 30,53 + Owner: Neutral + Actor75: t07 + Location: 30,57 + Owner: Neutral + Actor76: t11 + Location: 35,51 + Owner: Neutral + Actor77: t12 + Location: 32,51 + Owner: Neutral + Actor78: t12 + Location: 39,42 + Owner: Neutral + Actor79: t16 + Location: 30,30 + Owner: Neutral + Actor80: tc01 + Location: 89,39 + Owner: Neutral + Actor81: t16 + Location: 96,38 + Owner: Neutral + Actor82: tc05 + Location: 85,27 + Owner: Neutral + Actor83: tc04 + Location: 85,38 + Owner: Neutral + Actor84: tc01 + Location: 80,28 + Owner: Neutral + Actor85: tc05 + Location: 74,27 + Owner: Neutral + Actor86: t16 + Location: 73,27 + Owner: Neutral + Actor87: t01 + Location: 80,41 + Owner: Neutral + Actor88: t11 + Location: 85,41 + Owner: Neutral + Actor89: tc02 + Location: 78,42 + Owner: Neutral + Actor90: tc04 + Location: 52,42 + Owner: Neutral + Actor91: tc03 + Location: 56,42 + Owner: Neutral + Actor92: tc02 + Location: 60,41 + Owner: Neutral + Actor93: mine + Location: 38,32 + Owner: Neutral + Actor94: mine + Location: 53,35 + Owner: Neutral + Actor95: t01 + Location: 56,28 + Owner: Neutral + Actor96: t11 + Location: 40,37 + Owner: Neutral + Actor97: t13 + Location: 43,29 + Owner: Neutral + Actor98: t14 + Location: 33,30 + Owner: Neutral + Actor99: tc01 + Location: 69,28 + Owner: Neutral + Actor100: t16 + Location: 64,38 + Owner: Neutral + Actor101: tc05 + Location: 72,47 + Owner: Neutral + Actor102: tc04 + Location: 66,49 + Owner: Neutral + Actor103: tc03 + Location: 63,52 + Owner: Neutral + Actor104: tc01 + Location: 72,46 + Owner: Neutral + Actor105: t16 + Location: 78,45 + Owner: Neutral + Actor106: tc04 + Location: 61,56 + Owner: Neutral + Actor107: t02 + Location: 60,53 + Owner: Neutral + Actor108: tc04 + Location: 30,74 + Owner: Neutral + Actor109: tc02 + Location: 35,77 + Owner: Neutral + Actor110: tc03 + Location: 33,79 + Owner: Neutral + Actor111: tc05 + Location: 90,51 + Owner: Neutral + Actor112: tc04 + Location: 83,50 + Owner: Neutral + Actor113: tc02 + Location: 96,50 + Owner: Neutral + Actor114: tc01 + Location: 98,49 + Owner: Neutral + Actor115: tc02 + Location: 57,38 + Owner: Neutral + Actor116: tc01 + Location: 37,44 + Owner: Neutral + Actor117: mine + Location: 89,57 + Owner: Neutral + Actor118: tc04 + Location: 78,75 + Owner: Neutral + Actor119: tc05 + Location: 95,69 + Owner: Neutral + Actor120: tc03 + Location: 98,69 + Owner: Neutral + Actor121: tc05 + Location: 59,75 + Owner: Neutral + Actor122: tc02 + Location: 37,80 + Owner: Neutral + Actor123: tc05 + Location: 67,69 + Owner: Neutral + Actor124: tc04 + Location: 65,70 + Owner: Neutral + Actor125: tc01 + Location: 67,71 + Owner: Neutral + Actor126: tc03 + Location: 73,66 + Owner: Neutral + Actor127: t01 + Location: 43,85 + Owner: Neutral + Actor128: mine + Location: 58,82 + Owner: Neutral + Actor129: tc04 + Location: 29,85 + Owner: Neutral + Actor130: tc01 + Location: 58,72 + Owner: Neutral + Actor131: t16 + Location: 58,73 + Owner: Neutral + Actor132: t16 + Location: 69,78 + Owner: Neutral + Actor133: t13 + Location: 66,62 + Owner: Neutral + Actor134: tc02 + Location: 84,72 + Owner: Neutral + Actor135: mine + Location: 78,86 + Owner: Neutral + Actor136: t15 + Location: 30,63 + Owner: Neutral + Actor137: t08 + Location: 34,72 + Owner: Neutral + Actor138: t01 + Location: 71,62 + Owner: Neutral + Actor139: t02 + Location: 32,40 + Owner: Neutral + Actor140: t01 + Location: 72,54 + Owner: Neutral + Actor141: tc04 + Location: 42,73 + Owner: Neutral + Actor142: mine + Location: 80,90 + Owner: Neutral + Actor143: mine + Location: 87,60 + Owner: Neutral + Actor144: mine + Location: 93,58 + Owner: Neutral + Actor145: mine + Location: 86,55 + Owner: Neutral + Actor146: tsla + Location: 93,42 + Owner: BadGuy + Actor147: tsla + Location: 91,42 + Owner: BadGuy + Actor148: tsla + Location: 97,42 + Owner: BadGuy + Actor149: tsla + Location: 95,42 + Owner: BadGuy + Actor150: fact + Location: 82,29 + Owner: BadGuy + PowerPlant1: apwr + Location: 88,35 + Owner: BadGuy + PowerPlant2: apwr + Location: 85,36 + Owner: BadGuy + PowerPlant3: apwr + Location: 89,32 + Owner: BadGuy + PowerPlant4: apwr + Location: 91,35 + Owner: BadGuy + PowerPlant5: apwr + Location: 82,37 + Owner: BadGuy + Actor156: ftur + Location: 83,34 + Owner: BadGuy + Actor157: ftur + Location: 76,37 + Owner: BadGuy + Actor158: ftur + Location: 76,34 + Owner: BadGuy + BadGuyRax: barr + Location: 79,30 + Owner: BadGuy + Actor160: v19 + Location: 94,32 + Owner: Neutral + Actor161: brl3 + Location: 93,32 + Owner: BadGuy + Actor162: barl + Location: 94,33 + Owner: BadGuy + Actor163: brl3 + Location: 93,33 + Owner: BadGuy + Actor164: brl3 + Location: 94,35 + Owner: BadGuy + Actor165: barl + Location: 94,34 + Owner: BadGuy + Actor166: brl3 + Location: 92,31 + Owner: BadGuy + Actor167: barl + Location: 92,33 + Owner: BadGuy + Actor168: barl + Location: 92,30 + Owner: BadGuy + SarinLab1: bio + Location: 36,55 + Owner: USSR + SarinLab2: bio + Location: 38,57 + Owner: USSR + SarinLab3: bio + Location: 34,57 + Owner: USSR + SarinLab4: bio + Location: 31,66 + Owner: USSR + SarinLab5: bio + Location: 30,69 + Owner: USSR + Actor172: brl3 + Location: 34,55 + Owner: USSR + Actor173: barl + Location: 35,55 + Owner: USSR + Actor174: brl3 + Location: 34,56 + Owner: USSR + Actor175: barl + Location: 33,57 + Owner: USSR + Actor176: brl3 + Location: 39,55 + Owner: USSR + Actor177: barl + Location: 38,55 + Owner: USSR + Actor178: brl3 + Location: 39,56 + Owner: USSR + Actor179: brl3 + Location: 33,59 + Owner: USSR + Actor180: tsla + Location: 52,61 + Owner: USSR + Actor181: ftur + Location: 54,53 + Owner: USSR + Actor182: ftur + Location: 50,53 + Owner: USSR + Actor185: apwr + Location: 35,70 + Owner: USSR + Actor186: apwr + Location: 38,69 + Owner: USSR + Actor187: apwr + Location: 35,67 + Owner: USSR + Actor188: tsla + Location: 52,69 + Owner: USSR + Actor189: ftur + Location: 49,74 + Owner: USSR + Actor190: ftur + Location: 53,74 + Owner: USSR + Actor191: ftur + Location: 59,66 + Owner: USSR + Actor192: ftur + Location: 59,62 + Owner: USSR + Actor193: tsla + Location: 43,68 + Owner: USSR + USSRWarFactory: weap + Location: 55,59 + Owner: USSR + Actor195: fact + Location: 46,64 + Owner: USSR + Actor196: silo + Location: 31,63 + Owner: USSR + Actor197: silo + Location: 32,62 + Owner: USSR + Actor198: silo + Location: 33,63 + Owner: USSR + Actor199: silo + Location: 34,62 + Owner: USSR + Actor200: apwr + Location: 35,63 + Owner: USSR + Actor201: apwr + Location: 38,65 + Owner: USSR + Actor202: apwr + Location: 38,62 + Owner: USSR + ForwardCommand: fcom + Location: 46,61 + Owner: USSR + Actor204: apwr + Location: 42,61 + Owner: USSR + Actor205: apwr + Location: 42,64 + Owner: USSR + Actor206: ftur + Location: 51,65 + Owner: USSR + Actor207: ftur + Location: 48,59 + Owner: USSR + USSRRax1: barr + Location: 55,67 + Owner: USSR + USSRRax2: barr + Owner: USSR + Location: 56,71 + Actor209: kenn + Location: 49,69 + Owner: USSR + Actor210: fix + Location: 56,55 + Owner: USSR + Actor211: brl3 + Location: 30,66 + Owner: USSR + Actor212: barl + Location: 30,67 + Owner: USSR + Actor213: barl + Location: 30,68 + Owner: USSR + Actor214: brl3 + Location: 32,71 + Owner: USSR + Actor215: v19 + Location: 63,28 + Owner: Neutral + Actor216: brl3 + Location: 62,27 + Owner: BadGuy + VeryImportantBarrel: barl + Location: 62,29 + Owner: BadGuy + Actor218: barl + Location: 63,27 + Owner: BadGuy + Actor219: brl3 + Location: 64,27 + Owner: BadGuy + Actor220: v19 + Location: 64,28 + Owner: Neutral + Actor221: brl3 + Location: 62,28 + Owner: BadGuy + Airfield: afld + Location: 37,91 + Owner: USSR + Actor223: ftur + Location: 38,89 + Owner: BadGuy + PowerPlant6: powr + Location: 86,32 + Owner: BadGuy + APC: apc + Location: 35,48 + Owner: Greece + Facing: 764 + Actor226: v2rl + Location: 46,72 + Owner: USSR + Facing: 636 + Actor227: v2rl + Location: 59,70 + Owner: USSR + Facing: 636 + Actor228: 4tnk + Location: 53,65 + Owner: USSR + Facing: 636 + Actor229: 3tnk + Location: 62,64 + Owner: USSR + Facing: 892 + Actor230: 3tnk + Location: 55,61 + Owner: USSR + Facing: 380 + NorthMammoth: 4tnk + Location: 51,48 + Owner: BadGuy + Facing: 252 + SouthMammoth: 4tnk + Location: 33,77 + Owner: USSR + Facing: 380 + Actor233: 3tnk + Location: 45,68 + Owner: USSR + Facing: 636 + Alert1: e1 + Location: 75,34 + Owner: BadGuy + Facing: 252 + SubCell: 0 + Alert2: e1 + Location: 75,37 + Owner: BadGuy + Facing: 380 + SubCell: 0 + Alert3: e1 + Location: 75,35 + Owner: BadGuy + Facing: 380 + SubCell: 1 + Alert4: e1 + Location: 75,36 + Owner: BadGuy + Facing: 252 + SubCell: 3 + StartSpy: spy + Location: 35,47 + Owner: Greece + Facing: 764 + SubCell: 0 + Rifle1: e1 + Location: 34,46 + Owner: Greece + Facing: 764 + SubCell: 3 + Rifle2: e1 + Location: 33,47 + Owner: Greece + Facing: 764 + SubCell: 2 + Rifle3: e1 + Location: 33,48 + Owner: Greece + Facing: 764 + SubCell: 4 + Rifle4: e1 + Location: 34,49 + Owner: Greece + Facing: 764 + SubCell: 1 + Rocket1: e3 + Location: 32,46 + Owner: Greece + Facing: 764 + SubCell: 3 + Rocket2: e3 + Location: 32,47 + Owner: Greece + Facing: 764 + SubCell: 2 + Rocket3: e3 + Location: 32,48 + Owner: Greece + Facing: 764 + SubCell: 4 + Rocket4: e3 + Location: 31,48 + Owner: Greece + Facing: 764 + SubCell: 2 + Rocket5: e3 + Location: 32,49 + Owner: Greece + Facing: 764 + SubCell: 1 + Actor248: e2 + Location: 81,32 + Owner: BadGuy + Facing: 636 + SubCell: 3 + Actor249: e1 + Location: 80,33 + Owner: BadGuy + Facing: 508 + SubCell: 1 + Actor250: e1 + Location: 87,30 + Owner: BadGuy + Facing: 380 + SubCell: 4 + Actor251: e4 + Location: 80,35 + Owner: BadGuy + Facing: 380 + SubCell: 3 + Actor252: e1 + Location: 44,67 + Owner: USSR + Facing: 636 + SubCell: 4 + Actor253: e1 + Location: 50,52 + Owner: USSR + SubCell: 0 + Actor254: e4 + Location: 51,52 + Owner: USSR + SubCell: 1 + Actor255: e4 + Location: 53,52 + Owner: USSR + SubCell: 2 + Actor256: e1 + Location: 54,52 + Owner: USSR + SubCell: 0 + Actor257: e1 + Location: 56,69 + Owner: USSR + Facing: 636 + SubCell: 4 + Actor258: e2 + Location: 55,69 + Owner: USSR + Facing: 252 + SubCell: 4 + Actor259: e2 + Location: 56,70 + Owner: USSR + Facing: 636 + SubCell: 1 + Actor260: e1 + Location: 47,76 + Owner: USSR + Facing: 636 + SubCell: 2 + Actor261: e1 + Location: 46,76 + Owner: USSR + Facing: 380 + SubCell: 0 + Actor262: e1 + Location: 77,51 + Owner: USSR + Facing: 124 + SubCell: 4 + Actor263: e1 + Location: 79,52 + Owner: USSR + Facing: 892 + SubCell: 2 + Actor264: e1 + Location: 78,51 + Owner: USSR + Facing: 892 + SubCell: 4 + Actor265: e1 + Location: 61,68 + Owner: USSR + Facing: 764 + SubCell: 1 + Actor266: e4 + Location: 61,67 + Owner: USSR + Facing: 636 + SubCell: 1 + Actor267: e2 + Location: 61,63 + Owner: USSR + Facing: 764 + SubCell: 0 + Actor268: e2 + Location: 61,62 + Owner: USSR + Facing: 636 + SubCell: 1 + Actor269: dog + Location: 50,70 + Owner: USSR + Facing: 636 + SubCell: 4 + Actor270: dog + Location: 60,63 + Owner: USSR + Facing: 636 + SubCell: 0 + Actor271: e1 + Location: 69,80 + Owner: USSR + Facing: 636 + SubCell: 2 + Alert5: dog + Location: 74,36 + Owner: BadGuy + Facing: 380 + SubCell: 2 + Actor273: dog + Location: 52,54 + Owner: USSR + Facing: 636 + SubCell: 4 + Actor274: dog + Location: 57,69 + Owner: USSR + Facing: 636 + SubCell: 2 + Actor275: dog + Location: 58,77 + Owner: USSR + Facing: 636 + SubCell: 4 + Actor276: dog + Location: 48,69 + Owner: USSR + Facing: 380 + SubCell: 3 + Actor277: e2 + Location: 53,75 + Owner: USSR + Facing: 636 + SubCell: 3 + Actor278: e2 + Location: 50,75 + Owner: USSR + Facing: 380 + SubCell: 4 + Actor279: e2 + Location: 57,68 + Owner: USSR + Facing: 892 + SubCell: 2 + Actor280: e2 + Location: 56,54 + Owner: USSR + SubCell: 2 + Actor281: e2 + Location: 56,73 + Owner: USSR + Facing: 636 + SubCell: 3 + Actor282: e2 + Location: 38,88 + Owner: USSR + Facing: 636 + SubCell: 0 + Actor283: e2 + Location: 39,90 + Owner: USSR + SubCell: 2 + Actor284: e1 + Location: 41,88 + Owner: USSR + Facing: 892 + SubCell: 3 + Actor319: fenc + Owner: USSR + Location: 38,59 + Actor320: fenc + Owner: USSR + Location: 39,59 + Actor321: fenc + Owner: USSR + Location: 40,59 + Actor322: fenc + Owner: USSR + Location: 40,58 + Actor323: fenc + Owner: USSR + Location: 40,57 + Actor324: fenc + Owner: USSR + Location: 40,56 + Actor325: fenc + Owner: USSR + Location: 40,55 + Actor326: fenc + Owner: USSR + Location: 32,60 + Actor327: fenc + Owner: USSR + Location: 33,60 + Actor328: fenc + Owner: USSR + Location: 34,60 + Actor329: fenc + Owner: USSR + Location: 35,60 + Actor330: fenc + Owner: USSR + Location: 30,65 + Actor331: fenc + Owner: USSR + Location: 31,65 + Actor332: fenc + Owner: USSR + Location: 32,65 + Actor333: fenc + Owner: USSR + Location: 33,65 + Actor334: fenc + Owner: USSR + Location: 33,66 + Actor335: fenc + Owner: USSR + Location: 33,67 + Actor336: fenc + Owner: USSR + Location: 33,68 + Actor337: fenc + Owner: USSR + Location: 33,71 + Actor338: fenc + Owner: USSR + Location: 33,72 + Actor339: fenc + Owner: USSR + Location: 32,72 + Actor340: fenc + Owner: USSR + Location: 30,72 + Actor341: fenc + Owner: USSR + Location: 31,72 + Actor345: stek + Owner: USSR + Location: 41,69 + Actor348: e1 + Owner: BadGuy + Location: 50,33 + SubCell: 3 + Facing: 368 + Actor349: e1 + Owner: BadGuy + Location: 55,34 + SubCell: 3 + Facing: 368 + Actor352: e1 + Owner: BadGuy + Location: 63,29 + SubCell: 3 + Facing: 368 + Actor353: e1 + Owner: BadGuy + Location: 63,29 + SubCell: 1 + Facing: 368 + Actor358: 3tnk + Owner: BadGuy + Location: 73,89 + Facing: 648 + Actor360: sam + Owner: USSR + Location: 58,71 + TurretFacing: 368 + Actor361: sam + Owner: USSR + Location: 44,72 + TurretFacing: 368 + Actor362: sam + Owner: USSR + Location: 36,61 + TurretFacing: 368 + Actor363: sam + Owner: USSR + Location: 58,58 + TurretFacing: 368 + Actor365: fenc + Owner: USSR + Location: 36,90 + Actor366: fenc + Owner: USSR + Location: 37,90 + Actor367: fenc + Owner: USSR + Location: 38,90 + Actor368: fenc + Owner: USSR + Location: 40,90 + Actor369: fenc + Owner: USSR + Location: 40,91 + Actor370: fenc + Owner: USSR + Location: 40,92 + Actor371: fenc + Owner: USSR + Location: 41,92 + Actor372: dome + Owner: USSR + Location: 34,87 + Actor373: fenc + Owner: USSR + Location: 32,86 + Actor374: fenc + Owner: USSR + Location: 33,86 + Actor375: fenc + Owner: USSR + Location: 34,86 + Actor376: fenc + Owner: USSR + Location: 35,86 + Actor377: fenc + Owner: USSR + Location: 36,86 + Actor378: fenc + Owner: USSR + Location: 36,87 + Actor379: fenc + Owner: USSR + Location: 37,87 + Actor380: fenc + Owner: USSR + Location: 37,89 + waypoint1: waypoint + Location: 97,46 + Owner: Neutral + DefaultCameraPosition: waypoint + Location: 33,47 + Owner: Neutral + NorthPatrol1: waypoint + Location: 45,48 + Owner: Neutral + NorthPatrol2: waypoint + Location: 48,33 + Owner: Neutral + NorthPatrol3: waypoint + Location: 73,36 + Owner: Neutral + NorthPatrol4: waypoint + Location: 60,48 + Owner: Neutral + NorthPatrol5: waypoint + Location: 52,48 + Owner: Neutral + AlertGo: waypoint + Location: 64,29 + Owner: Neutral + BadGuyRaxSpawn: waypoint + Location: 79,31 + Owner: Neutral + BaseCam: waypoint + Location: 81,35 + Owner: Neutral + AlliesSpawn: waypoint + Owner: Neutral + Location: 99,46 + AlliesMove: waypoint + Location: 81,47 + Owner: Neutral + AlliedBase: waypoint + Location: 92,76 + Owner: Neutral + Proc1: waypoint + Owner: Neutral + Location: 45,54 + Proc2: waypoint + Owner: Neutral + Location: 41,55 + SouthPatrol1: waypoint + Location: 51,80 + Owner: Neutral + SouthPatrol2: waypoint + Location: 60,84 + Owner: Neutral + SouthPatrol3: waypoint + Location: 38,86 + Owner: Neutral + SovietGroundEntry1: waypoint + Location: 30,48 + Owner: Neutral + SovietGroundEntry2: waypoint + Location: 30,84 + Owner: Neutral + SovietGroundEntry3: waypoint + Location: 70,92 + Owner: Neutral + +Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/ra/maps/sarin-gas-3-controlled-burn/rules.yaml openra-20210321/mods/ra/maps/sarin-gas-3-controlled-burn/rules.yaml --- openra-20200503/mods/ra/maps/sarin-gas-3-controlled-burn/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/sarin-gas-3-controlled-burn/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,79 @@ +World: + LuaScript: + Scripts: campaign-global.lua, controlledburn.lua, controlledburn-AI.lua + MissionData: + WinVideo: apcescpe.vqa + LossVideo: tesla.vqa + Briefing: We have infiltrated the Soviet's Sarin facility. However, the main entrance is guarded by a wall of Tesla coils. We can't move a large force in until they are taken down.\n\nInfiltrate the power grid to the east or destroy its power plants. Once done, reinforcements will arrive.\n\nDestroy the Soviet compound, but capture all of the Sarin processor buildings intact -- we can't have a chemical spill. + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Values: + easy: Easy + normal: Normal + hard: Hard + Default: normal + +Player: + PlayerResources: + DefaultCash: 7500 + +APC: + Buildable: + Prerequisites: ~vehicles.allies + +TRUK: + Buildable: + Prerequisites: ~disabled + +MGG: + Buildable: + Prerequisites: ~disabled + +FTRK: + Buildable: + Prerequisites: ~disabled + +DTRK: + Buildable: + Prerequisites: ~disabled + +CTNK: + Buildable: + Prerequisites: ~disabled + +STNK: + Buildable: + Prerequisites: ~disabled + +MSLO: + Buildable: + Prerequisites: ~disabled + +ATEK: + Buildable: + Prerequisites: ~disabled + +BIO: + Tooltip: + Name: Sarin Processing Plant + +E7: + Buildable: + Prerequisites: ~disabled + +E3: + Buildable: + Prerequisites: ~tent + +MH60: + Buildable: + Prerequisites: ~disabled + +TRAN: + Buildable: + Prerequisites: ~disabled + +HELI: + Buildable: + Prerequisites: ~hpad Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/shadowfiend-II.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/shadowfiend-II.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/shock-therapy/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/shock-therapy/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/shock-therapy/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/shock-therapy/map.png differ diff -Nru openra-20200503/mods/ra/maps/shock-therapy/map.yaml openra-20210321/mods/ra/maps/shock-therapy/map.yaml --- openra-20200503/mods/ra/maps/shock-therapy/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/shock-therapy/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,998 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: Shock Therapy + +Author: Westwood Studios + +Tileset: TEMPERAT + +MapSize: 128,128 + +Bounds: 26,32,73,67 + +Visibility: MissionSelector + +Categories: Mission + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: england + PlayerReference@Spain: + Name: Spain + Faction: allies + Color: F6D679 + Allies: Greece, GoodGuy + Enemies: USSR + PlayerReference@Greece: + Name: Greece + Faction: allies + Color: E2E6F6 + Allies: Spain, GoodGuy + Enemies: USSR + PlayerReference@GoodGuy: + Name: GoodGuy + Faction: allies + Color: E2E6F6 + Allies: Spain, Greece + Enemies: USSR + PlayerReference@USSR: + Name: USSR + AllowBots: False + Playable: True + Required: True + LockFaction: True + Faction: soviet + LockColor: True + Color: FE1100 + LockSpawn: True + LockTeam: True + Enemies: Greece, GoodGuy, Spain + +Actors: + Actor0: sbag + Location: 26,39 + Owner: Greece + Actor1: sbag + Location: 27,39 + Owner: Greece + Actor2: sbag + Location: 28,39 + Owner: Greece + Actor3: sbag + Location: 29,39 + Owner: Greece + Actor4: sbag + Location: 30,39 + Owner: Greece + Actor5: sbag + Location: 26,40 + Owner: Greece + Actor6: sbag + Location: 30,40 + Owner: Greece + Actor7: sbag + Location: 31,40 + Owner: Greece + Actor8: sbag + Location: 26,41 + Owner: Greece + Actor9: sbag + Location: 31,41 + Owner: Greece + Actor10: sbag + Location: 32,41 + Owner: Greece + Actor11: sbag + Location: 26,42 + Owner: Greece + Actor12: sbag + Location: 32,42 + Owner: Greece + Actor13: sbag + Location: 33,42 + Owner: Greece + Actor14: sbag + Location: 34,42 + Owner: Greece + Actor15: sbag + Location: 35,42 + Owner: Greece + Actor16: sbag + Location: 26,43 + Owner: Greece + Actor17: sbag + Location: 35,43 + Owner: Greece + Actor18: sbag + Location: 36,43 + Owner: Greece + Actor19: sbag + Location: 37,43 + Owner: Greece + Actor20: sbag + Location: 26,44 + Owner: Greece + Actor21: sbag + Location: 36,44 + Owner: Greece + Actor22: sbag + Location: 37,44 + Owner: Greece + Actor23: sbag + Location: 26,45 + Owner: Greece + Actor24: sbag + Location: 36,45 + Owner: Greece + Actor25: sbag + Location: 37,45 + Owner: Greece + Actor26: sbag + Location: 26,46 + Owner: Greece + Actor27: sbag + Location: 26,47 + Owner: Greece + Actor28: sbag + Location: 26,48 + Owner: Greece + Actor29: sbag + Location: 26,49 + Owner: Greece + Actor30: sbag + Location: 36,49 + Owner: Greece + Actor31: sbag + Location: 37,49 + Owner: Greece + Actor32: sbag + Location: 26,50 + Owner: Greece + Actor33: sbag + Location: 36,50 + Owner: Greece + Actor34: sbag + Location: 37,50 + Owner: Greece + Actor35: sbag + Location: 26,51 + Owner: Greece + Actor36: sbag + Location: 36,51 + Owner: Greece + Actor37: sbag + Location: 37,51 + Owner: Greece + Actor38: sbag + Location: 26,52 + Owner: Greece + Actor39: sbag + Location: 37,52 + Owner: Greece + Actor40: sbag + Location: 26,53 + Owner: Greece + Actor41: sbag + Location: 36,53 + Owner: Greece + Actor42: sbag + Location: 37,53 + Owner: Greece + Actor43: sbag + Location: 26,54 + Owner: Greece + Actor44: sbag + Location: 36,54 + Owner: Greece + Actor45: sbag + Location: 26,55 + Owner: Greece + Actor46: sbag + Location: 36,55 + Owner: Greece + Actor47: sbag + Location: 26,56 + Owner: Greece + Actor48: sbag + Location: 36,56 + Owner: Greece + Actor49: sbag + Location: 26,57 + Owner: Greece + Actor50: sbag + Location: 27,57 + Owner: Greece + Actor51: sbag + Location: 28,57 + Owner: Greece + Actor52: sbag + Location: 29,57 + Owner: Greece + Actor53: sbag + Location: 30,57 + Owner: Greece + Actor54: sbag + Location: 31,57 + Owner: Greece + Actor55: sbag + Location: 32,57 + Owner: Greece + Actor56: sbag + Location: 33,57 + Owner: Greece + Health: 100 + Actor57: sbag + Location: 34,57 + Owner: Greece + Actor58: sbag + Location: 35,57 + Owner: Greece + Actor59: sbag + Location: 36,57 + Owner: Greece + Actor60: healcrate + Location: 70,61 + Owner: Greece + Actor61: sbag + Location: 72,85 + Owner: Greece + Actor62: sbag + Location: 73,85 + Owner: Greece + Actor63: sbag + Location: 74,85 + Owner: Greece + Actor64: sbag + Location: 75,85 + Owner: Greece + Actor65: sbag + Location: 76,85 + Owner: Greece + Actor66: sbag + Location: 77,85 + Owner: Greece + Actor67: sbag + Location: 78,85 + Owner: Greece + Actor68: sbag + Location: 79,85 + Owner: Greece + Actor69: sbag + Location: 80,85 + Owner: Greece + Actor70: sbag + Location: 81,85 + Owner: Greece + Actor71: sbag + Location: 87,85 + Owner: Greece + Actor72: sbag + Location: 88,85 + Owner: Greece + Actor73: sbag + Location: 89,85 + Owner: Greece + Actor74: sbag + Location: 71,86 + Owner: Greece + Actor75: sbag + Location: 72,86 + Owner: Greece + Actor76: sbag + Location: 79,86 + Owner: Greece + Actor77: sbag + Location: 80,86 + Owner: Greece + Actor78: sbag + Location: 81,86 + Owner: Greece + Actor79: sbag + Location: 87,86 + Owner: Greece + Actor80: sbag + Location: 88,86 + Owner: Greece + Actor81: sbag + Location: 89,86 + Owner: Greece + Actor82: sbag + Location: 71,87 + Owner: Greece + Actor83: sbag + Location: 89,87 + Owner: Greece + Actor84: sbag + Location: 71,88 + Owner: Greece + Actor85: sbag + Location: 89,88 + Owner: Greece + Actor86: sbag + Location: 71,89 + Owner: Greece + Actor87: sbag + Location: 72,89 + Owner: Greece + Actor88: sbag + Location: 89,89 + Owner: Greece + Actor89: sbag + Location: 71,90 + Owner: Greece + Actor90: sbag + Location: 72,90 + Owner: Greece + Actor91: sbag + Location: 89,90 + Owner: Greece + Actor92: healcrate + Location: 57,91 + Owner: Greece + Actor93: sbag + Location: 71,91 + Owner: Greece + Actor94: sbag + Location: 72,91 + Owner: Greece + Actor95: sbag + Location: 89,91 + Owner: Greece + Actor96: sbag + Location: 89,92 + Owner: Greece + Actor97: sbag + Location: 89,93 + Owner: Greece + Actor98: sbag + Location: 71,94 + Owner: Greece + Actor99: sbag + Location: 72,94 + Owner: Greece + Actor100: sbag + Location: 89,94 + Owner: Greece + Actor101: sbag + Location: 71,95 + Owner: Greece + Actor102: sbag + Location: 72,95 + Owner: Greece + Actor103: sbag + Location: 89,95 + Owner: Greece + Actor104: sbag + Location: 71,96 + Owner: Greece + Actor105: sbag + Location: 72,96 + Owner: Greece + Actor106: sbag + Location: 89,96 + Owner: Greece + Actor107: sbag + Location: 71,97 + Owner: Greece + Actor108: sbag + Location: 89,97 + Owner: Greece + Actor109: sbag + Location: 71,98 + Owner: Greece + Actor110: sbag + Location: 72,98 + Owner: Greece + Actor111: sbag + Location: 73,98 + Owner: Greece + Actor112: sbag + Location: 74,98 + Owner: Greece + Actor113: sbag + Location: 75,98 + Owner: Greece + Actor114: sbag + Location: 76,98 + Owner: Greece + Actor115: sbag + Location: 77,98 + Owner: Greece + Actor116: sbag + Location: 78,98 + Owner: Greece + Actor117: sbag + Location: 79,98 + Owner: Greece + Actor118: sbag + Location: 80,98 + Owner: Greece + Actor119: sbag + Location: 81,98 + Owner: Greece + Actor120: sbag + Location: 82,98 + Owner: Greece + Actor121: sbag + Location: 83,98 + Owner: Greece + Actor122: sbag + Location: 84,98 + Owner: Greece + Actor123: sbag + Location: 85,98 + Owner: Greece + Actor124: sbag + Location: 86,98 + Owner: Greece + Actor125: sbag + Location: 87,98 + Owner: Greece + Actor126: sbag + Location: 88,98 + Owner: Greece + Actor127: sbag + Location: 89,98 + Owner: Greece + Actor128: t03 + Location: 57,79 + Owner: Neutral + Actor129: t05 + Location: 55,92 + Owner: Neutral + Actor130: t02 + Location: 83,58 + Owner: Neutral + Actor131: t10 + Location: 60,47 + Owner: Neutral + Actor132: t16 + Location: 63,75 + Owner: Neutral + Actor133: tc04 + Location: 58,97 + Owner: Neutral + Actor134: tc05 + Location: 48,44 + Owner: Neutral + Actor135: tc05 + Location: 30,75 + Owner: Neutral + Actor136: tc04 + Location: 65,36 + Owner: Neutral + Actor137: tc04 + Location: 46,73 + Owner: Neutral + Actor138: tc03 + Location: 37,71 + Owner: Neutral + Actor139: tc03 + Location: 76,74 + Owner: Neutral + Actor140: tc03 + Location: 51,43 + Owner: Neutral + Actor141: tc02 + Location: 78,74 + Owner: Neutral + Actor142: tc02 + Location: 83,57 + Owner: Neutral + Actor143: tc01 + Location: 56,97 + Owner: Neutral + Actor144: tc01 + Location: 38,79 + Owner: Neutral + Actor145: tc01 + Location: 45,53 + Owner: Neutral + Actor146: t17 + Location: 45,90 + Owner: Neutral + Actor147: t17 + Location: 65,49 + Owner: Neutral + Actor148: t16 + Location: 56,91 + Owner: Neutral + Actor149: t16 + Location: 69,85 + Owner: Neutral + Actor150: t15 + Location: 51,47 + Owner: Neutral + Actor151: t15 + Location: 53,77 + Owner: Neutral + Actor152: t14 + Location: 85,76 + Owner: Neutral + Actor153: t14 + Location: 50,85 + Owner: Neutral + Actor154: t14 + Location: 59,76 + Owner: Neutral + Actor155: t13 + Location: 78,80 + Owner: Neutral + Actor156: t12 + Location: 30,76 + Owner: Neutral + Actor157: t11 + Location: 28,37 + Owner: Neutral + Actor158: t10 + Location: 50,66 + Owner: Neutral + Actor159: t08 + Location: 38,70 + Owner: Neutral + Actor160: t07 + Location: 60,83 + Owner: Neutral + Actor161: t06 + Location: 36,70 + Owner: Neutral + Actor162: t05 + Location: 46,75 + Owner: Neutral + Actor163: t03 + Location: 54,65 + Owner: Neutral + Actor164: t02 + Location: 27,64 + Owner: Neutral + Actor165: t01 + Location: 49,61 + Owner: Neutral + Actor166: tc05 + Location: 73,57 + Owner: Neutral + Actor167: tc04 + Location: 72,59 + Owner: Neutral + Actor168: t17 + Location: 73,60 + Owner: Neutral + Actor169: t16 + Location: 59,56 + Owner: Neutral + Actor170: tc02 + Location: 86,51 + Owner: Neutral + Actor171: tc02 + Location: 76,35 + Owner: Neutral + Actor172: tc02 + Location: 85,78 + Owner: Neutral + Actor173: mine + Location: 64,92 + Owner: Neutral + Actor174: mine + Location: 68,96 + Owner: Neutral + Actor175: tc05 + Location: 79,66 + Owner: Neutral + Actor176: tc04 + Location: 75,72 + Owner: Neutral + Actor177: tc03 + Location: 40,80 + Owner: Neutral + Actor178: tc04 + Location: 58,54 + Owner: Neutral + Actor179: tc05 + Location: 54,93 + Owner: Neutral + Actor180: tc03 + Location: 26,37 + Owner: Neutral + Actor181: t10 + Location: 27,79 + Owner: Neutral + Actor182: t08 + Location: 29,80 + Owner: Neutral + Actor183: tc04 + Location: 26,83 + Owner: Neutral + Actor184: tc03 + Location: 39,82 + Owner: Neutral + Actor185: tc04 + Location: 44,89 + Owner: Neutral + Actor186: tc01 + Location: 49,84 + Owner: Neutral + Actor187: t16 + Location: 46,97 + Owner: Neutral + Actor188: t15 + Location: 51,88 + Owner: Neutral + Actor189: t14 + Location: 28,72 + Owner: Neutral + Actor190: t12 + Location: 53,54 + Owner: Neutral + Actor191: t11 + Location: 34,65 + Owner: Neutral + Actor192: t12 + Location: 28,64 + Owner: Neutral + Actor193: t12 + Location: 35,66 + Owner: Neutral + SWVillage7: v04 + Location: 30,96 + Owner: Spain + SWVillage4: v03 + Location: 33,91 + Owner: Spain + SWVillage2: v02 + Location: 34,87 + Owner: Spain + SWVillage3: v01 + Location: 29,92 + Owner: Spain + SWVillage6: v07 + Location: 33,94 + Owner: Spain + SWVillage5: v08 + Location: 38,91 + Owner: Spain + SWVillage1: v10 + Location: 30,88 + Owner: Spain + SouthCabin: v11 + Location: 57,91 + Owner: Spain + NEVillage7: v10 + Location: 78,44 + Owner: Spain + NEVillage8: v11 + Location: 81,50 + Owner: Spain + NorthCabin: v08 + Location: 70,61 + Owner: Spain + NEVillage3: v07 + Location: 79,41 + Owner: Spain + NEVillage4: v06 + Location: 85,46 + Owner: Spain + NEVillage2: v05 + Location: 84,42 + Owner: Spain + NEVillage5: v04 + Location: 76,41 + Owner: Spain + NEVillage9: v03 + Location: 85,49 + Owner: Spain + NEVillage6: v02 + Location: 81,46 + Owner: Spain + NEVillage1: v01 + Location: 80,44 + Owner: Spain + Health: 53 + SETent1: tent + Location: 80,95 + Owner: Greece + NWTent2: tent + Location: 33,54 + Owner: GoodGuy + Actor214: hosp + Location: 86,87 + Owner: Greece + NWAdvPower: apwr + Location: 28,50 + Owner: GoodGuy + Actor216: apwr + Location: 79,87 + Owner: Greece + NWTent1: tent + Location: 30,54 + Owner: GoodGuy + SETent2: tent + Location: 77,95 + Owner: Greece + NWHospital: hosp + Location: 28,45 + Owner: GoodGuy + Actor220: v19 + Location: 42,96 + Owner: Greece + Actor221: v19 + Location: 44,94 + Owner: Greece + Actor222: v19 + Location: 63,49 + Owner: Neutral + Actor223: v19 + Location: 67,50 + Owner: Neutral + Actor224: brl3 + Location: 62,48 + Owner: Spain + Actor225: barl + Location: 65,49 + Owner: Spain + Actor226: barl + Location: 68,49 + Owner: Spain + Actor227: brl3 + Location: 44,95 + Owner: Greece + Actor228: barl + Location: 63,48 + Owner: Spain + Actor229: brl3 + Location: 67,49 + Owner: Spain + Actor230: brl3 + Location: 41,98 + Owner: Greece + Actor231: brl3 + Location: 43,97 + Owner: Greece + Actor232: brl3 + Location: 66,50 + Owner: Spain + Actor233: brl3 + Location: 64,48 + Owner: Spain + Actor234: barl + Location: 46,92 + Owner: Greece + Actor235: barl + Location: 69,49 + Owner: Spain + Actor236: barl + Location: 64,49 + Owner: Spain + Actor237: barl + Location: 66,49 + Owner: Spain + Actor238: barl + Location: 68,48 + Owner: Spain + Actor239: barl + Location: 44,96 + Owner: Greece + Actor240: barl + Location: 45,93 + Owner: Greece + Actor241: barl + Location: 42,97 + Owner: Greece + Actor242: barl + Location: 43,96 + Owner: Greece + Actor243: barl + Location: 45,94 + Owner: Greece + Actor244: barl + Location: 42,98 + Owner: Greece + Actor245: barl + Location: 41,97 + Owner: Greece + RadarDome: dome + Location: 28,40 + Owner: GoodGuy + Actor247: proc + Location: 73,88 + Owner: Greece + Actor248: silo + Location: 77,86 + Owner: Greece + Actor249: silo + Location: 77,87 + Owner: Greece + Actor250: silo + Location: 76,86 + Owner: Greece + Actor251: silo + Location: 76,87 + Owner: Greece + Actor252: silo + Location: 75,86 + Owner: Greece + Actor253: silo + Location: 75,87 + Owner: Greece + Actor254: apwr + Location: 86,95 + Owner: Greece + WarFactory: weap + Location: 73,95 + Owner: Greece + SouthPill1: pbox + Location: 79,81 + Owner: Greece + SouthPill2: pbox + Location: 85,78 + Owner: Greece + NorthPill1: pbox + Location: 46,53 + Owner: GoodGuy + NorthPill2: pbox + Location: 51,47 + Owner: GoodGuy + Actor260: powr + Location: 83,95 + Owner: Greece + Actor262: arty + Location: 79,68 + Owner: Greece + Facing: 63 + Actor263: arty + Location: 79,76 + Owner: Greece + Facing: 63 + Ltnk1: 1tnk + Location: 87,90 + Owner: Greece + Facing: 31 + Ltnk2: 1tnk + Location: 87,91 + Owner: Greece + Facing: 31 + Ltnk3: 1tnk + Location: 87,92 + Owner: Greece + Facing: 31 + Jeep3: jeep + Location: 88,92 + Owner: Greece + Facing: 31 + Jeep2: jeep + Location: 88,91 + Owner: Greece + Facing: 31 + Jeep1: jeep + Location: 88,90 + Owner: Greece + Facing: 31 + Actor270: e1 + Location: 38,45 + Owner: Greece + Health: 89 + Facing: 191 + SubCell: 1 + Actor271: e1 + Location: 87,84 + Owner: Greece + SubCell: 4 + Actor272: e1 + Location: 81,84 + Owner: Greece + SubCell: 3 + Actor273: e1 + Location: 38,49 + Owner: Greece + Facing: 191 + SubCell: 1 + LZ: waypoint + Location: 51,72 + Owner: Neutral + WaterEntryNW: waypoint + Location: 42,32 + Owner: Neutral + WaterLandingNW: waypoint + Location: 42,42 + Owner: Neutral + WaterEntryNE: waypoint + Location: 70,32 + Owner: Neutral + WaterLandingNE: waypoint + Location: 73,41 + Owner: Neutral + WaterEntrySE: waypoint + Location: 98,78 + Owner: Neutral + WaterLandingSE: waypoint + Location: 91,78 + Owner: Neutral + SouthwestLZ: waypoint + Location: 39,97 + Owner: Neutral + CivRallySE: waypoint + Location: 81,92 + Owner: Neutral + CivRallyNW: waypoint + Location: 31,47 + Owner: Neutral + NWSpawn1: waypoint + Location: 30,55 + Owner: Neutral + NWSpawn2: waypoint + Location: 33,55 + Owner: Neutral + NEHermitSpawn: waypoint + Location: 70,61 + Owner: Neutral + SouthHermitSpawn: waypoint + Location: 57,91 + Owner: Neutral + NECivSpawn1: waypoint + Location: 80,45 + Owner: Neutral + NECivSpawn2: waypoint + Location: 84,42 + Owner: Neutral + NECivSpawn3: waypoint + Location: 80,41 + Owner: Neutral + NECivSpawn4: waypoint + Location: 86,46 + Owner: Neutral + NECivSpawn5: waypoint + Location: 76,42 + Owner: Neutral + NECivSpawn6: waypoint + Location: 82,47 + Owner: Neutral + NECivSpawn9: waypoint + Location: 85,50 + Owner: Neutral + NECivSpawn8: waypoint + Location: 81,50 + Owner: Neutral + NECivSpawn7: waypoint + Location: 78,44 + Owner: Neutral + SWCivSpawn3: waypoint + Location: 29,93 + Owner: Neutral + SWCivSpawn4: waypoint + Location: 33,92 + Owner: Neutral + SWCivSpawn6: waypoint + Location: 33,94 + Owner: Neutral + SWCivSpawn2: waypoint + Location: 35,88 + Owner: Neutral + SWCivSpawn5: waypoint + Location: 38,91 + Owner: Neutral + SWCivSpawn1: waypoint + Location: 30,88 + Owner: Neutral + SWCivSpawn7: waypoint + Location: 30,97 + Owner: Neutral + SEBaseBombingRun: waypoint + Location: 78,87 + Owner: Neutral + MSubEntry: waypoint + Location: 98,57 + Owner: Neutral + MSubStop: waypoint + Location: 94,73 + Owner: Neutral + SEShockDrop: waypoint + Location: 83,79 + Owner: Neutral + +Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/ra/maps/shock-therapy/rules.yaml openra-20210321/mods/ra/maps/shock-therapy/rules.yaml --- openra-20200503/mods/ra/maps/shock-therapy/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/shock-therapy/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,30 @@ +World: + LuaScript: + Scripts: shock-therapy.lua + MissionData: + WinVideo: sovtstar.vqa + LossVideo: sovcemet.vqa + Briefing: A small border town has been voicing support for the Allied cause. These people are no longer soviets, but enemies to our great empire. As enemies, they must be destroyed.\n\nTake Stalin's elite shock troopers and show them the iron might of the Soviet army. No doubt, the rabble will seek help from the minute allied influence in the area.\n\nWhatever pathetic support they can muster, it will not be enough. Crush them all -- let nothing stop you. + +SHOCKDROP: + ParatroopersPower: + DisplayBeacon: False + DropItems: SHOK, SHOK, SHOK, SHOK, SHOK + AlwaysVisible: + +LST.Reinforcement: + Inherits: LST + RejectsOrders: + -Buildable: + -Selectable: + RenderSprites: + Image: lst + Interactable: + +powerproxy.parabombs: + AirstrikePower: + DisplayBeacon: False + +HEALCRATE: + Crate: + Lifetime: 0 diff -Nru openra-20200503/mods/ra/maps/shock-therapy/shock-therapy.lua openra-20210321/mods/ra/maps/shock-therapy/shock-therapy.lua --- openra-20200503/mods/ra/maps/shock-therapy/shock-therapy.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/shock-therapy/shock-therapy.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,347 @@ +--[[ + Copyright 2007-2021 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +Cabins = { NorthCabin, SouthCabin } +NWFootprintTrigger = { CPos.New(41, 49), CPos.New(41, 48), CPos.New(41, 47), CPos.New(41, 46), CPos.New(41, 45), CPos.New(41, 44) } +SWFootprintTrigger = { CPos.New(26, 77), CPos.New(27, 77), CPos.New(28, 77), CPos.New(29, 77), CPos.New(33, 77), CPos.New(34, 77), CPos.New(35, 77), CPos.New(36, 77), CPos.New(37, 77), CPos.New(38, 77), CPos.New(39, 77) } +SEFootprintTrigger = { CPos.New(75, 83), CPos.New(76, 83), CPos.New(77, 83), CPos.New(78, 83), CPos.New(79, 83), CPos.New(80, 83), CPos.New(81, 83), CPos.New(82, 83), CPos.New(83, 83), CPos.New(84, 83), CPos.New(85, 83), CPos.New(86, 83), CPos.New(87, 83), CPos.New(88, 83), CPos.New(89, 83) } +NWWaterPath = { WaterEntryNW.Location, WaterLandingNW.Location } +NEWaterPath = { WaterEntryNE.Location, WaterLandingNE.Location } +SEWaterPath = { WaterEntrySE.Location, WaterLandingSE.Location } +NWWaterUnits = { "dtrk", "ttnk", "ttnk", "ttnk", "3tnk" } +NEWaterUnits = { "dtrk", "v2rl", "e6", "e6", "e6" } +SEWaterUnits = { "ttnk", "ttnk", "shok", "shok", "shok" } +NorthPillboxes = { NorthPill1, NorthPill2 } +SouthPillboxes = { SouthPill1, SouthPill2 } +VehicleSquad1 = { Ltnk1, Jeep1 } +VehicleSquad2 = { Ltnk2, Jeep2 } +VehicleSquad3 = { Ltnk3, Jeep3 } +CivSquads = { { "c1", "c3", "c7", "c10" }, { "c2", "c4", "c6", "c11" }, { "c11", "c10", "c9" }, { "c8", "c7", "c6" }, { "c5", "c4", "c3" }, { "c5", "c10" }, { "c4", "c2" }, { "c3", "c5" }, { "c9", "c11" } } +AlliedInfantry = { "e1", "e1", "e1", "e3" } +AttackGroupSize = 4 +InfantryDelay = DateTime.Seconds(10) +IdlingUnits = { } +IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end + +MissionStart = function() + LZCamera = Actor.Create("camera", true, { Owner = USSR, Location = LZ.Location }) + ShockDrop.TargetParatroopers(LZ.CenterPosition, Angle.New(508)) + + Trigger.AfterDelay(DateTime.Seconds(1), function() + ShockDrop.TargetParatroopers(LZ.CenterPosition, Angle.New(520)) + end) + + Trigger.AfterDelay(DateTime.Seconds(4), function() + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + end) + + Trigger.AfterDelay(DateTime.Seconds(10), function() + LZCamera.Destroy() + TroopsArrived = true + end) + + InfantryProduction() +end + +InfantryProduction = function() + if (SETent1.IsDead or SETent1.Owner ~= Greece) and (SETent2.IsDead or SETent2.Owner ~= Greece) then + return + end + + local toBuild = { Utils.Random(AlliedInfantry) } + + Greece.Build(toBuild, function(unit) + IdlingUnits[#IdlingUnits + 1] = unit[1] + Trigger.AfterDelay(InfantryDelay, InfantryProduction) + + if #IdlingUnits >= (AttackGroupSize * 1.5) then + SendAttack() + end + end) +end + +SendAttack = function() + local units = { } + + for i = 0, AttackGroupSize, 1 do + local number = Utils.RandomInteger(1, #IdlingUnits) + + if IdlingUnits[number] and not IdlingUnits[number].IsDead then + units[i] = IdlingUnits[number] + table.remove(IdlingUnits, number) + end + end + + Utils.Do(units, function(unit) + if not unit.IsDead then + IdleHunt(unit) + end + end) +end + +DomeCaptured = false +MissionTriggers = function() + local neFootTriggered + Trigger.OnEnteredProximityTrigger(NECivSpawn1.CenterPosition, WDist.FromCells(9), function(actor, id) + if actor.Owner == USSR and actor.Type ~= "badr" and not neFootTriggered then + Trigger.RemoveFootprintTrigger(id) + neFootTriggered = true + + local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = USSR }) + proxy.TargetAirstrike(NECivSpawn6.CenterPosition, Angle.SouthEast) + proxy.Destroy() + + Utils.Do(VehicleSquad1, function(a) + if not a.IsDead then + a.AttackMove(NECivSpawn1.Location) + IdleHunt(a) + end + end) + + local neVillageCam = Actor.Create("camera", true, { Owner = USSR, Location = NECivSpawn1.Location }) + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + local neTroops = Reinforcements.ReinforceWithTransport(USSR, "lst.reinforcement", NEWaterUnits, NEWaterPath, { NEWaterPath[1] })[2] + Trigger.OnAllRemovedFromWorld(Utils.Where(neTroops, function(a) return a.Type == "e6" end), function() + if not DomeCaptured then + USSR.MarkFailedObjective(CaptureDome) + end + end) + + Trigger.AfterDelay(DateTime.Seconds(2), function() + if not NEVillage1.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { NECivSpawn1.Location, CivRallyNW.Location }, 0) + end + if not NEVillage2.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { NECivSpawn2.Location, CivRallyNW.Location }, 0) + end + end) + Trigger.AfterDelay(DateTime.Seconds(3), function() + if not NEVillage3.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { NECivSpawn3.Location, CivRallyNW.Location }, 0) + end + if not NEVillage4.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { NECivSpawn4.Location, CivRallyNW.Location }, 0) + end + end) + Trigger.AfterDelay(DateTime.Seconds(4), function() + if not NEVillage5.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { NECivSpawn5.Location, CivRallyNW.Location }, 0) + end + if not NEVillage6.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { NECivSpawn6.Location, CivRallySE.Location }, 0) + end + end) + Trigger.AfterDelay(DateTime.Seconds(5), function() + if not NEVillage7.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { NECivSpawn7.Location, CivRallySE.Location }, 0) + end + if not NEVillage8.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { NECivSpawn8.Location, CivRallySE.Location }, 0) + end + if not NEVillage9.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { NECivSpawn9.Location, CivRallySE.Location }, 0) + end + end) + + Trigger.AfterDelay(DateTime.Seconds(10), function() + neVillageCam.Destroy() + end) + end + end) + + Trigger.OnDamaged(NorthCabin, function() + if not NorthCabinDamaged then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { NEHermitSpawn.Location, CivRallyNW.Location }, 1) + NorthCabinDamaged = true + end + end) + + Trigger.OnDamaged(SouthCabin, function() + if not SouthCabinDamaged then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { SouthHermitSpawn.Location, CivRallySE.Location }, 1) + SouthCabinDamaged = true + end + end) + + Trigger.OnAllKilled(Cabins, function() + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + ShockDrop.TargetParatroopers(LZ.CenterPosition, Angle.SouthWest) + end) + + Trigger.OnAllKilled(NorthPillboxes, function() + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + ShockDrop.TargetParatroopers(LZ.CenterPosition, Angle.South) + end) + + local nwFootTriggered + Trigger.OnEnteredFootprint(NWFootprintTrigger, function(actor, id) + if actor.Owner == USSR and not nwFootTriggered then + Trigger.RemoveFootprintTrigger(id) + nwFootTriggered = true + + local nwBarracks1 = Reinforcements.Reinforce(GoodGuy, AlliedInfantry, { NWSpawn1.Location }, 0) + Utils.Do(nwBarracks1, IdleHunt) + local nwBarracks2 = Reinforcements.Reinforce(GoodGuy, AlliedInfantry, { NWSpawn2.Location }, 0) + Utils.Do(nwBarracks2, IdleHunt) + + Utils.Do(VehicleSquad2, function(a) + if not a.IsDead then + a.AttackMove(SWCivSpawn1.Location) + IdleHunt(a) + end + end) + end + end) + + Trigger.OnKilled(RadarDome, function() + if not DomeCaptured then + USSR.MarkFailedObjective(CaptureDome) + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + ShockDrop.TargetParatroopers(CivRallyNW.CenterPosition, Angle.West) + end + end) + + Trigger.OnCapture(RadarDome, function() + DomeCaptured = true + USSR.MarkCompletedObjective(CaptureDome) + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + local nwTroops = Reinforcements.ReinforceWithTransport(USSR, "lst.reinforcement", NWWaterUnits, NWWaterPath, { NWWaterPath[1] })[2] + end) + + Trigger.OnAllKilled(SouthPillboxes, function() + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + local seTroops = Reinforcements.ReinforceWithTransport(USSR, "lst.reinforcement", SEWaterUnits, SEWaterPath, { SEWaterPath[1] })[2] + + Trigger.AfterDelay(DateTime.Seconds(10), function() + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + Reinforcements.Reinforce(USSR, { "msub", "msub" }, { MSubEntry.Location, MSubStop.Location }) + ShockDrop.TargetParatroopers(SEShockDrop.CenterPosition, Angle.SouthWest) + end) + end) + + local swFootTriggered + Trigger.OnEnteredFootprint(SWFootprintTrigger, function(actor, id) + if actor.Owner == USSR and actor.Type ~= "badr" and not swFootTriggered then + Trigger.RemoveFootprintTrigger(id) + swFootTriggered = true + + local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = USSR }) + proxy.TargetAirstrike(SWCivSpawn3.CenterPosition, Angle.South) + proxy.Destroy() + local swVillageCam = Actor.Create("camera", true, { Owner = USSR, Location = SWCivSpawn2.Location }) + + local hiding = Reinforcements.Reinforce(Greece, { 'e1', 'e1', 'e3', 'e3', 'e3' }, { SWCivSpawn1.Location }, 0) + Utils.Do(hiding, IdleHunt) + + Trigger.AfterDelay(DateTime.Seconds(2), function() + if not SWVillage1.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { SWCivSpawn1.Location, CivRallySE.Location }, 0) + end + if not SWVillage2.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { SWCivSpawn2.Location, CivRallySE.Location }, 0) + end + end) + Trigger.AfterDelay(DateTime.Seconds(4), function() + if not SWVillage3.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { SWCivSpawn3.Location, CivRallySE.Location }, 0) + end + if not SWVillage4.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { SWCivSpawn4.Location, CivRallyNW.Location }, 0) + end + end) + Trigger.AfterDelay(DateTime.Seconds(5), function() + if not SWVillage5.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { SWCivSpawn5.Location, CivRallySE.Location }, 0) + end + if not SWVillage6.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { SWCivSpawn6.Location, CivRallyNW.Location }, 0) + end + if not SWVillage7.IsDead then + Reinforcements.Reinforce(Spain, Utils.Random(CivSquads), { SWCivSpawn7.Location, CivRallySE.Location }, 0) + end + end) + Trigger.AfterDelay(DateTime.Seconds(5), function() + ShockDrop.TargetParatroopers(SouthwestLZ.CenterPosition, Angle.SouthWest) + Utils.Do(VehicleSquad3, function(a) + if not a.IsDead then + a.AttackMove(NECivSpawn1.Location) + IdleHunt(a) + end + end) + swVillageCam.Destroy() + end) + end + end) + + local seFootTriggered + Trigger.OnEnteredFootprint(SEFootprintTrigger, function(actor, id) + if actor.Owner == USSR and not seFootTriggered then + Trigger.RemoveFootprintTrigger(id) + seFootTriggered = true + + local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = USSR }) + proxy.TargetAirstrike(SEBaseBombingRun.CenterPosition, Angle.East) + proxy.Destroy() + end + end) +end + +TroopsArrived = false +Tick = function() + if USSR.HasNoRequiredUnits() and TroopsArrived then + Greece.MarkCompletedObjective(BeatRussia) + end + + if Greece.HasNoRequiredUnits() and GoodGuy.HasNoRequiredUnits() and Spain.HasNoRequiredUnits() then + USSR.MarkCompletedObjective(KillAll) + end +end + +WorldLoaded = function() + USSR = Player.GetPlayer("USSR") + Greece = Player.GetPlayer("Greece") + GoodGuy = Player.GetPlayer("GoodGuy") + Spain = Player.GetPlayer("Spain") + + Trigger.OnObjectiveAdded(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") + end) + + BeatRussia = Greece.AddObjective("Stop Ivan.") + KillAll = USSR.AddObjective("Destroy all that oppose us.") + CaptureDome = USSR.AddObjective("Capture the enemy radar dome.", "Secondary", false) + + Trigger.OnObjectiveCompleted(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") + end) + Trigger.OnObjectiveFailed(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") + end) + + Trigger.OnPlayerLost(USSR, function() + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(USSR, "MissionFailed") + end) + end) + Trigger.OnPlayerWon(USSR, function() + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(USSR, "MissionAccomplished") + end) + end) + + Camera.Position = LZ.CenterPosition + ShockDrop = Actor.Create("shockdrop", false, { Owner = USSR }) + MissionStart() + MissionTriggers() +end + +OnAnyDamaged = function(actors, func) + Utils.Do(actors, function(actor) + Trigger.OnDamaged(actor, func) + end) +end diff -Nru openra-20200503/mods/ra/maps/siberian-conflict-1-fresh-tracks/fresh-tracks.lua openra-20210321/mods/ra/maps/siberian-conflict-1-fresh-tracks/fresh-tracks.lua --- openra-20200503/mods/ra/maps/siberian-conflict-1-fresh-tracks/fresh-tracks.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/siberian-conflict-1-fresh-tracks/fresh-tracks.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,282 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +TimerTicks = DateTime.Minutes(8) +Squad1 = { FirstSquad1, FirstSquad2, FirstSquad3 } +Squad2 = { SecondSquad1, SecondSquad2, SecondSquad3 } +PatrolMammothPath = { Patrol1.Location, Patrol2.Location, Patrol3.Location, Patrol4.Location, Patrol5.Location, Patrol6.Location, Patrol7.Location } +ConvoyEscape = { CPos.New(113, 42), CPos.New(117, 71) } + +IdleHunt = function(actor) if not actor.IsDead then Trigger.OnIdle(actor, actor.Hunt) end end + +ConvoyUnits = +{ + easy = { { "e2", "e2", "e2", "truk", "truk", "truk" }, { "3tnk", "3tnk", "truk", "truk", "truk" } }, + normal = { { "3tnk", "3tnk", "3tnk", "truk", "truk", "truk" }, { "3tnk", "v2rl", "e2", "e1", "e1", "truk", "truk", "truk" } }, + hard = { { "3tnk", "3tnk", "3tnk", "3tnk", "truk", "truk", "truk" }, { "3tnk", "v2rl", "v2rl", "e1", "e1", "e4", "e4", "truk", "truk", "truk", "4tnk" }, { "ttnk", "ttnk", "ttnk", "shok", "shok", "shok", "shok", "truk", "truk", "truk" } } +} + +BaseConvoyUnits = { "3tnk", "ttnk", "ttnk", "ttnk", "truk", "truk", "truk" } +FinalConvoyUnits = { "3tnk", "3tnk", "3tnk", "3tnk", "truk", "truk", "truk", "4tnk" } + +AttackPaths = +{ + { ExitNorth.Location }, + { ExitEast.Location }, + { AttackEntry1.Location }, + { AttackEntry2.Location } +} + +AttackWaveUnits = { { "3tnk", "3tnk" }, { "e1", "e1", "e1", "e2", "e2", "e4", "e4" }, { "shok", "shok", "shok", "shok", "shok" }, { "ttnk", "ttnk" }, { "4tnk", "e1", "e1", "e2" }, { "v2rl", "v2rl", "ftrk", "ftrk", "ftrk" } } + +ConvoyPaths = +{ + { NorthwestEntry.Location, NorthwestPath1.Location, NorthwestBridge.Location, Patrol7.Location, Patrol6.Location, NortheastBridge.Location, NorthwestPath3.Location, ExitNorth.Location }, + { CenterEntry.Location, CenterPath1.Location, CenterPath2.Location, Patrol1.Location, Patrol7.Location, Patrol6.Location, NortheastBridge.Location, NorthwestPath3.Location, ExitNorth.Location }, + { CenterEntry.Location, CenterPath1.Location, CenterPath2.Location, Patrol1.Location, Patrol2.Location, SouthPath2.Location, SoutheastBridge.Location, SouthPath3.Location, ExitEast.Location }, + { SouthEntry.Location, SouthPath1.Location, Patrol2.Location, SouthPath2.Location, SoutheastBridge.Location, SouthPath3.Location, ExitEast.Location } +} + +BaseConvoyPath = { BaseEntry.Location, BasePath1.Location, CenterPath2.Location, Patrol1.Location, Patrol7.Location, Patrol6.Location, NortheastBridge.Location, NorthwestPath3.Location, ExitNorth.Location } +FinalConvoyPath = { NorthEntry.Location, Patrol7.Location, Patrol6.Location, Patrol5.Location, FinalConvoy1.Location, ExitEast.Location } + +OpeningMoves = function() + Utils.Do(Squad1, function(actor) + actor.AttackMove(AlliedBase.Location) + end) + + Utils.Do(Squad2, function(actor) + actor.AttackMove(AlliedBase.Location) + end) + + PatrolMammoth.Patrol(PatrolMammothPath, true, 10) +end + +AttackWaveDelays = +{ + easy = { DateTime.Seconds(40), DateTime.Seconds(80) }, + normal = { DateTime.Seconds(30), DateTime.Seconds(60) }, + hard = { DateTime.Seconds(20), DateTime.Seconds(40) } +} + +AttackWaves = function() + local attackpath = Utils.Random(AttackPaths) + local attackers = Reinforcements.Reinforce(USSR, Utils.Random(AttackWaveUnits), { attackpath[1] }) + Utils.Do(attackers, function(unit) + Trigger.OnAddedToWorld(unit, function() + unit.AttackMove(AlliedBase.Location) + IdleHunt(unit) + end) + end) + + Trigger.AfterDelay(Utils.RandomInteger(AttackWaveDelay[1], AttackWaveDelay[2]), AttackWaves) +end + +ConvoyWaves = +{ + easy = 2, + normal = 3, + hard = 4 +} +ConvoysPassed = 0 + +SendConvoys = function() + ConvoysSent = true + Media.PlaySpeechNotification(Allies, "ConvoyApproaching") + local path = Utils.Random(ConvoyPaths) + local units = Reinforcements.Reinforce(USSR, Utils.Random(ConvoyUnits), { path[1] }) + local lastWaypoint = path[#path] + Utils.Do(units, function(unit) + Trigger.OnAddedToWorld(unit, function() + if unit.Type == "truk" then + Utils.Do(path, function(waypoint) + unit.Move(waypoint) + end) + + Trigger.OnIdle(unit, function() + unit.Move(lastWaypoint) + end) + else + unit.Patrol(path) + Trigger.OnIdle(unit, function() + unit.AttackMove(lastWaypoint) + end) + end + end) + end) + + ConvoysPassed = ConvoysPassed + 1 + if ConvoysPassed <= ConvoyWaves[Map.LobbyOption("difficulty")] then + Trigger.AfterDelay(DateTime.Seconds(90), SendConvoys) + else + FinalTrucks() + end +end + +FinalTrucks = function() + Trigger.AfterDelay(DateTime.Minutes(1), function() + Media.PlaySpeechNotification(Allies, "ConvoyApproaching") + local basePath = BaseConvoyPath + local baseWaypoint = basePath[#basePath] + local baseConvoy = Reinforcements.Reinforce(USSR, BaseConvoyUnits, { basePath[1] }) + Utils.Do(baseConvoy, function(unit) + Trigger.OnAddedToWorld(unit, function() + Utils.Do(basePath, function(waypoint) + unit.Move(waypoint) + end) + + Trigger.OnIdle(unit, function() + unit.Move(baseWaypoint) + end) + end) + end) + end) + + Trigger.AfterDelay(DateTime.Minutes(2), function() + Media.PlaySpeechNotification(Allies, "ConvoyApproaching") + local finalPath = FinalConvoyPath + local finalWaypoint = finalPath[#finalPath] + local finalConvoy = Reinforcements.Reinforce(USSR, FinalConvoyUnits, { finalPath[1] }) + Utils.Do(finalConvoy, function(unit) + Trigger.OnAddedToWorld(unit, function() + Utils.Do(finalPath, function(waypoint) + unit.Move(waypoint) + end) + + Trigger.OnIdle(unit, function() + unit.Move(finalWaypoint) + end) + end) + end) + + Trigger.OnAllKilled(Utils.Where(finalConvoy, function(a) return a.Type == "truk" end), function() + Allies.MarkCompletedObjective(StopTrucks) + end) + end) +end + +ConvoyExit = function() + Trigger.OnEnteredFootprint(ConvoyEscape, function(actor, id) + if actor.Owner == USSR and actor.Type == "truk" then + actor.Stop() + actor.Destroy() + Allies.MarkFailedObjective(StopTrucks) + elseif actor.Owner == USSR and actor.Type ~= "truk" then + actor.Stop() + actor.Destroy() + end + end) +end + +BridgeTriggers = function() + Trigger.OnKilled(BridgeBarrel1, function() + local theNorthEastBridge = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "bridge2" end)[1] + if not theNorthEastBridge.IsDead then + theNorthEastBridge.Kill() + end + end) + + Trigger.OnKilled(BridgeBarrel2, function() + local theNorthwestBridge = Map.ActorsInBox(NorthwestPath1.CenterPosition, NorthEntry.CenterPosition, function(self) return self.Type == "bridge1" end)[1] + if not theNorthwestBridge.IsDead then + theNorthwestBridge.Kill() + end + end) + + Trigger.OnKilled(BridgeBarrel3, function() + local theSoutheastBridge = Map.ActorsInBox(SoutheastBridge.CenterPosition, SouthPath3.CenterPosition, function(self) return self.Type == "bridge1" end)[1] + if not theSoutheastBridge.IsDead then + theSoutheastBridge.Kill() + end + end) + + AllThreeBridges = Utils.Where(Map.ActorsInWorld, function(actor) + return + actor.Type == "bridge1" or + actor.Type == "bridge2" + end) + + Trigger.OnAllKilled(AllThreeBridges, function() + Allies.MarkCompletedObjective(DestroyBridges) + end) +end + +FinishTimer = function() + for i = 0, 5 do + local c = TimerColor + if i % 2 == 0 then + c = HSLColor.White + end + + Trigger.AfterDelay(DateTime.Seconds(i), function() UserInterface.SetMissionText("The first trucks are entering your AO.", c) end) + end + Trigger.AfterDelay(DateTime.Seconds(6), function() UserInterface.SetMissionText("") end) +end + +ticked = TimerTicks +ConvoysSent = false +Tick = function() + if ticked > 0 then + UserInterface.SetMissionText("First trucks arrive in " .. Utils.FormatTime(ticked), TimerColor) + ticked = ticked - 1 + elseif ticked == 0 and not ConvoysSent then + SendConvoys() + FinishTimer() + end + + if Allies.HasNoRequiredUnits() then + USSR.MarkCompletedObjective(SovietObj) + end +end + +WorldLoaded = function() + Allies = Player.GetPlayer("Allies") + USSR = Player.GetPlayer("USSR") + + SovietObj = USSR.AddObjective("Defeat the Allies.") + StopTrucks = Allies.AddObjective("Destroy all Soviet convoy trucks.") + DestroyBridges = Allies.AddObjective("Destroy the nearby bridges to slow the\nconvoys down.", "Secondary", false) + + Trigger.OnObjectiveAdded(Allies, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") + end) + + Trigger.OnObjectiveCompleted(Allies, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") + end) + Trigger.OnObjectiveFailed(Allies, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") + end) + Trigger.OnPlayerLost(Allies, function() + Media.PlaySpeechNotification(Allies, "Lose") + end) + Trigger.OnPlayerWon(Allies, function() + Media.PlaySpeechNotification(Allies, "Win") + end) + + Trigger.AfterDelay(DateTime.Minutes(3), function() + Media.PlaySpeechNotification(Allies, "WarningFiveMinutesRemaining") + end) + Trigger.AfterDelay(DateTime.Minutes(5), function() + Media.PlaySpeechNotification(Allies, "WarningThreeMinutesRemaining") + end) + Trigger.AfterDelay(DateTime.Minutes(7), function() + Media.PlaySpeechNotification(Allies, "WarningOneMinuteRemaining") + end) + + Camera.Position = AlliedBase.CenterPosition + TimerColor = Allies.Color + OpeningMoves() + Trigger.AfterDelay(DateTime.Seconds(30), AttackWaves) + ConvoyExit() + BridgeTriggers() + + local difficulty = Map.LobbyOption("difficulty") + ConvoyUnits = ConvoyUnits[difficulty] + AttackWaveDelay = AttackWaveDelays[difficulty] +end Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/siberian-conflict-1-fresh-tracks/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/siberian-conflict-1-fresh-tracks/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/siberian-conflict-1-fresh-tracks/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/siberian-conflict-1-fresh-tracks/map.png differ diff -Nru openra-20200503/mods/ra/maps/siberian-conflict-1-fresh-tracks/map.yaml openra-20210321/mods/ra/maps/siberian-conflict-1-fresh-tracks/map.yaml --- openra-20200503/mods/ra/maps/siberian-conflict-1-fresh-tracks/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/siberian-conflict-1-fresh-tracks/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,672 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: Siberian Conflict 1: Fresh Tracks + +Author: Westwood Studios + +Tileset: SNOW + +MapSize: 128,128 + +Bounds: 28,42,90,46 + +Visibility: MissionSelector + +Categories: Mission + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: allies + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Faction: england + PlayerReference@Allies: + Name: Allies + AllowBots: False + Playable: True + Required: True + LockFaction: True + Faction: allies + LockColor: True + Color: ABB7E4 + LockSpawn: True + LockTeam: True + Allies: England + Enemies: USSR + PlayerReference@England: + Name: England + Faction: allies + Color: A0F08C + Allies: Allies + Enemies: USSR + PlayerReference@USSR: + Name: USSR + Faction: soviet + Color: FF1400 + Enemies: Allies, England + +Actors: + Actor0: brik + Location: 39,72 + Owner: Allies + Actor1: brik + Location: 40,72 + Owner: Allies + Actor2: brik + Location: 41,72 + Owner: Allies + Actor3: brik + Location: 42,72 + Owner: Allies + Actor4: brik + Location: 43,72 + Owner: Allies + Actor5: brik + Location: 44,72 + Owner: Allies + Actor6: brik + Location: 45,72 + Owner: Allies + Actor7: brik + Location: 46,72 + Owner: Allies + Actor8: brik + Location: 47,72 + Owner: Allies + Actor9: brik + Location: 48,72 + Owner: Allies + Actor10: brik + Location: 39,73 + Owner: Allies + Actor11: brik + Location: 40,73 + Owner: Allies + Actor12: brik + Location: 47,73 + Owner: Allies + Actor13: brik + Location: 48,73 + Owner: Allies + Actor14: brik + Location: 48,74 + Owner: Allies + Actor15: brik + Location: 47,75 + Owner: Allies + Actor16: brik + Location: 48,75 + Owner: Allies + Actor17: brik + Location: 47,76 + Owner: Allies + Actor18: brik + Location: 48,76 + Owner: Allies + Actor19: brik + Location: 47,82 + Owner: Allies + Actor20: brik + Location: 48,82 + Owner: Allies + Actor21: brik + Location: 47,83 + Owner: Allies + Actor22: brik + Location: 48,83 + Owner: Allies + Actor23: brik + Location: 47,84 + Owner: Allies + Actor24: brik + Location: 48,84 + Owner: Allies + Actor25: brik + Location: 47,85 + Owner: Allies + Actor26: brik + Location: 48,85 + Owner: Allies + Actor27: tc05 + Location: 42,85 + Owner: Neutral + Actor28: tc04 + Location: 28,68 + Owner: Neutral + Actor29: t16 + Location: 28,60 + Owner: Neutral + Actor30: t15 + Location: 30,71 + Owner: Neutral + Actor31: tc03 + Location: 32,86 + Owner: Neutral + Actor32: tc01 + Location: 28,86 + Owner: Neutral + Actor33: t01 + Location: 28,80 + Owner: Neutral + Actor34: tc05 + Location: 30,49 + Owner: Neutral + Actor35: tc03 + Location: 28,51 + Owner: Neutral + Actor36: tc03 + Location: 105,85 + Owner: Neutral + Actor37: tc04 + Location: 81,83 + Owner: Neutral + Actor38: tc05 + Location: 73,43 + Owner: Neutral + Actor39: tc04 + Location: 64,42 + Owner: Neutral + Actor40: tc05 + Location: 84,85 + Owner: Neutral + Actor41: t15 + Location: 104,41 + Owner: Neutral + Actor42: tc03 + Location: 74,86 + Owner: Neutral + Actor43: tc05 + Location: 56,54 + Owner: Neutral + Actor44: tc04 + Location: 70,58 + Owner: Neutral + Actor45: tc02 + Location: 71,47 + Owner: Neutral + Actor46: tc04 + Location: 50,43 + Owner: Neutral + Actor47: tc04 + Location: 44,54 + Owner: Neutral + Actor48: tc04 + Location: 88,54 + Owner: Neutral + Actor49: tc03 + Location: 83,54 + Owner: Neutral + Actor50: tc03 + Location: 112,51 + Owner: Neutral + Actor51: tc01 + Location: 115,53 + Owner: Neutral + Actor52: tc05 + Location: 88,72 + Owner: Neutral + Actor53: tc04 + Location: 82,72 + Owner: Neutral + Actor54: tc02 + Location: 86,74 + Owner: Neutral + Actor55: tc02 + Location: 101,71 + Owner: Neutral + Actor56: tc03 + Location: 102,73 + Owner: Neutral + Actor57: tc05 + Location: 96,79 + Owner: Neutral + Actor58: tc03 + Location: 51,56 + Owner: Neutral + Actor59: tc02 + Location: 52,57 + Owner: Neutral + Actor60: t14 + Location: 97,61 + Owner: Neutral + Actor61: tc01 + Location: 28,77 + Owner: Neutral + Actor62: tc03 + Location: 28,42 + Owner: Neutral + Actor63: tc04 + Location: 31,45 + Owner: Neutral + Actor64: tc04 + Location: 31,60 + Owner: Neutral + Actor65: t01 + Location: 89,42 + Owner: Neutral + Actor66: tc05 + Location: 99,42 + Owner: Neutral + Actor67: t15 + Location: 109,78 + Owner: Neutral + Actor68: tc05 + Location: 112,79 + Owner: Neutral + Actor69: tc03 + Location: 113,82 + Owner: Neutral + Actor70: tc01 + Location: 52,66 + Owner: Neutral + Actor71: t14 + Location: 53,69 + Owner: Neutral + Actor72: t02 + Location: 92,46 + Owner: Neutral + Actor73: tc02 + Location: 77,84 + Owner: Neutral + Actor74: t06 + Location: 74,60 + Owner: Neutral + Actor75: tc04 + Location: 107,81 + Owner: Neutral + Actor76: t16 + Location: 110,83 + Owner: Neutral + Actor77: t07 + Location: 88,50 + Owner: Neutral + Actor78: t01 + Location: 77,80 + Owner: Neutral + Actor79: tc05 + Location: 115,56 + Owner: Neutral + Actor80: tc02 + Location: 113,75 + Owner: Neutral + Actor81: tc02 + Location: 107,54 + Owner: Neutral + Actor82: t16 + Location: 117,43 + Owner: Neutral + Actor83: t14 + Location: 108,51 + Owner: Neutral + Actor84: t06 + Location: 115,63 + Owner: Neutral + Actor85: t10 + Location: 45,41 + Owner: Neutral + Actor86: tc01 + Location: 48,68 + Owner: Neutral + Actor87: t17 + Location: 50,69 + Owner: Neutral + Actor88: tc01 + Location: 70,65 + Owner: Neutral + Actor183: proc + Location: 44,73 + Owner: Allies + Actor184: proc + Location: 41,73 + Owner: Allies + Actor90: tent + Location: 39,74 + Owner: Allies + Actor91: apwr + Location: 32,81 + Owner: Allies + Actor92: hbox + Location: 38,72 + Owner: Allies + Actor93: hbox + Location: 48,77 + Owner: Allies + Actor94: weap + Location: 43,80 + Owner: Allies + Actor95: pbox + Location: 39,80 + Owner: Allies + Actor96: gun + Location: 48,81 + Owner: Allies + Facing: 636 + Actor97: gun + Location: 34,72 + Owner: Allies + Facing: 892 + Actor100: fix + Location: 39,82 + Owner: Allies + Actor102: dome + Location: 36,78 + Owner: Allies + Actor103: apwr + Location: 35,82 + Owner: Allies + Actor104: gun + Location: 41,79 + Owner: Allies + Facing: 764 + BridgeBarrel3: brl3 + Location: 105,78 + Owner: USSR + Actor106: barl + Location: 104,77 + Owner: USSR + Actor107: v19 + Location: 104,78 + Owner: Neutral + Actor108: hpad + Location: 33,77 + Owner: Allies + BridgeBarrel2: brl3 + Location: 42,45 + Owner: USSR + Actor110: v19 + Location: 41,45 + Owner: Neutral + Actor111: barl + Location: 41,44 + Owner: USSR + Actor112: brl3 + Location: 89,51 + Owner: USSR + Actor113: barl + Location: 88,52 + Owner: USSR + Actor114: barl + Location: 90,50 + Owner: USSR + BridgeBarrel1: brl3 + Location: 91,47 + Owner: USSR + Actor116: barl + Location: 91,46 + Owner: USSR + Actor117: v19 + Location: 91,45 + Owner: Neutral + Actor118: v19 + Location: 89,52 + Owner: Neutral + Actor119: barl + Location: 90,45 + Owner: USSR + Actor121: jeep + Location: 45,83 + Owner: Allies + Facing: 636 + Actor122: jeep + Location: 43,83 + Owner: Allies + Facing: 380 + Actor123: 3tnk + Location: 73,75 + Owner: USSR + Facing: 380 + Actor124: 3tnk + Location: 89,46 + Owner: USSR + Facing: 380 + Actor125: 3tnk + Location: 41,49 + Owner: USSR + Facing: 380 + PatrolMammoth: 4tnk + Location: 56,59 + Owner: USSR + Facing: 636 + Actor127: 3tnk + Location: 105,83 + Owner: USSR + Facing: 380 + Actor128: 1tnk + Location: 44,78 + Owner: Allies + Facing: 764 + Actor129: e1 + Location: 38,73 + Owner: Allies + Facing: 508 + SubCell: 1 + Actor130: e1 + Location: 47,77 + Owner: Allies + Facing: 764 + SubCell: 0 + Actor131: e1 + Location: 39,76 + Owner: Allies + Facing: 636 + SubCell: 4 + Actor132: e1 + Location: 104,83 + Owner: USSR + Facing: 380 + SubCell: 1 + Actor133: e2 + Location: 106,83 + Owner: USSR + SubCell: 2 + Actor134: e2 + Location: 105,77 + Owner: USSR + Facing: 636 + SubCell: 2 + Actor135: e2 + Location: 106,78 + Owner: USSR + Facing: 892 + SubCell: 1 + Actor136: e1 + Location: 109,78 + Owner: USSR + Facing: 380 + SubCell: 2 + Actor137: e1 + Location: 110,78 + Owner: USSR + Facing: 636 + SubCell: 2 + Actor138: e1 + Location: 84,49 + Owner: USSR + Facing: 124 + SubCell: 2 + Actor139: e1 + Location: 83,51 + Owner: USSR + Facing: 380 + SubCell: 2 + Actor140: e2 + Location: 85,50 + Owner: USSR + Facing: 636 + SubCell: 1 + Actor141: e2 + Location: 84,51 + Owner: USSR + Facing: 124 + SubCell: 2 + Actor142: e2 + Location: 91,51 + Owner: USSR + Facing: 636 + SubCell: 1 + Actor143: e2 + Location: 91,52 + Owner: USSR + Facing: 892 + SubCell: 3 + Actor144: e1 + Location: 90,52 + Owner: USSR + Facing: 764 + SubCell: 1 + Actor145: e1 + Location: 93,49 + Owner: USSR + Facing: 636 + SubCell: 0 + SecondSquad1: e1 + Location: 59,72 + Owner: USSR + Facing: 380 + SubCell: 4 + SecondSquad3: e1 + Location: 60,73 + Owner: USSR + Facing: 380 + SubCell: 1 + FirstSquad1: e2 + Location: 36,63 + Owner: USSR + SubCell: 0 + SecondSquad2: e2 + Location: 60,72 + Owner: USSR + Facing: 380 + SubCell: 4 + FirstSquad3: e1 + Location: 38,63 + Owner: USSR + SubCell: 1 + FirstSquad2: e1 + Location: 37,64 + Owner: USSR + SubCell: 1 + Actor152: e1 + Location: 40,77 + Owner: Allies + SubCell: 1 + Actor153: e1 + Location: 47,80 + Owner: Allies + Facing: 252 + SubCell: 2 + Actor154: e1 + Location: 34,73 + Owner: Allies + Facing: 892 + SubCell: 0 + Actor201: mine + Owner: Neutral + Location: 70,84 + Actor202: mine + Owner: Neutral + Location: 68,66 + Actor194: heli + Owner: Allies + Location: 34,79 + Facing: 868 + AlliedBase: waypoint + Location: 40,79 + Owner: Neutral + Patrol1: waypoint + Location: 58,61 + Owner: Neutral + Patrol2: waypoint + Location: 58,74 + Owner: Neutral + Patrol3: waypoint + Location: 71,76 + Owner: Neutral + Patrol4: waypoint + Location: 77,71 + Owner: Neutral + Patrol5: waypoint + Location: 79,60 + Owner: Neutral + Patrol6: waypoint + Location: 76,52 + Owner: Neutral + Patrol7: waypoint + Location: 65,52 + Owner: Neutral + NorthwestEntry: waypoint + Owner: Neutral + Location: 32,42 + CenterEntry: waypoint + Owner: Neutral + Location: 28,57 + BaseEntry: waypoint + Owner: Neutral + Location: 28,76 + SouthEntry: waypoint + Owner: Neutral + Location: 53,87 + NorthEntry: waypoint + Owner: Neutral + Location: 58,42 + ExitEast: waypoint + Owner: Neutral + Location: 117,71 + ExitNorth: waypoint + Owner: Neutral + Location: 113,42 + NortheastBridge: waypoint + Location: 87,46 + Owner: Neutral + NorthwestBridge: waypoint + Location: 41,48 + Owner: Neutral + SoutheastBridge: waypoint + Location: 103,82 + Owner: Neutral + NorthwestPath1: waypoint + Location: 38,49 + Owner: Neutral + NorthwestPath2: waypoint + Location: 81,48 + Owner: Neutral + NorthwestPath3: waypoint + Location: 99,50 + Owner: Neutral + BasePath1: waypoint + Location: 35,76 + Owner: Neutral + CenterPath1: waypoint + Location: 37,57 + Owner: Neutral + CenterPath2: waypoint + Location: 37,61 + Owner: Neutral + SouthPath1: waypoint + Location: 53,75 + Owner: Neutral + SouthPath2: waypoint + Location: 92,80 + Owner: Neutral + SouthPath3: waypoint + Location: 110,69 + Owner: Neutral + FinalConvoy1: waypoint + Location: 88,62 + Owner: Neutral + AttackEntry1: waypoint + Location: 81,42 + Owner: Neutral + AttackEntry2: waypoint + Location: 92,87 + Owner: Neutral + +Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/ra/maps/siberian-conflict-1-fresh-tracks/rules.yaml openra-20210321/mods/ra/maps/siberian-conflict-1-fresh-tracks/rules.yaml --- openra-20200503/mods/ra/maps/siberian-conflict-1-fresh-tracks/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/siberian-conflict-1-fresh-tracks/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,69 @@ +World: + LuaScript: + Scripts: fresh-tracks.lua + MissionData: + WinVideo: sovbatl.vqa + LossVideo: overrun.vqa + Briefing: Soviet activity in Siberia is increasing. A large shipment of atomic material is on its way through this area, and we need it stopped. Destroy all of the Soviet convoy trucks and prevent the Soviets from furthering their atomic testing.\n\nBe careful of the convoy truck cargo -- atomic material is highly unstable.\n\nThe mission is complete when all the convoy trucks from each convoy have been destroyed. + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Values: + easy: Easy + normal: Normal + hard: Hard + Default: normal + +Player: + PlayerResources: + DefaultCash: 2100 + +MONEYCRATE: + Crate: + Lifetime: 0 + ExplodeCrateAction: + Weapon: MiniNuke + Tooltip: + Name: Atomic Material + RenderSprites: + Image: wcrate + +SPY: + Buildable: + Prerequisites: ~disabled + +MECH: + Buildable: + Prerequisites: ~disabled + +E7: + Buildable: + Prerequisites: ~disabled + +TRAN: + Buildable: + Prerequisites: ~disabled + +HELI: + Buildable: + Prerequisites: ~hpad + +MRJ: + Buildable: + Prerequisites: ~disabled + +MCV: + Buildable: + Prerequisites: ~disabled + +2TNK: + Buildable: + Prerequisites: ~disabled + +ARTY: + Buildable: + Prerequisites: ~disabled + +MH60: + Buildable: + Prerequisites: ~disabled Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/sidestep.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/sidestep.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/situation-critical/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/situation-critical/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/situation-critical/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/situation-critical/map.png differ diff -Nru openra-20200503/mods/ra/maps/situation-critical/map.yaml openra-20210321/mods/ra/maps/situation-critical/map.yaml --- openra-20200503/mods/ra/maps/situation-critical/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/situation-critical/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,567 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: Situation Critical + +Author: Westwood Studios + +Tileset: SNOW + +MapSize: 128,128 + +Bounds: 30,33,65,60 + +Visibility: MissionSelector + +Categories: Mission + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: england + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Faction: england + PlayerReference@Turkey: + Name: Turkey + Faction: allies + Color: D2997D + Bot: campaign + Enemies: USSR + PlayerReference@USSR: + Name: USSR + AllowBots: False + Playable: True + Required: True + LockFaction: True + Faction: soviet + LockColor: True + Color: FE1100 + LockSpawn: True + LockTeam: True + Enemies: Turkey + +Actors: + Actor0: brik + Location: 56,54 + Owner: Neutral + Actor1: brik + Location: 57,54 + Owner: Neutral + Actor2: brik + Location: 58,54 + Owner: Neutral + Actor3: brik + Location: 59,54 + Owner: Neutral + Actor4: brik + Location: 60,54 + Owner: Neutral + Actor5: brik + Location: 61,54 + Owner: Neutral + Actor6: brik + Location: 62,54 + Owner: Neutral + Actor7: brik + Location: 63,54 + Owner: Neutral + Actor8: brik + Location: 56,55 + Owner: Neutral + Actor9: brik + Location: 59,55 + Owner: Neutral + Actor10: brik + Location: 60,55 + Owner: Neutral + Actor11: brik + Location: 63,55 + Owner: Neutral + Actor12: brik + Location: 56,56 + Owner: Neutral + Actor13: brik + Location: 57,56 + Owner: Neutral + Actor14: brik + Location: 58,56 + Owner: Neutral + Actor15: brik + Location: 59,56 + Owner: Neutral + Actor16: brik + Location: 60,56 + Owner: Neutral + Actor17: brik + Location: 61,56 + Owner: Neutral + Actor18: brik + Location: 62,56 + Owner: Neutral + Actor19: brik + Location: 63,56 + Owner: Neutral + Actor20: brik + Location: 56,57 + Owner: Neutral + Actor21: brik + Location: 63,57 + Owner: Neutral + Actor22: brik + Location: 56,58 + Owner: Neutral + Actor23: brik + Location: 63,58 + Owner: Neutral + Actor24: brik + Location: 56,59 + Owner: Neutral + Actor25: brik + Location: 63,59 + Owner: Neutral + Actor26: brik + Location: 56,60 + Owner: Neutral + Actor27: brik + Location: 57,60 + Owner: Neutral + Actor28: brik + Location: 62,60 + Owner: Neutral + Actor29: brik + Location: 63,60 + Owner: Neutral + Actor30: brik + Location: 56,61 + Owner: Neutral + Actor31: brik + Location: 57,61 + Owner: Neutral + Actor32: brik + Location: 62,61 + Owner: Neutral + Actor33: brik + Location: 63,61 + Owner: Neutral + Actor34: t01 + Location: 83,83 + Owner: Neutral + Actor35: tc04 + Location: 39,47 + Owner: Neutral + Actor36: tc04 + Location: 72,55 + Owner: Neutral + Actor37: tc05 + Location: 70,67 + Owner: Neutral + Actor38: tc02 + Location: 59,86 + Owner: Neutral + Actor39: tc04 + Location: 58,71 + Owner: Neutral + Actor40: tc03 + Location: 59,73 + Owner: Neutral + Actor41: tc01 + Location: 48,66 + Owner: Neutral + Actor42: t02 + Location: 48,46 + Owner: Neutral + Actor43: ice04 + Location: 86,60 + Owner: Neutral + Actor44: ice02 + Location: 50,82 + Owner: Neutral + Actor45: ice05 + Location: 38,52 + Owner: Neutral + Actor46: ice01 + Location: 38,42 + Owner: Neutral + Actor47: ice02 + Location: 37,43 + Owner: Neutral + Actor48: ice05 + Location: 59,39 + Owner: Neutral + Actor49: ice05 + Location: 69,42 + Owner: Neutral + Actor50: ice04 + Location: 69,41 + Owner: Neutral + Actor51: ice04 + Location: 80,40 + Owner: Neutral + Actor52: ice05 + Location: 83,43 + Owner: Neutral + Actor53: ice04 + Location: 82,53 + Owner: Neutral + Actor54: ice03 + Location: 85,59 + Owner: Neutral + Actor55: ice02 + Location: 70,83 + Owner: Neutral + Actor56: ice01 + Location: 71,83 + Owner: Neutral + Actor57: ice03 + Location: 70,85 + Owner: Neutral + Actor58: ice04 + Location: 72,85 + Owner: Neutral + Actor59: tc05 + Location: 71,46 + Owner: Neutral + Actor60: t13 + Location: 69,74 + Owner: Neutral + Actor61: tc03 + Location: 89,58 + Owner: Neutral + Actor62: t17 + Location: 53,67 + Owner: Neutral + Actor63: tc01 + Location: 59,52 + Owner: Neutral + Actor64: t13 + Location: 48,55 + Owner: Neutral + Actor65: t13 + Location: 90,59 + Owner: Neutral + Actor66: t15 + Location: 80,49 + Owner: Neutral + Actor67: tc04 + Location: 81,82 + Owner: Neutral + Actor68: tc05 + Location: 80,84 + Owner: Neutral + Actor69: tc03 + Location: 83,85 + Owner: Neutral + Actor70: t17 + Location: 91,58 + Owner: Neutral + Actor71: tsla + Location: 48,85 + Owner: Turkey + Actor72: tsla + Location: 59,86 + Owner: Turkey + Actor73: tsla + Location: 78,70 + Owner: Turkey + Actor74: tsla + Location: 76,42 + Owner: Turkey + Actor75: tsla + Location: 42,42 + Owner: Turkey + Sam1: sam + Location: 67,75 + Owner: Turkey + Sam2: sam + Location: 65,75 + Owner: Turkey + Sam3: sam + Location: 66,76 + Owner: Turkey + Sam4: sam + Location: 48,64 + Owner: Turkey + Sam5: sam + Location: 50,64 + Owner: Turkey + Sam6: sam + Location: 49,63 + Owner: Turkey + Sam7: sam + Location: 48,51 + Owner: Turkey + Sam8: sam + Location: 50,51 + Owner: Turkey + Sam9: sam + Location: 49,50 + Owner: Turkey + Sam10: sam + Location: 71,51 + Owner: Turkey + Sam11: sam + Location: 73,51 + Owner: Turkey + Sam12: sam + Location: 72,52 + Owner: Turkey + BioLab: bio + Location: 59,57 + Owner: Turkey + Silo1: mslo + Location: 57,55 + Owner: Turkey + Silo2: mslo + Location: 61,55 + Owner: Turkey + Actor91: tsla + Location: 42,67 + Owner: Turkey + Actor92: powr + Location: 46,83 + Owner: Turkey + Actor93: powr + Location: 44,83 + Owner: Turkey + Actor94: powr + Location: 42,68 + Owner: Turkey + Actor95: powr + Location: 43,71 + Owner: Turkey + Actor96: powr + Location: 44,41 + Owner: Turkey + Actor97: powr + Location: 42,43 + Owner: Turkey + Actor98: powr + Location: 74,42 + Owner: Turkey + Actor99: powr + Location: 77,42 + Owner: Turkey + Actor100: powr + Location: 77,71 + Owner: Turkey + Actor101: powr + Location: 77,67 + Owner: Turkey + Actor102: powr + Location: 63,85 + Owner: Turkey + Actor103: powr + Location: 65,85 + Owner: Turkey + TeamOne1: e1 + Location: 47,54 + Owner: Turkey + Facing: 124 + SubCell: 3 + TeamOne2: e2 + Location: 46,54 + Owner: Turkey + SubCell: 0 + TeamOne3: e1 + Location: 47,55 + Owner: Turkey + SubCell: 1 + TeamTwo1: e1 + Location: 51,71 + Owner: Turkey + Facing: 124 + SubCell: 4 + TeamTwo2: e1 + Location: 51,71 + Owner: Turkey + Facing: 124 + SubCell: 1 + TeamTwo3: e2 + Location: 50,70 + Owner: Turkey + SubCell: 2 + TeamThree1: e1 + Location: 68,79 + Owner: Turkey + Facing: 252 + SubCell: 1 + TeamThree2: e1 + Location: 68,79 + Owner: Turkey + Facing: 252 + SubCell: 4 + TeamThree3: e2 + Location: 68,79 + Owner: Turkey + Facing: 252 + SubCell: 5 + TeamFour1: e1 + Location: 66,44 + Owner: Turkey + Facing: 636 + SubCell: 1 + TeamFour2: e1 + Location: 66,43 + Owner: Turkey + Facing: 636 + SubCell: 3 + TeamFour3: e2 + Location: 66,44 + Owner: Turkey + Facing: 636 + SubCell: 2 + TeamFive1: e1 + Location: 75,58 + Owner: Turkey + Facing: 508 + SubCell: 4 + TeamFive2: e2 + Location: 75,58 + Owner: Turkey + Facing: 508 + SubCell: 3 + TeamFive3: e1 + Location: 75,58 + Owner: Turkey + Facing: 508 + SubCell: 1 + Shok1: shok + Location: 54,50 + Owner: Turkey + Facing: 380 + SubCell: 1 + Shok2: shok + Location: 51,62 + Owner: Turkey + SubCell: 0 + Shok3: shok + Location: 63,68 + Owner: Turkey + Facing: 380 + SubCell: 1 + Shok4: shok + Location: 69,52 + Owner: Turkey + Facing: 636 + SubCell: 0 + Actor123: ss + Location: 35,34 + Owner: USSR + Facing: 764 + Actor124: ss + Location: 36,35 + Owner: USSR + Facing: 764 + Actor125: ss + Location: 35,36 + Owner: USSR + Facing: 764 + MSub1: msub + Location: 32,35 + Owner: USSR + Facing: 764 + MSub2: msub + Location: 31,36 + Owner: USSR + Facing: 764 + MSub3: msub + Location: 31,34 + Owner: USSR + Facing: 764 + MSub4: msub + Location: 30,35 + Owner: USSR + Facing: 764 + Actor129: ss + Location: 71,36 + Owner: Turkey + Facing: 124 + Actor130: ss + Location: 81,60 + Owner: Turkey + Facing: 892 + Actor131: ss + Location: 59,83 + Owner: Turkey + Facing: 252 + Actor132: ss + Location: 34,57 + Owner: Turkey + Facing: 124 + Actor133: ss + Location: 36,81 + Owner: Turkey + Actor134: ss + Location: 74,87 + Owner: Turkey + Facing: 892 + Actor135: ss + Location: 91,39 + Owner: Turkey + Facing: 380 + Actor137: ss + Location: 34,35 + Owner: USSR + Facing: 764 + DefaultCameraPosition: waypoint + Location: 32,35 + Owner: Neutral + LZ: waypoint + Location: 53,75 + Owner: Neutral + LSTEntry: waypoint + Location: 54,92 + Owner: Neutral + InnerPatrol1: waypoint + Location: 54,50 + Owner: Neutral + InnerPatrol2: waypoint + Location: 68,50 + Owner: Neutral + InnerPatrol3: waypoint + Location: 63,68 + Owner: Neutral + InnerPatrol4: waypoint + Location: 51,62 + Owner: Neutral + OuterPatrol1: waypoint + Location: 44,44 + Owner: Neutral + OuterPatrol2: waypoint + Location: 64,42 + Owner: Neutral + OuterPatrol3: waypoint + Location: 80,44 + Owner: Neutral + OuterPatrol4: waypoint + Location: 75,56 + Owner: Neutral + OuterPatrol5: waypoint + Location: 70,79 + Owner: Neutral + OuterPatrol6: waypoint + Location: 48,71 + Owner: Neutral + OuterPatrol7: waypoint + Location: 46,56 + Owner: Neutral + TacticalNuke1: waypoint + Location: 60,56 + Owner: Neutral + TacticalNuke2: waypoint + Location: 55,58 + Owner: Neutral + TacticalNuke3: waypoint + Location: 57,61 + Owner: Neutral + +Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml + +Weapons: weapons.yaml diff -Nru openra-20200503/mods/ra/maps/situation-critical/rules.yaml openra-20210321/mods/ra/maps/situation-critical/rules.yaml --- openra-20200503/mods/ra/maps/situation-critical/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/situation-critical/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,82 @@ +World: + LuaScript: + Scripts: situation-critical.lua + MissionData: + WinVideo: flare.vqa + LossVideo: nukestok.vqa + Briefing: A radical faction of our forces has stolen a biological weapon, threatening to use it on Allied emplacements. Since the weapon is highly unstable, it could destroy us all if released. \n\nThe facility must be destroyed, but the weapon must be neutralized first. Destroy the island's defenses, then use Volkov to assist our scientist in reaching the bio-research center. If either are killed before the weapon is neutralized, the mission is a failure.\n\nOnce the scientist completes his mission, destroy the base. + +VOLK: + Inherits: GNRL + -AutoTarget: + -AutoTargetPriority@DEFAULT: + -AutoTargetPriority@ATTACKANYTHING: + AttackMove: + -AssaultMoveCondition: + Valued: + Cost: 1200 + Tooltip: + Name: Volkov + Health: + HP: 15000 + Armor: + Type: Heavy + RevealsShroud: + Range: 6c0 + Demolition: + Mobile: + Voice: Action + AttackFrontal: + Voice: Action + AttackMove: + Voice: Action + Passenger: + Voice: Action + Guard: + Voice: Action + Voiced: + VoiceSet: GenericVoice + Armament: + Weapon: VolkovWeapon + RenderSprites: + Image: GNRL + +LST.Reinforcement: + Inherits: LST + RejectsOrders: + -Buildable: + -Selectable: + RenderSprites: + Image: lst + Interactable: + +MSLO: + Power: + Amount: 0 + -WithColoredOverlay@IDISABLE: + -NukePower: + +SAM: + -WithColoredOverlay@IDISABLE: + +BADR.Bomber: + Aircraft: + Speed: 373 + Tooltip: + Name: Strategic Bomber + RenderSprites: + Image: U2 + +powerproxy.parabombs: + AirstrikePower: + DisplayBeacon: False + +DELPHI: + Tooltip: + Name: Scientist + Infiltrates: + Types: ScientistInfiltrate + +BIO: + Targetable: + TargetTypes: GroundActor, Structure, C4, DetonateAttack, ScientistInfiltrate diff -Nru openra-20200503/mods/ra/maps/situation-critical/situation-critical.lua openra-20210321/mods/ra/maps/situation-critical/situation-critical.lua --- openra-20200503/mods/ra/maps/situation-critical/situation-critical.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/situation-critical/situation-critical.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,205 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +MissleSubs = { MSub1, MSub2, MSub3, MSub4 } +VolkovEntryPath = { LSTEntry.Location, LZ.Location } +VolkovandFriend = { "volk", "delphi" } +InsertionTransport = "lst.reinforcement" +SamSites = { Sam1, Sam2, Sam3, Sam4, Sam5, Sam6, Sam7, Sam8, Sam9, Sam10, Sam11, Sam12 } +PrimaryTargets = { BioLab, Silo1, Silo2 } +TimerTicks = DateTime.Minutes(8) + +Shocktroopers = { Shok1, Shok2, Shok3, Shok4 } + +InnerPatrolPaths = +{ + { InnerPatrol2.Location, InnerPatrol3.Location, InnerPatrol4.Location, InnerPatrol1.Location }, + { InnerPatrol3.Location, InnerPatrol2.Location, InnerPatrol1.Location, InnerPatrol4.Location }, + { InnerPatrol4.Location, InnerPatrol1.Location, InnerPatrol2.Location, InnerPatrol3.Location }, + { InnerPatrol1.Location, InnerPatrol4.Location, InnerPatrol3.Location, InnerPatrol2.Location } +} + +OuterPatrols = +{ + { TeamOne1, TeamOne2, TeamOne3 }, + { TeamTwo1, TeamTwo2, TeamTwo3 }, + { TeamThree1, TeamThree2, TeamThree3 }, + { TeamFour1, TeamFour2, TeamFour3 }, + { TeamFive1, TeamFive2, TeamFive3 } +} + +OuterPatrolPaths = +{ + { OuterPatrol1.Location, OuterPatrol2.Location, OuterPatrol3.Location, OuterPatrol4.Location, OuterPatrol5.Location, OuterPatrol6.Location, OuterPatrol7.Location }, + { OuterPatrol5.Location, OuterPatrol4.Location, OuterPatrol3.Location, OuterPatrol2.Location, OuterPatrol1.Location, OuterPatrol7.Location, OuterPatrol6.Location }, + { OuterPatrol6.Location, OuterPatrol7.Location, OuterPatrol1.Location, OuterPatrol2.Location, OuterPatrol3.Location, OuterPatrol4.Location, OuterPatrol5.Location }, + { OuterPatrol3.Location, OuterPatrol4.Location, OuterPatrol5.Location, OuterPatrol6.Location, OuterPatrol7.Location, OuterPatrol1.Location, OuterPatrol2.Location }, + { OuterPatrol3.Location, OuterPatrol2.Location, OuterPatrol1.Location, OuterPatrol7.Location, OuterPatrol6.Location, OuterPatrol5.Location, OuterPatrol4.Location } +} + +GroupPatrol = function(units, waypoints, delay) + local i = 1 + local stop = false + + Utils.Do(units, function(unit) + Trigger.OnIdle(unit, function() + if stop then + return + end + if unit.Location == waypoints[i] then + local bool = Utils.All(units, function(actor) return actor.IsIdle end) + if bool then + stop = true + i = i + 1 + if i > #waypoints then + i = 1 + end + Trigger.AfterDelay(delay, function() stop = false end) + end + else + unit.AttackMove(waypoints[i]) + end + end) + end) +end + +StartPatrols = function() + for i = 1, 5 do + GroupPatrol(OuterPatrols[i], OuterPatrolPaths[i], DateTime.Seconds(3)) + end + + for i = 1, 4 do + Trigger.AfterDelay(DateTime.Seconds(3* (i - 1)), function() + Trigger.OnIdle(Shocktroopers[i], function() + Shocktroopers[i].Patrol(InnerPatrolPaths[i]) + end) + end) + end +end + +LabInfiltrated = false +SetupTriggers = function() + Trigger.OnAllKilled(SamSites, function() + local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = USSR }) + proxy.TargetAirstrike(TacticalNuke1.CenterPosition, Angle.SouthWest) + proxy.TargetAirstrike(TacticalNuke2.CenterPosition, Angle.SouthWest) + proxy.TargetAirstrike(TacticalNuke3.CenterPosition, Angle.SouthWest) + proxy.Destroy() + end) + + Trigger.OnInfiltrated(BioLab, function() + Media.DisplayMessage("Plans stolen; erasing all data.", "Scientist") + Trigger.AfterDelay(DateTime.Seconds(5), function() + USSR.MarkCompletedObjective(InfiltrateLab) + LabInfiltrated = true + end) + end) + + Trigger.OnKilled(BioLab, function() + if not LabInfiltrated then + USSR.MarkFailedObjective(InfiltrateLab) + end + end) + + Trigger.OnAllKilled(PrimaryTargets, function() + USSR.MarkCompletedObjective(DestroyFacility) + USSR.MarkCompletedObjective(VolkovSurvive) + end) + + Trigger.OnAllKilled(MissleSubs, function() + if not VolkovArrived then + USSR.MarkFailedObjective(KillPower) + end + end) +end + +SendInVolkov = function() + if not VolkovArrived then + USSR.MarkCompletedObjective(KillPower) + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + local teamVolkov = Reinforcements.ReinforceWithTransport(USSR, InsertionTransport, VolkovandFriend, VolkovEntryPath, { VolkovEntryPath[1] })[2] + VolkovArrived = true + Trigger.OnKilled(teamVolkov[1], function() + USSR.MarkFailedObjective(VolkovSurvive) + end) + Trigger.OnAddedToWorld(teamVolkov[1], function(a) + Media.DisplayMessage("IFF software update failed. Require manual target input.", "Volkov") + end) + + Trigger.OnAddedToWorld(teamVolkov[2], function(b) + Trigger.OnKilled(b, function() + if not LabInfiltrated then + USSR.MarkFailedObjective(InfiltrateLab) + end + end) + end) + end +end + +ticked = TimerTicks +Tick = function() + if Turkey.PowerState ~= "Normal" then + SendInVolkov() + end + + if ticked > 0 then + UserInterface.SetMissionText("Missiles launch in " .. Utils.FormatTime(ticked), TimerColor) + ticked = ticked - 1 + elseif ticked == 0 then + UserInterface.SetMissionText("We're too late!", USSR.Color) + Turkey.MarkCompletedObjective(LaunchMissles) + end +end + +WorldLoaded = function() + USSR = Player.GetPlayer("USSR") + Turkey = Player.GetPlayer("Turkey") + + Trigger.OnObjectiveAdded(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") + end) + + LaunchMissles = Turkey.AddObjective("Survive until time expires.") + KillPower = USSR.AddObjective("Bring the base to low power. Volkov will arrive\nonce the defenses are down.") + InfiltrateLab = USSR.AddObjective("Infiltrate the bio-weapons lab with the scientist.") + DestroyFacility = USSR.AddObjective("Destroy all sam sites on the island.\nOur strategic bombers will finish the rest.") + VolkovSurvive = USSR.AddObjective("Volkov must survive.") + + Trigger.OnObjectiveCompleted(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") + end) + Trigger.OnObjectiveFailed(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") + end) + + Trigger.OnPlayerLost(USSR, function() + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(USSR, "MissionFailed") + end) + end) + Trigger.OnPlayerWon(USSR, function() + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(USSR, "MissionAccomplished") + end) + end) + + Trigger.AfterDelay(DateTime.Minutes(3), function() + Media.PlaySpeechNotification(USSR, "WarningFiveMinutesRemaining") + end) + Trigger.AfterDelay(DateTime.Minutes(5), function() + Media.PlaySpeechNotification(USSR, "WarningThreeMinutesRemaining") + end) + Trigger.AfterDelay(DateTime.Minutes(7), function() + Media.PlaySpeechNotification(USSR, "WarningOneMinuteRemaining") + end) + + StartPatrols() + SetupTriggers() + Camera.Position = DefaultCameraPosition.CenterPosition + TimerColor = Turkey.Color +end diff -Nru openra-20200503/mods/ra/maps/situation-critical/weapons.yaml openra-20210321/mods/ra/maps/situation-critical/weapons.yaml --- openra-20200503/mods/ra/maps/situation-critical/weapons.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/situation-critical/weapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,80 @@ +VolkovWeapon: + Inherits: SilencedPPK + ReloadDelay: 25 + Range: 6c0 + Warhead@1Dam: SpreadDamage + Spread: 128 + Versus: + None: 90 + Wood: 75 + Light: 60 + Heavy: 25 + Concrete: 0 + DamageTypes: Prone50Percent, TriggerProne, FireDeath + Warhead@2Eff: CreateEffect + Explosions: piff + ValidTargets: Ground, GroundActor, Ship, Trees + Warhead@3EffWater: CreateEffect + Explosions: water_piff + ValidTargets: Water, Underwater + InvalidTargets: Ship, Structure, Bridge + +ParaBomb: + ReloadDelay: 50 + ValidTargets: Ground, Water, GroundActor, WaterActor, Underwater, AirborneActor, Trees + Warhead@1Dam_impact: SpreadDamage + Spread: 1c0 + Damage: 15000 + Falloff: 1000, 368, 135, 50, 18, 7, 0 + ValidTargets: GroundActor, WaterActor, Underwater, AirborneActor, Trees + Versus: + Wood: 1000 + Concrete: 25 + DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary + Warhead@3Smu_impact: LeaveSmudge + SmudgeType: Scorch + ValidTargets: Ground, Infantry + Size: 1 + Warhead@4Eff_impact: CreateEffect + Explosions: nuke + ImpactSounds: kaboom1.aud + ImpactActors: false + ValidTargets: Ground, Water, Air + Warhead@5Dam_areanuke1: SpreadDamage + Spread: 2c0 + Damage: 6000 + Falloff: 1000, 368, 135, 50, 18, 7, 0 + Delay: 5 + ValidTargets: GroundActor, WaterActor, Underwater, AirborneActor, Trees + Versus: + Wood: 1000 + Concrete: 25 + DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary + Warhead@7Smu_areanuke1: LeaveSmudge + SmudgeType: Scorch + ValidTargets: Ground, Infantry + Size: 2 + Delay: 5 + Warhead@8Eff_areanuke1: CreateEffect + ImpactSounds: kaboom22.aud + Delay: 5 + ImpactActors: false + Warhead@9Dam_areanuke2: SpreadDamage + Spread: 3c0 + Damage: 6000 + Falloff: 1000, 368, 135, 50, 18, 7, 0 + Delay: 10 + ValidTargets: GroundActor, Trees, WaterActor, Underwater, AirborneActor + Versus: + Wood: 50 + Tree: 200 + Concrete: 25 + DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary + Warhead@12Smu_areanuke2: LeaveSmudge + SmudgeType: Scorch + ValidTargets: Ground, Infantry + Size: 3 + Delay: 10 + Warhead@13FlashEffect: FlashPaletteEffect + Duration: 20 + FlashType: Nuke Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/six-below-zero/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/six-below-zero/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/six-below-zero/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/six-below-zero/map.png differ diff -Nru openra-20200503/mods/ra/maps/six-below-zero/map.yaml openra-20210321/mods/ra/maps/six-below-zero/map.yaml --- openra-20200503/mods/ra/maps/six-below-zero/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/six-below-zero/map.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,2591 +0,0 @@ -MapFormat: 11 - -RequiresMod: ra - -Title: Six Below Zero - -Author: Echo of Damnation - -Tileset: SNOW - -MapSize: 130,130 - -Bounds: 1,1,128,128 - -Visibility: Lobby - -Categories: Conquest - -Players: - PlayerReference@Neutral: - Name: Neutral - OwnsWorld: True - NonCombatant: True - Faction: england - PlayerReference@Creeps: - Name: Creeps - NonCombatant: True - Faction: england - Enemies: Multi0, Multi1, Multi2, Multi3, Multi4, Multi5 - PlayerReference@Multi0: - Name: Multi0 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi1: - Name: Multi1 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi2: - Name: Multi2 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi3: - Name: Multi3 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi4: - Name: Multi4 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi5: - Name: Multi5 - Playable: True - Faction: Random - Enemies: Creeps - -Actors: - Actor1: gmine - Owner: Neutral - Location: 123,64 - Actor2: gmine - Owner: Neutral - Location: 6,64 - Actor3: gmine - Owner: Neutral - Location: 64,64 - Actor5: tc03 - Owner: Neutral - Location: 45,66 - Actor7: t07 - Owner: Neutral - Location: 82,59 - Actor8: t08 - Owner: Neutral - Location: 85,60 - Actor9: t08 - Owner: Neutral - Location: 43,67 - Actor10: t02 - Owner: Neutral - Location: 45,63 - Actor11: t05 - Owner: Neutral - Location: 85,63 - Actor12: t11 - Owner: Neutral - Location: 105,64 - Actor13: t11 - Owner: Neutral - Location: 25,62 - Actor14: oilb - Owner: Neutral - Location: 46,46 - Actor15: oilb - Owner: Neutral - Location: 81,81 - Actor16: fenc - Owner: Neutral - Location: 75,83 - Actor17: fenc - Owner: Neutral - Location: 76,83 - Actor18: fenc - Owner: Neutral - Location: 76,83 - Actor19: fenc - Owner: Neutral - Location: 77,83 - Actor20: fenc - Owner: Neutral - Location: 77,84 - Actor21: fenc - Owner: Neutral - Location: 80,86 - Actor22: fenc - Owner: Neutral - Location: 80,87 - Actor23: fenc - Owner: Neutral - Location: 80,88 - Actor24: fenc - Owner: Neutral - Location: 79,86 - Actor25: fenc - Owner: Neutral - Location: 83,77 - Actor26: fenc - Owner: Neutral - Location: 83,76 - Actor27: fenc - Owner: Neutral - Location: 83,75 - Actor28: fenc - Owner: Neutral - Location: 84,77 - Actor29: fenc - Owner: Neutral - Location: 86,80 - Actor30: fenc - Owner: Neutral - Location: 87,80 - Actor31: fenc - Owner: Neutral - Location: 88,80 - Actor32: fenc - Owner: Neutral - Location: 86,79 - Actor33: fenc - Owner: Neutral - Location: 51,45 - Actor34: fenc - Owner: Neutral - Location: 52,45 - Actor35: fenc - Owner: Neutral - Location: 53,45 - Actor36: fenc - Owner: Neutral - Location: 51,44 - Actor37: fenc - Owner: Neutral - Location: 45,53 - Actor38: fenc - Owner: Neutral - Location: 45,52 - Actor39: fenc - Owner: Neutral - Location: 45,51 - Actor40: fenc - Owner: Neutral - Location: 44,51 - Actor41: fenc - Owner: Neutral - Location: 48,42 - Actor42: fenc - Owner: Neutral - Location: 48,41 - Actor43: fenc - Owner: Neutral - Location: 48,40 - Actor44: fenc - Owner: Neutral - Location: 49,42 - Actor45: fenc - Owner: Neutral - Location: 40,48 - Actor46: fenc - Owner: Neutral - Location: 41,48 - Actor47: fenc - Owner: Neutral - Location: 42,48 - Actor49: fenc - Owner: Neutral - Location: 42,49 - Actor48: tc03 - Owner: Neutral - Location: 48,49 - Actor50: tc03 - Owner: Neutral - Location: 79,78 - Actor51: v11 - Owner: Neutral - Location: 84,84 - Actor52: v12 - Owner: Neutral - Location: 83,85 - Actor53: t08 - Owner: Neutral - Location: 84,83 - Actor54: brl3 - Owner: Neutral - Location: 80,82 - Actor55: brl3 - Owner: Neutral - Location: 83,81 - Actor56: barl - Owner: Neutral - Location: 81,83 - Actor57: barl - Owner: Neutral - Location: 82,80 - Actor58: brl3 - Owner: Neutral - Location: 46,48 - Actor59: brl3 - Owner: Neutral - Location: 47,45 - Actor60: barl - Owner: Neutral - Location: 48,46 - Actor61: barl - Owner: Neutral - Location: 45,47 - Actor62: v09 - Owner: Neutral - Location: 44,44 - Actor63: v13 - Owner: Neutral - Location: 45,43 - Actor64: t16 - Owner: Neutral - Location: 43,44 - Actor65: t16 - Owner: Neutral - Location: 68,69 - Actor66: tc01 - Owner: Neutral - Location: 59,69 - Actor67: tc03 - Owner: Neutral - Location: 59,57 - Actor68: t02 - Owner: Neutral - Location: 70,59 - Actor69: t15 - Owner: Neutral - Location: 57,59 - Actor70: tc04 - Owner: Neutral - Location: 103,71 - Actor71: tc03 - Owner: Neutral - Location: 104,70 - Actor72: t11 - Owner: Neutral - Location: 103,69 - Actor73: tc05 - Owner: Neutral - Location: 25,55 - Actor74: tc03 - Owner: Neutral - Location: 25,57 - Actor75: t14 - Owner: Neutral - Location: 25,58 - Actor76: t15 - Owner: Neutral - Location: 29,52 - Actor77: tc01 - Owner: Neutral - Location: 99,74 - Actor78: tc02 - Owner: Neutral - Location: 79,65 - Actor82: tc02 - Owner: Neutral - Location: 62,26 - Actor84: t03 - Owner: Neutral - Location: 65,100 - Actor85: t11 - Owner: Neutral - Location: 63,27 - Actor86: t11 - Owner: Neutral - Location: 48,65 - Actor87: t07 - Owner: Neutral - Location: 79,61 - Actor91: t15 - Owner: Neutral - Location: 50,63 - Actor92: mine - Owner: Neutral - Location: 88,88 - Actor93: mine - Owner: Neutral - Location: 40,40 - Actor94: t11 - Owner: Neutral - Location: 29,95 - Actor95: tc03 - Owner: Neutral - Location: 29,98 - Actor96: t15 - Owner: Neutral - Location: 26,98 - Actor97: t01 - Owner: Neutral - Location: 28,98 - Actor98: tc02 - Owner: Neutral - Location: 29,99 - Actor99: tc01 - Owner: Neutral - Location: 27,99 - Actor100: tc04 - Owner: Neutral - Location: 27,100 - Actor101: tc02 - Owner: Neutral - Location: 27,101 - Actor102: t13 - Owner: Neutral - Location: 29,100 - Actor103: tc05 - Owner: Neutral - Location: 27,102 - Actor104: t08 - Owner: Neutral - Location: 23,103 - Actor105: tc01 - Owner: Neutral - Location: 24,102 - Actor106: t11 - Owner: Neutral - Location: 25,102 - Actor107: tc02 - Owner: Neutral - Location: 26,103 - Actor108: t08 - Owner: Neutral - Location: 29,105 - Actor109: t08 - Owner: Neutral - Location: 63,1 - Actor110: t01 - Owner: Neutral - Location: 102,6 - Actor111: t15 - Owner: Neutral - Location: 27,121 - Actor112: tc02 - Owner: Neutral - Location: 35,88 - Actor113: tc01 - Owner: Neutral - Location: 37,89 - Actor114: t11 - Owner: Neutral - Location: 34,88 - Actor115: t15 - Owner: Neutral - Location: 38,90 - Actor117: boxes04 - Owner: Neutral - Location: 79,80 - Actor118: barl - Owner: Neutral - Location: 78,81 - Actor119: brl3 - Owner: Neutral - Location: 82,78 - Actor120: brl3 - Owner: Neutral - Location: 50,48 - Actor121: barl - Owner: Neutral - Location: 43,46 - Actor122: boxes07 - Owner: Neutral - Location: 47,50 - Actor124: v13 - Owner: Neutral - Location: 79,64 - Actor125: tc03 - Owner: Neutral - Location: 90,38 - Actor126: t10 - Owner: Neutral - Location: 89,37 - Actor127: tc02 - Owner: Neutral - Location: 92,39 - Actor128: t15 - Owner: Neutral - Location: 93,40 - Actor129: t15 - Owner: Neutral - Location: 92,38 - Actor131: tc01 - Owner: Neutral - Location: 89,40 - Actor132: tc01 - Owner: Neutral - Location: 34,90 - Actor133: tc02 - Owner: Neutral - Location: 93,36 - Actor136: tc03 - Owner: Neutral - Location: 66,98 - Actor137: tc01 - Owner: Neutral - Location: 69,99 - Actor138: t08 - Owner: Neutral - Location: 71,100 - Actor139: t11 - Owner: Neutral - Location: 68,98 - Actor140: tc05 - Owner: Neutral - Location: 99,67 - Actor141: tc04 - Owner: Neutral - Location: 96,67 - Actor142: tc02 - Owner: Neutral - Location: 98,68 - Actor143: tc03 - Owner: Neutral - Location: 101,66 - Actor144: tc01 - Owner: Neutral - Location: 100,69 - Actor145: tc03 - Owner: Neutral - Location: 61,29 - Actor146: t08 - Owner: Neutral - Location: 61,31 - Actor147: tc02 - Owner: Neutral - Location: 59,28 - Actor148: t07 - Owner: Neutral - Location: 58,28 - Actor149: t12 - Owner: Neutral - Location: 48,63 - Actor150: tc04 - Owner: Neutral - Location: 87,82 - Actor153: tc04 - Owner: Neutral - Location: 44,38 - Actor154: t08 - Owner: Neutral - Location: 45,40 - Actor155: t11 - Owner: Neutral - Location: 38,44 - Actor156: t11 - Owner: Neutral - Location: 89,83 - Actor157: t08 - Owner: Neutral - Location: 83,89 - Actor158: tc04 - Owner: Neutral - Location: 28,58 - Actor159: tc05 - Owner: Neutral - Location: 31,58 - Actor160: tc01 - Owner: Neutral - Location: 30,59 - Actor161: tc03 - Owner: Neutral - Location: 27,61 - Actor162: t08 - Owner: Neutral - Location: 29,61 - Actor163: tc02 - Owner: Neutral - Location: 29,57 - Actor164: t12 - Owner: Neutral - Location: 29,59 - Actor165: tc05 - Owner: Neutral - Location: 100,23 - Actor166: tc01 - Owner: Neutral - Location: 103,24 - Actor167: t08 - Owner: Neutral - Location: 105,24 - Actor168: tc04 - Owner: Neutral - Location: 98,25 - Actor169: tc02 - Owner: Neutral - Location: 99,24 - Actor170: t11 - Owner: Neutral - Location: 98,23 - Actor171: t05 - Owner: Neutral - Location: 99,23 - Actor172: t08 - Owner: Neutral - Location: 99,22 - Actor173: tc03 - Owner: Neutral - Location: 100,26 - Actor174: t11 - Owner: Neutral - Location: 98,31 - Actor175: tc05 - Owner: Neutral - Location: 98,27 - Actor176: t11 - Owner: Neutral - Location: 97,28 - Actor177: t16 - Owner: Neutral - Location: 98,29 - Actor178: t08 - Owner: Neutral - Location: 101,28 - Actor179: mine - Owner: Neutral - Location: 117,117 - Actor181: mine - Owner: Neutral - Location: 12,12 - Actor183: tc05 - Owner: Neutral - Location: 38,43 - Actor184: tc05 - Owner: Neutral - Location: 82,87 - Actor185: mine - Owner: Neutral - Location: 31,65 - Actor186: mine - Owner: Neutral - Location: 99,63 - Actor187: mine - Owner: Neutral - Location: 63,96 - Actor188: mine - Owner: Neutral - Location: 65,33 - Actor189: mine - Owner: Neutral - Location: 94,118 - Actor190: mine - Owner: Neutral - Location: 35,11 - Actor193: mine - Owner: Neutral - Location: 101,101 - Actor180: mine - Owner: Neutral - Location: 27,27 - Actor182: mine - Owner: Neutral - Location: 33,27 - Actor191: mine - Owner: Neutral - Location: 27,33 - Actor192: mine - Owner: Neutral - Location: 95,101 - Actor194: mine - Owner: Neutral - Location: 101,95 - Actor195: mine - Owner: Neutral - Location: 10,30 - Actor196: mine - Owner: Neutral - Location: 119,99 - Actor197: mine - Owner: Neutral - Location: 43,116 - Actor198: mine - Owner: Neutral - Location: 87,14 - Actor199: mine - Owner: Neutral - Location: 12,89 - Actor200: mine - Owner: Neutral - Location: 118,39 - Actor201: oilb - Owner: Neutral - Location: 84,43 - Actor202: oilb - Owner: Neutral - Location: 43,84 - Actor203: fenc - Owner: Neutral - Location: 45,85 - Actor204: fenc - Owner: Neutral - Location: 45,86 - Actor205: fenc - Owner: Neutral - Location: 44,86 - Actor206: fenc - Owner: Neutral - Location: 43,83 - Actor207: fenc - Owner: Neutral - Location: 42,83 - Actor208: fenc - Owner: Neutral - Location: 42,84 - Actor209: fenc - Owner: Neutral - Location: 85,45 - Actor210: fenc - Owner: Neutral - Location: 86,45 - Actor211: fenc - Owner: Neutral - Location: 86,44 - Actor212: fenc - Owner: Neutral - Location: 83,43 - Actor213: fenc - Owner: Neutral - Location: 83,42 - Actor214: fenc - Owner: Neutral - Location: 84,42 - Actor215: fenc - Owner: Neutral - Location: 87,38 - Actor216: fenc - Owner: Neutral - Location: 87,39 - Actor217: fenc - Owner: Neutral - Location: 86,39 - Actor218: fenc - Owner: Neutral - Location: 91,42 - Actor219: fenc - Owner: Neutral - Location: 90,42 - Actor220: fenc - Owner: Neutral - Location: 90,43 - Actor221: fenc - Owner: Neutral - Location: 41,88 - Actor222: fenc - Owner: Neutral - Location: 41,89 - Actor223: fenc - Owner: Neutral - Location: 42,89 - Actor224: tc02 - Owner: Neutral - Location: 38,86 - Actor225: fenc - Owner: Neutral - Location: 38,86 - Actor226: fenc - Owner: Neutral - Location: 37,86 - Actor227: fenc - Owner: Neutral - Location: 37,85 - Actor228: brl3 - Owner: Neutral - Location: 41,84 - Actor229: brl3 - Owner: Neutral - Location: 42,88 - Actor230: barl - Owner: Neutral - Location: 44,87 - Actor231: barl - Owner: Neutral - Location: 38,85 - Actor232: brl3 - Owner: Neutral - Location: 87,44 - Actor233: brl3 - Owner: Neutral - Location: 87,40 - Actor234: barl - Owner: Neutral - Location: 89,42 - Actor235: barl - Owner: Neutral - Location: 84,41 - Actor236: brl3 - Owner: Neutral - Location: 84,45 - Actor237: barl - Owner: Neutral - Location: 45,84 - Actor238: brl3 - Owner: Neutral - Location: 83,41 - Actor239: brl3 - Owner: Neutral - Location: 91,43 - Actor240: brl3 - Owner: Neutral - Location: 45,88 - Actor241: brl3 - Owner: Neutral - Location: 37,84 - Actor242: tc04 - Owner: Neutral - Location: 31,30 - Actor243: tc05 - Owner: Neutral - Location: 95,95 - Actor244: t02 - Owner: Neutral - Location: 95,96 - Actor245: t08 - Owner: Neutral - Location: 33,32 - Actor247: v03 - Owner: Neutral - Location: 52,80 - Actor246: v10 - Owner: Neutral - Location: 50,80 - Actor248: v06 - Owner: Neutral - Location: 57,83 - Actor249: v17 - Owner: Neutral - Location: 57,84 - Actor250: v17 - Owner: Neutral - Location: 58,84 - Actor251: v17 - Owner: Neutral - Location: 59,84 - Actor252: wood - Owner: Neutral - Location: 57,85 - Actor253: wood - Owner: Neutral - Location: 58,85 - Actor254: wood - Owner: Neutral - Location: 59,85 - Actor255: wood - Owner: Neutral - Location: 60,85 - Actor256: wood - Owner: Neutral - Location: 60,84 - Actor257: wood - Owner: Neutral - Location: 60,83 - Actor258: wood - Owner: Neutral - Location: 59,83 - Actor259: wood - Owner: Neutral - Location: 59,82 - Actor260: wood - Owner: Neutral - Location: 58,82 - Actor261: wood - Owner: Neutral - Location: 57,82 - Actor262: wood - Owner: Neutral - Location: 56,85 - Actor263: wood - Owner: Neutral - Location: 56,84 - Actor265: v04 - Owner: Neutral - Location: 60,81 - Actor266: v11 - Owner: Neutral - Location: 56,83 - Actor264: v07 - Owner: Neutral - Location: 57,87 - Actor267: v01 - Owner: Neutral - Location: 57,79 - Actor268: t11 - Owner: Neutral - Location: 59,79 - Actor269: v08 - Owner: Neutral - Location: 55,79 - Actor270: tc01 - Owner: Neutral - Location: 55,77 - Actor271: tc03 - Owner: Neutral - Location: 61,83 - Actor273: t08 - Owner: Neutral - Location: 52,81 - Actor274: t10 - Owner: Neutral - Location: 48,78 - Actor275: tc01 - Owner: Neutral - Location: 49,85 - Actor272: fenc - Owner: Neutral - Location: 57,76 - Actor276: fenc - Owner: Neutral - Location: 58,76 - Actor277: fenc - Owner: Neutral - Location: 61,76 - Actor278: fenc - Owner: Neutral - Location: 62,76 - Actor282: fenc - Owner: Neutral - Location: 57,77 - Actor283: v19 - Owner: Neutral - Location: 58,77 - Actor284: v19 - Owner: Neutral - Location: 61,77 - Actor285: fenc - Owner: Neutral - Location: 62,77 - Actor286: fenc - Owner: Neutral - Location: 57,78 - Actor287: fenc - Owner: Neutral - Location: 58,78 - Actor288: fenc - Owner: Neutral - Location: 59,78 - Actor289: fenc - Owner: Neutral - Location: 59,78 - Actor290: tc02 - Owner: Neutral - Location: 59,78 - Actor291: fenc - Owner: Neutral - Location: 60,78 - Actor292: fenc - Owner: Neutral - Location: 61,78 - Actor293: fenc - Owner: Neutral - Location: 62,78 - Actor279: brl3 - Owner: Neutral - Location: 60,77 - Actor280: barl - Owner: Neutral - Location: 59,77 - Actor281: fenc - Owner: Neutral - Location: 66,50 - Actor294: fenc - Owner: Neutral - Location: 67,50 - Actor295: fenc - Owner: Neutral - Location: 70,50 - Actor296: fenc - Owner: Neutral - Location: 71,50 - Actor297: fenc - Owner: Neutral - Location: 66,51 - Actor298: v19 - Owner: Neutral - Location: 67,51 - Actor301: v19 - Owner: Neutral - Location: 70,51 - Actor302: fenc - Owner: Neutral - Location: 71,51 - Actor303: fenc - Owner: Neutral - Location: 66,52 - Actor304: fenc - Owner: Neutral - Location: 67,52 - Actor309: fenc - Owner: Neutral - Location: 70,52 - Actor310: fenc - Owner: Neutral - Location: 71,52 - Actor305: fenc - Owner: Neutral - Location: 68,50 - Actor306: fenc - Owner: Neutral - Location: 69,50 - Actor299: brl3 - Owner: Neutral - Location: 68,51 - Actor300: barl - Owner: Neutral - Location: 69,51 - Actor307: tc01 - Owner: Neutral - Location: 72,49 - Actor308: tc02 - Owner: Neutral - Location: 68,48 - Actor311: t11 - Owner: Neutral - Location: 68,47 - Actor313: v08 - Owner: Neutral - Location: 73,48 - Actor316: v10 - Owner: Neutral - Location: 78,48 - Actor314: v03 - Owner: Neutral - Location: 75,47 - Actor315: t08 - Owner: Neutral - Location: 76,46 - Actor317: tc03 - Owner: Neutral - Location: 65,45 - Actor318: v07 - Owner: Neutral - Location: 70,41 - Actor324: v01 - Owner: Neutral - Location: 70,47 - Actor319: wood - Owner: Neutral - Location: 68,43 - Actor320: wood - Owner: Neutral - Location: 69,43 - Actor321: wood - Owner: Neutral - Location: 70,43 - Actor322: wood - Owner: Neutral - Location: 71,43 - Actor323: wood - Owner: Neutral - Location: 67,44 - Actor325: v17 - Owner: Neutral - Location: 68,44 - Actor326: v17 - Owner: Neutral - Location: 69,44 - Actor327: v18 - Owner: Neutral - Location: 70,44 - Actor328: wood - Owner: Neutral - Location: 71,44 - Actor329: wood - Owner: Neutral - Location: 67,45 - Actor330: wood - Owner: Neutral - Location: 68,45 - Actor331: v06 - Owner: Neutral - Location: 69,45 - Actor332: v11 - Owner: Neutral - Location: 71,45 - Actor333: wood - Owner: Neutral - Location: 68,46 - Actor337: wood - Owner: Neutral - Location: 69,46 - Actor338: wood - Owner: Neutral - Location: 70,46 - Actor339: wood - Owner: Neutral - Location: 67,43 - Actor334: wood - Owner: Neutral - Location: 71,46 - Actor335: tc01 - Owner: Neutral - Location: 78,41 - Actor336: t03 - Owner: Neutral - Location: 79,48 - Actor341: oilb - Owner: Neutral - Location: 63,123 - Actor342: fenc - Owner: Neutral - Location: 63,122 - Actor343: fenc - Owner: Neutral - Location: 64,122 - Actor344: fenc - Owner: Neutral - Location: 65,122 - Actor346: fenc - Owner: Neutral - Location: 62,122 - Actor347: fenc - Owner: Neutral - Location: 62,123 - Actor348: fenc - Owner: Neutral - Location: 66,123 - Actor349: fenc - Owner: Neutral - Location: 67,123 - Actor350: fenc - Owner: Neutral - Location: 61,123 - Actor351: fenc - Owner: Neutral - Location: 60,123 - Actor352: fenc - Owner: Neutral - Location: 68,123 - Actor353: fenc - Owner: Neutral - Location: 59,123 - Actor354: fenc - Owner: Neutral - Location: 59,124 - Actor355: fenc - Owner: Neutral - Location: 66,122 - Actor345: fenc - Owner: Neutral - Location: 69,123 - Actor356: fenc - Owner: Neutral - Location: 69,124 - Actor357: boxes05 - Owner: Neutral - Location: 65,123 - Actor358: v11 - Owner: Neutral - Location: 65,124 - Actor359: tc05 - Owner: Neutral - Location: 73,125 - Actor360: tc04 - Owner: Neutral - Location: 53,125 - Actor361: tc03 - Owner: Neutral - Location: 56,125 - Actor362: t15 - Owner: Neutral - Location: 55,124 - Actor364: t08 - Owner: Neutral - Location: 61,124 - Actor365: brl3 - Owner: Neutral - Location: 66,124 - Actor366: barl - Owner: Neutral - Location: 62,124 - Actor367: brl3 - Owner: Neutral - Location: 61,126 - Actor368: barl - Owner: Neutral - Location: 67,126 - Actor369: t11 - Owner: Neutral - Location: 68,126 - Actor363: t07 - Owner: Neutral - Location: 67,123 - Actor370: tc02 - Owner: Neutral - Location: 47,127 - Actor371: t02 - Owner: Neutral - Location: 58,127 - Actor372: t12 - Owner: Neutral - Location: 70,127 - Actor374: t14 - Owner: Neutral - Location: 78,127 - Actor375: tc03 - Owner: Neutral - Location: 60,128 - Actor376: t08 - Owner: Neutral - Location: 63,127 - Actor377: t12 - Owner: Neutral - Location: 65,127 - Actor378: oilb - Owner: Neutral - Location: 64,5 - Actor379: fenc - Owner: Neutral - Location: 65,7 - Actor380: fenc - Owner: Neutral - Location: 64,7 - Actor381: fenc - Owner: Neutral - Location: 63,7 - Actor382: fenc - Owner: Neutral - Location: 62,7 - Actor383: fenc - Owner: Neutral - Location: 66,7 - Actor384: fenc - Owner: Neutral - Location: 66,6 - Actor385: fenc - Owner: Neutral - Location: 67,6 - Actor386: fenc - Owner: Neutral - Location: 68,6 - Actor387: fenc - Owner: Neutral - Location: 69,6 - Actor388: fenc - Owner: Neutral - Location: 62,6 - Actor389: fenc - Owner: Neutral - Location: 61,6 - Actor390: fenc - Owner: Neutral - Location: 60,6 - Actor391: fenc - Owner: Neutral - Location: 59,6 - Actor392: fenc - Owner: Neutral - Location: 69,5 - Actor393: fenc - Owner: Neutral - Location: 59,5 - Actor394: boxes08 - Owner: Neutral - Location: 63,6 - Actor395: v09 - Owner: Neutral - Location: 63,5 - Actor398: t01 - Owner: Neutral - Location: 61,4 - Actor399: t08 - Owner: Neutral - Location: 67,5 - Actor396: barl - Owner: Neutral - Location: 66,5 - Actor401: brl3 - Owner: Neutral - Location: 67,3 - Actor397: brl3 - Owner: Neutral - Location: 62,5 - Actor400: barl - Owner: Neutral - Location: 60,3 - Actor402: tc02 - Owner: Neutral - Location: 53,3 - Actor403: tc01 - Owner: Neutral - Location: 55,3 - Actor404: t11 - Owner: Neutral - Location: 55,4 - Actor405: tc04 - Owner: Neutral - Location: 73,2 - Actor406: t11 - Owner: Neutral - Location: 60,2 - Actor407: t17 - Owner: Neutral - Location: 59,1 - Actor408: t14 - Owner: Neutral - Location: 49,2 - Actor409: tc02 - Owner: Neutral - Location: 78,1 - Actor410: t01 - Owner: Neutral - Location: 68,1 - Actor411: t12 - Owner: Neutral - Location: 70,123 - Actor412: t12 - Owner: Neutral - Location: 58,4 - Actor414: v08 - Owner: Neutral - Location: 56,127 - Actor413: tc03 - Owner: Neutral - Location: 71,4 - Actor415: snowhut - Owner: Neutral - Location: 72,2 - Actor416: t13 - Owner: Neutral - Location: 73,4 - Actor417: tc04 - Owner: Neutral - Location: 120,53 - Actor418: tc03 - Owner: Neutral - Location: 121,73 - Actor419: t16 - Owner: Neutral - Location: 120,72 - Actor420: t15 - Owner: Neutral - Location: 122,73 - Actor421: tc05 - Owner: Neutral - Location: 6,72 - Actor422: t07 - Owner: Neutral - Location: 6,73 - Actor424: t03 - Owner: Neutral - Location: 8,54 - Actor425: t08 - Owner: Neutral - Location: 7,55 - Actor426: tc05 - Owner: Neutral - Location: 43,79 - Actor427: t08 - Owner: Neutral - Location: 43,80 - Actor428: tc03 - Owner: Neutral - Location: 84,47 - Actor429: t01 - Owner: Neutral - Location: 84,46 - Actor430: t08 - Owner: Neutral - Location: 86,48 - Actor431: t11 - Owner: Neutral - Location: 83,46 - Actor432: t07 - Owner: Neutral - Location: 83,47 - Actor439: oilb - Owner: Neutral - Location: 8,125 - Actor444: fenc - Owner: Neutral - Location: 119,5 - Actor445: fenc - Owner: Neutral - Location: 118,5 - Actor447: fenc - Owner: Neutral - Location: 117,4 - Actor448: fenc - Owner: Neutral - Location: 116,4 - Actor449: fenc - Owner: Neutral - Location: 115,4 - Actor441: fenc - Owner: Neutral - Location: 127,9 - Actor450: fenc - Owner: Neutral - Location: 127,8 - Actor451: fenc - Owner: Neutral - Location: 127,7 - Actor452: fenc - Owner: Neutral - Location: 126,7 - Actor453: fenc - Owner: Neutral - Location: 126,6 - Actor462: fenc - Owner: Neutral - Location: 11,124 - Actor463: fenc - Owner: Neutral - Location: 12,124 - Actor464: fenc - Owner: Neutral - Location: 12,125 - Actor465: fenc - Owner: Neutral - Location: 13,125 - Actor466: fenc - Owner: Neutral - Location: 14,125 - Actor459: fenc - Owner: Neutral - Location: 8,124 - Actor460: fenc - Owner: Neutral - Location: 8,124 - Actor461: fenc - Owner: Neutral - Location: 7,124 - Actor470: fenc - Owner: Neutral - Location: 8,124 - Actor471: fenc - Owner: Neutral - Location: 9,124 - Actor467: fenc - Owner: Neutral - Location: 11,123 - Actor468: fenc - Owner: Neutral - Location: 10,123 - Actor469: fenc - Owner: Neutral - Location: 9,123 - Actor473: fenc - Owner: Neutral - Location: 3,123 - Actor474: fenc - Owner: Neutral - Location: 3,122 - Actor475: fenc - Owner: Neutral - Location: 3,121 - Actor476: fenc - Owner: Neutral - Location: 3,121 - Actor477: fenc - Owner: Neutral - Location: 3,120 - Actor478: fenc - Owner: Neutral - Location: 3,119 - Actor479: fenc - Owner: Neutral - Location: 4,124 - Actor480: fenc - Owner: Neutral - Location: 5,124 - Actor472: fenc - Owner: Neutral - Location: 4,123 - Actor481: snowhut - Owner: Neutral - Location: 10,123 - Actor484: fenc - Owner: Neutral - Location: 15,126 - Actor483: fenc - Owner: Neutral - Location: 14,126 - Actor485: fenc - Owner: Neutral - Location: 15,127 - Actor486: fenc - Owner: Neutral - Location: 15,128 - Actor487: fenc - Owner: Neutral - Location: 15,129 - Actor488: fenc - Owner: Neutral - Location: 2,119 - Actor489: fenc - Owner: Neutral - Location: 2,118 - Actor490: fenc - Owner: Neutral - Location: 1,118 - Actor491: fenc - Owner: Neutral - Location: 1,117 - Actor492: fenc - Owner: Neutral - Location: 0,117 - Actor493: fenc - Owner: Neutral - Location: 0,116 - Actor494: hosp - Owner: Neutral - Location: 2,124 - Actor495: v02 - Owner: Neutral - Location: 4,127 - Actor496: v07 - Owner: Neutral - Location: 1,122 - Actor497: brl3 - Owner: Neutral - Location: 11,127 - Actor498: barl - Owner: Neutral - Location: 10,127 - Actor499: v03 - Owner: Neutral - Location: 5,126 - Actor500: tc05 - Owner: Neutral - Location: 0,119 - Actor502: fenc - Owner: Neutral - Location: 128,10 - Actor503: fenc - Owner: Neutral - Location: 128,11 - Actor504: fenc - Owner: Neutral - Location: 128,11 - Actor505: fenc - Owner: Neutral - Location: 128,12 - Actor506: fenc - Owner: Neutral - Location: 129,12 - Actor507: fenc - Owner: Neutral - Location: 129,13 - Actor508: fenc - Owner: Neutral - Location: 115,3 - Actor509: fenc - Owner: Neutral - Location: 114,3 - Actor510: fenc - Owner: Neutral - Location: 114,2 - Actor511: fenc - Owner: Neutral - Location: 114,1 - Actor512: fenc - Owner: Neutral - Location: 114,0 - Actor515: fenc - Owner: Neutral - Location: 117,5 - Actor522: v08 - Owner: Neutral - Location: 118,4 - Actor516: brl3 - Owner: Neutral - Location: 118,2 - Actor517: barl - Owner: Neutral - Location: 119,2 - Actor526: fenc - Owner: Neutral - Location: 125,6 - Actor527: fenc - Owner: Neutral - Location: 124,6 - Actor528: fenc - Owner: Neutral - Location: 127,10 - Actor514: fenc - Owner: Neutral - Location: 119,6 - Actor501: oilb - Owner: Neutral - Location: 120,3 - Actor520: tc02 - Owner: Neutral - Location: 128,8 - Actor521: tc01 - Owner: Neutral - Location: 128,7 - Actor523: v05 - Owner: Neutral - Location: 128,7 - Actor524: hosp - Owner: Neutral - Location: 126,4 - Actor525: v06 - Owner: Neutral - Location: 124,1 - Actor518: v07 - Owner: Neutral - Location: 123,2 - Actor519: ctflag - Owner: Neutral - Location: 118,3 - Actor529: ctflag - Owner: Neutral - Location: 11,125 - Actor530: t11 - Owner: Neutral - Location: 66,83 - Actor531: t11 - Owner: Neutral - Location: 61,43 - Actor532: tc03 - Owner: Neutral - Location: 66,109 - Actor533: tc03 - Owner: Neutral - Location: 60,19 - Actor534: t10 - Owner: Neutral - Location: 62,18 - Actor535: t17 - Owner: Neutral - Location: 65,109 - Actor536: t15 - Owner: Neutral - Location: 62,101 - Actor537: t12 - Owner: Neutral - Location: 66,26 - Actor538: v03 - Owner: Neutral - Location: 67,26 - Actor539: v02 - Owner: Neutral - Location: 59,103 - Actor540: t02 - Owner: Neutral - Location: 58,102 - Actor542: tc05 - Owner: Neutral - Location: 80,27 - Actor543: t15 - Owner: Neutral - Location: 79,28 - Actor544: tc04 - Owner: Neutral - Location: 48,98 - Actor545: t11 - Owner: Neutral - Location: 50,99 - Actor546: t08 - Owner: Neutral - Location: 49,100 - Actor547: tc02 - Owner: Neutral - Location: 54,102 - Actor548: tc01 - Owner: Neutral - Location: 74,25 - Actor549: tc03 - Owner: Neutral - Location: 92,92 - Actor550: tc03 - Owner: Neutral - Location: 35,34 - Actor551: tc03 - Owner: Neutral - Location: 1,126 - Actor552: tc03 - Owner: Neutral - Location: 127,2 - Actor553: tc04 - Owner: Neutral - Location: 97,9 - Actor554: tc05 - Owner: Neutral - Location: 94,9 - Actor555: tc05 - Owner: Neutral - Location: 31,117 - Actor556: tc04 - Owner: Neutral - Location: 34,117 - Actor557: t08 - Owner: Neutral - Location: 64,85 - Actor558: t08 - Owner: Neutral - Location: 64,43 - Actor559: tc02 - Owner: Neutral - Location: 66,101 - Actor560: railmine - Owner: Neutral - Location: 68,102 - Actor561: t10 - Owner: Neutral - Location: 102,82 - Actor562: t08 - Owner: Neutral - Location: 103,83 - Actor563: t16 - Owner: Neutral - Location: 104,82 - Actor565: tc03 - Owner: Neutral - Location: 52,50 - Actor566: tc04 - Owner: Neutral - Location: 6,53 - Actor567: v13 - Owner: Neutral - Location: 7,53 - Actor568: v12 - Owner: Neutral - Location: 122,75 - Actor569: t11 - Owner: Neutral - Location: 122,52 - Actor570: t11 - Owner: Neutral - Location: 6,74 - Actor571: v12 - Owner: Neutral - Location: 47,83 - Actor572: v13 - Owner: Neutral - Location: 48,84 - Actor573: v13 - Owner: Neutral - Location: 81,45 - Actor574: v12 - Owner: Neutral - Location: 80,44 - Actor575: t08 - Owner: Neutral - Location: 81,44 - Actor576: t08 - Owner: Neutral - Location: 47,84 - Actor577: t15 - Owner: Neutral - Location: 55,72 - Actor578: t08 - Owner: Neutral - Location: 54,72 - Actor579: t08 - Owner: Neutral - Location: 74,56 - Actor580: t10 - Owner: Neutral - Location: 71,54 - Actor581: t07 - Owner: Neutral - Location: 77,63 - Actor582: tc02 - Owner: Neutral - Location: 81,103 - Actor583: t11 - Owner: Neutral - Location: 82,104 - Actor584: tc01 - Owner: Neutral - Location: 46,24 - Actor585: t11 - Owner: Neutral - Location: 45,23 - Actor586: tc02 - Owner: Neutral - Location: 26,44 - Actor587: t11 - Owner: Neutral - Location: 25,45 - Actor588: t14 - Owner: Neutral - Location: 21,113 - Actor589: t01 - Owner: Neutral - Location: 106,14 - Actor590: t12 - Owner: Neutral - Location: 63,110 - Actor591: t12 - Owner: Neutral - Location: 66,18 - Actor592: v05 - Owner: Neutral - Location: 83,61 - Actor593: v08 - Owner: Neutral - Location: 43,65 - Actor594: v12 - Owner: Neutral - Location: 58,104 - Actor595: snowhut - Owner: Neutral - Location: 61,101 - Actor596: v13 - Owner: Neutral - Location: 70,26 - Actor597: t06 - Owner: Neutral - Location: 71,25 - Actor598: v11 - Owner: Neutral - Location: 71,25 - Actor599: v04 - Owner: Neutral - Location: 29,55 - Actor600: v07 - Owner: Neutral - Location: 99,72 - Actor601: tc01 - Owner: Neutral - Location: 51,93 - Actor602: tc02 - Owner: Neutral - Location: 76,33 - Actor603: t01 - Owner: Neutral - Location: 65,82 - Actor604: t01 - Owner: Neutral - Location: 63,44 - Actor605: t08 - Owner: Neutral - Location: 68,103 - Actor606: t08 - Owner: Neutral - Location: 61,26 - Actor607: t03 - Owner: Neutral - Location: 60,26 - Actor608: v06 - Owner: Neutral - Location: 105,28 - Actor609: wood - Owner: Neutral - Location: 106,27 - Actor610: wood - Owner: Neutral - Location: 105,27 - Actor611: wood - Owner: Neutral - Location: 104,27 - Actor612: wood - Owner: Neutral - Location: 104,28 - Actor613: wood - Owner: Neutral - Location: 104,29 - Actor614: wood - Owner: Neutral - Location: 103,29 - Actor615: wood - Owner: Neutral - Location: 103,30 - Actor616: v03 - Owner: Neutral - Location: 104,29 - Actor619: wood - Owner: Neutral - Location: 107,27 - Actor621: wood - Owner: Neutral - Location: 108,28 - Actor622: wood - Owner: Neutral - Location: 108,29 - Actor617: wood - Owner: Neutral - Location: 103,31 - Actor618: v17 - Owner: Neutral - Location: 106,29 - Actor623: v17 - Owner: Neutral - Location: 107,29 - Actor624: v13 - Owner: Neutral - Location: 104,31 - Actor625: wood - Owner: Neutral - Location: 103,32 - Actor626: wood - Owner: Neutral - Location: 104,32 - Actor620: v11 - Owner: Neutral - Location: 107,28 - Actor627: wood - Owner: Neutral - Location: 108,27 - Actor628: v02 - Owner: Neutral - Location: 97,33 - Actor629: v05 - Owner: Neutral - Location: 30,94 - Actor630: wood - Owner: Neutral - Location: 20,101 - Actor631: wood - Owner: Neutral - Location: 20,100 - Actor632: wood - Owner: Neutral - Location: 20,99 - Actor633: wood - Owner: Neutral - Location: 21,101 - Actor634: wood - Owner: Neutral - Location: 22,101 - Actor635: wood - Owner: Neutral - Location: 23,101 - Actor636: wood - Owner: Neutral - Location: 24,101 - Actor637: wood - Owner: Neutral - Location: 24,100 - Actor639: wood - Owner: Neutral - Location: 24,99 - Actor644: v08 - Owner: Neutral - Location: 21,100 - Actor645: v06 - Owner: Neutral - Location: 22,100 - Actor643: v17 - Owner: Neutral - Location: 21,99 - Actor646: v17 - Owner: Neutral - Location: 22,99 - Actor638: wood - Owner: Neutral - Location: 25,99 - Actor640: wood - Owner: Neutral - Location: 25,98 - Actor641: wood - Owner: Neutral - Location: 25,97 - Actor647: v12 - Owner: Neutral - Location: 24,97 - Actor648: wood - Owner: Neutral - Location: 25,96 - Actor649: wood - Owner: Neutral - Location: 24,96 - Actor642: v02 - Owner: Neutral - Location: 23,98 - Actor650: tc03 - Owner: Neutral - Location: 26,95 - Actor651: tc03 - Owner: Neutral - Location: 101,32 - Actor652: t01 - Owner: Neutral - Location: 101,30 - Actor653: t08 - Owner: Neutral - Location: 102,31 - Actor654: t08 - Owner: Neutral - Location: 27,97 - Actor655: t14 - Owner: Neutral - Location: 25,96 - Actor656: t08 - Owner: Neutral - Location: 29,93 - Actor657: t08 - Owner: Neutral - Location: 98,35 - Actor658: tc05 - Owner: Neutral - Location: 100,48 - Actor659: tc03 - Owner: Neutral - Location: 98,48 - Actor661: t15 - Owner: Neutral - Location: 102,49 - Actor662: tc04 - Owner: Neutral - Location: 101,46 - Actor663: t07 - Owner: Neutral - Location: 100,45 - Actor660: t08 - Owner: Neutral - Location: 97,50 - Actor664: t07 - Owner: Neutral - Location: 98,49 - Actor665: t11 - Owner: Neutral - Location: 102,45 - Actor666: t12 - Owner: Neutral - Location: 101,45 - Actor667: t11 - Owner: Neutral - Location: 99,51 - Actor668: t11 - Owner: Neutral - Location: 31,77 - Actor669: t08 - Owner: Neutral - Location: 32,78 - Actor670: tc05 - Owner: Neutral - Location: 27,77 - Actor671: tc02 - Owner: Neutral - Location: 30,78 - Actor672: tc04 - Owner: Neutral - Location: 27,79 - Actor674: t12 - Owner: Neutral - Location: 29,80 - Actor676: t14 - Owner: Neutral - Location: 27,80 - Actor675: tc02 - Owner: Neutral - Location: 32,80 - Actor677: t15 - Owner: Neutral - Location: 97,46 - Actor678: t08 - Owner: Neutral - Location: 26,76 - Actor679: t08 - Owner: Neutral - Location: 104,52 - Actor680: tc01 - Owner: Neutral - Location: 72,108 - Actor681: tc02 - Owner: Neutral - Location: 55,19 - Actor682: tc03 - Owner: Neutral - Location: 44,108 - Actor683: t10 - Owner: Neutral - Location: 45,108 - Actor684: snowhut - Owner: Neutral - Location: 88,73 - Actor685: t10 - Owner: Neutral - Location: 89,73 - Actor686: v09 - Owner: Neutral - Location: 40,54 - Actor687: t14 - Owner: Neutral - Location: 38,53 - Actor688: v04 - Owner: Neutral - Location: 77,96 - Actor689: t01 - Owner: Neutral - Location: 79,95 - Actor691: t07 - Owner: Neutral - Location: 49,31 - Actor690: v05 - Owner: Neutral - Location: 50,31 - Actor692: v19 - Owner: Neutral - Location: 57,33 - Actor693: v19 - Owner: Neutral - Location: 57,35 - Actor694: fenc - Owner: Neutral - Location: 56,32 - Actor695: fenc - Owner: Neutral - Location: 57,32 - Actor696: fenc - Owner: Neutral - Location: 58,32 - Actor697: fenc - Owner: Neutral - Location: 58,33 - Actor698: fenc - Owner: Neutral - Location: 58,34 - Actor699: fenc - Owner: Neutral - Location: 58,35 - Actor700: fenc - Owner: Neutral - Location: 58,36 - Actor701: fenc - Owner: Neutral - Location: 57,36 - Actor702: fenc - Owner: Neutral - Location: 56,36 - Actor705: fenc - Owner: Neutral - Location: 56,37 - Actor706: fenc - Owner: Neutral - Location: 56,31 - Actor703: brl3 - Owner: Neutral - Location: 57,34 - Actor704: barl - Owner: Neutral - Location: 56,35 - Actor707: barl - Owner: Neutral - Location: 56,33 - Actor708: fenc - Owner: Neutral - Location: 70,93 - Actor719: fenc - Owner: Neutral - Location: 70,97 - Actor715: fenc - Owner: Neutral - Location: 72,98 - Actor716: fenc - Owner: Neutral - Location: 70,96 - Actor718: fenc - Owner: Neutral - Location: 70,95 - Actor722: fenc - Owner: Neutral - Location: 70,94 - Actor709: fenc - Owner: Neutral - Location: 72,97 - Actor710: fenc - Owner: Neutral - Location: 71,97 - Actor711: fenc - Owner: Neutral - Location: 71,93 - Actor712: fenc - Owner: Neutral - Location: 72,93 - Actor713: fenc - Owner: Neutral - Location: 72,92 - Actor714: v19 - Owner: Neutral - Location: 71,96 - Actor717: v19 - Owner: Neutral - Location: 71,94 - Actor720: brl3 - Owner: Neutral - Location: 71,95 - Actor721: barl - Owner: Neutral - Location: 72,94 - Actor723: barl - Owner: Neutral - Location: 72,96 - Actor724: tc04 - Owner: Neutral - Location: 69,90 - Actor725: tc05 - Owner: Neutral - Location: 57,36 - Actor726: t08 - Owner: Neutral - Location: 57,38 - Actor727: t15 - Owner: Neutral - Location: 70,91 - Actor728: t11 - Owner: Neutral - Location: 38,105 - Actor729: t14 - Owner: Neutral - Location: 88,20 - Actor730: tc04 - Owner: Neutral - Location: 11,100 - Actor731: tc05 - Owner: Neutral - Location: 116,26 - Actor732: t08 - Owner: Neutral - Location: 116,28 - Actor733: t17 - Owner: Neutral - Location: 13,101 - Actor734: t11 - Owner: Neutral - Location: 19,108 - Actor735: t11 - Owner: Neutral - Location: 109,19 - Actor736: t01.husk - Owner: Neutral - Location: 90,57 - Actor737: t17.husk - Owner: Neutral - Location: 38,70 - Actor738: tc03 - Owner: Neutral - Location: 75,77 - Actor739: tc02 - Owner: Neutral - Location: 79,72 - Actor740: t08 - Owner: Neutral - Location: 75,80 - Actor741: t08 - Owner: Neutral - Location: 52,48 - Actor742: v11 - Owner: Neutral - Location: 41,99 - Actor743: snowhut - Owner: Neutral - Location: 89,29 - Actor744: v06 - Owner: Neutral - Location: 53,48 - Actor745: wood - Owner: Neutral - Location: 52,49 - Actor746: wood - Owner: Neutral - Location: 53,49 - Actor747: wood - Owner: Neutral - Location: 54,49 - Actor748: wood - Owner: Neutral - Location: 55,49 - Actor749: v06 - Owner: Neutral - Location: 73,80 - Actor750: wood - Owner: Neutral - Location: 76,79 - Actor751: wood - Owner: Neutral - Location: 75,79 - Actor752: wood - Owner: Neutral - Location: 74,79 - Actor753: wood - Owner: Neutral - Location: 73,79 - Actor754: wood - Owner: Neutral - Location: 72,79 - Actor755: t08 - Owner: Neutral - Location: 87,63 - Actor756: t03 - Owner: Neutral - Location: 41,63 - Actor757: t08 - Owner: Neutral - Location: 47,30 - Actor758: t08 - Owner: Neutral - Location: 81,98 - Actor759: railmine - Owner: Neutral - Location: 78,106 - Actor760: t08 - Owner: Neutral - Location: 79,107 - Actor761: t08 - Owner: Neutral - Location: 49,22 - Actor762: v08 - Owner: Neutral - Location: 49,23 - Actor763: t15 - Owner: Neutral - Location: 24,9 - Actor764: t15 - Owner: Neutral - Location: 11,22 - Actor765: t01 - Owner: Neutral - Location: 18,17 - Actor766: tc05 - Owner: Neutral - Location: 45,11 - Actor767: v13 - Owner: Neutral - Location: 13,44 - Actor768: v12 - Owner: Neutral - Location: 12,44 - Actor769: t14 - Owner: Neutral - Location: 11,42 - Actor770: v02 - Owner: Neutral - Location: 10,43 - Actor771: v11 - Owner: Neutral - Location: 13,23 - Actor772: v11 - Owner: Neutral - Location: 13,23 - Actor774: v12 - Owner: Neutral - Location: 117,84 - Actor775: v13 - Owner: Neutral - Location: 116,84 - Actor773: v02 - Owner: Neutral - Location: 118,84 - Actor776: t08 - Owner: Neutral - Location: 117,85 - Actor777: t08 - Owner: Neutral - Location: 104,118 - Actor778: t07 - Owner: Neutral - Location: 110,109 - Actor779: t14 - Owner: Neutral - Location: 115,104 - Actor780: v10 - Owner: Neutral - Location: 115,105 - Actor781: tc04 - Owner: Neutral - Location: 82,116 - Actor782: t13 - Owner: Neutral - Location: 20,95 - Actor783: v03 - Owner: Neutral - Location: 16,79 - Actor784: t11 - Owner: Neutral - Location: 19,80 - Actor785: t11 - Owner: Neutral - Location: 111,46 - Actor786: v02 - Owner: Neutral - Location: 113,47 - Actor787: t14 - Owner: Neutral - Location: 110,31 - Actor788: tc02 - Owner: Neutral - Location: 102,21 - Actor789: tc01 - Owner: Neutral - Location: 25,105 - Actor791: ice01 - Owner: Neutral - Location: 16,52 - Actor792: ice04 - Owner: Neutral - Location: 18,53 - Actor790: ice01 - Owner: Neutral - Location: 113,75 - Actor794: ice04 - Owner: Neutral - Location: 114,77 - Actor795: ice04 - Owner: Neutral - Location: 16,51 - Actor796: ice05 - Owner: Neutral - Location: 18,51 - Actor797: ice05 - Owner: Neutral - Location: 113,77 - Actor793: ice04 - Owner: Neutral - Location: 112,75 - Actor798: ice02 - Owner: Neutral - Location: 57,114 - Actor799: ice02 - Owner: Neutral - Location: 71,14 - Actor800: ice04 - Owner: Neutral - Location: 10,71 - Actor801: ice05 - Owner: Neutral - Location: 119,57 - Actor802: ice03 - Owner: Neutral - Location: 123,126 - Actor803: ice02 - Owner: Neutral - Location: 125,124 - Actor804: ice05 - Owner: Neutral - Location: 5,3 - Actor805: ice04 - Owner: Neutral - Location: 6,3 - Actor806: ice02 - Owner: Neutral - Location: 4,4 - Actor807: ice01 - Owner: Neutral - Location: 14,119 - Actor808: ice03 - Owner: Neutral - Location: 12,120 - Actor810: ice01 - Owner: Neutral - Location: 115,9 - Actor809: ice05 - Owner: Neutral - Location: 117,9 - Actor811: ice04 - Owner: Neutral - Location: 116,8 - Actor812: ice04 - Owner: Neutral - Location: 68,117 - Actor813: ice04 - Owner: Neutral - Location: 60,13 - Actor814: ice05 - Owner: Neutral - Location: 72,7 - Actor815: ice05 - Owner: Neutral - Location: 57,124 - Actor816: ice02 - Owner: Neutral - Location: 6,47 - Actor817: ice02 - Owner: Neutral - Location: 123,80 - Actor818: ice03 - Owner: Neutral - Location: 31,128 - Actor819: ice03 - Owner: Neutral - Location: 96,1 - Actor820: ice03 - Owner: Neutral - Location: 125,46 - Actor821: ice03 - Owner: Neutral - Location: 3,82 - Actor822: t17 - Owner: Neutral - Location: 101,10 - Actor823: t17 - Owner: Neutral - Location: 29,117 - Actor825: railmine - Owner: Neutral - Location: 36,89 - Actor824: c8 - Owner: Neutral - Location: 72,46 - SubCell: 3 - Facing: 92 - Actor826: c7 - Owner: Neutral - Location: 76,49 - SubCell: 3 - Facing: 92 - Actor827: c3 - Owner: Neutral - Location: 69,42 - SubCell: 3 - Facing: 92 - Actor828: c4 - Owner: Neutral - Location: 55,48 - SubCell: 3 - Facing: 92 - Actor829: c3 - Owner: Neutral - Location: 72,80 - SubCell: 3 - Facing: 92 - Actor830: c3 - Owner: Neutral - Location: 57,88 - SubCell: 3 - Facing: 92 - Actor831: c1 - Owner: Neutral - Location: 53,82 - SubCell: 3 - Facing: 92 - Actor832: c2 - Owner: Neutral - Location: 57,81 - SubCell: 3 - Facing: 92 - Actor833: c3 - Owner: Neutral - Location: 106,31 - SubCell: 3 - Facing: 92 - Actor835: c1 - Owner: Neutral - Location: 127,6 - SubCell: 3 - Facing: 92 - Actor836: c4 - Owner: Neutral - Location: 122,2 - SubCell: 3 - Facing: 92 - Actor837: c5 - Owner: Neutral - Location: 83,84 - SubCell: 3 - Facing: 92 - Actor838: c3 - Owner: Neutral - Location: 60,103 - SubCell: 1 - Facing: 92 - Actor840: c4 - Owner: Neutral - Location: 2,123 - SubCell: 3 - Facing: 92 - Actor841: c9 - Owner: Neutral - Location: 5,126 - SubCell: 1 - Facing: 92 - Actor842: c9 - Owner: Neutral - Location: 22,98 - SubCell: 3 - Facing: 92 - Actor843: c1 - Owner: Neutral - Location: 119,86 - SubCell: 3 - Facing: 92 - Actor844: c2 - Owner: Neutral - Location: 17,81 - SubCell: 3 - Facing: 92 - Actor845: c3 - Owner: Neutral - Location: 11,45 - SubCell: 3 - Facing: 92 - Actor846: c6 - Owner: Neutral - Location: 114,47 - SubCell: 1 - Facing: 92 - Actor847: c5 - Owner: Neutral - Location: 45,44 - SubCell: 3 - Facing: 92 - Actor848: c5 - Owner: Neutral - Location: 69,26 - SubCell: 3 - Facing: 92 - Actor849: c4 - Owner: Neutral - Location: 68,124 - SubCell: 3 - Facing: 92 - Actor850: c7 - Owner: Neutral - Location: 60,5 - SubCell: 3 - Facing: 92 - Actor851: railmine - Owner: Neutral - Location: 101,52 - Actor852: railmine - Owner: Neutral - Location: 57,31 - Actor854: v19 - Owner: Neutral - Location: 117,2 - Actor855: v19 - Owner: Neutral - Location: 115,2 - Actor856: brl3 - Owner: Neutral - Location: 116,2 - Actor857: v19 - Owner: Neutral - Location: 12,127 - Actor858: v19 - Owner: Neutral - Location: 14,127 - Actor859: brl3 - Owner: Neutral - Location: 13,127 - Actor834: c7 - Owner: Neutral - Location: 12,126 - SubCell: 3 - Facing: 92 - Actor839: tc03 - Owner: Neutral - Location: 48,61 - Actor853: t11 - Owner: Neutral - Location: 81,61 - Actor860: t11 - Owner: Neutral - Location: 30,75 - Actor867: mpspawn - Owner: Neutral - Location: 18,37 - Actor868: mpspawn - Owner: Neutral - Location: 20,20 - Actor869: mpspawn - Owner: Neutral - Location: 40,19 - Actor870: mpspawn - Owner: Neutral - Location: 89,110 - Actor871: mpspawn - Owner: Neutral - Location: 108,108 - Actor872: mpspawn - Owner: Neutral - Location: 110,91 - -Rules: rules.yaml diff -Nru openra-20200503/mods/ra/maps/six-below-zero/rules.yaml openra-20210321/mods/ra/maps/six-below-zero/rules.yaml --- openra-20200503/mods/ra/maps/six-below-zero/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/six-below-zero/rules.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -World: - WeatherOverlay: - ChangingWindLevel: true - WindLevels: -5, -3, -2, 0, 2, 3, 5, 6 - WindTick: 150, 550 - InstantWindChanges: false - UseSquares: true - ParticleSize: 2, 3 - ScatterDirection: -1, 1 - Gravity: 1.00, 2.00 - SwingOffset: 1.0, 1.5 - SwingSpeed: 0.001, 0.025 - SwingAmplitude: 1.0, 1.5 - ParticleColors: ECECEC, E4E4E4, D0D0D0, BCBCBC - LineTailAlphaValue: 0 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/snow-off/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/snow-off/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/snow-off/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/snow-off/map.png differ diff -Nru openra-20200503/mods/ra/maps/snow-off/map.yaml openra-20210321/mods/ra/maps/snow-off/map.yaml --- openra-20200503/mods/ra/maps/snow-off/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/snow-off/map.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,888 +0,0 @@ -MapFormat: 11 - -RequiresMod: ra - -Title: Snow Off - -Author: Aaron Lloyd - -Tileset: SNOW - -MapSize: 62,52 - -Bounds: 1,1,60,50 - -Visibility: Lobby - -Categories: Conquest - -Players: - PlayerReference@Neutral: - Name: Neutral - OwnsWorld: True - NonCombatant: True - Faction: england - PlayerReference@Creeps: - Name: Creeps - NonCombatant: True - Faction: england - Enemies: Multi0, Multi1 - PlayerReference@Multi0: - Name: Multi0 - Playable: True - Faction: Random - Enemies: Creeps - PlayerReference@Multi1: - Name: Multi1 - Playable: True - Faction: Random - Enemies: Creeps - -Actors: - Actor4: oilb - Owner: Neutral - Location: 25,23 - Actor3: oilb - Owner: Neutral - Location: 33,25 - Actor6: tc03 - Owner: Neutral - Location: 35,21 - Actor7: boxes02 - Owner: Neutral - Location: 27,24 - Actor8: boxes06 - Owner: Neutral - Location: 34,27 - Actor9: t17 - Owner: Neutral - Location: 30,24 - Actor10: tc03 - Owner: Neutral - Location: 21,23 - Actor12: tc04 - Owner: Neutral - Location: 26,27 - Actor14: t17 - Owner: Neutral - Location: 34,21 - Actor17: t02 - Owner: Neutral - Location: 37,24 - Actor18: t05 - Owner: Neutral - Location: 19,27 - Actor19: t05 - Owner: Neutral - Location: 33,21 - Actor20: t08 - Owner: Neutral - Location: 22,29 - Actor21: v07 - Owner: Neutral - Location: 30,23 - Actor23: mine - Owner: Neutral - Location: 47,30 - Actor45: c5 - Owner: Neutral - Location: 29,25 - SubCell: 3 - Facing: 93 - Actor71: cycl - Owner: Neutral - Location: 48,17 - Actor72: cycl - Owner: Neutral - Location: 49,17 - Actor74: cycl - Owner: Neutral - Location: 50,17 - Actor75: cycl - Owner: Neutral - Location: 51,17 - Actor79: oilb - Owner: Neutral - Location: 49,15 - Actor76: cycl - Owner: Neutral - Location: 48,16 - Actor77: cycl - Owner: Neutral - Location: 48,15 - Actor78: cycl - Owner: Neutral - Location: 51,16 - Actor73: cycl - Owner: Neutral - Location: 10,34 - Actor83: cycl - Owner: Neutral - Location: 11,34 - Actor84: cycl - Owner: Neutral - Location: 12,34 - Actor86: cycl - Owner: Neutral - Location: 13,34 - Actor87: cycl - Owner: Neutral - Location: 10,35 - Actor89: oilb - Owner: Neutral - Location: 11,35 - Actor91: cycl - Owner: Neutral - Location: 13,35 - Actor92: cycl - Owner: Neutral - Location: 10,36 - Actor93: cycl - Owner: Neutral - Location: 13,36 - Actor95: cycl - Owner: Neutral - Location: 13,37 - Actor90: v13 - Owner: Neutral - Location: 7,27 - Actor96: v03 - Owner: Neutral - Location: 58,21 - Actor97: v05 - Owner: Neutral - Location: 54,21 - Actor98: v04 - Owner: Neutral - Location: 57,19 - Actor104: t03 - Owner: Neutral - Location: 3,27 - Actor106: tc03 - Owner: Neutral - Location: 8,35 - Actor107: tc04 - Owner: Neutral - Location: 52,15 - Actor109: t15 - Owner: Neutral - Location: 53,21 - Actor110: t13 - Owner: Neutral - Location: 58,19 - Actor111: t08 - Owner: Neutral - Location: 57,22 - Actor112: tc05 - Owner: Neutral - Location: 4,47 - Actor114: t16 - Owner: Neutral - Location: 1,42 - Actor115: t11 - Owner: Neutral - Location: 1,46 - Actor116: tc04 - Owner: Neutral - Location: 4,45 - Actor117: tc03 - Owner: Neutral - Location: 2,47 - Actor118: t15 - Owner: Neutral - Location: 1,49 - Actor119: tc02 - Owner: Neutral - Location: 3,49 - Actor120: tc03 - Owner: Neutral - Location: 0,40 - Actor121: tc03 - Owner: Neutral - Location: 7,49 - Actor122: tc03 - Owner: Neutral - Location: 58,49 - Actor123: tc02 - Owner: Neutral - Location: 55,49 - Actor124: tc01 - Owner: Neutral - Location: 59,45 - Actor125: t15 - Owner: Neutral - Location: 56,47 - Actor126: t17 - Owner: Neutral - Location: 58,47 - Actor127: tc02 - Owner: Neutral - Location: 59,43 - Actor128: tc05 - Owner: Neutral - Location: 56,45 - Actor129: tc05 - Owner: Neutral - Location: 52,49 - Actor130: tc03 - Owner: Neutral - Location: 55,47 - Actor131: tc03 - Owner: Neutral - Location: 1,1 - Actor132: tc05 - Owner: Neutral - Location: 0,3 - Actor133: tc01 - Owner: Neutral - Location: 5,1 - Actor134: tc01 - Owner: Neutral - Location: 1,6 - Actor135: t02 - Owner: Neutral - Location: 4,2 - Actor136: t01 - Owner: Neutral - Location: 1,8 - Actor137: t01 - Owner: Neutral - Location: 57,2 - Actor138: t01 - Owner: Neutral - Location: 58,3 - Actor139: tc01 - Owner: Neutral - Location: 59,7 - Actor140: tc02 - Owner: Neutral - Location: 57,5 - Actor141: tc05 - Owner: Neutral - Location: 53,1 - Actor142: tc03 - Owner: Neutral - Location: 55,4 - Actor143: tc01 - Owner: Neutral - Location: 57,3 - Actor144: t10 - Owner: Neutral - Location: 58,5 - Actor145: t11 - Owner: Neutral - Location: 58,1 - Actor146: t13 - Owner: Neutral - Location: 59,3 - Actor147: t17 - Owner: Neutral - Location: 56,8 - Actor148: t16 - Owner: Neutral - Location: 3,4 - Actor149: t11 - Owner: Neutral - Location: 2,2 - Actor150: t11 - Owner: Neutral - Location: 6,3 - Actor151: tc01 - Owner: Neutral - Location: 7,1 - Actor152: tc03 - Owner: Neutral - Location: 9,2 - Actor153: tc03 - Owner: Neutral - Location: 10,1 - Actor154: tc04 - Owner: Neutral - Location: 8,0 - Actor156: tc04 - Owner: Neutral - Location: 51,0 - Actor159: tc03 - Owner: Neutral - Location: 0,10 - Actor161: tc02 - Owner: Neutral - Location: 38,1 - Actor162: tc05 - Owner: Neutral - Location: 23,48 - Actor163: t17 - Owner: Neutral - Location: 1,35 - Actor164: t11 - Owner: Neutral - Location: 59,15 - Actor165: t17 - Owner: Neutral - Location: 59,36 - Actor166: t16 - Owner: Neutral - Location: 8,44 - Actor167: t14 - Owner: Neutral - Location: 49,3 - Actor155: tc01 - Owner: Neutral - Location: 4,4 - Actor160: t15 - Owner: Neutral - Location: 2,5 - Actor168: v03 - Owner: Neutral - Location: 2,29 - Actor169: v09 - Owner: Neutral - Location: 3,31 - Actor170: tc01 - Owner: Neutral - Location: 6,29 - Actor171: t16 - Owner: Neutral - Location: 6,26 - Actor172: t17 - Owner: Neutral - Location: 8,26 - Actor173: t08 - Owner: Neutral - Location: 2,31 - Actor174: tc03 - Owner: Neutral - Location: 3,31 - Actor175: t01 - Owner: Neutral - Location: 57,20 - Actor176: t01 - Owner: Neutral - Location: 60,22 - Actor177: t06 - Owner: Neutral - Location: 2,26 - Actor180: t15 - Owner: Neutral - Location: 4,10 - Actor181: t10 - Owner: Neutral - Location: 56,39 - Actor182: t08 - Owner: Neutral - Location: 43,23 - Actor190: c3 - Owner: Neutral - Location: 4,28 - SubCell: 3 - Facing: 92 - Actor191: c4 - Owner: Neutral - Location: 55,20 - SubCell: 3 - Facing: 92 - Actor192: c9 - Owner: Neutral - Location: 6,31 - SubCell: 3 - Facing: 92 - Actor193: c9 - Owner: Neutral - Location: 57,23 - SubCell: 3 - Facing: 92 - Actor196: t11 - Owner: Neutral - Location: 42,48 - Actor197: tc01 - Owner: Neutral - Location: 43,49 - Actor198: tc01 - Owner: Neutral - Location: 18,1 - Actor199: tc02 - Owner: Neutral - Location: 16,2 - Actor183: tc05 - Owner: Neutral - Location: 23,29 - Actor184: t16 - Owner: Neutral - Location: 19,32 - Actor188: tc04 - Owner: Neutral - Location: 27,32 - Actor194: t15 - Owner: Neutral - Location: 28,33 - Actor200: tc01 - Owner: Neutral - Location: 30,33 - Actor201: t05 - Owner: Neutral - Location: 37,34 - Actor202: mine - Owner: Neutral - Location: 19,37 - Actor203: v10 - Owner: Neutral - Location: 40,37 - Actor204: t16 - Owner: Neutral - Location: 37,37 - Actor205: c3 - Owner: Neutral - SubCell: 3 - Facing: 92 - Location: 40,38 - Actor206: tc01 - Owner: Neutral - Location: 41,37 - Actor207: v01 - Owner: Neutral - Location: 42,38 - Actor208: mine - Owner: Neutral - Location: 18,39 - Actor209: v03 - Owner: Neutral - Location: 37,39 - Actor210: c9 - Owner: Neutral - SubCell: 3 - Facing: 92 - Location: 39,40 - Actor211: c7 - Owner: Neutral - SubCell: 3 - Facing: 92 - Location: 41,40 - Actor212: t17 - Owner: Neutral - Location: 42,39 - Actor213: c10 - Owner: Neutral - SubCell: 3 - Facing: 92 - Location: 43,40 - Actor214: t16 - Owner: Neutral - Location: 39,40 - Actor215: v12 - Owner: Neutral - Location: 40,41 - Actor216: t11 - Owner: Neutral - Location: 41,41 - Actor217: v05 - Owner: Neutral - Location: 42,42 - Actor218: tc02 - Owner: Neutral - Location: 44,38 - Actor185: v02 - Owner: Neutral - Location: 21,9 - Actor186: v04 - Owner: Neutral - Location: 22,10 - Actor187: c4 - Owner: Neutral - SubCell: 3 - Facing: 92 - Location: 21,11 - Actor195: mine - Owner: Neutral - Location: 43,12 - Actor219: c10 - Owner: Neutral - SubCell: 3 - Facing: 92 - Location: 23,13 - Actor220: v12 - Owner: Neutral - Location: 24,13 - Actor221: v11 - Owner: Neutral - Location: 21,14 - Actor222: mine - Owner: Neutral - Location: 42,14 - Actor223: t06 - Owner: Neutral - Location: 22,14 - Actor224: t16 - Owner: Neutral - Location: 24,14 - Actor227: t16 - Owner: Neutral - Location: 30,16 - Actor228: tc03 - Owner: Neutral - Location: 31,17 - Actor229: tc02 - Owner: Neutral - Location: 32,17 - Actor230: t17 - Owner: Neutral - Location: 42,17 - Actor231: t17 - Owner: Neutral - Location: 29,18 - Actor232: t16 - Owner: Neutral - Location: 30,19 - Actor234: tc04 - Owner: Neutral - Location: 37,19 - Actor235: t11 - Owner: Neutral - Location: 16,8 - Actor236: v08 - Owner: Neutral - Location: 18,9 - Actor237: t05 - Owner: Neutral - Location: 20,9 - Actor238: t08 - Owner: Neutral - Location: 17,11 - Actor239: c2 - Owner: Neutral - SubCell: 3 - Facing: 92 - Location: 18,11 - Actor241: v03 - Owner: Neutral - Location: 18,12 - Actor242: c10 - Owner: Neutral - SubCell: 3 - Facing: 92 - Location: 20,13 - Actor243: tc02 - Owner: Neutral - Location: 19,13 - Actor245: mine - Owner: Neutral - Location: 13,20 - Actor178: v02 - Owner: Neutral - Location: 6,28 - Actor179: tc01 - Owner: Neutral - Location: 21,18 - Actor226: t15 - Owner: Neutral - Location: 15,28 - Actor233: tc01 - Owner: Neutral - Location: 28,19 - Actor246: tc03 - Owner: Neutral - Location: 26,29 - Actor247: tc03 - Owner: Neutral - Location: 39,31 - Actor248: tc02 - Owner: Neutral - Location: 35,19 - Actor249: t16 - Owner: Neutral - Location: 34,20 - Actor250: t15 - Owner: Neutral - Location: 23,26 - Actor252: utilpol2 - Owner: Neutral - Location: 54,20 - Actor253: tc05 - Owner: Neutral - Location: 47,21 - Actor254: tc02 - Owner: Neutral - Location: 18,29 - Actor255: tc03 - Owner: Neutral - Location: 31,30 - Actor256: t15 - Owner: Neutral - Location: 32,30 - Actor257: tc04 - Owner: Neutral - Location: 34,29 - Actor258: tc03 - Owner: Neutral - Location: 19,18 - Actor259: tc02 - Owner: Neutral - Location: 13,30 - Actor260: tc03 - Owner: Neutral - Location: 47,20 - Actor261: t17 - Owner: Neutral - Location: 42,20 - Actor262: t15 - Owner: Neutral - Location: 41,31 - Actor263: t12 - Owner: Neutral - Location: 17,27 - Actor264: t08 - Owner: Neutral - Location: 14,28 - Actor265: t01 - Owner: Neutral - Location: 30,29 - Actor266: t12 - Owner: Neutral - Location: 32,20 - Actor267: t16 - Owner: Neutral - Location: 11,9 - Actor268: t08 - Owner: Neutral - Location: 48,9 - Actor269: tc01 - Owner: Neutral - Location: 44,20 - Actor270: t05 - Owner: Neutral - Location: 40,21 - Actor271: t16 - Owner: Neutral - Location: 46,19 - Actor272: t15 - Owner: Neutral - Location: 40,22 - Actor273: t05 - Owner: Neutral - Location: 50,38 - Actor274: t10 - Owner: Neutral - Location: 26,19 - Actor275: tc02 - Owner: Neutral - Location: 20,23 - Actor276: t07 - Owner: Neutral - Location: 29,26 - Actor277: t08 - Owner: Neutral - Location: 29,30 - Actor278: t12 - Owner: Neutral - Location: 28,29 - Actor279: tc03 - Owner: Neutral - Location: 29,20 - Actor280: tc01 - Owner: Neutral - Location: 38,21 - Actor281: tc03 - Owner: Neutral - Location: 40,21 - Actor282: t14 - Owner: Neutral - Location: 42,21 - Actor283: tc03 - Owner: Neutral - Location: 17,28 - Actor284: t13 - Owner: Neutral - Location: 16,29 - Actor285: t16 - Owner: Neutral - Location: 15,29 - Actor286: t02 - Owner: Neutral - Location: 20,28 - Actor287: t03 - Owner: Neutral - Location: 37,22 - Actor288: t08 - Owner: Neutral - Location: 31,21 - Actor289: tc05 - Owner: Neutral - Location: 34,22 - Actor290: tc05 - Owner: Neutral - Location: 38,23 - Actor291: t16 - Owner: Neutral - Location: 39,24 - Actor292: t08 - Owner: Neutral - Location: 38,25 - Actor294: tc03 - Owner: Neutral - Location: 18,27 - Actor296: t06 - Owner: Neutral - Location: 21,27 - Actor297: tc04 - Owner: Neutral - Location: 21,27 - Actor298: tc03 - Owner: Neutral - Location: 58,25 - Actor299: tc01 - Owner: Neutral - Location: 2,23 - Actor300: t11 - Owner: Neutral - Location: 29,28 - Actor301: t03 - Owner: Neutral - Location: 38,31 - Actor302: t03 - Owner: Neutral - Location: 44,22 - Actor303: t13 - Owner: Neutral - Location: 43,21 - Actor304: t16 - Owner: Neutral - Location: 42,22 - Actor305: t05 - Owner: Neutral - Location: 46,20 - Actor306: tc01 - Owner: Neutral - Location: 10,28 - Actor307: t11 - Owner: Neutral - Location: 13,26 - Actor308: tc03 - Owner: Neutral - Location: 14,28 - Actor309: t12 - Owner: Neutral - Location: 15,27 - Actor293: tc01 - Owner: Neutral - Location: 25,26 - Actor295: t15 - Owner: Neutral - Location: 23,27 - Actor310: tc03 - Owner: Neutral - Location: 24,28 - Actor311: tc03 - Owner: Neutral - Location: 25,28 - Actor244: tc03 - Owner: Neutral - Location: 20,1 - Actor312: tc03 - Owner: Neutral - Location: 40,49 - Actor313: t13 - Owner: Neutral - Location: 1,27 - Actor314: t12 - Owner: Neutral - Location: 22,20 - Actor315: tc03 - Owner: Neutral - Location: 26,26 - Actor316: tc03 - Owner: Neutral - Location: 28,28 - Actor317: tc01 - Owner: Neutral - Location: 32,21 - Actor318: t13 - Owner: Neutral - Location: 33,22 - Actor319: t17 - Owner: Neutral - Location: 16,11 - Actor320: t02 - Owner: Neutral - Location: 11,11 - Actor321: t03 - Owner: Neutral - Location: 51,36 - Actor322: t05 - Owner: Neutral - Location: 31,29 - Actor323: t12 - Owner: Neutral - Location: 36,26 - Actor324: t08 - Owner: Neutral - Location: 17,24 - Actor325: tc01 - Owner: Neutral - Location: 1,43 - Actor326: tc01 - Owner: Neutral - Location: 7,45 - Actor327: t06 - Owner: Neutral - Location: 51,3 - Actor328: t06 - Owner: Neutral - Location: 47,42 - Actor329: t01 - Owner: Neutral - Location: 14,8 - Actor330: t10 - Owner: Neutral - Location: 7,2 - Actor331: t10 - Owner: Neutral - Location: 60,16 - Actor332: t16 - Owner: Neutral - Location: 58,44 - Actor333: t02 - Owner: Neutral - Location: 25,19 - Actor334: tc03 - Owner: Neutral - Location: 22,19 - Actor335: tc03 - Owner: Neutral - Location: 2,45 - Actor336: v11 - Owner: Neutral - Location: 52,23 - Actor337: tc02 - Owner: Neutral - Location: 58,27 - Actor338: t15 - Owner: Neutral - Location: 1,21 - Actor339: brl3 - Owner: Creeps - Location: 48,14 - Actor340: brl3 - Owner: Creeps - Location: 13,38 - Actor341: barl - Owner: Creeps - Location: 51,15 - Actor342: barl - Owner: Creeps - Location: 11,37 - Actor344: t06 - Owner: Neutral - Location: 46,21 - Actor345: t03 - Owner: Neutral - Location: 47,22 - Actor346: t05 - Owner: Neutral - Location: 45,22 - Actor347: mpspawn - Owner: Neutral - Location: 26,38 - Actor348: mpspawn - Owner: Neutral - Location: 35,12 - -Rules: rules.yaml diff -Nru openra-20200503/mods/ra/maps/snow-off/rules.yaml openra-20210321/mods/ra/maps/snow-off/rules.yaml --- openra-20200503/mods/ra/maps/snow-off/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/snow-off/rules.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -World: - WeatherOverlay: - ParticleDensityFactor: 7 - ChangingWindLevel: true - WindLevels: -2, 0, 2 - WindTick: 150, 550 - InstantWindChanges: false - UseSquares: true - ParticleSize: 1, 3 - ScatterDirection: 0, 0 - Gravity: 0.50, 1.50 - SwingOffset: 1, 2 - SwingSpeed: 0.01, 0.02 - SwingAmplitude: 0, 0 - ParticleColors: fbfbfb90, f4f4f480, f1f1f1, ffffff50 diff -Nru openra-20200503/mods/ra/maps/soviet-01/map.yaml openra-20210321/mods/ra/maps/soviet-01/map.yaml --- openra-20200503/mods/ra/maps/soviet-01/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-01/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -213,7 +213,7 @@ Location: 41,54 Owner: France Health: 52 - Actor54: v07 + HayHouse: v07 Location: 54,65 Owner: France Health: 44 @@ -339,7 +339,7 @@ Actor98: barl Location: 45,50 Owner: Germany - Actor99: v04 + ParaHut: v04 Location: 58,54 Owner: France Health: 41 @@ -415,20 +415,20 @@ Location: 46,52 Owner: France Health: 66 - Facing: 96 + Facing: 384 Actor125: jeep Location: 55,57 Owner: France - Facing: 160 + Facing: 640 Actor126: jeep Location: 39,65 Owner: France Health: 63 - Facing: 64 + Facing: 256 Actor127: c9 Location: 50,64 Owner: France - Facing: 192 + Facing: 768 SubCell: 1 Actor128: c8 Location: 47,61 @@ -437,12 +437,12 @@ Actor129: c8 Location: 41,50 Owner: France - Facing: 224 + Facing: 896 SubCell: 3 Actor130: c6 Location: 46,61 Owner: France - Facing: 128 + Facing: 512 SubCell: 2 Actor131: c5 Location: 46,61 @@ -451,57 +451,57 @@ Actor132: c4 Location: 44,67 Owner: France - Facing: 96 + Facing: 384 SubCell: 1 Actor133: c2 Location: 40,54 Owner: France - Facing: 160 + Facing: 640 SubCell: 2 Actor134: c2 Location: 45,61 Owner: France - Facing: 64 + Facing: 256 SubCell: 4 Actor135: e1 Location: 54,60 Owner: France - Facing: 160 + Facing: 640 SubCell: 4 Actor136: e1 Location: 49,60 Owner: France - Facing: 128 + Facing: 512 SubCell: 2 Actor137: c5 Location: 45,51 Owner: France - Facing: 224 + Facing: 896 SubCell: 0 Actor138: e1 Location: 34,58 Owner: France - Facing: 96 + Facing: 384 SubCell: 0 Actor139: e1 Location: 53,54 Owner: France - Facing: 128 + Facing: 512 SubCell: 2 Actor140: e1 Location: 58,56 Owner: France - Facing: 128 + Facing: 512 SubCell: 1 Actor141: e1 Location: 58,52 Owner: France - Facing: 160 + Facing: 640 SubCell: 0 Actor142: e1 Location: 54,64 Owner: France - Facing: 160 + Facing: 640 SubCell: 3 Actor143: c7 Location: 56,54 @@ -510,12 +510,12 @@ Actor144: e1 Location: 40,51 Owner: France - Facing: 160 + Facing: 640 SubCell: 0 Actor145: e1 Location: 35,53 Owner: France - Facing: 96 + Facing: 384 SubCell: 1 Actor146: e1 Location: 35,54 @@ -524,17 +524,17 @@ Actor147: e1 Location: 43,64 Owner: France - Facing: 96 + Facing: 384 SubCell: 0 Actor148: e1 Location: 56,63 Owner: France - Facing: 192 + Facing: 768 SubCell: 2 Actor149: e1 Location: 40,67 Owner: France - Facing: 32 + Facing: 128 SubCell: 4 Church: v01 Location: 40,63 @@ -544,7 +544,7 @@ Location: 44,76 Owner: France Health: 52 - Facing: 32 + Facing: 128 LonelyGuard: e1 Location: 42,81 Owner: USSR @@ -583,5 +583,8 @@ YakEntry: waypoint Location: 51,84 Owner: Neutral + CivSpawn: waypoint + Location: 55,65 + Owner: Neutral Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/ra/maps/soviet-01/rules.yaml openra-20210321/mods/ra/maps/soviet-01/rules.yaml --- openra-20200503/mods/ra/maps/soviet-01/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-01/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -13,6 +13,11 @@ SpawnActorOnDeath: Actor: healcrate +powerproxy.paratroopers: + ParatroopersPower: + DisplayBeacon: False + DropItems: E1,E1,E1,E2,E2 + ^CivBuilding: MustBeDestroyed: @@ -20,7 +25,7 @@ Explodes: ProximityExternalCondition@JAMMER: Range: 10c0 - ValidStances: Enemy, Neutral + ValidRelationships: Enemy, Neutral Condition: jammed YAK: @@ -35,8 +40,7 @@ AirstrikePower@spyplane: Prerequisites: ~disabled ParatroopersPower@paratroopers: - ChargeInterval: 1500 - DropItems: E1,E1,E1,E2,E2 + Prerequisites: ~disabled -RallyPoint: -Sellable: Demolishable: diff -Nru openra-20200503/mods/ra/maps/soviet-01/soviet01.lua openra-20210321/mods/ra/maps/soviet-01/soviet01.lua --- openra-20200503/mods/ra/maps/soviet-01/soviet01.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-01/soviet01.lua 2021-03-21 11:10:05.000000000 +0000 @@ -24,9 +24,9 @@ JeepDemolishingBridge = function() StartJeep.Move(StartJeepMovePoint.Location) - Trigger.OnIdle(StartJeep, function() - Trigger.ClearAll(StartJeep) - if not BridgeBarrel.IsDead then + Trigger.OnEnteredFootprint({ StartJeepMovePoint.Location }, function(actor, id) + if actor.Owner == france and not BridgeBarrel.IsDead then + Trigger.RemoveFootprintTrigger(id) BridgeBarrel.Kill() end @@ -39,6 +39,34 @@ end) end +Paratroopers = function() + Trigger.OnKilled(StartJeep, function() + Media.PlaySpeechNotification(player, "ReinforcementsArrived") + Paradrop.TargetParatroopers(StartJeepMovePoint.CenterPosition, Angle.East) + end) + + Trigger.OnKilled(Church, function() + Media.PlaySpeechNotification(player, "ReinforcementsArrived") + Paradrop.TargetParatroopers(StartJeepMovePoint.CenterPosition, Angle.East) + end) + + Trigger.OnKilled(ParaHut, function() + Media.PlaySpeechNotification(player, "ReinforcementsArrived") + Paradrop.TargetParatroopers(StartJeepMovePoint.CenterPosition, Angle.East) + end) +end + +PanicAttack = function() + if not HouseDamaged then + local panicTeam = Reinforcements.Reinforce(france, { "c3", "c6", "c9" }, { CivSpawn.Location }, 0) + Utils.Do(panicTeam, function(a) + a.Move(a.Location + CVec.New(-1,-1)) + a.Panic() + end) + end + HouseDamaged = true +end + WorldLoaded = function() player = Player.GetPlayer("USSR") france = Player.GetPlayer("France") @@ -70,7 +98,10 @@ Media.PlaySpeechNotification(player, "MissionFailed") end) + Paradrop = Actor.Create("powerproxy.paratroopers", false, { Owner = player }) Trigger.AfterDelay(DateTime.Seconds(2), InsertYaks) + Paratroopers() + Trigger.OnDamaged(HayHouse, PanicAttack) end Tick = function() diff -Nru openra-20200503/mods/ra/maps/soviet-02a/map.yaml openra-20210321/mods/ra/maps/soviet-02a/map.yaml --- openra-20200503/mods/ra/maps/soviet-02a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-02a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -167,18 +167,18 @@ Actor42: gun Location: 39,61 Owner: Greece - Facing: 96 + Facing: 384 Actor44: powr Location: 36,49 Owner: Greece Actor45: gun Location: 50,55 Owner: Greece - Facing: 96 + Facing: 384 Actor46: gun Location: 50,59 Owner: Greece - Facing: 32 + Facing: 128 Actor47: brl3 Location: 38,48 Owner: Greece @@ -269,109 +269,109 @@ Actor80: jeep Location: 57,43 Owner: Greece - Facing: 96 + Facing: 384 Actor81: jeep Location: 46,70 Owner: Greece - Facing: 96 + Facing: 384 Actor82: jeep Location: 42,48 Owner: Greece - Facing: 32 + Facing: 128 Actor83: e1 Location: 70,52 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 4 Actor84: e1 Location: 70,55 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 3 Actor86: e1 Location: 44,67 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 0 Actor87: e1 Location: 68,53 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 2 Actor88: e1 Location: 69,54 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 0 Actor89: e1 Location: 70,56 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 4 Actor90: e1 Location: 69,57 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 2 Actor91: e1 Location: 69,55 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 3 Actor92: dog Location: 77,58 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 3 Actor93: dog Location: 82,50 Owner: USSR - Facing: 192 + Facing: 768 SubCell: 0 Actor96: dog Location: 73,50 Owner: USSR - Facing: 32 + Facing: 128 SubCell: 3 Actor97: dog Location: 73,58 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 1 Actor98: e3 Location: 47,44 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 0 Actor99: e3 Location: 49,57 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 1 Actor100: e3 Location: 44,49 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 0 Actor101: e3 Location: 39,51 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 4 Actor102: e3 Location: 43,60 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 0 Actor103: e3 Location: 42,56 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 3 Actor104: e1 Location: 48,43 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 1 Actor113: e1 Location: 71,50 @@ -441,37 +441,37 @@ Follower: e1 Location: 69,53 Owner: USSR - Facing: 160 + Facing: 640 SubCell: 2 Fleeing1: e1 Location: 62,52 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 4 Fleeing2: e1 Location: 63,53 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 4 Attacker1: e1 Location: 59,44 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 4 Attacker2: e1 Location: 60,44 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 1 Attacker3: e1 Location: 59,43 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 4 Attacker4: e1 Location: 59,44 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 1 Hunter1: e3 Location: 74,67 diff -Nru openra-20200503/mods/ra/maps/soviet-02a/rules.yaml openra-20210321/mods/ra/maps/soviet-02a/rules.yaml --- openra-20200503/mods/ra/maps/soviet-02a/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-02a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -88,11 +88,6 @@ ParatroopersPower@paratroopers: Prerequisites: ~disabled -HARV: - Harvester: - SearchFromProcRadius: 50 - SearchFromHarvesterRadius: 50 - powerproxy.paratroopers: ParatroopersPower: DropItems: E2,E2,E2,E2,E2 diff -Nru openra-20200503/mods/ra/maps/soviet-02a/soviet02a.lua openra-20210321/mods/ra/maps/soviet-02a/soviet02a.lua --- openra-20200503/mods/ra/maps/soviet-02a/soviet02a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-02a/soviet02a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -123,8 +123,8 @@ -- When destroying the allied radar dome or the refinery drop 2 badgers with 5 grenadiers each Trigger.OnAnyKilled({ AlliedDome, AlliedProc }, function() local powerproxy = Actor.Create("powerproxy.paratroopers", true, { Owner = player }) - powerproxy.ActivateParatroopers(ParadropLZ.CenterPosition, Facing.South) - powerproxy.ActivateParatroopers(ParadropLZ.CenterPosition, Facing.SouthEast) + powerproxy.TargetParatroopers(ParadropLZ.CenterPosition, Angle.South) + powerproxy.TargetParatroopers(ParadropLZ.CenterPosition, Angle.SouthEast) powerproxy.Destroy() end) end diff -Nru openra-20200503/mods/ra/maps/soviet-02b/map.yaml openra-20210321/mods/ra/maps/soviet-02b/map.yaml --- openra-20200503/mods/ra/maps/soviet-02b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-02b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -288,119 +288,119 @@ Actor86: jeep Location: 85,66 Owner: Greece - Facing: 128 + Facing: 512 Actor89: jeep Location: 55,56 Owner: Greece - Facing: 224 + Facing: 896 Actor90: jeep Location: 79,54 Owner: Greece - Facing: 128 + Facing: 512 Actor92: e1 Location: 47,75 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 4 Actor93: e1 Location: 48,75 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 3 Actor94: e1 Location: 47,76 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 2 Actor95: e1 Location: 48,76 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 1 Actor96: dog Location: 49,73 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 3 Actor97: dog Location: 49,76 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 1 Actor98: dog Location: 49,75 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 3 Actor99: dog Location: 49,74 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 1 Actor100: e3 Location: 88,68 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 3 Actor103: e1 Location: 79,64 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 3 Actor104: e1 Location: 79,64 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 4 Actor105: e3 Location: 78,57 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 4 Actor106: e2 Location: 47,73 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 4 Actor107: e2 Location: 47,74 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 2 Actor108: e2 Location: 48,74 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 1 Actor109: e2 Location: 48,73 Owner: USSR - Facing: 64 + Facing: 256 SubCell: 3 Actor110: e1 Location: 72,61 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 0 Actor111: e1 Location: 40,54 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 0 Actor112: e1 Location: 83,85 Owner: Greece - Facing: 224 + Facing: 896 SubCell: 3 Actor113: e1 Location: 82,68 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 4 Actor114: e1 Location: 69,55 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 0 BarrelBase: brl3 Location: 71,55 @@ -441,25 +441,25 @@ BridgeGun1: gun Location: 68,64 Owner: Greece - Facing: 160 + Facing: 640 BridgeGun2: gun Location: 74,64 Owner: Greece - Facing: 160 + Facing: 640 IntroSoldier1: e1 Location: 71,65 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 3 IntroSoldier2: e1 Location: 71,60 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 3 IntroSoldier3: e1 Location: 70,60 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 4 ParachuteBase1: waypoint Location: 66,54 @@ -473,7 +473,7 @@ TransportTruck: truk Location: 75,58 Owner: Greece - Facing: 192 + Facing: 768 TransportWaypoint1: waypoint Location: 75,58 Owner: Neutral diff -Nru openra-20200503/mods/ra/maps/soviet-02b/rules.yaml openra-20210321/mods/ra/maps/soviet-02b/rules.yaml --- openra-20200503/mods/ra/maps/soviet-02b/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-02b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -92,11 +92,6 @@ -RepairableBuilding: -WithBuildingRepairDecoration: -HARV: - Harvester: - SearchFromProcRadius: 50 - SearchFromHarvesterRadius: 50 - powerproxy.paratroopers: ParatroopersPower: DropItems: E1,E1,E2,E2,E2 diff -Nru openra-20200503/mods/ra/maps/soviet-02b/soviet02b.lua openra-20210321/mods/ra/maps/soviet-02b/soviet02b.lua --- openra-20200503/mods/ra/maps/soviet-02b/soviet02b.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-02b/soviet02b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -17,16 +17,16 @@ SendUSSRParadrops = function() paraproxy1 = Actor.Create("powerproxy.paratroopers", false, { Owner = player }) - paraproxy1.ActivateParatroopers(ParachuteBaseEntrance.CenterPosition, Facing.North) + paraproxy1.TargetParatroopers(ParachuteBaseEntrance.CenterPosition, Angle.North) paraproxy1.Destroy() end SendUSSRParadropsBase = function() paraproxy2 = Actor.Create("powerproxy.paratroopers2", false, { Owner = player }) - paraproxy2.ActivateParatroopers(ParachuteBase1.CenterPosition, Facing.East) + paraproxy2.TargetParatroopers(ParachuteBase1.CenterPosition, Angle.East) paraproxy2.Destroy() paraproxy3 = Actor.Create("powerproxy.paratroopers3", false, { Owner = player }) - paraproxy3.ActivateParatroopers(ParachuteBase2.CenterPosition, Facing.East) + paraproxy3.TargetParatroopers(ParachuteBase2.CenterPosition, Angle.East) paraproxy3.Destroy() end diff -Nru openra-20200503/mods/ra/maps/soviet-03/map.yaml openra-20210321/mods/ra/maps/soviet-03/map.yaml --- openra-20200503/mods/ra/maps/soviet-03/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-03/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -450,62 +450,62 @@ Actor184: e1 Location: 64,41 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 3 Actor185: e1 Location: 64,42 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 0 Actor186: e1 Location: 63,42 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 0 Actor187: e1 Location: 59,45 Owner: Greece - Facing: 32 + Facing: 128 SubCell: 2 Actor188: e1 Location: 56,44 Owner: Greece - Facing: 32 + Facing: 128 SubCell: 4 Actor191: e1 Location: 56,45 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 4 Actor192: e1 Location: 57,44 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 2 Actor193: e1 Location: 60,44 Owner: Greece - Facing: 32 + Facing: 128 SubCell: 1 Actor194: e1 Location: 56,46 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 4 Actor195: e1 Location: 53,37 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 2 Actor196: e1 Location: 52,38 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 3 Actor197: e1 Location: 52,37 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 4 Actor264: fenc Owner: BadGuy @@ -813,32 +813,32 @@ BarrierSoldier1: e1 Location: 63,49 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 4 BarrierSoldier2: e1 Location: 64,50 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 0 BarrierSoldier3: e1 Location: 64,49 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 4 BarrierSoldier4: e1 Location: 66,50 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 4 BarrierSoldier5: e1 Location: 65,49 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 3 BarrierSoldier6: e1 Location: 66,49 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 3 BaseBarrel1: barl Location: 72,31 @@ -929,7 +929,7 @@ Farmer3: e3 Location: 89,37 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 2 FarmSpawn: waypoint Location: 90,39 @@ -990,12 +990,12 @@ RSoldier3: e3 Location: 36,37 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 1 RSoldier4: e3 Location: 36,37 Owner: Greece - Facing: 64 + Facing: 256 SubCell: 4 RSoldierTrap: barl Location: 42,38 diff -Nru openra-20200503/mods/ra/maps/soviet-03/notifications.yaml openra-20210321/mods/ra/maps/soviet-03/notifications.yaml --- openra-20200503/mods/ra/maps/soviet-03/notifications.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-03/notifications.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,3 +1,3 @@ -Sounds: - Notifications: - sking: sking1 \ No newline at end of file +Sounds: + Notifications: + sking: sking1 diff -Nru openra-20200503/mods/ra/maps/soviet-03/rules.yaml openra-20210321/mods/ra/maps/soviet-03/rules.yaml --- openra-20200503/mods/ra/maps/soviet-03/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-03/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -30,10 +30,10 @@ HP: 900000 V01: + Inherits@CARGOPIPS: ^CargoPips Cargo: Types: Infantry MaxWeight: 1 - PipCount: 1 V05: SpawnActorOnDeath: diff -Nru openra-20200503/mods/ra/maps/soviet-03/soviet03.lua openra-20210321/mods/ra/maps/soviet-03/soviet03.lua --- openra-20200503/mods/ra/maps/soviet-03/soviet03.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-03/soviet03.lua 2021-03-21 11:10:05.000000000 +0000 @@ -96,7 +96,7 @@ SendUSSRParadrops = function() paraproxy = Actor.Create("powerproxy.paratroopers", false, { Owner = player }) - paraproxy.ActivateParatroopers(ReinforcementDropOff.CenterPosition, 0) + paraproxy.TargetParatroopers(ReinforcementDropOff.CenterPosition, Angle.North) paraproxy.Destroy() end diff -Nru openra-20200503/mods/ra/maps/soviet-04a/map.yaml openra-20210321/mods/ra/maps/soviet-04a/map.yaml --- openra-20200503/mods/ra/maps/soviet-04a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-04a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -339,63 +339,63 @@ Actor133: 2tnk Location: 69,54 Owner: Greece - Facing: 64 + Facing: 256 Actor136: 1tnk Location: 59,68 Owner: Greece - Facing: 128 + Facing: 512 Actor137: 1tnk Location: 46,71 Owner: Greece - Facing: 128 + Facing: 512 Actor139: jeep Location: 57,54 Owner: Greece - Facing: 96 + Facing: 384 Actor140: 1tnk Location: 62,46 Owner: Greece - Facing: 160 + Facing: 640 Actor141: 1tnk Location: 60,57 Owner: Greece - Facing: 128 + Facing: 512 Actor142: 1tnk Location: 54,57 Owner: Greece - Facing: 128 + Facing: 512 Actor143: 2tnk Location: 92,53 Owner: Greece - Facing: 192 + Facing: 768 Actor144: 2tnk Location: 92,55 Owner: Greece - Facing: 192 + Facing: 768 Actor145: 2tnk Location: 86,58 Owner: Greece - Facing: 160 + Facing: 640 Actor146: jeep Location: 89,60 Owner: Greece - Facing: 160 + Facing: 640 Actor151: 2tnk Location: 40,55 Owner: Greece - Facing: 128 + Facing: 512 Actor152: 2tnk Location: 44,55 Owner: Greece - Facing: 128 + Facing: 512 Actor154: 2tnk Location: 67,64 Owner: Greece - Facing: 160 + Facing: 640 Actor155: 2tnk Location: 69,63 Owner: Greece - Facing: 160 + Facing: 640 Actor159: mine Location: 77,46 Owner: Neutral @@ -427,23 +427,23 @@ Gun1: gun Location: 87,57 Owner: Greece - Facing: 96 + Facing: 384 Gun2: gun Location: 84,58 Owner: Greece - Facing: 96 + Facing: 384 Gun3: gun Location: 53,48 Owner: Greece - Facing: 96 + Facing: 384 Gun4: gun Location: 67,65 Owner: Greece - Facing: 96 + Facing: 384 Gun5: gun Location: 70,63 Owner: Greece - Facing: 96 + Facing: 384 Pbox1: pbox Location: 57,70 Owner: Greece @@ -521,7 +521,7 @@ civ1: c6 Location: 53,80 Owner: Spain - Facing: 64 + Facing: 256 SubCell: 2 civ2: c7 Location: 58,79 @@ -530,19 +530,19 @@ civ3: c5 Location: 57,81 Owner: Spain - Facing: 64 + Facing: 256 SubCell: 3 Harvester: harv Location: 76,47 Owner: Greece - Facing: 160 + Facing: 640 Runner1: jeep Location: 88,83 Owner: Greece Runner2: jeep Location: 84,83 Owner: Greece - Facing: 64 + Facing: 256 GreeceCYard: waypoint Location: 59,47 Owner: Neutral diff -Nru openra-20200503/mods/ra/maps/soviet-04b/map.yaml openra-20210321/mods/ra/maps/soviet-04b/map.yaml --- openra-20200503/mods/ra/maps/soviet-04b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-04b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -364,57 +364,57 @@ Actor125: gun Location: 84,61 Owner: Greece - Facing: 192 + Facing: 768 Actor126: gun Location: 97,63 Owner: Greece - Facing: 128 + Facing: 512 Actor129: 1tnk Location: 56,71 Owner: Greece - Facing: 96 + Facing: 384 Actor130: 1tnk Location: 53,71 Owner: Greece - Facing: 96 + Facing: 384 Actor135: mcv Location: 33,90 Owner: USSR Actor136: 1tnk Location: 117,62 Owner: Greece - Facing: 96 + Facing: 384 Actor137: 1tnk Location: 114,62 Owner: Greece - Facing: 96 + Facing: 384 Actor138: 2tnk Location: 111,53 Owner: Greece - Facing: 128 + Facing: 512 Actor139: 2tnk Location: 112,53 Owner: Greece - Facing: 128 + Facing: 512 Actor142: jeep Location: 74,91 Owner: Greece Actor143: jeep Location: 48,49 Owner: Greece - Facing: 160 + Facing: 640 Actor144: 1tnk Location: 86,90 Owner: Greece - Facing: 32 + Facing: 128 Actor145: 1tnk Location: 96,86 Owner: Greece - Facing: 96 + Facing: 384 Actor146: 2tnk Location: 96,47 Owner: Greece - Facing: 160 + Facing: 640 Actor148: e1 Location: 76,57 Owner: Greece @@ -563,7 +563,7 @@ Harvester: harv Location: 93,78 Owner: Greece - Facing: 128 + Facing: 512 Tank1: 3tnk Location: 32,87 Owner: USSR @@ -579,12 +579,12 @@ civ1: c1 Location: 41,53 Owner: Spain - Facing: 160 + Facing: 640 SubCell: 0 civ2: c2 Location: 47,49 Owner: Spain - Facing: 224 + Facing: 896 SubCell: 1 civ3: c3 Location: 39,51 @@ -593,20 +593,20 @@ civ4: c4 Location: 46,52 Owner: Spain - Facing: 96 + Facing: 384 SubCell: 4 Guard1: 1tnk Location: 105,59 Owner: Greece - Facing: 64 + Facing: 256 Guard2: 1tnk Location: 105,60 Owner: Greece - Facing: 64 + Facing: 256 Guard3: 2tnk Location: 105,61 Owner: Greece - Facing: 64 + Facing: 256 NRoadPoint: waypoint Location: 75,45 Owner: Neutral diff -Nru openra-20200503/mods/ra/maps/soviet-05/map.yaml openra-20210321/mods/ra/maps/soviet-05/map.yaml --- openra-20200503/mods/ra/maps/soviet-05/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-05/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -227,7 +227,7 @@ Actor55: gun Location: 69,49 Owner: Greece - Facing: 32 + Facing: 128 RadarDome: dome Location: 70,45 Owner: France @@ -264,11 +264,11 @@ Actor67: gun Location: 61,44 Owner: Greece - Facing: 192 + Facing: 768 Actor68: gun Location: 61,48 Owner: Greece - Facing: 160 + Facing: 640 Actor69: agun Location: 68,47 Owner: Greece @@ -294,86 +294,82 @@ startmcv: mcv Location: 22,80 Owner: USSR - Facing: 192 + Facing: 768 Actor77: 2tnk Location: 59,43 Owner: Greece - Facing: 32 - TurretFacing: 32 + Facing: 128 Actor78: 1tnk Location: 58,48 Owner: Greece - Facing: 32 - TurretFacing: 32 + Facing: 128 Actor79: 1tnk Location: 57,44 Owner: Greece - Facing: 96 - TurretFacing: 96 + Facing: 384 Actor80: 1tnk Location: 67,49 Owner: Greece - Facing: 224 - TurretFacing: 224 + Facing: 896 Harvester: harv Location: 45,45 Owner: Greece - Facing: 96 + Facing: 384 mcvGG: mcv Location: 75,46 - Owner: GoodGuy - Facing: 192 + Owner: Greece + Facing: 768 Actor83: 1tnk Location: 43,47 Owner: Greece - Facing: 224 - TurretFacing: 64 + Facing: 896 + TurretFacing: 384 Actor84: e1 Location: 61,45 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 1 Actor85: e1 Location: 62,46 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 0 Actor86: e1 Location: 61,49 Owner: Greece - Facing: 224 + Facing: 896 SubCell: 2 Runner1: e1 Location: 25,75 - Owner: GoodGuy + Owner: Greece SubCell: 0 Runner2: e1 Location: 25,76 - Owner: GoodGuy + Owner: Greece SubCell: 2 Runner3: e1 Location: 26,75 - Owner: GoodGuy + Owner: Greece SubCell: 0 Actor90: e1 Location: 64,49 Owner: Greece - Facing: 96 + Facing: 384 SubCell: 2 Actor91: e3 Location: 66,44 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 4 Actor92: e3 Location: 63,49 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 4 Actor93: e1 Location: 58,46 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 2 Actor94: e1 Location: 60,48 @@ -383,100 +379,89 @@ Location: 41,45 Owner: Greece SubCell: 4 - Facing: 64 - TurretFacing: 128 + Facing: 256 + TurretFacing: 256 Actor97: e3 Location: 41,44 Owner: Greece SubCell: 1 - Facing: 96 - TurretFacing: 160 + Facing: 384 + TurretFacing: 256 Actor98: e3 Location: 40,45 Owner: Greece SubCell: 4 - Facing: 64 - TurretFacing: 160 + Facing: 256 + TurretFacing: 384 Actor99: e3 Location: 40,43 Owner: Greece SubCell: 1 - Facing: 96 - TurretFacing: 160 + Facing: 384 + TurretFacing: 256 Actor100: e1 Location: 39,45 Owner: Greece - Facing: 160 + Facing: 640 SubCell: 0 Actor101: e1 Location: 39,44 Owner: Greece SubCell: 1 - Facing: 96 - TurretFacing: 192 + Facing: 384 + TurretFacing: 384 Minelayer: mnly - Owner: GoodGuy + Owner: Greece Location: 67,45 - Facing: 92 + Facing: 368 Actor166: pt - Owner: GoodGuy + Owner: Greece Location: 67,54 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor167: pt - Owner: GoodGuy + Owner: Greece Location: 67,59 - Facing: 60 - TurretFacing: 60 + Facing: 240 Actor168: pt - Owner: GoodGuy + Owner: Greece Location: 83,56 - Facing: 28 - TurretFacing: 28 + Facing: 112 Actor169: pt - Owner: GoodGuy + Owner: Greece Location: 83,51 - Facing: 92 - TurretFacing: 92 + Facing: 368 mcvtransport: lst - Owner: GoodGuy + Owner: Greece Location: 80,45 - Facing: 92 + Facing: 368 Actor171: dd - Owner: GoodGuy + Owner: Greece Location: 91,51 - Facing: 28 - TurretFacing: 28 + Facing: 112 Actor172: dd - Owner: GoodGuy + Owner: Greece Location: 84,44 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor173: dd - Owner: GoodGuy + Owner: Greece Location: 96,44 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor174: pt - Owner: GoodGuy + Owner: Greece Location: 96,51 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor175: dd - Owner: GoodGuy + Owner: Greece Location: 101,49 - Facing: 60 - TurretFacing: 60 + Facing: 240 Actor176: pt - Owner: GoodGuy + Owner: Greece Location: 107,70 - Facing: 188 - TurretFacing: 188 + Facing: 752 Actor177: pt - Owner: GoodGuy + Owner: Greece Location: 58,89 - Facing: 60 - TurretFacing: 60 + Facing: 240 Actor181: mine Owner: Neutral Location: 63,65 diff -Nru openra-20200503/mods/ra/maps/soviet-05/rules.yaml openra-20210321/mods/ra/maps/soviet-05/rules.yaml --- openra-20200503/mods/ra/maps/soviet-05/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-05/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,6 +1,64 @@ Player: PlayerResources: DefaultCash: 5000 + ExternalCondition@luaAI: + Condition: ai-active + HarvesterBotModule: + RequiresCondition: ai-active + BuildingRepairBotModule: + RequiresCondition: ai-active + McvManagerBotModule: + RequiresCondition: ai-active + BaseBuilderBotModule@campaign: + RequiresCondition: ai-active + MinimumExcessPower: 60 + MaximumExcessPower: 160 + ExcessPowerIncrement: 40 + ExcessPowerIncreaseThreshold: 4 + ConstructionYardTypes: fact + RefineryTypes: proc + PowerTypes: powr + BarracksTypes: tent + VehiclesFactoryTypes: weap + ProductionTypes: tent, weap + SiloTypes: silo + BuildingLimits: + powr: 6 + tent: 1 + hbox: 3 + proc: 3 + weap: 1 + gun: 6 + agun: 2 + silo: 1 + BuildingFractions: + tent: 50 + hbox: 50 + proc: 90 + weap: 20 + gun: 30 + agun: 20 + silo: 10 + SquadManagerBotModule@campaign: + RequiresCondition: ai-active + SquadSize: 10 + ExcludeFromSquadsTypes: harv, mcv + NavalUnitsTypes: dd, ca, lst, pt + ConstructionYardTypes: fact + UnitBuilderBotModule@campaign: + RequiresCondition: ai-active + UnitsToBuild: + e1: 60 + e3: 30 + jeep: 50 + 1tnk: 50 + harv: 30 + UnitLimits: + e1: 20 + e3: 10 + harv: 6 + jeep: 10 + 1tnk: 10 World: LuaScript: @@ -22,10 +80,6 @@ hard: Hard Default: easy -HARV: - Harvester: - SearchFromProcRadius: 44 - MCV.CAM: Inherits: CAMERA RevealsShroud: diff -Nru openra-20200503/mods/ra/maps/soviet-05/soviet05-AI.lua openra-20210321/mods/ra/maps/soviet-05/soviet05-AI.lua --- openra-20200503/mods/ra/maps/soviet-05/soviet05-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-05/soviet05-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -6,11 +6,12 @@ the License, or (at your option) any later version. For more information, see COPYING. ]] + IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end IdlingUnits = function() local lazyUnits = Utils.Where(Map.ActorsInWorld, function(actor) - return actor.HasProperty("Hunt") and (actor.Owner == GoodGuy or actor.Owner == Greece) end) + return actor.HasProperty("Hunt") and actor.Owner == Greece end) Utils.Do(lazyUnits, function(unit) Trigger.OnDamaged(unit, function() @@ -20,64 +21,6 @@ end) end -BaseBuildings = -{ - { type = "powr", pos = CVec.New(3, -2), cost = 300 }, - { type = "tent", pos = CVec.New(0, 4), cost = 400 }, - { type = "hbox", pos = CVec.New(3, 6), cost = 600 }, - { type = "proc", pos = CVec.New(4, 2), cost = 1400 }, - { type = "powr", pos = CVec.New(5, -3), cost = 300 }, - { type = "weap", pos = CVec.New(-5, 3), cost = 2000 }, - { type = "hbox", pos = CVec.New(-6, 5), cost = 600 }, - { type = "gun", pos = CVec.New(0, 8), cost = 600 }, - { type = "gun", pos = CVec.New(-4, 7), cost = 600 }, - { type = "powr", pos = CVec.New(-4, -3), cost = 300 }, - { type = "proc", pos = CVec.New(-9, 1), cost = 1400 }, - { type = "powr", pos = CVec.New(-8, -2), cost = 300 }, - { type = "silo", pos = CVec.New(6, 0), cost = 150 }, - { type = "agun", pos = CVec.New(-3, 0), cost = 800 }, - { type = "powr", pos = CVec.New(-6, -2), cost = 300 }, - { type = "agun", pos = CVec.New(4, 1), cost = 800 }, - { type = "gun", pos = CVec.New(-9, 5), cost = 600 }, - { type = "gun", pos = CVec.New(-2, -3), cost = 600 }, - { type = "powr", pos = CVec.New(4, 6), cost = 300 }, - { type = "gun", pos = CVec.New(3, -6), cost = 600 }, - { type = "hbox", pos = CVec.New(3, -4), cost = 600 }, - { type = "gun", pos = CVec.New(2, 3), cost = 600 } -} - -BuildBase = function() - if not CheckForCYard() then - return - end - - for i,v in ipairs(BaseBuildings) do - if not v.exists then - BuildBuilding(v) - return - end - end - - Trigger.AfterDelay(DateTime.Seconds(5), BuildBase) -end - -BuildBuilding = function(building) - Trigger.AfterDelay(Actor.BuildTime(building.type), function() - local actor = Actor.Create(building.type, true, { Owner = GoodGuy, Location = MCVDeploy.Location + building.pos }) - GoodGuy.Cash = GoodGuy.Cash - building.cost - - building.exists = true - Trigger.OnKilled(actor, function() building.exists = false end) - Trigger.OnDamaged(actor, function(building) - if building.Owner == GoodGuy and building.Health < building.MaxHealth * 3/4 then - building.StartBuildingRepairs() - end - end) - - Trigger.AfterDelay(DateTime.Seconds(1), BuildBase) - end) -end - ProduceInfantry = function() if Barr.IsDead then return @@ -115,46 +58,6 @@ end end) end - -ProduceInfantryGG = function() - if not BaseBuildings[2][4] then - return - end - - local delay = Utils.RandomInteger(DateTime.Seconds(3), DateTime.Seconds(9)) - local toBuild = { Utils.Random(AlliedInfantryTypes) } - GoodGuy.Build(toBuild, function(unit) - GGInfAttack[#GGInfAttack + 1] = unit[1] - - if #GGInfAttack >= 10 then - SendUnits(GGInfAttack, InfantryGGWaypoints) - GGInfAttack = { } - Trigger.AfterDelay(DateTime.Minutes(2), ProduceInfantryGG) - else - Trigger.AfterDelay(delay, ProduceInfantryGG) - end - end) -end - -ProduceTanksGG = function() - if not BaseBuildings[6][4] then - return - end - - local delay = Utils.RandomInteger(DateTime.Seconds(12), DateTime.Seconds(17)) - local toBuild = { Utils.Random(AlliedTankTypes) } - GoodGuy.Build(toBuild, function(unit) - TankAttackGG[#TankAttackGG + 1] = unit[1] - - if #TankAttackGG >= 6 then - SendUnits(TankAttackGG, TanksGGWaypoints) - TankAttackGG = { } - Trigger.AfterDelay(DateTime.Minutes(3), ProduceTanksGG) - else - Trigger.AfterDelay(delay, ProduceTanksGG) - end - end) -end SendUnits = function(units, waypoints) Utils.Do(units, function(unit) diff -Nru openra-20200503/mods/ra/maps/soviet-05/soviet05.lua openra-20210321/mods/ra/maps/soviet-05/soviet05.lua --- openra-20200503/mods/ra/maps/soviet-05/soviet05.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-05/soviet05.lua 2021-03-21 11:10:05.000000000 +0000 @@ -100,39 +100,31 @@ mcvtransport.Move(GGUnloadPoint.Location) mcvtransport.UnloadPassengers() - Trigger.AfterDelay(DateTime.Seconds(12), function() + mcvtransport.CallFunc(function() if mcvGG.IsDead then return end mcvGG.Move(MCVDeploy.Location) - Trigger.AfterDelay(DateTime.Seconds(4), function() - if not mcvGG.IsDead then - mcvGG.Deploy() - Trigger.AfterDelay(DateTime.Seconds(4), function() - local fact = Map.ActorsInBox(mcvGGLoadPoint.CenterPosition, ReinfEastPoint.CenterPosition, function(actor) - return actor.Type == "fact" and actor.Owner == GoodGuy end) - if #fact == 0 then - return - else - Trigger.OnDamaged(fact[1], function() - if fact[1].Owner == GoodGuy and fact[1].Health < fact[1].MaxHealth * 3/4 then - fact[1].StartBuildingRepairs() - end - end) - end - end) + mcvGG.CallFunc(function() + + -- Avoid crashing through modifying the actor list from mcvGG's tick + Trigger.AfterDelay(0, function() + mcvGG.Owner = GoodGuy IslandTroops1() Trigger.AfterDelay(DateTime.Minutes(3), IslandTroops2) Trigger.AfterDelay(DateTime.Minutes(6), IslandTroops3) - Trigger.AfterDelay(DateTime.Seconds(7), BuildBase) - end - if not mcvtransport.IsDead then - mcvtransport.Move(ReinfNorthPoint.Location) - mcvtransport.Destroy() - end + if not mcvtransport.IsDead then + mcvtransport.Move(ReinfNorthPoint.Location) + mcvtransport.Destroy() + end + end) + + Trigger.AfterDelay(DateTime.Seconds(1), function() + GoodGuy.GrantCondition("ai-active") + end) end) end) end) @@ -263,8 +255,6 @@ Trigger.RemoveProximityTrigger(id) Para2() - ProduceInfantryGG() - ProduceTanksGG() local units = Reinforcements.ReinforceWithTransport(player, "lst", SovietMCVReinf, { ReinfSouthPoint.Location, USSRlstPoint.Location }, { ReinfSouthPoint.Location })[2] Utils.Do(units, function(unit) diff -Nru openra-20200503/mods/ra/maps/soviet-05/soviet05-reinforcements_teams.lua openra-20210321/mods/ra/maps/soviet-05/soviet05-reinforcements_teams.lua --- openra-20200503/mods/ra/maps/soviet-05/soviet05-reinforcements_teams.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-05/soviet05-reinforcements_teams.lua 2021-03-21 11:10:05.000000000 +0000 @@ -6,6 +6,7 @@ the License, or (at your option) any later version. For more information, see COPYING. ]] + SovietStartReinf = { "e2", "e2" } SovietStartToBasePath = { StartPoint.Location, SovietBasePoint.Location } SovietMCVReinf = { "mcv", "3tnk", "3tnk", "e1", "e1" } @@ -46,13 +47,13 @@ Para = function() local powerproxy = Actor.Create("powerproxy.paratroopers", false, { Owner = player }) - powerproxy.ActivateParatroopers(ParaPoint.CenterPosition, 28) + powerproxy.TargetParatroopers(ParaPoint.CenterPosition, Angle.New(112)) powerproxy.Destroy() end Para2 = function() local powerproxy = Actor.Create("powerproxy.paratroopers", false, { Owner = player }) - powerproxy.ActivateParatroopers(USSRExpansionPoint.CenterPosition, 28) + powerproxy.TargetParatroopers(USSRExpansionPoint.CenterPosition, Angle.New(112)) powerproxy.Destroy() end @@ -92,7 +93,7 @@ end IslandTroops2 = function() - local units = Reinforcements.ReinforceWithTransport(GoodGuy, "lst", ArmorReinfGreece, NorthReinfPath, { ReinfEastPoint.Location })[2] + local units = Reinforcements.ReinforceWithTransport(Greece, "lst", ArmorReinfGreece, NorthReinfPath, { ReinfEastPoint.Location })[2] Utils.Do(units, function(unit) Trigger.OnIdle(unit, function(patrols) patrols.Patrol(GoodGuyOrefieldPatrolPath, true, 150) @@ -114,7 +115,7 @@ end IslandTroops3 = function() - local units = Reinforcements.ReinforceWithTransport(GoodGuy, "lst", SovExpansionPointGuard, SouthReinfPath, { ReinfEastPoint.Location })[2] + local units = Reinforcements.ReinforceWithTransport(Greece, "lst", SovExpansionPointGuard, SouthReinfPath, { ReinfEastPoint.Location })[2] Utils.Do(units, function(unit) Trigger.OnIdle(unit, function(guards) guards.AttackMove(USSRExpansionPoint.Location) diff -Nru openra-20200503/mods/ra/maps/soviet-06a/map.yaml openra-20210321/mods/ra/maps/soviet-06a/map.yaml --- openra-20200503/mods/ra/maps/soviet-06a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-06a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -521,11 +521,11 @@ Actor158: gun Location: 20,23 Owner: Greece - Facing: 128 + Facing: 512 Actor159: gun Location: 28,23 Owner: Greece - Facing: 128 + Facing: 512 Actor163: gap Location: 24,22 Owner: Greece @@ -535,11 +535,11 @@ Actor167: gun Location: 33,5 Owner: Greece - Facing: 192 + Facing: 768 Actor168: gun Location: 33,9 Owner: Greece - Facing: 192 + Facing: 768 Actor169: v07 Location: 66,4 Owner: Greece @@ -566,123 +566,123 @@ Actor179: 2tnk Location: 73,35 Owner: Greece - Facing: 160 + Facing: 640 Actor180: 2tnk Location: 72,34 Owner: Greece - Facing: 160 + Facing: 640 Actor181: 2tnk Location: 71,33 Owner: Greece - Facing: 160 + Facing: 640 Actor182: arty Location: 74,33 Owner: Greece - Facing: 160 + Facing: 640 Actor183: arty Location: 73,32 Owner: Greece - Facing: 160 + Facing: 640 Actor186: 3tnk Location: 56,47 Owner: USSR - Facing: 32 + Facing: 128 Actor187: 3tnk Location: 60,49 Owner: USSR - Facing: 32 + Facing: 128 Actor191: v2rl Location: 57,49 Owner: USSR - Facing: 32 + Facing: 128 Actor193: 2tnk Location: 73,31 Owner: Greece - Facing: 160 + Facing: 640 Actor194: 2tnk Location: 75,33 Owner: Greece - Facing: 160 + Facing: 640 Actor195: 2tnk Location: 85,18 Owner: Greece - Facing: 160 + Facing: 640 Actor196: 2tnk Location: 88,20 Owner: Greece - Facing: 160 + Facing: 640 Actor197: 2tnk Location: 22,23 Owner: Greece - Facing: 128 + Facing: 512 Actor198: 2tnk Location: 26,23 Owner: Greece - Facing: 128 + Facing: 512 Actor199: arty Location: 18,23 Owner: Greece - Facing: 96 + Facing: 384 Actor200: arty Location: 30,23 Owner: Greece - Facing: 160 + Facing: 640 Actor202: 1tnk Location: 23,21 Owner: Greece - Facing: 128 + Facing: 512 Actor203: 1tnk Location: 25,21 Owner: Greece - Facing: 128 + Facing: 512 Actor204: 2tnk Location: 40,6 Owner: Greece - Facing: 192 + Facing: 768 Actor205: 2tnk Location: 40,8 Owner: Greece - Facing: 192 + Facing: 768 Actor206: arty Location: 40,7 Owner: Greece - Facing: 192 + Facing: 768 Actor207: 1tnk Location: 77,10 Owner: Greece - Facing: 192 + Facing: 768 Actor208: 1tnk Location: 77,11 Owner: Greece - Facing: 192 + Facing: 768 Actor209: 1tnk Location: 77,12 Owner: Greece - Facing: 192 + Facing: 768 Actor210: ca Location: 87,29 Owner: Greece - Facing: 224 + Facing: 896 Actor211: ca Location: 87,25 Owner: Greece - Facing: 160 + Facing: 640 Actor212: ca Location: 76,22 Owner: Greece - Facing: 224 + Facing: 896 Actor213: pt Location: 38,4 Owner: Greece - Facing: 192 + Facing: 768 Actor214: pt Location: 38,10 Owner: Greece - Facing: 192 + Facing: 768 Actor215: dd Location: 55,15 Owner: Greece - Facing: 192 + Facing: 768 Actor216: waypoint Location: 39,13 Owner: Neutral @@ -716,7 +716,7 @@ AGun: agun Owner: Greece Location: 25,5 - TurretFacing: 92 + TurretFacing: 368 APCWaypoint1: waypoint Location: 52,50 Owner: Neutral @@ -741,11 +741,11 @@ BaseAttacker1: 1tnk Location: 76,35 Owner: Greece - Facing: 160 + Facing: 640 BaseAttacker2: 1tnk Location: 71,30 Owner: Greece - Facing: 160 + Facing: 640 CameraBarrier: camera Location: 70,36 Owner: Neutral @@ -792,21 +792,21 @@ Location: 63,42 Owner: Greece Health: 28 - Facing: 160 + Facing: 640 IntroEnemy2: jeep Location: 64,42 Owner: Greece Health: 43 - Facing: 160 + Facing: 640 IntroEnemy3: 1tnk Location: 64,43 Owner: Greece Health: 50 - Facing: 160 + Facing: 640 Mcv: mcv Location: 61,45 Owner: USSR - Facing: 96 + Facing: 384 McvWaypoint: waypoint Location: 53,53 Owner: Neutral @@ -817,11 +817,11 @@ Truck1: truk Location: 54,52 Owner: USSR - Facing: 32 + Facing: 128 Truck2: truk Location: 55,51 Owner: USSR - Facing: 32 + Facing: 128 Weap: weap Location: 22,15 Owner: Greece diff -Nru openra-20200503/mods/ra/maps/soviet-06a/rules.yaml openra-20210321/mods/ra/maps/soviet-06a/rules.yaml --- openra-20200503/mods/ra/maps/soviet-06a/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-06a/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -142,11 +142,6 @@ Buildable: Prerequisites: ~disabled -HARV: - Harvester: - SearchFromProcRadius: 50 - SearchFromHarvesterRadius: 50 - AFLD: ParatroopersPower@paratroopers: DropItems: E1,E1,E1,E1,E1 diff -Nru openra-20200503/mods/ra/maps/soviet-06b/map.yaml openra-20210321/mods/ra/maps/soviet-06b/map.yaml --- openra-20200503/mods/ra/maps/soviet-06b/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-06b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -287,95 +287,95 @@ Actor92: gun Location: 57,46 Owner: Greece - Facing: 160 + Facing: 640 Actor93: gun Location: 61,48 Owner: Greece - Facing: 160 + Facing: 640 Actor103: 2tnk Location: 76,30 Owner: Greece - Facing: 160 + Facing: 640 Actor104: 2tnk Location: 76,29 Owner: Greece - Facing: 160 + Facing: 640 Actor106: arty Location: 63,47 Owner: Greece - Facing: 160 + Facing: 640 Actor107: arty Location: 58,44 Owner: Greece - Facing: 160 + Facing: 640 Actor110: 3tnk Location: 43,63 Owner: USSR - Facing: 32 + Facing: 128 Actor111: 3tnk Location: 44,62 Owner: USSR - Facing: 32 + Facing: 128 Actor112: v2rl Location: 41,64 Owner: USSR - Facing: 32 + Facing: 128 Actor113: v2rl Location: 43,64 Owner: USSR - Facing: 32 + Facing: 128 Actor115: 2tnk Location: 75,30 Owner: Greece - Facing: 160 + Facing: 640 Actor116: 2tnk Location: 75,31 Owner: Greece - Facing: 160 + Facing: 640 Actor117: 2tnk Location: 83,20 Owner: Greece - Facing: 160 + Facing: 640 Actor118: 2tnk Location: 88,21 Owner: Greece - Facing: 160 + Facing: 640 Actor119: 2tnk Location: 62,44 Owner: Greece - Facing: 160 + Facing: 640 Actor120: 1tnk Location: 59,44 Owner: Greece - Facing: 160 + Facing: 640 Actor121: 1tnk Location: 63,46 Owner: Greece - Facing: 160 + Facing: 640 Actor123: ca Location: 87,29 Owner: Greece - Facing: 224 + Facing: 896 Actor124: ca Location: 87,31 Owner: Greece - Facing: 160 + Facing: 640 Actor125: ca Location: 75,25 Owner: Greece - Facing: 224 + Facing: 896 Actor126: pt Location: 71,16 Owner: Greece - Facing: 224 + Facing: 896 Actor127: pt Location: 65,20 Owner: Greece - Facing: 224 + Facing: 896 Actor128: dd Location: 70,20 Owner: Greece - Facing: 224 + Facing: 896 Actor129: waypoint Location: 46,60 Owner: Neutral @@ -418,7 +418,7 @@ AGun: agun Owner: Greece Location: 69,49 - TurretFacing: 92 + TurretFacing: 368 APCWaypoint1: waypoint Location: 39,62 Owner: Neutral @@ -470,20 +470,20 @@ IntroEnemy1: 1tnk Location: 55,49 Owner: Greece - Facing: 160 + Facing: 640 IntroEnemy2: 2tnk Location: 56,50 Owner: Greece - Facing: 160 + Facing: 640 IntroEnemy3: 1tnk Location: 58,50 Owner: Greece - Facing: 160 + Facing: 640 Mcv: mcv Location: 51,55 Owner: USSR Health: 82 - Facing: 160 + Facing: 640 McvWaypoint: waypoint Location: 39,67 Owner: Neutral @@ -494,11 +494,11 @@ Truck1: truk Location: 42,66 Owner: USSR - Facing: 32 + Facing: 128 Truck2: truk Location: 39,65 Owner: USSR - Facing: 32 + Facing: 128 Weap: weap Location: 67,41 Owner: Greece diff -Nru openra-20200503/mods/ra/maps/soviet-06b/rules.yaml openra-20210321/mods/ra/maps/soviet-06b/rules.yaml --- openra-20200503/mods/ra/maps/soviet-06b/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-06b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -142,11 +142,6 @@ Buildable: Prerequisites: ~disabled -HARV: - Harvester: - SearchFromProcRadius: 50 - SearchFromHarvesterRadius: 50 - AFLD: ParatroopersPower@paratroopers: DropItems: E1,E1,E1,E1,E1 diff -Nru openra-20200503/mods/ra/maps/soviet-07/map.yaml openra-20210321/mods/ra/maps/soviet-07/map.yaml --- openra-20200503/mods/ra/maps/soviet-07/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-07/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -443,12 +443,12 @@ Actor150: e1 Location: 84,67 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 4 Actor172: e1 Location: 77,80 Owner: Greece - Facing: 224 + Facing: 896 SubCell: 2 Actor214: healcrate Owner: Neutral @@ -519,33 +519,33 @@ CCGuard1: e1 Location: 87,67 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 3 CCGuard2: e1 Location: 88,67 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 4 CCGuard3: e1 Location: 88,68 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 1 CCGuard4: e1 Location: 87,68 Owner: Greece - Facing: 192 + Facing: 768 SubCell: 3 Dog1: dog Location: 84,84 Owner: Soviet - Facing: 224 + Facing: 896 SubCell: 1 Dog2: dog Owner: Soviet Location: 84,83 SubCell: 3 - Facing: 92 + Facing: 368 Dog3: dog Location: 82,83 Owner: Soviet @@ -553,27 +553,27 @@ Dog4: dog Location: 80,83 Owner: Soviet - Facing: 64 + Facing: 256 SubCell: 2 Dog5: dog Location: 85,82 Owner: Soviet - Facing: 224 + Facing: 896 SubCell: 1 Dog6: dog Location: 85,79 Owner: Soviet - Facing: 192 + Facing: 768 SubCell: 4 Dog7: dog Location: 85,81 Owner: Soviet - Facing: 192 + Facing: 768 SubCell: 4 Dog8: dog Location: 86,83 Owner: Soviet - Facing: 224 + Facing: 896 SubCell: 1 Dog9: dog Location: 86,84 @@ -582,12 +582,12 @@ Dog10: dog Location: 86,82 Owner: Soviet - Facing: 192 + Facing: 768 SubCell: 0 Dog11: dog Location: 82,84 Owner: Soviet - Facing: 32 + Facing: 128 SubCell: 1 Dog12: dog Location: 83,84 @@ -596,7 +596,7 @@ Dog13: dog Location: 86,81 Owner: Soviet - Facing: 32 + Facing: 128 SubCell: 1 Dog14: dog Location: 85,83 @@ -621,7 +621,7 @@ Dog19: dog Location: 86,79 Owner: Soviet - Facing: 224 + Facing: 896 SubCell: 0 EntranceGuard1: e1 Location: 100,57 @@ -658,27 +658,27 @@ Tanya: e7 Location: 75,54 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 2 GoalGuard1: e1 Location: 74,54 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 2 GoalGuard2: e1 Location: 73,54 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 2 GoalGuard3: e1 Location: 76,54 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 2 GoalGuard4: e1 Location: 77,54 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 2 FTurBottom: ftur Location: 62,79 @@ -707,27 +707,27 @@ Prisoner1: e6 Location: 44,46 Owner: Soviet - Facing: 160 + Facing: 640 SubCell: 4 Prisoner2: e6 Location: 44,47 Owner: Soviet - Facing: 128 + Facing: 512 SubCell: 4 Prisoner3: e6 Location: 46,47 Owner: Soviet - Facing: 96 + Facing: 384 SubCell: 0 Prisoner4: e6 Location: 45,47 Owner: Soviet - Facing: 96 + Facing: 384 SubCell: 1 Prisoner5: e6 Location: 46,46 Owner: Soviet - Facing: 128 + Facing: 512 SubCell: 3 Prisoner6: e1 Location: 46,46 @@ -737,7 +737,7 @@ PrisonEntranceGuard: e1 Location: 46,69 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 1 PrisonerGuard1: e1 Location: 45,48 @@ -746,25 +746,23 @@ PrisonerGuard2: e1 Location: 46,49 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 0 PrisonerGuard3: e1 Location: 44,49 Owner: Greece - Facing: 128 + Facing: 512 SubCell: 0 RSoldier1: e3 Owner: Greece Location: 65,72 SubCell: 3 - Facing: 92 - TurretFacing: 92 + Facing: 368 RSoldier2: e3 Location: 65,74 Owner: Greece - Facing: 92 + Facing: 368 SubCell: 2 - TurretFacing: 92 RSoldierTrap1: brl3 Owner: Creeps Location: 68,72 diff -Nru openra-20200503/mods/ra/maps/soviet-08a/map.yaml openra-20210321/mods/ra/maps/soviet-08a/map.yaml --- openra-20200503/mods/ra/maps/soviet-08a/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-08a/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -532,7 +532,7 @@ Actor159: gun Location: 70,69 Owner: Germany - Facing: 159 + Facing: 636 Actor160: weaf Location: 71,65 Owner: Germany @@ -623,135 +623,135 @@ Actor189: jeep Location: 85,92 Owner: Germany - Facing: 191 + Facing: 764 Actor190: 2tnk Location: 55,49 Owner: Greece - Facing: 159 + Facing: 636 Actor191: 2tnk Location: 58,47 Owner: Greece - Facing: 159 + Facing: 636 Actor192: 2tnk Location: 42,69 Owner: Greece - Facing: 127 + Facing: 508 Actor193: 2tnk Location: 44,69 Owner: Greece - Facing: 127 + Facing: 508 Actor194: 2tnk Location: 43,52 Owner: Greece - Facing: 127 + Facing: 508 Actor195: 2tnk Location: 39,52 Owner: Greece - Facing: 127 + Facing: 508 Actor196: 2tnk Location: 67,43 Owner: Greece - Facing: 191 + Facing: 764 Actor197: 2tnk Location: 67,45 Owner: Greece - Facing: 191 + Facing: 764 Actor198: jeep Location: 57,42 Owner: Greece - Facing: 159 + Facing: 636 Actor199: jeep Location: 54,46 Owner: Greece - Facing: 159 + Facing: 636 Actor200: jeep Location: 41,51 Owner: Greece - Facing: 127 + Facing: 508 Actor201: jeep Location: 61,44 Owner: Greece - Facing: 191 + Facing: 764 Actor202: arty Location: 42,67 Owner: Greece - Facing: 127 + Facing: 508 Actor203: arty Location: 45,67 Owner: Greece - Facing: 95 + Facing: 380 Actor204: arty Location: 63,44 Owner: Greece - Facing: 191 + Facing: 764 Actor205: arty Location: 56,46 Owner: Greece - Facing: 159 + Facing: 636 Actor206: arty Location: 40,50 Owner: Greece - Facing: 159 + Facing: 636 Actor207: jeep Location: 72,72 Owner: Germany - Facing: 159 + Facing: 636 Actor208: jeep Location: 84,70 Owner: Germany - Facing: 159 + Facing: 636 Actor209: 1tnk Location: 57,96 Owner: Germany - Facing: 191 + Facing: 764 Actor210: 1tnk Location: 73,68 Owner: Germany - Facing: 127 + Facing: 508 Actor211: 2tnk Location: 43,68 Owner: Greece - Facing: 127 + Facing: 508 Actor212: 2tnk Location: 60,65 Owner: Greece - Facing: 159 + Facing: 636 Actor213: 2tnk Location: 61,64 Owner: Greece - Facing: 127 + Facing: 508 Actor214: 2tnk Location: 63,65 Owner: Greece - Facing: 95 + Facing: 380 Actor215: 2tnk Location: 62,64 Owner: Greece - Facing: 127 + Facing: 508 Actor216: e1 Location: 86,91 Owner: Germany - Facing: 159 + Facing: 636 SubCell: 4 Actor217: e1 Location: 86,92 Owner: Germany - Facing: 159 + Facing: 636 SubCell: 3 Actor218: e1 Location: 87,91 Owner: Germany - Facing: 191 + Facing: 764 SubCell: 4 Actor219: e1 Location: 86,93 Owner: Germany - Facing: 159 + Facing: 636 SubCell: 4 Actor220: e1 Location: 88,91 Owner: USSR - Facing: 95 + Facing: 380 SubCell: 4 Actor221: e1 Location: 88,93 @@ -760,82 +760,82 @@ Actor222: e1 Location: 87,92 Owner: USSR - Facing: 63 + Facing: 252 SubCell: 4 Actor223: e1 Location: 78,68 Owner: Germany - Facing: 159 + Facing: 636 SubCell: 1 Actor224: e1 Location: 74,69 Owner: Germany - Facing: 159 + Facing: 636 SubCell: 2 Actor225: e3 Location: 70,66 Owner: Germany - Facing: 159 + Facing: 636 SubCell: 2 Actor226: e3 Location: 85,72 Owner: Germany - Facing: 159 + Facing: 636 SubCell: 2 Actor227: e3 Location: 88,72 Owner: Germany - Facing: 95 + Facing: 380 SubCell: 4 Actor228: e3 Location: 87,72 Owner: Germany - Facing: 223 + Facing: 892 SubCell: 3 Actor229: e3 Location: 66,97 Owner: Germany - Facing: 191 + Facing: 764 SubCell: 2 Actor230: e3 Location: 66,99 Owner: Germany - Facing: 223 + Facing: 892 SubCell: 2 Actor231: e1 Location: 60,85 Owner: Germany - Facing: 191 + Facing: 764 SubCell: 3 Actor232: e1 Location: 60,84 Owner: Germany - Facing: 191 + Facing: 764 SubCell: 4 Actor233: e3 Location: 72,74 Owner: Germany - Facing: 159 + Facing: 636 SubCell: 3 Actor234: e3 Location: 76,74 Owner: Germany - Facing: 95 + Facing: 380 SubCell: 4 Actor235: e3 Location: 57,97 Owner: Germany - Facing: 191 + Facing: 764 SubCell: 1 Actor236: e1 Location: 86,63 Owner: Germany - Facing: 159 + Facing: 636 SubCell: 4 Actor237: e1 Location: 92,68 Owner: Germany - Facing: 95 + Facing: 380 SubCell: 2 Actor238: c3 Location: 83,64 @@ -844,12 +844,12 @@ Actor239: c4 Location: 95,62 Owner: Germany - Facing: 159 + Facing: 636 SubCell: 3 Actor240: c5 Location: 90,67 Owner: Germany - Facing: 95 + Facing: 380 SubCell: 4 Actor241: c6 Location: 84,67 @@ -862,17 +862,17 @@ Actor243: c1 Location: 90,60 Owner: Germany - Facing: 95 + Facing: 380 SubCell: 3 Actor244: e3 Location: 60,64 Owner: Greece - Facing: 159 + Facing: 636 SubCell: 1 Actor245: e3 Location: 63,64 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 0 Actor246: c2 Location: 88,61 @@ -904,51 +904,51 @@ Actor253: ss Location: 101,94 Owner: USSR - Facing: 191 + Facing: 764 Actor254: ss Location: 101,93 Owner: USSR - Facing: 223 + Facing: 892 Actor255: ss Location: 101,96 Owner: USSR - Facing: 191 + Facing: 764 Actor256: ss Location: 101,97 Owner: USSR - Facing: 159 + Facing: 636 Actor257: ss Location: 100,97 Owner: USSR - Facing: 127 - Actor258: pt + Facing: 508 + Boat1: pt Location: 19,26 Owner: Greece - Facing: 191 - Actor259: pt + Facing: 764 + Boat2: pt Location: 19,58 Owner: Greece - Facing: 159 - Actor260: pt + Facing: 636 + Boat3: pt Location: 49,109 Owner: Greece - Facing: 223 - Actor261: pt + Facing: 892 + Boat4: pt Location: 109,75 Owner: Greece - Facing: 31 - Actor262: pt + Facing: 124 + Boat5: pt Location: 109,31 Owner: Greece - Facing: 63 - Actor263: pt + Facing: 252 + Boat6: pt Location: 69,18 Owner: Greece - Facing: 63 - Actor264: dd + Facing: 252 + Boat7: dd Location: 48,23 Owner: Greece - Facing: 159 + Facing: 636 Oreref: proc Owner: Greece Location: 43,38 @@ -1063,5 +1063,8 @@ DDPatrol2Point7: waypoint Location: 97,78 Owner: Neutral + BoatRally: waypoint + Location: 97,93 + Owner: Neutral Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/ra/maps/soviet-08a/soviet08a-AI.lua openra-20210321/mods/ra/maps/soviet-08a/soviet08a-AI.lua --- openra-20200503/mods/ra/maps/soviet-08a/soviet08a-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-08a/soviet08a-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -8,8 +8,7 @@ ]] IdlingUnits = { } -DDPatrol1 = { "dd", "dd" } -DDPatrol2 = { "dd", "dd" } +DDPatrol = { "dd", "dd" } DDPatrol1Path = { DDPatrol1Point1.Location, DDPatrol1Point2.Location, DDPatrol1Point3.Location, DDPatrol1Point4.Location, DDPatrol1Point5.Location, DDPatrol1Point6.Location } DDPatrol2Path = { DDPatrol2Point1.Location, DDPatrol2Point2.Location, DDPatrol2Point3.Location, DDPatrol2Point4.Location, DDPatrol2Point5.Location, DDPatrol2Point6.Location, DDPatrol2Point7.Location } ShipArrivePath = { DDEntry.Location, DDEntryStop.Location } @@ -33,9 +32,9 @@ WTransDelays = { - easy = 5, - normal = 3, - hard = 2 + easy = DateTime.Minutes(5), + normal = DateTime.Minutes(3), + hard = DateTime.Minutes(2) } AttackGroup = { } @@ -62,7 +61,7 @@ WTransWaves = function() local way = Utils.Random(WTransWays) local units = Utils.Random(WTransUnits) - local attackUnits = Reinforcements.ReinforceWithTransport(greece, "lst", units , way, { way[2], way[1] })[2] + local attackUnits = Reinforcements.ReinforceWithTransport(Greece, "lst", units , way, { way[2], way[1] })[2] Utils.Do(attackUnits, function(a) Trigger.OnAddedToWorld(a, function() a.AttackMove(SovietStart.Location) @@ -70,7 +69,7 @@ end) end) - Trigger.AfterDelay(DateTime.Minutes(WTransDelays), WTransWaves) + Trigger.AfterDelay(WTransDelays, WTransWaves) end SendAttackGroup = function() @@ -88,11 +87,11 @@ end ProduceInfantry = function() - if (GreeceTent1.IsDead or GreeceTent1.Owner ~= greece) and (GreeceTent2.IsDead or GreeceTent2.Owner ~= greece) then + if (GreeceTent1.IsDead or GreeceTent1.Owner ~= Greece) and (GreeceTent2.IsDead or GreeceTent2.Owner ~= Greece) then return end - greece.Build({ Utils.Random(AlliedInfantry) }, function(units) + Greece.Build({ Utils.Random(AlliedInfantry) }, function(units) table.insert(AttackGroup, units[1]) SendAttackGroup() Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceInfantry) @@ -100,55 +99,36 @@ end ProduceVehicles = function() - if GreeceWarFactory.IsDead or GreeceWarFactory.Owner ~= greece then + if GreeceWarFactory.IsDead or GreeceWarFactory.Owner ~= Greece then return end - greece.Build({ Utils.Random(AlliedVehicles[AlliedVehicleType]) }, function(units) + Greece.Build({ Utils.Random(AlliedVehicles[AlliedVehicleType]) }, function(units) table.insert(AttackGroup, units[1]) SendAttackGroup() Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceVehicles) end) end -BringDDPatrol1 = function() - local units = Reinforcements.Reinforce(greece, DDPatrol1, ShipArrivePath, 0) +BringDDPatrol = function(patrolPath) + local units = Reinforcements.Reinforce(Greece, DDPatrol, ShipArrivePath) Utils.Do(units, function(unit) Trigger.OnIdle(unit, function(patrols) - patrols.Patrol(DDPatrol1Path, true, 200) + patrols.Patrol(patrolPath, true, 200) end) end) - if GreeceNavalYard.IsDead then - return - else - Trigger.OnAllKilled(units, function() - if Map.LobbyOption("difficulty") == "easy" then - Trigger.AfterDelay(DateTime.Minutes(7), BringDDPatrol1) - else - Trigger.AfterDelay(DateTime.Minutes(4), BringDDPatrol1) - end - end) - end -end -BringDDPatrol2 = function() - local units = Reinforcements.Reinforce(greece, DDPatrol2, ShipArrivePath, 0) - Utils.Do(units, function(unit) - Trigger.OnIdle(unit, function(patrols) - patrols.Patrol(DDPatrol2Path, true, 200) - end) - end) - if GreeceNavalYard.IsDead then - return - else - Trigger.OnAllKilled(units, function() + Trigger.OnAllKilled(units, function() + if GreeceNavalYard.IsDead then + return + else if Map.LobbyOption("difficulty") == "easy" then - Trigger.AfterDelay(DateTime.Minutes(7), BringDDPatrol2) + Trigger.AfterDelay(DateTime.Minutes(7), function() BringDDPatrol(patrolPath) end) else - Trigger.AfterDelay(DateTime.Minutes(4), BringDDPatrol2) + Trigger.AfterDelay(DateTime.Minutes(4), function() BringDDPatrol(patrolPath) end) end - end) - end + end + end) end ActivateAI = function() @@ -156,10 +136,10 @@ WTransUnits = WTransUnits[difficulty] WTransDelays = WTransDelays[difficulty] - local buildings = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == greece and self.HasProperty("StartBuildingRepairs") end) + local buildings = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == Greece and self.HasProperty("StartBuildingRepairs") end) Utils.Do(buildings, function(actor) Trigger.OnDamaged(actor, function(building) - if building.Owner == greece and building.Health < building.MaxHealth * 3/4 then + if building.Owner == Greece and building.Health < building.MaxHealth * 3/4 then building.StartBuildingRepairs() end end) @@ -167,10 +147,10 @@ Trigger.AfterDelay(DateTime.Minutes(3), WTransWaves) - Trigger.AfterDelay(AlliedVehiclesUpgradeDelay, function() AlliedVehicleType = "Upgraded" end) + Trigger.AfterDelay(AlliedVehiclesUpgradeDelay, function() AlliedVehicleType = "Upgraded" end) ProduceInfantry() ProduceVehicles() - BringDDPatrol1() - Trigger.AfterDelay(DateTime.Minutes(1), BringDDPatrol2) + BringDDPatrol(DDPatrol1Path) + Trigger.AfterDelay(DateTime.Minutes(1), function() BringDDPatrol(DDPatrol2Path) end) end diff -Nru openra-20200503/mods/ra/maps/soviet-08a/soviet08a.lua openra-20210321/mods/ra/maps/soviet-08a/soviet08a.lua --- openra-20200503/mods/ra/maps/soviet-08a/soviet08a.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-08a/soviet08a.lua 2021-03-21 11:10:05.000000000 +0000 @@ -6,9 +6,9 @@ the License, or (at your option) any later version. For more information, see COPYING. ]] -alliedScouts = { Actor189, Actor216, Actor217, Actor218, Actor219 } +AlliedScouts = { Actor189, Actor216, Actor217, Actor218, Actor219 } -ussrReinforcements = +SovReinforcements = { east = { @@ -30,66 +30,58 @@ } } -Obj2ActorTriggerActivator = { Church, Actor147, Actor148, Actor149, Actor150, Actor151, Actor152, Actor153 } +Village = { Church, Actor147, Actor148, Actor149, Actor150, Actor151, Actor152, Actor153 } ActivateAIDelay = DateTime.Seconds(45) AddEastReinforcementTrigger = function() Trigger.AfterDelay(DateTime.Seconds(30), function() - Media.PlaySpeechNotification(ussr, "ReinforcementsArrived") - local reinforcement = ussrReinforcements.east - Reinforcements.ReinforceWithTransport(ussr, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + local reinforcement = SovReinforcements.east + Reinforcements.ReinforceWithTransport(USSR, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) end) end AddSouthReinforcementTrigger = function() Trigger.AfterDelay(DateTime.Seconds(60), function() - Media.PlaySpeechNotification(ussr, "ReinforcementsArrived") - local reinforcement = ussrReinforcements.south - Reinforcements.ReinforceWithTransport(ussr, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + local reinforcement = SovReinforcements.south + Reinforcements.ReinforceWithTransport(USSR, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) end) end AddParadropReinforcementTrigger = function() Trigger.AfterDelay(DateTime.Seconds(90), function() - Media.PlaySpeechNotification(ussr, "ReinforcementsArrived") - scripteddrop.ActivateParatroopers(ScriptedParadrop.CenterPosition, 10) + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + ScriptedDrop.TargetParatroopers(ScriptedParadrop.CenterPosition, Angle.New(40)) end) end ChurchAmbushTrigger = function() if not AmbushSwitch then - local hiding = Reinforcements.Reinforce(germany, { 'e1', 'e1', 'e1', 'e1', 'e1', 'e1', 'e1', 'e3', 'e3', 'e3' }, { ChurchAmbush.Location, AmbushMove.Location }) - Utils.Do(hiding, function(actor) - IdleHunt(actor) - end) + local hiding = Reinforcements.Reinforce(Germany, { 'e1', 'e1', 'e1', 'e1', 'e1', 'e1', 'e1', 'e3', 'e3', 'e3' }, { ChurchAmbush.Location, AmbushMove.Location }, 0) + Utils.Do(hiding, IdleHunt) end AmbushSwitch = true end Trigger.OnKilled(Church, function() - Actor.Create("moneycrate", true, { Owner = ussr, Location = ChurchAmbush.Location }) + Actor.Create("moneycrate", true, { Owner = USSR, Location = ChurchAmbush.Location }) end) -Obj2TriggerFunction = function() - ussr.MarkCompletedObjective(DestroyVillageObjective) - Media.PlaySpeechNotification(ussr, "ReinforcementsArrived") - local reinforcement = ussrReinforcements.mammoth - Reinforcements.ReinforceWithTransport(ussr, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) -end - -AddReinforcmentTriggers = function() - AddEastReinforcementTrigger() - AddSouthReinforcementTrigger() - AddParadropReinforcementTrigger() +DestroyVillage = function() + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + USSR.MarkCompletedObjective(DestroyVillageObjective) + local reinforcement = SovReinforcements.mammoth + Reinforcements.ReinforceWithTransport(USSR, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) end AddRetreatTrigger = function() Trigger.OnEnteredProximityTrigger(Actor222.CenterPosition, WDist.FromCells(12), function(actor, id) - if actor.Owner == ussr and actor.Type == "barr" then - alliedScouts = Utils.Where(alliedScouts, function(scout) return not scout.IsDead end) + if actor.Owner == USSR and actor.Type == "barr" then + AlliedScouts = Utils.Where(AlliedScouts, function(scout) return not scout.IsDead end) local removed - Utils.Do(alliedScouts, function(scout) + Utils.Do(AlliedScouts, function(scout) if scout.Type == "e1" and not removed then removed = true else @@ -102,61 +94,78 @@ end) end +BoatAttack = function(boat) + if boat.IsDead then + return + else + boat.AttackMove(BoatRally.Location) + end +end + Tick = function() - greece.Cash = 1000 + Greece.Cash = 1000 - if greece.HasNoRequiredUnits() and germany.HasNoRequiredUnits() then - ussr.MarkCompletedObjective(KillAll) + if Greece.HasNoRequiredUnits() and Germany.HasNoRequiredUnits() then + USSR.MarkCompletedObjective(KillAll) end - if ussr.HasNoRequiredUnits() then - greece.MarkCompletedObjective(BeatUSSR) + if USSR.HasNoRequiredUnits() then + Greece.MarkCompletedObjective(BeatUSSR) end end WorldLoaded = function() - ussr = Player.GetPlayer("USSR") - germany = Player.GetPlayer("Germany") - greece = Player.GetPlayer("Greece") - - Trigger.OnObjectiveAdded(ussr, function(p, id) + USSR = Player.GetPlayer("USSR") + Germany = Player.GetPlayer("Germany") + Greece = Player.GetPlayer("Greece") + + Trigger.OnObjectiveAdded(USSR, function(p, id) Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") end) - - KillAll = ussr.AddPrimaryObjective("Destroy all Allied units and structures.") - DestroyVillageObjective = ussr.AddSecondaryObjective("Destroy the village of Allied sympathizers.") - BeatUSSR = greece.AddPrimaryObjective("Defeat the Soviet forces.") - - Trigger.OnObjectiveCompleted(ussr, function(p, id) + + KillAll = USSR.AddObjective("Destroy all Allied units and structures.") + DestroyVillageObjective = USSR.AddObjective("Destroy the village of Allied sympathizers.", "Secondary", false) + BeatUSSR = Greece.AddObjective("Defeat the Soviet forces.") + + Trigger.OnObjectiveCompleted(USSR, function(p, id) Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") end) - Trigger.OnObjectiveFailed(ussr, function(p, id) + Trigger.OnObjectiveFailed(USSR, function(p, id) Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") end) - Trigger.OnPlayerLost(ussr, function() + Trigger.OnPlayerLost(USSR, function() Trigger.AfterDelay(DateTime.Seconds(1), function() - Media.PlaySpeechNotification(ussr, "MissionFailed") + Media.PlaySpeechNotification(USSR, "MissionFailed") end) end) - Trigger.OnPlayerWon(ussr, function() + Trigger.OnPlayerWon(USSR, function() Trigger.AfterDelay(DateTime.Seconds(1), function() - Media.PlaySpeechNotification(ussr, "MissionAccomplished") + Media.PlaySpeechNotification(USSR, "MissionAccomplished") end) end) - AddReinforcmentTriggers() + AddEastReinforcementTrigger() + AddSouthReinforcementTrigger() + AddParadropReinforcementTrigger() AddRetreatTrigger() - - scripteddrop = Actor.Create("scripteddrop", false, { Owner = ussr }) - - OnAnyDamaged(Obj2ActorTriggerActivator, ChurchAmbushTrigger) - - Trigger.OnAllRemovedFromWorld(Obj2ActorTriggerActivator, Obj2TriggerFunction) - + + ScriptedDrop = Actor.Create("scripteddrop", false, { Owner = USSR }) + + OnAnyDamaged(Village, ChurchAmbushTrigger) + + Trigger.OnAllRemovedFromWorld(Village, DestroyVillage) + Camera.Position = SovietBase.CenterPosition - + Trigger.AfterDelay(ActivateAIDelay, ActivateAI) + Trigger.AfterDelay(DateTime.Minutes(2), function() BoatAttack(Boat1) end) + Trigger.AfterDelay(DateTime.Minutes(5), function() BoatAttack(Boat2) end) + Trigger.AfterDelay(DateTime.Minutes(7), function() BoatAttack(Boat3) end) + Trigger.AfterDelay(DateTime.Minutes(10), function() BoatAttack(Boat4) end) + Trigger.AfterDelay(DateTime.Minutes(12), function() BoatAttack(Boat5) end) + Trigger.AfterDelay(DateTime.Minutes(14), function() BoatAttack(Boat6) end) + Trigger.AfterDelay(DateTime.Minutes(15), function() BoatAttack(Boat7) end) end OnAnyDamaged = function(actors, func) Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/soviet-08b/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/soviet-08b/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/soviet-08b/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/soviet-08b/map.png differ diff -Nru openra-20200503/mods/ra/maps/soviet-08b/map.yaml openra-20210321/mods/ra/maps/soviet-08b/map.yaml --- openra-20200503/mods/ra/maps/soviet-08b/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-08b/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,892 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: 08b: Investigate Elba Island + +Author: Westwood Studios + +Tileset: TEMPERAT + +MapSize: 128,128 + +Bounds: 28,27,87,79 + +Visibility: MissionSelector + +Categories: Campaign + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: england + PlayerReference@USSR: + Name: USSR + AllowBots: False + Playable: True + Required: True + LockFaction: True + Faction: soviet + LockColor: True + Color: FE1100 + LockSpawn: True + LockTeam: True + Enemies: Germany, Greece + PlayerReference@Germany: + Name: Germany + Bot: campaign + Faction: allies + Color: 505050 + Allies: Greece + Enemies: USSR + PlayerReference@Greece: + Name: Greece + Bot: campaign + Faction: allies + Color: E2E6F6 + Allies: Germany + Enemies: USSR + +Actors: + Actor0: sbag + Location: 61,56 + Owner: Germany + Actor1: sbag + Location: 62,56 + Owner: Germany + Actor2: sbag + Location: 62,57 + Owner: Germany + Actor3: wood + Location: 74,57 + Owner: Neutral + Actor4: wood + Location: 76,57 + Owner: Neutral + Actor5: wood + Location: 77,57 + Owner: Neutral + Actor6: sbag + Location: 62,58 + Owner: Germany + Actor7: wood + Location: 80,59 + Owner: Neutral + Actor8: wood + Location: 82,59 + Owner: Neutral + Actor9: sbag + Location: 53,62 + Owner: Germany + Actor10: sbag + Location: 53,63 + Owner: Germany + Actor11: sbag + Location: 54,63 + Owner: Germany + Actor12: sbag + Location: 55,63 + Owner: Germany + Actor13: sbag + Location: 56,63 + Owner: Germany + Actor14: sbag + Location: 57,63 + Owner: Germany + Actor15: sbag + Location: 58,63 + Owner: Germany + Actor16: wood + Location: 68,65 + Owner: Neutral + Actor17: v13 + Location: 71,65 + Owner: Neutral + Actor18: sbag + Location: 83,66 + Owner: Germany + Actor19: sbag + Location: 84,66 + Owner: Germany + Actor20: sbag + Location: 86,66 + Owner: Germany + Actor21: sbag + Location: 87,66 + Owner: Germany + Actor22: v14 + Location: 68,67 + Owner: Neutral + Actor23: v14 + Location: 69,67 + Owner: Neutral + Actor24: v14 + Location: 70,67 + Owner: Neutral + Actor25: sbag + Location: 84,67 + Owner: Germany + Actor26: sbag + Location: 86,67 + Owner: Germany + Actor27: sbag + Location: 65,68 + Owner: Germany + Actor28: sbag + Location: 65,69 + Owner: Germany + Actor29: sbag + Location: 65,72 + Owner: Germany + Actor30: sbag + Location: 65,73 + Owner: Germany + Actor31: sbag + Location: 47,81 + Owner: Germany + Actor32: sbag + Location: 48,81 + Owner: Germany + Actor33: sbag + Location: 49,81 + Owner: Germany + Actor34: sbag + Location: 47,85 + Owner: Germany + Actor35: sbag + Location: 48,85 + Owner: Germany + Actor36: sbag + Location: 49,85 + Owner: Germany + Actor37: t11 + Location: 54,100 + Owner: Neutral + Actor38: t15 + Location: 56,100 + Owner: Neutral + Actor39: tc05 + Location: 89,64 + Owner: Neutral + Actor40: tc04 + Location: 92,64 + Owner: Neutral + Actor41: tc02 + Location: 92,63 + Owner: Neutral + Actor42: tc01 + Location: 93,60 + Owner: Neutral + Actor43: tc02 + Location: 98,73 + Owner: Neutral + Actor44: tc02 + Location: 46,89 + Owner: Neutral + Actor45: tc05 + Location: 35,87 + Owner: Neutral + Actor46: tc05 + Location: 50,66 + Owner: Neutral + Actor47: t15 + Location: 37,53 + Owner: Neutral + Actor48: t08 + Location: 37,55 + Owner: Neutral + Actor49: tc05 + Location: 74,69 + Owner: Neutral + Actor50: t11 + Location: 78,69 + Owner: Neutral + Actor51: t08 + Location: 70,69 + Owner: Neutral + Actor52: t08 + Location: 90,73 + Owner: Neutral + Actor53: t10 + Location: 85,95 + Owner: Neutral + Actor54: t07 + Location: 83,97 + Owner: Neutral + Actor55: t08 + Location: 85,97 + Owner: Neutral + Actor56: tc04 + Location: 92,91 + Owner: Neutral + Actor57: tc03 + Location: 97,88 + Owner: Neutral + Actor58: tc02 + Location: 68,89 + Owner: Neutral + Actor59: tc04 + Location: 54,54 + Owner: Neutral + Actor60: tc02 + Location: 52,56 + Owner: Neutral + Actor61: tc01 + Location: 57,54 + Owner: Neutral + Actor62: t01 + Location: 68,67 + Owner: Neutral + Actor63: t11 + Location: 66,62 + Owner: Neutral + Actor64: tc03 + Location: 72,57 + Owner: Neutral + Actor65: tc05 + Location: 77,57 + Owner: Neutral + Actor66: tc02 + Location: 78,66 + Owner: Neutral + Actor67: t02 + Location: 81,37 + Owner: Neutral + Actor68: t02 + Location: 78,39 + Owner: Neutral + Actor69: tc03 + Location: 80,40 + Owner: Neutral + Actor70: tc04 + Location: 92,39 + Owner: Neutral + Actor71: tc05 + Location: 89,40 + Owner: Neutral + Actor72: tc02 + Location: 95,36 + Owner: Neutral + Actor73: tc01 + Location: 86,42 + Owner: Neutral + Actor74: tc04 + Location: 77,52 + Owner: Neutral + Actor75: tc02 + Location: 72,49 + Owner: Neutral + Actor76: t15 + Location: 83,35 + Owner: Neutral + Actor77: t14 + Location: 80,36 + Owner: Neutral + Actor78: t14 + Location: 104,44 + Owner: Neutral + Actor79: tc04 + Location: 55,64 + Owner: Neutral + Actor80: tc02 + Location: 63,66 + Owner: Neutral + Actor81: tc01 + Location: 54,70 + Owner: Neutral + Actor82: t17 + Location: 49,71 + Owner: Neutral + Actor83: t16 + Location: 59,75 + Owner: Neutral + Actor84: tc02 + Location: 67,53 + Owner: Neutral + Actor85: tc02 + Location: 75,53 + Owner: Neutral + Actor86: tc05 + Location: 71,46 + Owner: Neutral + Actor87: mine + Location: 89,93 + Owner: Neutral + Actor88: mine + Location: 91,96 + Owner: Neutral + Actor89: mine + Location: 38,87 + Owner: Neutral + Actor90: mine + Location: 46,81 + Owner: Neutral + Actor91: mine + Location: 91,69 + Owner: Neutral + Actor92: mine + Location: 84,55 + Owner: Neutral + Actor93: fact + Location: 79,83 + Owner: USSR + Actor94: powr + Location: 76,85 + Owner: USSR + Actor95: fact + Location: 50,38 + Owner: Greece + Actor96: spen + Location: 77,92 + Owner: USSR + Actor97: tent + Location: 57,59 + Owner: Germany + Actor98: weaf + Location: 58,56 + Owner: Germany + Actor99: facf + Location: 52,58 + Owner: Germany + Actor100: powr + Location: 55,56 + Owner: Germany + Actor101: hbox + Location: 56,62 + Owner: Germany + Actor102: gun + Location: 61,60 + Owner: Germany + Facing: 636 + Church: v01 + Location: 75,57 + Owner: Germany + Civ1: v02 + Location: 80,60 + Owner: Germany + Health: 89 + Civ2: v03 + Location: 76,62 + Owner: Germany + Civ3: v04 + Location: 71,60 + Owner: Germany + Health: 41 + Civ4: v05 + Location: 66,60 + Owner: Germany + Health: 37 + Civ5: v06 + Location: 69,65 + Owner: Germany + Civ6: v07 + Location: 71,66 + Owner: Germany + Health: 31 + Civ7: v09 + Location: 68,62 + Owner: Germany + Civ8: v11 + Location: 69,58 + Owner: Germany + Jeep1: jeep + Location: 79,80 + Owner: Germany + Facing: 636 + Jeep2: jeep + Location: 76,82 + Owner: Germany + Facing: 636 + Actor114: 1tnk + Location: 64,56 + Owner: Germany + Facing: 636 + Actor115: jeep + Location: 85,65 + Owner: Germany + Facing: 508 + Actor116: jeep + Location: 61,70 + Owner: Germany + Facing: 764 + Actor117: 2tnk + Location: 72,51 + Owner: Greece + Facing: 508 + Actor118: 2tnk + Location: 74,51 + Owner: Greece + Facing: 380 + Actor119: 2tnk + Location: 75,53 + Owner: Greece + Facing: 252 + Actor120: 1tnk + Location: 40,84 + Owner: Germany + Facing: 764 + Actor121: 2tnk + Location: 44,52 + Owner: Greece + Facing: 508 + Actor122: 2tnk + Location: 45,53 + Owner: Greece + Facing: 508 + Actor123: 2tnk + Location: 46,52 + Owner: Greece + Facing: 508 + Actor124: arty + Location: 44,51 + Owner: Greece + Facing: 508 + Actor125: arty + Location: 46,51 + Owner: Greece + Facing: 508 + Actor126: 2tnk + Location: 69,42 + Owner: Greece + Facing: 764 + Actor127: 2tnk + Location: 69,44 + Owner: Greece + Facing: 764 + Actor128: 2tnk + Location: 70,33 + Owner: Greece + Facing: 764 + Actor129: 2tnk + Location: 70,35 + Owner: Greece + Facing: 892 + Actor130: jeep + Location: 67,34 + Owner: Greece + Facing: 636 + Actor131: jeep + Location: 63,38 + Owner: Greece + Facing: 252 + Actor132: jeep + Location: 70,43 + Owner: Greece + Facing: 764 + Actor133: arty + Location: 69,34 + Owner: Greece + Facing: 764 + Actor134: arty + Location: 68,43 + Owner: Greece + Facing: 764 + Actor135: 2tnk + Location: 74,52 + Owner: Greece + Facing: 380 + Actor136: e1 + Location: 78,82 + Owner: USSR + SubCell: 4 + Actor137: e1 + Location: 79,82 + Owner: USSR + SubCell: 1 + Actor138: e1 + Location: 79,81 + Owner: USSR + SubCell: 4 + Rifle1: e1 + Location: 76,81 + Owner: Germany + Facing: 636 + SubCell: 4 + Rifle2: e1 + Location: 77,81 + Owner: Germany + Facing: 636 + SubCell: 2 + Rifle3: e1 + Location: 78,80 + Owner: Germany + Facing: 508 + SubCell: 3 + Rifle4: e1 + Location: 80,79 + Owner: Germany + Facing: 636 + SubCell: 3 + Actor143: e1 + Location: 48,82 + Owner: Germany + Facing: 636 + SubCell: 0 + Actor144: e3 + Location: 48,84 + Owner: Germany + Facing: 892 + SubCell: 4 + Actor145: e1 + Location: 64,68 + Owner: Germany + Facing: 636 + SubCell: 4 + Actor146: e1 + Location: 64,72 + Owner: Germany + Facing: 764 + SubCell: 4 + Actor147: e3 + Location: 83,65 + Owner: Germany + Facing: 636 + SubCell: 4 + Actor148: e3 + Location: 87,65 + Owner: Germany + Facing: 380 + SubCell: 4 + Actor149: e3 + Location: 93,74 + Owner: Germany + Facing: 508 + SubCell: 2 + Actor150: e3 + Location: 95,73 + Owner: Germany + Facing: 508 + SubCell: 0 + Actor151: e3 + Location: 97,74 + Owner: Germany + Facing: 508 + SubCell: 3 + Actor152: e1 + Location: 61,57 + Owner: Germany + SubCell: 4 + Actor153: e1 + Location: 63,58 + Owner: Germany + SubCell: 1 + Actor154: e3 + Location: 58,62 + Owner: Germany + Facing: 764 + SubCell: 0 + Actor155: e3 + Location: 73,51 + Owner: Greece + Facing: 508 + SubCell: 2 + Actor156: e3 + Location: 75,52 + Owner: Greece + Facing: 252 + SubCell: 2 + Actor157: e3 + Location: 75,50 + Owner: Greece + Facing: 380 + SubCell: 3 + Actor158: e3 + Location: 41,85 + Owner: Germany + Facing: 892 + SubCell: 0 + Actor159: c8 + Location: 68,64 + Owner: Germany + SubCell: 2 + Actor160: c8 + Location: 67,57 + Owner: Germany + SubCell: 1 + Actor161: c8 + Location: 81,59 + Owner: Germany + SubCell: 0 + Actor162: c6 + Location: 80,62 + Owner: Germany + SubCell: 3 + Actor163: c5 + Location: 78,61 + Owner: Germany + SubCell: 1 + Actor164: c4 + Location: 74,58 + Owner: Germany + SubCell: 2 + Actor165: c4 + Location: 74,60 + Owner: Germany + SubCell: 4 + Actor166: c3 + Location: 70,63 + Owner: Germany + SubCell: 4 + Actor167: c2 + Location: 66,62 + Owner: Germany + SubCell: 1 + Actor168: c2 + Location: 77,60 + Owner: Germany + SubCell: 1 + Actor169: c2 + Location: 74,66 + Owner: Germany + SubCell: 4 + Actor170: c1 + Location: 73,59 + Owner: Germany + SubCell: 2 + Actor171: c1 + Location: 73,65 + Owner: Germany + SubCell: 0 + Actor172: e1 + Location: 76,64 + Owner: Germany + Facing: 764 + SubCell: 1 + Actor173: e1 + Location: 68,59 + Owner: Germany + Facing: 636 + SubCell: 1 + Actor174: ss + Location: 74,92 + Owner: USSR + Facing: 380 + Actor175: ss + Location: 76,96 + Owner: USSR + Facing: 380 + Actor176: ss + Location: 74,94 + Owner: USSR + Facing: 380 + Actor177: ss + Location: 79,96 + Owner: USSR + Facing: 508 + Gunboat1: pt + Location: 112,36 + Owner: Greece + Gunboat2: pt + Location: 29,31 + Owner: Greece + Gunboat3: pt + Location: 30,50 + Owner: Greece + Gunboat4: pt + Location: 41,104 + Owner: Greece + Gunboat5: pt + Location: 112,54 + Owner: Greece + Gunboat6: pt + Location: 88,29 + Owner: Greece + GreeceWarFactory: weap + Owner: Greece + Location: 49,43 + Actor253: agun + Owner: Greece + Location: 51,36 + TurretFacing: 368 + Actor255: hbox + Owner: Greece + Location: 46,36 + TurretFacing: 368 + Actor256: apwr + Owner: Greece + Location: 43,35 + Actor257: apwr + Owner: Greece + Location: 47,33 + Actor258: apwr + Owner: Greece + Location: 44,32 + Actor259: dome + Owner: Greece + Location: 44,38 + Actor260: agun + Owner: Greece + Location: 47,40 + TurretFacing: 368 + GreeceTent1: tent + Owner: Greece + Location: 45,41 + Actor262: hbox + Owner: Greece + Location: 47,44 + TurretFacing: 368 + GreeceNavalYard: syrd + Owner: Greece + Location: 56,30 + Actor264: fix + Owner: Greece + Location: 54,36 + Actor265: agun + Owner: Greece + Location: 55,40 + TurretFacing: 368 + Actor266: hbox + Owner: Greece + Location: 57,40 + TurretFacing: 368 + Actor267: proc + Owner: Greece + Location: 56,41 + Actor268: silo + Owner: Greece + Location: 56,41 + Actor269: silo + Owner: Greece + Location: 58,41 + Actor270: proc + Owner: Greece + Location: 58,36 + Actor271: silo + Owner: Greece + Location: 58,36 + Actor272: silo + Owner: Greece + Location: 60,36 + GreeceTent2: tent + Owner: Greece + Location: 61,40 + Actor274: gun + Owner: Greece + Location: 64,40 + TurretFacing: 368 + Actor275: gun + Owner: Greece + Location: 64,43 + TurretFacing: 368 + Actor276: gun + Owner: Greece + Location: 64,46 + TurretFacing: 368 + Actor277: gun + Owner: Greece + Location: 63,34 + TurretFacing: 368 + Actor278: gun + Owner: Greece + Location: 63,36 + TurretFacing: 368 + Actor279: gun + Owner: Greece + Location: 44,46 + TurretFacing: 368 + Actor280: gun + Owner: Greece + Location: 48,48 + TurretFacing: 368 + Actor242: apwr + Owner: Greece + Location: 47,36 + ScoutRetreat: waypoint + Location: 61,72 + Owner: Neutral + SouthEntry: waypoint + Location: 74,105 + Owner: Neutral + Unload1: waypoint + Location: 72,90 + Owner: Neutral + Unload2: waypoint + Location: 76,90 + Owner: Neutral + ScriptedParadrop: waypoint + Location: 74,76 + Owner: Neutral + ChurchAmbush: waypoint + Location: 75,58 + Owner: Neutral + AmbushMove: waypoint + Location: 75,64 + Owner: Neutral + DDEntry: waypoint + Location: 39,27 + Owner: Neutral + DDEntryStop: waypoint + Location: 39,29 + Owner: Neutral + DDPatrol1Point1: waypoint + Location: 31,43 + Owner: Neutral + DDPatrol1Point2: waypoint + Location: 30,89 + Owner: Neutral + DDPatrol1Point3: waypoint + Location: 41,99 + Owner: Neutral + DDPatrol1Point4: waypoint + Location: 53,88 + Owner: Neutral + DDPatrol2Point1: waypoint + Location: 62,29 + Owner: Neutral + DDPatrol2Point2: waypoint + Location: 111,29 + Owner: Neutral + DDPatrol2Point3: waypoint + Location: 109,71 + Owner: Neutral + DDPatrol2Point4: waypoint + Location: 99,82 + Owner: Neutral + WaterUnloadEntry1: waypoint + Location: 28,32 + Owner: Neutral + WaterUnload1: waypoint + Location: 37,48 + Owner: Neutral + WaterUnloadEntry2: waypoint + Location: 28,50 + Owner: Neutral + WaterUnload2: waypoint + Location: 41,63 + Owner: Neutral + WaterUnloadEntry3: waypoint + Location: 28,72 + Owner: Neutral + WaterUnload3: waypoint + Location: 36,80 + Owner: Neutral + WaterUnloadEntry4: waypoint + Location: 39,105 + Owner: Neutral + WaterUnload4: waypoint + Location: 41,92 + Owner: Neutral + WaterUnloadEntry5: waypoint + Location: 114,42 + Owner: Neutral + WaterUnload5: waypoint + Location: 99,58 + Owner: Neutral + WaterUnloadEntry6: waypoint + Location: 114,37 + Owner: Neutral + WaterUnload6: waypoint + Location: 102,38 + Owner: Neutral + SovietBase: waypoint + Location: 77,82 + Owner: Neutral + BoatRally: waypoint + Location: 78,91 + Owner: Neutral + +Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/ra/maps/soviet-08b/rules.yaml openra-20210321/mods/ra/maps/soviet-08b/rules.yaml --- openra-20200503/mods/ra/maps/soviet-08b/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-08b/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,134 @@ +World: + LuaScript: + Scripts: soviet08b.lua, soviet08b-AI.lua + MissionData: + Briefing: We have detected Allied activity on Elba island. The Allies plan to use this island to stage an attack on the Soviet Empire.\n\nYou must ensure that the island ceases to be under Allied control. Destroy all Allied units on and around the island.\n\nThe local population has been aiding the Allies as well. There is only one punishment for helping the enemy - Death. + BriefingVideo: soviet8.vqa + StartVideo: slntsrvc.vqa + WinVideo: bombrun.vqa + LossVideo: allymorf.vqa + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Values: + easy: Easy + normal: Normal + hard: Hard + Default: easy + +Player: + PlayerResources: + DefaultCash: 5000 + +CAMERA: + RevealsShroud: + Range: 6c0 + +LST.Reinforcement: + Inherits: LST + RejectsOrders: + -Buildable: + -Selectable: + RenderSprites: + Image: lst + Interactable: + +SCRIPTEDDROP: + ParatroopersPower: + DisplayBeacon: False + DropItems: E1,E1,E4,E4,E4 + AlwaysVisible: + +AFLD: + AirstrikePower@parabombs: + Prerequisites: aircraft.soviet + ParatroopersPower@paratroopers: + DropItems: E1,E1,E1,E2,E2 + +MONEYCRATE: + GiveCashCrateAction: + Amount: 2000 + +STEK: + Buildable: + Prerequisites: ~disabled + +ATEK: + Buildable: + Prerequisites: ~disabled + +HPAD: + Buildable: + Prerequisites: ~disabled + +SAM: + Buildable: + Prerequisites: ~disabled + +IRON: + Buildable: + Prerequisites: ~disabled + +MSLO: + Buildable: + Prerequisites: ~disabled + +TRUK: + Buildable: + Prerequisites: ~disabled + +FTRK: + Buildable: + Prerequisites: ~disabled + +4TNK: + Buildable: + Prerequisites: ~disabled + +QTNK: + Buildable: + Prerequisites: ~disabled + +MRJ: + Buildable: + Prerequisites: ~disabled + +MIG: + Buildable: + Prerequisites: ~disabled + +HELI: + Buildable: + Prerequisites: ~disabled + +MSUB: + Buildable: + Prerequisites: ~disabled + +CA: + Buildable: + Prerequisites: ~disabled + +THF: + Buildable: + Prerequisites: ~disabled + +GAP: + Buildable: + Prerequisites: ~disabled + +PDOX: + Buildable: + Prerequisites: ~disabled + +E7: + Buildable: + Prerequisites: ~disabled + +MECH: + Buildable: + Prerequisites: ~disabled + +E3: + Buildable: + Prerequisites: ~tent diff -Nru openra-20200503/mods/ra/maps/soviet-08b/soviet08b-AI.lua openra-20210321/mods/ra/maps/soviet-08b/soviet08b-AI.lua --- openra-20200503/mods/ra/maps/soviet-08b/soviet08b-AI.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-08b/soviet08b-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,156 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +IdlingUnits = { } + +DDPatrol = { "dd", "dd" } +DDPatrol1Path = { DDPatrol1Point1.Location, DDPatrol1Point2.Location, DDPatrol1Point3.Location, DDPatrol1Point4.Location } +DDPatrol2Path = { DDPatrol2Point1.Location, DDPatrol2Point2.Location, DDPatrol2Point3.Location, DDPatrol2Point4.Location } +ShipArrivePath = { DDEntry.Location, DDEntryStop.Location } + +WTransWays = +{ + { WaterUnloadEntry1.Location, WaterUnload1.Location }, + { WaterUnloadEntry2.Location, WaterUnload2.Location }, + { WaterUnloadEntry3.Location, WaterUnload3.Location }, + { WaterUnloadEntry4.Location, WaterUnload4.Location }, + { WaterUnloadEntry5.Location, WaterUnload5.Location }, + { WaterUnloadEntry6.Location, WaterUnload6.Location } +} + +WTransUnits = +{ + hard = { { "2tnk", "1tnk", "e1", "e3", "e3" }, { "2tnk", "2tnk", "2tnk" } }, + normal = { { "1tnk", "1tnk", "e3", "e3", "jeep" }, { "2tnk", "e3", "e3", "jeep" } }, + easy = { { "1tnk", "e1", "e1", "e3", "e3" }, { "e3", "e3", "jeep", "jeep" } } +} + +WTransDelays = +{ + easy = DateTime.Minutes(4), + normal = DateTime.Minutes(2), + hard = DateTime.Minutes(1) +} + +AttackGroup = { } +AttackGroupSize = 10 + +ProductionInterval = +{ + easy = DateTime.Seconds(30), + normal = DateTime.Seconds(20), + hard = DateTime.Seconds(10) +} + +AlliedInfantry = { "e1", "e3" } +AlliedVehiclesUpgradeDelay = DateTime.Minutes(15) +AlliedVehicleType = "Normal" +AlliedVehicles = +{ + Normal = { "jeep", "1tnk", "1tnk" }, + Upgraded = { "2tnk", "arty" } +} + +IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end + +WTransWaves = function() + local way = Utils.Random(WTransWays) + local units = Utils.Random(WTransUnits) + local attackUnits = Reinforcements.ReinforceWithTransport(Greece, "lst", units , way, { way[2], way[1] })[2] + Utils.Do(attackUnits, function(a) + Trigger.OnAddedToWorld(a, function() + a.AttackMove(SovietBase.Location) + IdleHunt(a) + end) + end) + + Trigger.AfterDelay(WTransDelays, WTransWaves) +end + +SendAttackGroup = function() + if #AttackGroup < AttackGroupSize then + return + end + + Utils.Do(AttackGroup, function(unit) + if not unit.IsDead then + Trigger.OnIdle(unit, unit.Hunt) + end + end) + + AttackGroup = { } +end + +ProduceInfantry = function() + if (GreeceTent1.IsDead or GreeceTent1.Owner ~= Greece) and (GreeceTent2.IsDead or GreeceTent2.Owner ~= Greece) then + return + end + + Greece.Build({ Utils.Random(AlliedInfantry) }, function(units) + table.insert(AttackGroup, units[1]) + SendAttackGroup() + Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceInfantry) + end) +end + +ProduceVehicles = function() + if GreeceWarFactory.IsDead or GreeceWarFactory.Owner ~= Greece then + return + end + + Greece.Build({ Utils.Random(AlliedVehicles[AlliedVehicleType]) }, function(units) + table.insert(AttackGroup, units[1]) + SendAttackGroup() + Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceVehicles) + end) +end + +BringDDPatrol = function(patrolPath) + local units = Reinforcements.Reinforce(Greece, DDPatrol, ShipArrivePath) + Utils.Do(units, function(unit) + Trigger.OnIdle(unit, function(patrols) + patrols.Patrol(patrolPath, true, 200) + end) + end) + + Trigger.OnAllKilled(units, function() + if GreeceNavalYard.IsDead then + return + else + if Map.LobbyOption("difficulty") == "easy" then + Trigger.AfterDelay(DateTime.Minutes(7), function() BringDDPatrol(patrolPath) end) + else + Trigger.AfterDelay(DateTime.Minutes(4), function() BringDDPatrol(patrolPath) end) + end + end + end) +end + +ActivateAI = function() + local difficulty = Map.LobbyOption("difficulty") + WTransUnits = WTransUnits[difficulty] + WTransDelays = WTransDelays[difficulty] + + local buildings = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == Greece and self.HasProperty("StartBuildingRepairs") end) + Utils.Do(buildings, function(actor) + Trigger.OnDamaged(actor, function(building) + if building.Owner == Greece and building.Health < building.MaxHealth * 3/4 then + building.StartBuildingRepairs() + end + end) + end) + + Trigger.AfterDelay(DateTime.Minutes(3), WTransWaves) + + Trigger.AfterDelay(AlliedVehiclesUpgradeDelay, function() AlliedVehicleType = "Upgraded" end) + + ProduceInfantry() + ProduceVehicles() + BringDDPatrol(DDPatrol1Path) + Trigger.AfterDelay(DateTime.Minutes(1), function() BringDDPatrol(DDPatrol2Path) end) +end diff -Nru openra-20200503/mods/ra/maps/soviet-08b/soviet08b.lua openra-20210321/mods/ra/maps/soviet-08b/soviet08b.lua --- openra-20200503/mods/ra/maps/soviet-08b/soviet08b.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-08b/soviet08b.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,174 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +AlliedScouts = { Jeep1, Jeep2, Rifle1, Rifle2, Rifle3, Rifle4 } + +SovReinforcements = +{ + one = + { + actors = { "e1", "e1", "e1", "e1", "e1" }, + entryPath = { SouthEntry.Location, Unload1.Location + CVec.New(1, 0) }, + exitPath = { SouthEntry.Location }, + }, + two = + { + actors = { "e4", "e4", "e1", "e1", "e1" }, + entryPath = { SouthEntry.Location, Unload2.Location + CVec.New(0, 1) }, + exitPath = { SouthEntry.Location } + }, + mammoth = + { + actors = { "4tnk" }, + entryPath = { SouthEntry.Location, Unload1.Location + CVec.New(0, 1) }, + exitPath = { SouthEntry.Location } + } +} + +Village = { Church, Civ1, Civ2, Civ3, Civ4, Civ5, Civ6, Civ7, Civ8 } + +ActivateAIDelay = DateTime.Seconds(45) + +FirstReinforcementTrigger = function() + Trigger.AfterDelay(DateTime.Seconds(30), function() + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + local reinforcement = SovReinforcements.one + Reinforcements.ReinforceWithTransport(USSR, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) + end) +end + +SecondReinforcementTrigger = function() + Trigger.AfterDelay(DateTime.Seconds(60), function() + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + local reinforcement = SovReinforcements.two + Reinforcements.ReinforceWithTransport(USSR, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) + end) +end + +AddParadropReinforcementTrigger = function() + Trigger.AfterDelay(DateTime.Seconds(90), function() + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + ScriptedDrop.TargetParatroopers(ScriptedParadrop.CenterPosition, Angle.New(0)) + end) +end + +ChurchAmbushTrigger = function() + if not AmbushSwitch then + local hiding = Reinforcements.Reinforce(Germany, { 'e1', 'e1', 'e1', 'e1', 'e1', 'e1', 'e1', 'e3', 'e3', 'e3' }, { ChurchAmbush.Location, AmbushMove.Location }, 0) + Utils.Do(hiding, IdleHunt) + end + AmbushSwitch = true +end + +Trigger.OnKilled(Church, function() + Actor.Create("moneycrate", true, { Owner = USSR, Location = ChurchAmbush.Location }) +end) + +DestroyVillage = function() + Media.PlaySpeechNotification(USSR, "ReinforcementsArrived") + USSR.MarkCompletedObjective(DestroyVillageObjective) + local reinforcement = SovReinforcements.mammoth + Reinforcements.ReinforceWithTransport(USSR, "lst.reinforcement", reinforcement.actors, reinforcement.entryPath, reinforcement.exitPath) +end + +AddRetreatTrigger = function() + Trigger.OnEnteredProximityTrigger(Jeep2.CenterPosition, WDist.FromCells(12), function(actor, id) + if actor.Owner == USSR and actor.Type == "barr" then + AlliedScouts = Utils.Where(AlliedScouts, function(scout) return not scout.IsDead end) + local removed + Utils.Do(AlliedScouts, function(scout) + if scout.Type == "e1" and not removed then + removed = true + else + scout.Stop() + scout.Move(ScoutRetreat.Location, 1) + end + end) + Trigger.RemoveProximityTrigger(id) + end + end) +end + +BoatAttack = function(boat) + if boat.IsDead then + return + else + boat.AttackMove(BoatRally.Location) + end +end + +Tick = function() + Greece.Cash = 1000 + + if Greece.HasNoRequiredUnits() and Germany.HasNoRequiredUnits() then + USSR.MarkCompletedObjective(KillAll) + end + + if USSR.HasNoRequiredUnits() then + Greece.MarkCompletedObjective(BeatUSSR) + end +end + +WorldLoaded = function() + USSR = Player.GetPlayer("USSR") + Germany = Player.GetPlayer("Germany") + Greece = Player.GetPlayer("Greece") + + Trigger.OnObjectiveAdded(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") + end) + + KillAll = USSR.AddObjective("Destroy all Allied units and structures.") + DestroyVillageObjective = USSR.AddObjective("Destroy the village of Allied sympathizers.", "Secondary", false) + BeatUSSR = Greece.AddObjective("Defeat the Soviet forces.") + + Trigger.OnObjectiveCompleted(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") + end) + Trigger.OnObjectiveFailed(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") + end) + + Trigger.OnPlayerLost(USSR, function() + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(USSR, "MissionFailed") + end) + end) + Trigger.OnPlayerWon(USSR, function() + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(USSR, "MissionAccomplished") + end) + end) + + FirstReinforcementTrigger() + SecondReinforcementTrigger() + AddParadropReinforcementTrigger() + AddRetreatTrigger() + + ScriptedDrop = Actor.Create("scripteddrop", false, { Owner = USSR }) + + OnAnyDamaged(Village, ChurchAmbushTrigger) + + Trigger.OnAllRemovedFromWorld(Village, DestroyVillage) + + Camera.Position = SovietBase.CenterPosition + + Trigger.AfterDelay(ActivateAIDelay, ActivateAI) + Trigger.AfterDelay(DateTime.Minutes(2), function() BoatAttack(Gunboat1) end) + Trigger.AfterDelay(DateTime.Minutes(5), function() BoatAttack(Gunboat2) end) + Trigger.AfterDelay(DateTime.Minutes(7), function() BoatAttack(Gunboat3) end) + Trigger.AfterDelay(DateTime.Minutes(10), function() BoatAttack(Gunboat4) end) + Trigger.AfterDelay(DateTime.Minutes(12), function() BoatAttack(Gunboat5) end) + Trigger.AfterDelay(DateTime.Minutes(14), function() BoatAttack(Gunboat6) end) +end + +OnAnyDamaged = function(actors, func) + Utils.Do(actors, function(actor) + Trigger.OnDamaged(actor, func) + end) +end Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/soviet-09/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/soviet-09/map.bin differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/soviet-09/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/soviet-09/map.png differ diff -Nru openra-20200503/mods/ra/maps/soviet-09/map.yaml openra-20210321/mods/ra/maps/soviet-09/map.yaml --- openra-20200503/mods/ra/maps/soviet-09/map.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-09/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,1498 @@ +MapFormat: 11 + +RequiresMod: ra + +Title: 09: Liability Elimination + +Author: Westwood Studios + +Tileset: TEMPERAT + +MapSize: 128,128 + +Bounds: 10,30,101,84 + +Visibility: MissionSelector + +Categories: Campaign + +LockPreview: True + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: england + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Faction: england + PlayerReference@Greece: + Name: Greece + Bot: campaign + Faction: allies + Color: E2E6F6 + Allies: Germany + Enemies: Greece, USSR + PlayerReference@USSR: + Name: USSR + AllowBots: False + Playable: True + Required: True + LockFaction: True + Faction: soviet + LockColor: True + Color: FE1100 + LockSpawn: True + LockTeam: True + Enemies: Germany, Greece + PlayerReference@Germany: + Name: Germany + Bot: campaign + Faction: allies + Color: 505050 + Allies: Greece + Enemies: USSR, Germany + +Actors: + Actor0: sbag + Location: 56,30 + Owner: Greece + Actor1: sbag + Location: 57,30 + Owner: Greece + Actor2: sbag + Location: 67,30 + Owner: Greece + Actor3: sbag + Location: 68,30 + Owner: Greece + Actor4: sbag + Location: 69,30 + Owner: Greece + Actor5: sbag + Location: 70,30 + Owner: Greece + Actor6: sbag + Location: 71,30 + Owner: Greece + Actor7: sbag + Location: 72,30 + Owner: Greece + Actor8: sbag + Location: 73,30 + Owner: Greece + Actor9: sbag + Location: 74,30 + Owner: Greece + Actor10: sbag + Location: 75,30 + Owner: Greece + Actor11: sbag + Location: 76,30 + Owner: Greece + Actor12: sbag + Location: 77,30 + Owner: Greece + Actor13: sbag + Location: 78,30 + Owner: Greece + Actor14: sbag + Location: 79,30 + Owner: Greece + Actor15: sbag + Location: 80,30 + Owner: Greece + Actor16: sbag + Location: 81,30 + Owner: Greece + Actor17: sbag + Location: 56,31 + Owner: Greece + Actor18: sbag + Location: 81,31 + Owner: Greece + Actor19: sbag + Location: 56,32 + Owner: Greece + Actor20: cycl + Location: 71,32 + Owner: Greece + Actor21: cycl + Location: 72,32 + Owner: Greece + Actor22: cycl + Location: 73,32 + Owner: Greece + Actor23: cycl + Location: 74,32 + Owner: Greece + Actor24: sbag + Location: 81,32 + Owner: Greece + Actor25: sbag + Location: 56,33 + Owner: Greece + Actor26: cycl + Location: 71,33 + Owner: Greece + Actor27: cycl + Location: 74,33 + Owner: Greece + Actor28: sbag + Location: 81,33 + Owner: Greece + Actor29: sbag + Location: 54,34 + Owner: Greece + Actor30: sbag + Location: 55,34 + Owner: Greece + Actor31: sbag + Location: 56,34 + Owner: Greece + Actor32: cycl + Location: 71,34 + Owner: Greece + Actor33: cycl + Location: 74,34 + Owner: Greece + Actor34: sbag + Location: 81,34 + Owner: Greece + Actor35: sbag + Location: 82,34 + Owner: Greece + Actor36: cycl + Location: 74,35 + Owner: Greece + Actor37: sbag + Location: 54,37 + Owner: Greece + Actor38: sbag + Location: 55,37 + Owner: Greece + Actor39: sbag + Location: 56,37 + Owner: Greece + Actor40: sbag + Location: 56,38 + Owner: Greece + Actor41: sbag + Location: 81,38 + Owner: Greece + Actor42: sbag + Location: 82,38 + Owner: Greece + Actor43: sbag + Location: 56,39 + Owner: Greece + Actor44: sbag + Location: 57,39 + Owner: Greece + Actor45: sbag + Location: 81,39 + Owner: Greece + Actor46: sbag + Location: 79,40 + Owner: Greece + Actor47: sbag + Location: 80,40 + Owner: Greece + Actor48: sbag + Location: 81,40 + Owner: Greece + Actor49: sbag + Location: 79,41 + Owner: Greece + Actor50: sbag + Location: 59,42 + Owner: Greece + Actor51: sbag + Location: 60,42 + Owner: Greece + Actor52: sbag + Location: 72,42 + Owner: Greece + Actor53: sbag + Location: 73,42 + Owner: Greece + Actor54: sbag + Location: 74,42 + Owner: Greece + Actor55: sbag + Location: 75,42 + Owner: Greece + Actor56: sbag + Location: 76,42 + Owner: Greece + Actor57: sbag + Location: 77,42 + Owner: Greece + Actor58: sbag + Location: 78,42 + Owner: Greece + Actor59: sbag + Location: 79,42 + Owner: Greece + Actor60: sbag + Location: 60,43 + Owner: Greece + Actor61: sbag + Location: 61,43 + Owner: Greece + Actor62: sbag + Location: 70,43 + Owner: Greece + Actor63: sbag + Location: 71,43 + Owner: Greece + Actor64: sbag + Location: 72,43 + Owner: Greece + Actor65: brik + Location: 88,85 + Owner: USSR + Actor66: brik + Location: 89,85 + Owner: USSR + Actor67: brik + Location: 90,85 + Owner: USSR + Actor68: brik + Location: 91,85 + Owner: USSR + Actor69: brik + Location: 92,85 + Owner: USSR + Actor70: brik + Location: 93,85 + Owner: USSR + Actor71: brik + Location: 94,85 + Owner: USSR + Actor72: brik + Location: 95,85 + Owner: USSR + Actor73: brik + Location: 96,85 + Owner: USSR + Actor74: brik + Location: 97,85 + Owner: USSR + Actor75: brik + Location: 98,85 + Owner: USSR + Actor76: brik + Location: 103,85 + Owner: USSR + Actor77: brik + Location: 104,85 + Owner: USSR + Actor78: brik + Location: 105,85 + Owner: USSR + Actor79: brik + Location: 106,85 + Owner: USSR + Actor80: brik + Location: 107,85 + Owner: USSR + Actor81: brik + Location: 108,85 + Owner: USSR + Actor82: brik + Location: 109,85 + Owner: USSR + Actor83: brik + Location: 110,85 + Owner: USSR + Actor86: brik + Location: 88,86 + Owner: USSR + Actor87: brik + Location: 97,86 + Owner: USSR + Actor88: brik + Location: 98,86 + Owner: USSR + Actor89: brik + Location: 103,86 + Owner: USSR + Actor90: brik + Location: 104,86 + Owner: USSR + Actor91: brik + Location: 110,86 + Owner: USSR + Actor93: brik + Location: 88,87 + Owner: USSR + Actor94: brik + Location: 110,87 + Owner: USSR + Actor99: brik + Location: 88,88 + Owner: USSR + Actor100: brik + Location: 110,88 + Owner: USSR + Actor102: brik + Location: 88,89 + Owner: USSR + Actor103: brik + Location: 110,89 + Owner: USSR + Actor105: brik + Location: 88,90 + Owner: USSR + Actor106: brik + Location: 110,90 + Owner: USSR + Actor108: brik + Location: 88,91 + Owner: USSR + Actor109: brik + Location: 89,91 + Owner: USSR + Actor110: brik + Location: 110,91 + Owner: USSR + Actor112: brik + Location: 88,92 + Owner: USSR + Actor113: brik + Location: 89,92 + Owner: USSR + Actor114: brik + Location: 110,92 + Owner: USSR + Actor116: brik + Location: 110,93 + Owner: USSR + Actor118: brik + Location: 110,94 + Owner: USSR + Actor120: brik + Location: 110,95 + Owner: USSR + Actor122: brik + Location: 110,96 + Owner: USSR + Actor124: brik + Location: 110,97 + Owner: USSR + Actor126: brik + Location: 88,98 + Owner: USSR + Actor127: brik + Location: 89,98 + Owner: USSR + Actor128: brik + Location: 110,98 + Owner: USSR + Actor130: brik + Location: 88,99 + Owner: USSR + Actor131: brik + Location: 89,99 + Owner: USSR + Actor132: brik + Location: 110,99 + Owner: USSR + Actor134: brik + Location: 88,100 + Owner: USSR + Actor135: brik + Location: 110,100 + Owner: USSR + Actor137: brik + Location: 88,101 + Owner: USSR + Actor138: brik + Location: 110,101 + Owner: USSR + Actor140: brik + Location: 88,102 + Owner: USSR + Actor141: brik + Location: 110,102 + Owner: USSR + Actor143: brik + Location: 88,103 + Owner: USSR + Actor144: brik + Location: 100,103 + Owner: USSR + Actor145: brik + Location: 101,103 + Owner: USSR + Actor146: brik + Location: 105,103 + Owner: USSR + Actor147: brik + Location: 106,103 + Owner: USSR + Actor148: brik + Location: 110,103 + Owner: USSR + Actor150: brik + Location: 88,104 + Owner: USSR + Actor151: brik + Location: 93,104 + Owner: USSR + Actor152: brik + Location: 94,104 + Owner: USSR + Actor153: brik + Location: 95,104 + Owner: USSR + Actor154: brik + Location: 96,104 + Owner: USSR + Actor155: brik + Location: 97,104 + Owner: USSR + Actor156: brik + Location: 98,104 + Owner: USSR + Actor157: brik + Location: 99,104 + Owner: USSR + Actor158: brik + Location: 100,104 + Owner: USSR + Actor159: brik + Location: 101,104 + Owner: USSR + Actor160: brik + Location: 105,104 + Owner: USSR + Actor161: brik + Location: 106,104 + Owner: USSR + Actor162: brik + Location: 107,104 + Owner: USSR + Actor163: brik + Location: 108,104 + Owner: USSR + Actor164: brik + Location: 109,104 + Owner: USSR + Actor165: brik + Location: 110,104 + Owner: USSR + Actor169: brik + Location: 88,105 + Owner: USSR + Actor170: brik + Location: 89,105 + Owner: USSR + Actor171: brik + Location: 90,105 + Owner: USSR + Actor172: brik + Location: 91,105 + Owner: USSR + Actor173: brik + Location: 92,105 + Owner: USSR + Actor174: brik + Location: 93,105 + Owner: USSR + Actor175: t12 + Location: 92,37 + Owner: Neutral + Actor176: t17 + Location: 107,40 + Owner: Neutral + Actor177: t16 + Location: 108,35 + Owner: Neutral + Actor178: tc05 + Location: 90,32 + Owner: Neutral + Actor179: tc02 + Location: 38,31 + Owner: Neutral + Actor180: tc03 + Location: 28,35 + Owner: Neutral + Actor181: t14 + Location: 80,40 + Owner: Neutral + Actor182: tc01 + Location: 71,46 + Owner: Neutral + Actor183: tc03 + Location: 59,46 + Owner: Neutral + Actor184: t08 + Location: 109,100 + Owner: Neutral + Actor185: tc05 + Location: 93,82 + Owner: Neutral + Actor186: t14 + Location: 100,95 + Owner: Neutral + Actor187: tc04 + Location: 105,85 + Owner: Neutral + Actor188: t16 + Location: 86,86 + Owner: Neutral + Actor189: t11 + Location: 38,89 + Owner: Neutral + Actor190: tc03 + Location: 91,83 + Owner: Neutral + Actor191: tc02 + Location: 86,84 + Owner: Neutral + Actor192: tc04 + Location: 34,99 + Owner: Neutral + Actor193: tc01 + Location: 32,98 + Owner: Neutral + Actor194: t17 + Location: 31,98 + Owner: Neutral + Actor195: t15 + Location: 29,98 + Owner: Neutral + Actor196: t11 + Location: 25,103 + Owner: Neutral + Actor197: t08 + Location: 26,102 + Owner: Neutral + Actor198: tc05 + Location: 60,64 + Owner: Neutral + Actor199: tc04 + Location: 66,59 + Owner: Neutral + Actor200: tc04 + Location: 31,59 + Owner: Neutral + Actor201: tc01 + Location: 24,57 + Owner: Neutral + Actor202: tc03 + Location: 76,76 + Owner: Neutral + Actor203: tc02 + Location: 78,73 + Owner: Neutral + Actor204: tc05 + Location: 73,69 + Owner: Neutral + Actor205: tc01 + Location: 82,76 + Owner: Neutral + Actor206: t15 + Location: 72,76 + Owner: Neutral + Actor207: t13 + Location: 105,72 + Owner: Neutral + Actor208: tc01 + Location: 106,70 + Owner: Neutral + Actor209: tc03 + Location: 88,75 + Owner: Neutral + Actor210: tc04 + Location: 108,71 + Owner: Neutral + Actor211: tc05 + Location: 108,44 + Owner: Neutral + Actor212: tc04 + Location: 10,31 + Owner: Neutral + Actor213: tc05 + Location: 11,78 + Owner: Neutral + Actor214: tc04 + Location: 10,84 + Owner: Neutral + Actor215: tc03 + Location: 17,88 + Owner: Neutral + Actor216: t16 + Location: 19,88 + Owner: Neutral + Actor217: t15 + Location: 16,89 + Owner: Neutral + Actor218: t15 + Location: 16,74 + Owner: Neutral + Actor219: t14 + Location: 23,76 + Owner: Neutral + Actor220: tc04 + Location: 103,51 + Owner: Neutral + Actor221: t15 + Location: 102,56 + Owner: Neutral + Actor222: t13 + Location: 102,53 + Owner: Neutral + Actor223: t10 + Location: 106,51 + Owner: Neutral + Actor224: tc02 + Location: 107,61 + Owner: Neutral + Actor225: tc05 + Location: 106,57 + Owner: Neutral + Actor226: t08 + Location: 102,52 + Owner: Neutral + Actor227: t07 + Location: 103,54 + Owner: Neutral + Actor228: t02 + Location: 105,53 + Owner: Neutral + Actor229: t10 + Location: 95,104 + Owner: Neutral + Actor230: tc03 + Location: 109,108 + Owner: Neutral + Actor231: t08 + Location: 94,105 + Owner: Neutral + Actor232: tc05 + Location: 28,105 + Owner: Neutral + Actor233: tc02 + Location: 44,106 + Owner: Neutral + Actor234: tc01 + Location: 37,104 + Owner: Neutral + Actor235: tc04 + Location: 63,37 + Owner: Neutral + Actor236: t08 + Location: 62,38 + Owner: Neutral + Actor237: tc02 + Location: 69,37 + Owner: Neutral + Actor238: tc01 + Location: 70,38 + Owner: Neutral + Actor239: tc01 + Location: 71,30 + Owner: Neutral + Actor240: t14 + Location: 73,30 + Owner: Neutral + Actor241: t13 + Location: 67,30 + Owner: Neutral + Actor242: t15 + Location: 79,38 + Owner: Neutral + Actor243: t15 + Location: 57,37 + Owner: Neutral + Actor244: t08 + Location: 59,38 + Owner: Neutral + Actor245: t14 + Location: 60,37 + Owner: Neutral + Actor246: t13 + Location: 57,32 + Owner: Neutral + Actor247: mine + Location: 80,84 + Owner: Neutral + Actor248: mine + Location: 77,110 + Owner: Neutral + Actor249: mine + Location: 79,111 + Owner: Neutral + Actor250: mine + Location: 34,108 + Owner: Neutral + Actor251: mine + Location: 39,108 + Owner: Neutral + GreeceMine: mine + Location: 108,32 + Owner: Neutral + GermanyMine1: mine + Location: 36,89 + Owner: Neutral + GermanyMine2: mine + Location: 43,92 + Owner: Neutral + Actor252: apwr + Location: 75,39 + Owner: Greece + Actor253: barl + Location: 97,32 + Owner: Greece + Actor254: barl + Location: 94,31 + Owner: Greece + Actor255: barl + Location: 97,31 + Owner: Greece + Actor256: brl3 + Location: 98,31 + Owner: Greece + Actor257: gun + Location: 54,33 + Owner: Greece + Health: 99 + Facing: 252 + Actor258: minv + Location: 58,49 + Owner: Greece + Actor259: minv + Location: 58,48 + Owner: Greece + Actor260: minv + Location: 59,48 + Owner: Greece + Actor261: minv + Location: 59,49 + Owner: Greece + Actor262: minv + Location: 71,49 + Owner: Greece + Actor263: minv + Location: 71,48 + Owner: Greece + Actor264: minv + Location: 61,51 + Owner: Greece + Actor265: minv + Location: 61,50 + Owner: Greece + Actor266: minv + Location: 70,48 + Owner: Greece + Actor267: minv + Location: 70,49 + Owner: Greece + Actor268: minv + Location: 69,51 + Owner: Greece + Actor269: minv + Location: 69,50 + Owner: Greece + Actor270: minv + Location: 68,51 + Owner: Greece + Actor271: minv + Location: 68,50 + Owner: Greece + Actor272: minv + Location: 67,49 + Owner: Greece + Actor273: minv + Location: 67,48 + Owner: Greece + Actor274: minv + Location: 66,49 + Owner: Greece + Actor275: minv + Location: 66,48 + Owner: Greece + Actor276: minv + Location: 65,51 + Owner: Greece + Actor277: minv + Location: 65,50 + Owner: Greece + Actor278: minv + Location: 64,51 + Owner: Greece + Actor279: minv + Location: 64,50 + Owner: Greece + Actor280: minv + Location: 62,49 + Owner: Greece + Actor281: minv + Location: 62,48 + Owner: Greece + Actor282: minv + Location: 63,49 + Owner: Greece + Actor283: minv + Location: 63,48 + Owner: Greece + Actor284: minv + Location: 60,51 + Owner: Greece + Actor285: minv + Location: 60,50 + Owner: Greece + Bridgemine1: minv + Location: 90,53 + Owner: Greece + Bridgemine2: minv + Location: 92,52 + Owner: Greece + Bridgemine3: minv + Location: 93,50 + Owner: Greece + Bridgemine4: minv + Location: 95,49 + Owner: Greece + Bridgemine5: minv + Location: 97,47 + Owner: Greece + Actor286: tent + Location: 60,39 + Owner: Greece + Health: 99 + Actor287: apwr + Location: 75,31 + Owner: Greece + Actor288: apwr + Location: 78,31 + Owner: Greece + Actor289: silo + Location: 101,31 + Owner: Greece + Actor290: silo + Location: 96,31 + Owner: Greece + Actor291: proc + Location: 98,31 + Owner: Greece + Health: 99 + Actor292: fact + Location: 68,31 + Owner: Greece + Health: 99 + Actor293: gun + Location: 54,38 + Owner: Greece + Health: 99 + Facing: 252 + Actor294: gun + Location: 101,38 + Owner: Greece + Health: 99 + Facing: 508 + Actor295: gun + Location: 96,38 + Owner: Greece + Health: 99 + Facing: 508 + Actor296: gun + Location: 70,42 + Owner: Greece + Health: 99 + Facing: 508 + Actor297: gun + Location: 61,42 + Owner: Greece + Health: 99 + Facing: 508 + Actor298: gap + Location: 64,34 + Owner: Greece + Health: 97 + Actor299: gap + Location: 75,35 + Owner: Greece + Health: 97 + Actor300: dome + Location: 73,39 + Owner: Greece + Health: 97 + Actor301: weap + Location: 66,37 + Owner: Greece + Health: 97 + CommandCenter: fcom + Location: 102,94 + Owner: USSR + Health: 98 + Actor303: barr + Location: 106,92 + Owner: USSR + Health: 31 + Actor304: proc + Location: 92,91 + Owner: USSR + Health: 34 + Actor305: fact + Location: 98,98 + Owner: USSR + Health: 39 + Actor306: hbox + Location: 62,43 + Owner: Greece + Actor307: hbox + Location: 69,43 + Owner: Greece + GreeceHpad1: hpad + Location: 94,32 + Owner: Greece + GreeceHpad2: hpad + Location: 103,35 + Owner: Greece + Actor309: agun + Location: 82,33 + Owner: Greece + Facing: 508 + Actor310: agun + Location: 82,40 + Owner: Greece + Facing: 636 + Actor311: agun + Location: 55,38 + Owner: Greece + Facing: 380 + Actor312: agun + Location: 55,33 + Owner: Greece + Facing: 508 + Actor313: agun + Location: 67,34 + Owner: Greece + Facing: 508 + Actor314: tsla + Location: 89,95 + Owner: USSR + Health: 22 + Actor315: apwr + Location: 107,101 + Owner: USSR + Health: 56 + Actor316: apwr + Location: 95,101 + Owner: USSR + Health: 47 + Actor317: apwr + Location: 102,31 + Owner: Greece + Actor319: fix + Location: 104,96 + Owner: USSR + Health: 43 + Actor320: hbox + Location: 104,56 + Owner: Germany + Actor321: hbox + Location: 106,56 + Owner: Germany + Actor322: hbox + Location: 106,53 + Owner: Germany + Actor323: hbox + Location: 104,53 + Owner: Germany + Actor324: agun + Location: 103,56 + Owner: Germany + Facing: 380 + Actor325: agun + Location: 107,57 + Owner: Germany + Facing: 636 + Actor326: syrd + Location: 59,30 + Owner: Greece + Actor327: dome + Location: 108,91 + Owner: USSR + Health: 39 + Actor328: powr + Location: 107,53 + Owner: Germany + Actor329: arty + Location: 61,44 + Owner: Greece + Facing: 508 + Actor330: arty + Location: 70,44 + Owner: Greece + Facing: 508 + Actor331: arty + Location: 81,36 + Owner: Greece + Facing: 636 + Actor333: 2tnk + Location: 95,36 + Owner: Greece + Health: 99 + Facing: 636 + Actor334: 2tnk + Location: 102,37 + Owner: Greece + Health: 99 + Facing: 380 + Actor335: 2tnk + Location: 82,39 + Owner: Greece + Health: 99 + Facing: 892 + Actor336: 2tnk + Location: 83,34 + Owner: Greece + Health: 99 + Facing: 764 + Actor337: 2tnk + Location: 54,36 + Owner: Greece + Health: 99 + Facing: 124 + Actor338: 2tnk + Location: 69,44 + Owner: Greece + Health: 99 + Facing: 508 + Actor339: 2tnk + Location: 62,44 + Owner: Greece + Health: 99 + Facing: 508 + Actor341: 4tnk + Location: 94,97 + Owner: USSR + Health: 26 + Facing: 892 + Actor342: harv + Location: 81,85 + Owner: USSR + Facing: 252 + Actor343: 4tnk + Location: 91,98 + Owner: USSR + Health: 62 + Facing: 252 + Actor344: 3tnk + Location: 99,97 + Owner: USSR + Health: 53 + Actor345: 3tnk + Location: 105,99 + Owner: USSR + Facing: 124 + Actor346: 3tnk + Location: 91,103 + Owner: USSR + Facing: 892 + Actor347: v2rl + Location: 96,97 + Owner: USSR + Facing: 892 + Actor348: v2rl + Location: 91,100 + Owner: USSR + Facing: 124 + Actor350: 1tnk + Location: 26,51 + Owner: Greece + Facing: 636 + Actor351: 1tnk + Location: 27,50 + Owner: Greece + Facing: 636 + Actor352: 1tnk + Location: 24,51 + Owner: Greece + Facing: 636 + Actor353: arty + Location: 24,50 + Owner: Greece + Facing: 636 + Actor354: arty + Location: 26,49 + Owner: Greece + Facing: 636 + Actor355: arty + Location: 30,36 + Owner: Greece + Facing: 508 + Actor356: arty + Location: 35,37 + Owner: Greece + Facing: 380 + Actor357: 2tnk + Location: 30,38 + Owner: Greece + Facing: 380 + Actor358: 2tnk + Location: 32,37 + Owner: Greece + Facing: 380 + Actor359: 2tnk + Location: 96,92 + Owner: Greece + Health: 39 + Facing: 380 + Actor360: 2tnk + Location: 99,94 + Owner: Greece + Health: 51 + Facing: 508 + Actor361: 2tnk + Location: 102,92 + Owner: Greece + Health: 41 + Facing: 636 + Actor363: 2tnk + Location: 105,56 + Owner: Germany + Facing: 508 + Actor364: 2tnk + Location: 106,55 + Owner: Germany + Facing: 508 + Actor365: 2tnk + Location: 104,55 + Owner: Germany + Facing: 508 + Actor366: arty + Location: 107,56 + Owner: Germany + Facing: 380 + Actor367: arty + Location: 108,56 + Owner: Germany + Facing: 380 + Actor368: arty + Location: 102,56 + Owner: Germany + Facing: 636 + Actor369: arty + Location: 102,55 + Owner: Germany + Facing: 636 + Actor370: 2tnk + Location: 44,62 + Owner: Greece + Facing: 252 + Actor371: 2tnk + Location: 44,64 + Owner: Greece + Facing: 252 + Actor372: 2tnk + Location: 48,62 + Owner: Greece + Facing: 764 + Actor373: 2tnk + Location: 48,64 + Owner: Greece + Facing: 764 + Actor374: 2tnk + Location: 65,61 + Owner: Greece + Facing: 636 + Actor375: 2tnk + Location: 63,63 + Owner: Greece + Facing: 636 + Actor376: arty + Location: 63,61 + Owner: Greece + Facing: 636 + Actor377: arty + Location: 81,68 + Owner: Greece + Facing: 636 + Actor378: arty + Location: 83,68 + Owner: Greece + Facing: 636 + Actor379: 2tnk + Location: 83,69 + Owner: Greece + Facing: 636 + Actor380: 2tnk + Location: 81,69 + Owner: Greece + Facing: 636 + Actor386: gnrl + Location: 73,34 + Owner: Greece + Facing: 252 + SubCell: 2 + Actor387: chan + Location: 73,33 + Owner: Greece + Facing: 252 + SubCell: 2 + Actor388: chan + Location: 73,34 + Owner: Greece + Facing: 252 + SubCell: 5 + Actor389: ca + Location: 47,41 + Owner: Greece + Health: 99 + Facing: 508 + Actor390: dd + Location: 32,78 + Owner: Greece + Health: 99 + Facing: 380 + Actor391: dd + Location: 27,74 + Owner: Greece + Health: 99 + Facing: 636 + Actor392: ca + Location: 18,68 + Owner: Greece + Health: 99 + Facing: 508 + Actor393: pt + Location: 33,73 + Owner: Greece + Facing: 508 + PinchHitter: powr + Owner: Greece + Location: 96,33 + Actor416: proc + Owner: Germany + Location: 38,80 + Actor417: silo + Owner: Germany + Location: 37,84 + Actor418: silo + Owner: Germany + Location: 38,84 + Actor419: silo + Owner: Germany + Location: 38,85 + Actor420: silo + Owner: Germany + Location: 37,85 + GermanyHpad1: hpad + Owner: Germany + Location: 40,77 + GermanyHpad2: hpad + Owner: Germany + Location: 55,70 + GermanyTent: tent + Owner: Germany + Location: 49,82 + GermanyWarFactory: weap + Owner: Germany + Location: 55,74 + Actor422: proc + Owner: Germany + Location: 42,84 + Actor424: apwr + Owner: Germany + Location: 51,79 + Actor425: apwr + Owner: Germany + Location: 50,76 + Actor426: apwr + Owner: Germany + Location: 51,73 + Actor427: apwr + Owner: Germany + Location: 47,74 + Actor430: fact + Owner: Germany + Location: 44,79 + Actor431: gun + Owner: Germany + Location: 45,88 + TurretFacing: 368 + Actor432: gun + Owner: Germany + Location: 42,89 + TurretFacing: 368 + Actor433: gun + Owner: Germany + Location: 40,91 + TurretFacing: 368 + Actor434: gun + Owner: Germany + Location: 59,79 + TurretFacing: 368 + Actor435: gun + Owner: Germany + Location: 59,75 + TurretFacing: 372 + Actor436: hbox + Owner: Germany + Location: 60,77 + TurretFacing: 368 + Actor437: hbox + Owner: Germany + Location: 47,70 + TurretFacing: 368 + Actor438: gun + Owner: Germany + Location: 44,69 + TurretFacing: 368 + Actor439: gun + Owner: Germany + Location: 50,69 + TurretFacing: 368 + Actor440: moneycrate + Owner: Germany + Location: 104,54 + Actor441: moneycrate + Owner: Germany + Location: 105,55 + Actor442: moneycrate + Owner: Germany + Location: 106,54 + Actor443: healcrate + Owner: Neutral + Location: 105,53 + StartAttack1tnk1: 1tnk + Location: 101,74 + Owner: Greece + Facing: 508 + StartAttack1tnk2: 1tnk + Location: 103,74 + Owner: Greece + Facing: 508 + StartAttackArty1: arty + Location: 102,74 + Owner: Greece + Facing: 508 + StartAttackArty2: arty + Location: 101,73 + Owner: Greece + Facing: 508 + StartAttackArty3: arty + Location: 103,73 + Owner: Greece + Facing: 508 + StolenTruck: truk + Location: 99,91 + Owner: Greece + SouthAttack1: waypoint + Location: 40,87 + Owner: Neutral + SouthAttack2: waypoint + Location: 53,93 + Owner: Neutral + DefaultCameraPosition: waypoint + Location: 99,95 + Owner: Neutral + LZ1: waypoint + Location: 89,86 + Owner: Neutral + LZ2: waypoint + Location: 108,88 + Owner: Neutral + LZ3: waypoint + Location: 107,109 + Owner: Neutral + LZ4: waypoint + Location: 86,108 + Owner: Neutral + ChinookEntrySouth: waypoint + Location: 57,113 + Owner: Neutral + SeaEntryEast: waypoint + Location: 110,67 + Owner: Neutral + SeaEntryWest1: waypoint + Location: 10,111 + Owner: Neutral + SeaEntryWest2: waypoint + Location: 10,95 + Owner: Neutral + SeaWestPath1: waypoint + Location: 25,85 + Owner: Neutral + SeaWestPath2: waypoint + Location: 39,96 + Owner: Neutral + SeaWestPath3: waypoint + Location: 49,101 + Owner: Neutral + SeaEastLZ: waypoint + Location: 96,70 + Owner: Neutral + SeaWestLZ1: waypoint + Location: 29,89 + Owner: Neutral + SeaWestLZ2: waypoint + Location: 39,72 + Owner: Neutral + SeaWestLZ3: waypoint + Location: 69,94 + Owner: Neutral + SeaWestLZ4: waypoint + Location: 69,106 + Owner: Neutral + TruckStop1: waypoint + Location: 101,77 + Owner: Neutral + TruckStop2: waypoint + Location: 82,75 + Owner: Neutral + TruckStop3: waypoint + Location: 64,65 + Owner: Neutral + TruckStop4: waypoint + Location: 63,52 + Owner: Neutral + TruckStop5: waypoint + Location: 63,50 + Owner: Neutral + TruckStop6: waypoint + Location: 66,47 + Owner: Neutral + TruckStop7: waypoint + Location: 72,40 + Owner: Neutral + TruckStop8: waypoint + Location: 72,33 + Owner: Neutral + TruckAlarm: waypoint + Owner: Neutral + Location: 69,35 + LandEntryWest: waypoint + Owner: Neutral + Location: 10,58 + TruckEscape1: waypoint + Owner: Neutral + Location: 72,36 + TruckEcsape2: waypoint + Owner: Neutral + Location: 33,35 + TruckEscape3: waypoint + Owner: Neutral + Location: 25,50 + TruckEscape4: waypoint + Owner: Neutral + Location: 30,63 + TruckEscape5: waypoint + Owner: Neutral + Location: 15,82 + TruckEscapeWest: waypoint + Owner: Neutral + Location: 10,82 + TruckEscapeEast: waypoint + Location: 110,40 + Owner: Neutral + +Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml diff -Nru openra-20200503/mods/ra/maps/soviet-09/rules.yaml openra-20210321/mods/ra/maps/soviet-09/rules.yaml --- openra-20200503/mods/ra/maps/soviet-09/rules.yaml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-09/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,121 @@ +World: + LuaScript: + Scripts: campaign-global.lua, soviet09.lua, soviet09-AI.lua + MissionData: + BriefingVideo: soviet9.vqa + WinVideo: v2rocket.vqa + LossVideo: sfrozen.vqa + StartVideo: movingin.vqa + Briefing: The Allied forces have intercepted and destroyed a convoy that carried parts for our secret weapon. One truck remains, but they have captured that last truck and its cargo.\n\nThis is not acceptable! You are to destroy that truck before the Allies leave the area with it. + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Values: + easy: Easy + normal: Normal + hard: Hard + Default: easy + SmudgeLayer@SCORCH: + InitialSmudges: + 98,87: sc3,0 + 100,87: sc2,0 + 108,87: sc1,0 + 88,93: sc6,0 + 104,101: sc3,0 + SmudgeLayer@CRATER: + InitialSmudges: + 99,87: cr1,2 + 86,93: cr1,0 + 87,93: cr1,1 + +Player: + PlayerResources: + DefaultCash: 8000 + +AFLD: + AirstrikePower@parabombs: + Prerequisites: ~disabled + +ATEK: + Buildable: + Prerequisites: ~disabled + +HPAD: + Buildable: + Prerequisites: ~structures.allies + +IRON: + Buildable: + Prerequisites: ~disabled + +MSLO: + Buildable: + Prerequisites: ~disabled + +TRUK: + Buildable: + Prerequisites: ~disabled + -SpawnActorOnDeath: + +FTRK: + Buildable: + Prerequisites: ~disabled + +QTNK: + Buildable: + Prerequisites: ~disabled + +MRJ: + Buildable: + Prerequisites: ~disabled + +HELI: + Buildable: + Prerequisites: ~hpad + +HIND: + Buildable: + Prerequisites: ~disabled + +MIG: + Buildable: + Prerequisites: ~disabled + +MSUB: + Buildable: + Prerequisites: ~disabled + +CA: + Buildable: + Prerequisites: ~disabled + +THF: + Buildable: + Prerequisites: ~disabled + +GAP: + Buildable: + Prerequisites: ~disabled + +PDOX: + Buildable: + Prerequisites: ~disabled + +E7: + Buildable: + Prerequisites: ~disabled + +MECH: + Buildable: + Prerequisites: ~disabled + +SPY: + Buildable: + Prerequisites: ~disabled + +E3: + Buildable: + Prerequisites: ~tent + +CHAN: + -Wanders: diff -Nru openra-20200503/mods/ra/maps/soviet-09/soviet09-AI.lua openra-20210321/mods/ra/maps/soviet-09/soviet09-AI.lua --- openra-20200503/mods/ra/maps/soviet-09/soviet09-AI.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-09/soviet09-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,192 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +IdleHunt = function(unit) if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end end + +AttackGroup = { } +AttackGroupSize = 12 +AlliedInfantry = { "e1", "e3" } +AlliedVehicles = { "jeep", "1tnk", "2tnk", "2tnk" } +AlliedAircraftType = { "heli" } +Longbows = { } + +ProductionInterval = +{ + easy = DateTime.Seconds(25), + normal = DateTime.Seconds(15), + hard = DateTime.Seconds(5) +} +AttackPaths = +{ + { SouthAttack1.Location, SouthAttack2.Location, DefaultCameraPosition.Location }, + { TruckStop2.Location, TruckStop1.Location, DefaultCameraPosition.Location } +} + +WTransUnits = { { "2tnk", "1tnk", "1tnk", "e3", "e3" }, { "2tnk", "2tnk", "2tnk" } } +WTransDelays = +{ + easy = DateTime.Minutes(5), + normal = DateTime.Minutes(3), + hard = DateTime.Minutes(1) +} +WTransWays = +{ + { SeaEntryEast.Location, SeaEastLZ.Location }, + { SeaEntryWest1.Location, SeaWestLZ1.Location }, + { SeaEntryWest1.Location, SeaWestPath1.Location, SeaWestLZ2.Location }, + { SeaEntryWest2.Location, SeaWestPath2.Location, SeaWestPath3.Location, SeaWestLZ3.Location }, + { SeaEntryWest2.Location, SeaWestPath2.Location, SeaWestPath3.Location, SeaWestLZ4.Location } +} + +ChinookChalk = { "e1", "e1", "e1", "e1", "e3", "e3", "e3", "e3" } +ChinookPaths = +{ + { SeaEntryEast.Location, LZ1.Location }, + { TruckEscapeEast.Location, LZ2.Location }, + { ChinookEntrySouth.Location, LZ3.Location }, + { SeaEntryWest2.Location, LZ4.Location } +} +ChinookDelay = +{ + easy = { DateTime.Minutes(1), DateTime.Seconds(90) }, + normal = { DateTime.Seconds(45), DateTime.Seconds(75) }, + hard = { DateTime.Seconds(30), DateTime.Minutes(1) } +} +ChinookWaves = +{ + easy = 4, + normal = 8, + hard = 12 +} +ChinookAttacks = 0 + +ChinookAttack = function() + Trigger.AfterDelay(Utils.RandomInteger(ChinookDelay[1], ChinookDelay[2]), function() + local way = Utils.Random(ChinookPaths) + local units = ChinookChalk + local chalk = Reinforcements.ReinforceWithTransport(Greece, "tran", units , way, { way[2], way[1] })[2] + Utils.Do(chalk, function(unit) + Trigger.OnAddedToWorld(unit, IdleHunt) + end) + + ChinookAttacks = ChinookAttacks + 1 + if ChinookAttacks <= ChinookWaves[Map.LobbyOption("difficulty")] then + ChinookAttack() + end + end) +end + +ProduceInfantry = function() + if GermanyTent.IsDead or GermanyTent.Owner ~= Germany then + return + end + + Germany.Build({ Utils.Random(AlliedInfantry) }, function(units) + table.insert(AttackGroup, units[1]) + SendAttackGroup() + Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceInfantry) + end) +end + +ProduceVehicles = function() + if GermanyWarFactory.IsDead or GermanyWarFactory.Owner ~= Germany then + return + end + + Germany.Build({ Utils.Random(AlliedVehicles) }, function(units) + table.insert(AttackGroup, units[1]) + SendAttackGroup() + Trigger.AfterDelay(ProductionInterval[Map.LobbyOption("difficulty")], ProduceVehicles) + end) +end + +SendAttackGroup = function() + if #AttackGroup < AttackGroupSize then + return + end + + Utils.Do(AttackGroup, IdleHunt) + + AttackGroup = { } +end + +GreeceAircraft = function() + if (GreeceHpad1.IsDead or GreeceHpad1.Owner ~= Greece) and (GreeceHpad2.IsDead or GreeceHpad2.Owner ~= Greece) then + return + end + + Greece.Build(AlliedAircraftType, function(units) + local longbow = units[1] + Longbows[#Longbows + 1] = longbow + + Trigger.OnKilled(longbow, GreeceAircraft) + + local alive = Utils.Where(Longbows, function(y) return not y.IsDead end) + if #alive < 2 then + Trigger.AfterDelay(DateTime.Seconds(90), GreeceAircraft) + end + + InitializeAttackAircraft(longbow, USSR) + end) +end + +GermanAircraft = function() + if (GermanyHpad1.IsDead or GermanyHpad1.Owner ~= Germany) and (GermanyHpad2.IsDead or GermanyHpad2.Owner ~= Germany) then + return + end + + Germany.Build(AlliedAircraftType, function(units) + local longbow = units[1] + Longbows[#Longbows + 1] = longbow + + Trigger.OnKilled(longbow, GermanAircraft) + + local alive = Utils.Where(Longbows, function(y) return not y.IsDead end) + if #alive < 2 then + Trigger.AfterDelay(DateTime.Seconds(ProductionInterval[Map.LobbyOption("difficulty")] / 2), GermanAircraft) + end + + InitializeAttackAircraft(longbow, USSR) + end) +end + +WTransWaves = function() + local way = Utils.Random(WTransWays) + local units = Utils.Random(WTransUnits) + local attackUnits = Reinforcements.ReinforceWithTransport(Greece, "lst", units , way, { way[2], way[1] })[2] + Utils.Do(attackUnits, function(a) + Trigger.OnAddedToWorld(a, function() + a.AttackMove(DefaultCameraPosition.Location) + IdleHunt(a) + end) + end) + + Trigger.AfterDelay(WTransDelays, WTransWaves) +end + +ActivateAI = function() + local difficulty = Map.LobbyOption("difficulty") + WTransDelays = WTransDelays[difficulty] + ChinookDelay = ChinookDelay[difficulty] + + local buildings = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner ~= USSR and self.HasProperty("StartBuildingRepairs") end) + Utils.Do(buildings, function(actor) + Trigger.OnDamaged(actor, function(building) + if building.Owner ~= USSR and building.Health < building.MaxHealth * 3/4 then + building.StartBuildingRepairs() + end + end) + end) + + Trigger.AfterDelay(DateTime.Minutes(3), WTransWaves) + ChinookAttack() + ProduceInfantry() + ProduceVehicles() + GreeceAircraft() + GermanAircraft() +end diff -Nru openra-20200503/mods/ra/maps/soviet-09/soviet09.lua openra-20210321/mods/ra/maps/soviet-09/soviet09.lua --- openra-20200503/mods/ra/maps/soviet-09/soviet09.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-09/soviet09.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,109 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] + +TruckStops = { TruckStop1, TruckStop2, TruckStop3, TruckStop4, TruckStop5, TruckStop6, TruckStop7, TruckStop8 } +MissionStartAttackUnits = { StartAttack1tnk1, StartAttack1tnk2, StartAttackArty1, StartAttackArty2, StartAttackArty3 } +TruckEscape = { TruckEscape1, TruckEscape2, TruckEscape3, TruckEscape4, TruckEscape5, TruckEscapeWest } +BackupRoute = { TruckEscape2, TruckEscape1, TruckEscapeEast } + +MissionStart = function() + Utils.Do(TruckStops, function(waypoint) + StolenTruck.Move(waypoint.Location) + end) + + Trigger.AfterDelay(DateTime.Seconds(5), function() + Utils.Do(MissionStartAttackUnits, function(actor) + actor.AttackMove(DefaultCameraPosition.Location) + end) + end) + + Trigger.AfterDelay(DateTime.Seconds(45), function() + Media.DisplayMessage("Commander, the truck has stopped at a nearby allied base.\nAllied radio intercepts say the truck has orders to flee the battlefield\nif any Soviet units approach the base.") + end) + + Trigger.OnKilled(StolenTruck, function() + USSR.MarkCompletedObjective(DestroyTruck) + USSR.MarkCompletedObjective(DefendCommand) + end) + + Trigger.OnKilled(CommandCenter, function() + USSR.MarkFailedObjective(DefendCommand) + end) +end + +Trigger.OnEnteredProximityTrigger(TruckAlarm.CenterPosition, WDist.FromCells(11), function(actor, triggerflee) + if actor.Owner == USSR and actor.Type ~= "badr" and actor.Type ~= "u2" and actor.Type ~= "camera.spyplane" then + Trigger.RemoveProximityTrigger(triggerflee) + Media.DisplayMessage("The convoy truck is attempting to escape!") + EscapeCamera = Actor.Create("camera", true, { Owner = USSR, Location = TruckAlarm.Location }) + Media.PlaySoundNotification(USSR, "AlertBleep") + Utils.Do(TruckEscape, function(waypoint) + StolenTruck.Move(waypoint.Location) + end) + + Trigger.AfterDelay(DateTime.Seconds(5), function() + EscapeCamera.Destroy() + end) + + Trigger.OnIdle(StolenTruck, function() + Utils.Do(BackupRoute, function(waypoint) + StolenTruck.Move(waypoint.Location) + end) + end) + end +end) + +Trigger.OnEnteredFootprint(({ TruckEscapeWest.Location } or { TruckEscapeEast.Location }), function(actor, triggerlose) + if actor.Owner == Greece and actor.Type == "truk" then + Trigger.RemoveFootprintTrigger(triggerlose) + actor.Destroy() + USSR.MarkFailedObjective(DestroyTruck) + end +end) + +Tick = function() + Greece.Cash = 50000 + Germany.Cash = 50000 +end + +WorldLoaded = function() + USSR = Player.GetPlayer("USSR") + Germany = Player.GetPlayer("Germany") + Greece = Player.GetPlayer("Greece") + + Trigger.OnObjectiveAdded(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") + end) + + DestroyTruck = USSR.AddObjective("Destroy the stolen convoy truck.\nDo not let it escape.") + DefendCommand = USSR.AddObjective("Defend our forward command center.") + + Trigger.OnObjectiveCompleted(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") + end) + Trigger.OnObjectiveFailed(USSR, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") + end) + + Trigger.OnPlayerLost(USSR, function() + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(USSR, "MissionFailed") + end) + end) + Trigger.OnPlayerWon(USSR, function() + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(USSR, "MissionAccomplished") + end) + end) + + Camera.Position = DefaultCameraPosition.CenterPosition + + MissionStart() + ActivateAI() +end Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/map.bin and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/map.bin differ diff -Nru openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/map.yaml openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/map.yaml --- openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -31,11 +31,11 @@ Enemies: Greece, GoodGuy, Spain, France, USSR PlayerReference@Greece: Name: Greece + Bot: campaign Faction: allies Color: ABB7E4 Allies: Spain, France, GoodGuy Enemies: USSR, Creeps - Bot: campaign PlayerReference@USSR: Name: USSR AllowBots: False @@ -50,25 +50,25 @@ Enemies: Greece, GoodGuy, Spain, France, Creeps PlayerReference@GoodGuy: Name: GoodGuy + Bot: campaign Faction: allies Color: ABB7E4 Allies: Greece, Spain, France Enemies: USSR, Creeps - Bot: campaign PlayerReference@Spain: Name: Spain + Bot: campaign Faction: allies Color: F6D679 Allies: Greece, GoodGuy, France Enemies: USSR, Creeps - Bot: campaign PlayerReference@France: Name: France + Bot: campaign Faction: allies Color: 5DC2A5 Allies: Greece, GoodGuy, Spain Enemies: USSR, Creeps - Bot: campaign Actors: Actor0: cycl @@ -83,51 +83,18 @@ Actor3: cycl Location: 60,23 Owner: Greece - Actor4: brik - Location: 92,23 - Owner: Neutral Actor5: cycl Location: 50,24 Owner: Greece Actor6: cycl Location: 60,24 Owner: Greece - Actor7: brik - Location: 92,24 - Owner: Neutral - Actor8: brik - Location: 92,25 - Owner: Neutral - Actor9: brik - Location: 92,26 - Owner: Neutral - Actor10: brik - Location: 92,27 - Owner: Neutral - Actor11: brik - Location: 92,28 - Owner: Neutral - Actor12: brik - Location: 92,29 - Owner: Neutral - Actor13: brik - Location: 92,30 - Owner: Neutral - Actor14: brik - Location: 92,31 - Owner: Neutral - Actor15: brik - Location: 92,32 - Owner: Neutral Actor16: cycl Location: 50,33 Owner: Greece Actor17: cycl Location: 60,33 Owner: Greece - Actor18: brik - Location: 92,33 - Owner: Neutral Actor19: cycl Location: 50,34 Owner: Greece @@ -140,9 +107,6 @@ Actor22: cycl Location: 60,34 Owner: Greece - Actor23: brik - Location: 92,34 - Owner: Neutral Actor24: cycl Location: 71,35 Owner: Greece @@ -164,39 +128,24 @@ Actor30: cycl Location: 77,35 Owner: Greece - Actor31: brik - Location: 92,35 - Owner: Neutral Actor32: cycl Location: 71,36 Owner: Greece Actor33: cycl Location: 77,36 Owner: Greece - Actor34: brik - Location: 92,36 - Owner: Neutral Actor35: cycl Location: 77,37 Owner: Greece - Actor36: brik - Location: 92,37 - Owner: Neutral Actor37: cycl Location: 77,38 Owner: Greece - Actor38: brik - Location: 92,38 - Owner: Neutral Actor39: cycl Location: 71,39 Owner: Greece Actor40: cycl Location: 77,39 Owner: Greece - Actor41: brik - Location: 92,39 - Owner: Neutral Actor42: cycl Location: 71,40 Owner: Greece @@ -218,75 +167,6 @@ Actor48: cycl Location: 77,40 Owner: Greece - Actor49: brik - Location: 92,40 - Owner: Neutral - Actor50: brik - Location: 92,41 - Owner: Neutral - Actor51: brik - Location: 92,42 - Owner: Neutral - Actor52: brik - Location: 92,43 - Owner: Neutral - Actor53: brik - Location: 92,44 - Owner: Neutral - Actor54: brik - Location: 92,45 - Owner: Neutral - Actor55: brik - Location: 92,46 - Owner: Neutral - Actor56: brik - Location: 92,47 - Owner: Neutral - Actor57: brik - Location: 92,48 - Owner: Neutral - Actor58: brik - Location: 92,49 - Owner: Neutral - Actor59: brik - Location: 92,50 - Owner: Neutral - Actor60: brik - Location: 92,51 - Owner: Neutral - Actor61: brik - Location: 92,52 - Owner: Neutral - Actor62: brik - Location: 83,53 - Owner: Neutral - Actor63: brik - Location: 84,53 - Owner: Neutral - Actor64: brik - Location: 85,53 - Owner: Neutral - Actor65: brik - Location: 86,53 - Owner: Neutral - Actor66: brik - Location: 87,53 - Owner: Neutral - Actor67: brik - Location: 88,53 - Owner: Neutral - Actor68: brik - Location: 89,53 - Owner: Neutral - Actor69: brik - Location: 90,53 - Owner: Neutral - Actor70: brik - Location: 91,53 - Owner: Neutral - Actor71: brik - Location: 92,53 - Owner: Neutral Actor72: brik Location: 51,56 Owner: Greece @@ -506,12 +386,6 @@ Actor144: brik Location: 55,95 Owner: USSR - Actor145: brik - Location: 55,96 - Owner: Neutral - Actor146: brik - Location: 78,86 - Owner: Neutral Actor147: tc02 Location: 45,23 Owner: Neutral @@ -875,15 +749,15 @@ HTurret01: hgun Location: 53,68 Owner: France - Facing: 127 + Facing: 508 HTurret02: hgun Location: 55,68 Owner: France - Facing: 127 + Facing: 508 HTurret03: hgun Location: 57,68 Owner: France - Facing: 127 + Facing: 508 Actor270: barl Location: 26,75 Owner: Greece @@ -989,87 +863,87 @@ SupplyTruck01: truk Location: 57,25 Owner: Greece - Facing: 159 + Facing: 636 LightTankGuard01: 1tnk Location: 32,26 Owner: Greece - Facing: 95 + Facing: 380 SupplyTruck02: truk Location: 56,26 Owner: Greece - Facing: 159 + Facing: 636 RangerGuard04: jeep Location: 52,27 Owner: Greece - Facing: 63 + Facing: 252 LightTankGuard02: 1tnk Location: 61,30 Owner: Greece - Facing: 63 + Facing: 252 RangerGuard03: jeep Location: 37,33 Owner: Greece - Facing: 31 + Facing: 124 RangerGuard02: jeep Location: 21,46 Owner: Greece - Facing: 223 + Facing: 892 LightTankGuard03: 1tnk Location: 71,56 Owner: Greece - Facing: 31 + Facing: 124 MediumTankGuard01: 2tnk Location: 19,62 Owner: Greece - Facing: 159 + Facing: 636 RangerGuard01: jeep Location: 23,72 Owner: Greece - Facing: 159 + Facing: 636 PlyrHvyTnk01: 3tnk Location: 68,85 Owner: USSR - Facing: 31 + Facing: 124 PlyrMthTnk01: 4tnk Location: 69,85 Owner: USSR - Facing: 31 + Facing: 124 PlyrHvyTnk02: 3tnk Location: 71,85 Owner: USSR - Facing: 31 + Facing: 124 PlyrHvyTnk03: 3tnk Location: 65,86 Owner: USSR - Facing: 31 + Facing: 124 PlyrHvyTnk04: 3tnk Location: 66,86 Owner: USSR - Facing: 31 + Facing: 124 PlyrMthTnk02: 4tnk Location: 67,86 Owner: USSR - Facing: 31 + Facing: 124 PlyrHvyTnk05: 3tnk Location: 72,86 Owner: USSR - Facing: 31 + Facing: 124 PlyrV2RL01: v2rl Location: 71,87 Owner: USSR - Facing: 31 + Facing: 124 PlyrV2RL02: v2rl Location: 69,88 Owner: USSR - Facing: 31 + Facing: 124 PlyrV2RL03: v2rl Location: 73,89 Owner: USSR - Facing: 31 + Facing: 124 PlyrV2RL04: v2rl Location: 71,90 Owner: USSR - Facing: 31 + Facing: 124 Actor327: c7 Location: 58,23 Owner: Greece @@ -1097,12 +971,12 @@ Actor333: e3 Location: 34,27 Owner: Greece - Facing: 31 + Facing: 124 SubCell: 3 RiflemanGuard01: e1 Location: 39,28 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 1 InfGuardSquad03Unit01: e1 Location: 53,28 @@ -1127,7 +1001,7 @@ Actor340: e3 Location: 34,35 Owner: Greece - Facing: 63 + Facing: 252 SubCell: 4 InfGuardSquad02Unit01: e3 Location: 25,44 @@ -1144,7 +1018,7 @@ MineSoldier01: e1 Location: 32,49 Owner: GoodGuy - Facing: 159 + Facing: 636 SubCell: 1 Stance: HoldFire TanyaSquadUnit01: e1 @@ -1158,7 +1032,7 @@ MineSoldier02: e1 Location: 31,50 Owner: GoodGuy - Facing: 127 + Facing: 508 SubCell: 4 Stance: HoldFire TanyaSquadUnit03: e1 @@ -1176,13 +1050,13 @@ MineSoldier03: e1 Location: 32,51 Owner: GoodGuy - Facing: 127 + Facing: 508 SubCell: 1 Stance: HoldFire MineSoldier04: e1 Location: 34,51 Owner: GoodGuy - Facing: 95 + Facing: 380 SubCell: 2 Stance: HoldFire TanyaSquadUnit05: e1 @@ -1196,24 +1070,24 @@ MineSoldier05: e1 Location: 30,52 Owner: GoodGuy - Facing: 127 + Facing: 508 SubCell: 2 Stance: HoldFire MineSoldier06: e1 Location: 33,52 Owner: GoodGuy - Facing: 127 + Facing: 508 SubCell: 1 Stance: HoldFire TownMedic01: medi Location: 26,57 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 4 TownMedic02: medi Location: 30,57 Owner: Greece - Facing: 159 + Facing: 636 SubCell: 2 Actor359: e1 Location: 75,57 @@ -1238,7 +1112,7 @@ TownMedic03: medi Location: 31,59 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 4 Actor365: e1 Location: 69,59 @@ -1255,27 +1129,27 @@ InfGuardSquad01Unit01: e3 Location: 23,61 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 5 InfGuardSquad01Unit02: e3 Location: 24,61 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 5 InfGuardSquad01Unit03: e3 Location: 24,61 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 4 InfGuardSquad01Unit04: e3 Location: 24,61 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 1 InfGuardSquad01Unit05: e3 Location: 24,62 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 1 InitialHuntUnit01: e3 Location: 28,74 @@ -1292,13 +1166,13 @@ InitialRifleman01: e1 Location: 24,76 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 4 Health: 1 InitialRifleman02: e1 Location: 24,76 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 5 Health: 1 InitialHuntUnit04: e3 @@ -1312,7 +1186,7 @@ InitialHuntUnit06: e3 Location: 30,76 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 3 InitialHuntUnit07: e3 Location: 26,77 @@ -1329,19 +1203,19 @@ TnkGrd01: 2tnk Location: 54,69 Owner: Greece - Facing: 127 + Facing: 508 TnkGrd02: 2tnk Location: 53,71 Owner: Greece - Facing: 127 + Facing: 508 TnkGrd03: 2tnk Location: 57,71 Owner: Greece - Facing: 127 + Facing: 508 TnkGrd04: 2tnk Location: 56,69 Owner: Greece - Facing: 127 + Facing: 508 waypoint13: waypoint Location: 56,25 Owner: Neutral diff -Nru openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/notifications.yaml openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/notifications.yaml --- openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/notifications.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/notifications.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,3 +1,3 @@ -Sounds: - Notifications: - rokroll: rokroll1 \ No newline at end of file +Sounds: + Notifications: + rokroll: rokroll1 diff -Nru openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/rules.yaml openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/rules.yaml --- openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,6 +1,6 @@ World: LuaScript: - Scripts: scu35ea.lua, scu35ea-AI.lua + Scripts: soviet-soldier-volkov-n-chitzkoi.lua, soviet-soldier-volkov-n-chitzkoi-AI.lua MissionData: Briefing: The Allies have stolen a new armor plating from us. With it, they can make structures nearly invulnerable. Their processing plant must be destroyed.\n\nFor this critical mission, we are allowing you access to Soldier Volkov. Use him and his cybernetic dog to sabotage the Allied control center, allowing our units in the southeast access to the alloy facility.\n\nThe mission is a success when Volkov destroys the control center, and our units destroy the alloy facility.\n WinVideo: grvestne.vqa @@ -14,18 +14,7 @@ hard: Hard Default: easy -Player: - LobbyPrerequisiteCheckbox@GLOBALBOUNTY: - Enabled: False - Locked: True - -MSLO: - Buildable: - Prerequisites: ~disabled - E7: - Buildable: - Prerequisites: ~disabled Health: HP: 25000 Armor: @@ -35,10 +24,6 @@ Buildable: Prerequisites: ~vehicles.allies, ~techlevel.medium -CA: - Buildable: - Prerequisites: ~syrd, ~techlevel.high - C2: Inherits@2: ^ArmedCivilian @@ -68,15 +53,13 @@ Actor: healcrate HOSP: - Tooltip: - GenericName: Hospital - GenericVisibility: Enemy, Ally, Neutral - GenericStancePrefix: false - -TooltipDescription@ally: - -TooltipDescription@other: SpawnActorOnDeath: Actor: healcrate +HEALCRATE: + Crate: + Lifetime: 0 + ^Vehicle: -Demolishable: @@ -86,8 +69,6 @@ AFAC: Inherits: BIO - Buildable: - Prerequisites: ~disabled Health: HP: 400000 Tooltip: @@ -95,25 +76,16 @@ GenericName: Alloy Facility GenericVisibility: Enemy, Ally, Neutral GenericStancePrefix: false - Capturable: - Types: ~disabled - -EngineerRepairable: - -GpsDot: RenderSprites: Image: BIO CCEN: Inherits: ATEK - Buildable: - Prerequisites: ~disabled Tooltip: Name: Control Center GenericName: Control Center GenericVisibility: Enemy, Ally, Neutral GenericStancePrefix: false - Capturable: - Types: ~disabled - -EngineerRepairable: GpsPower: Prerequisites: ~disabled Power: @@ -123,8 +95,6 @@ HGUN: Inherits: GUN - Buildable: - Prerequisites: ~disabled Valued: Cost: 2800 Tooltip: @@ -142,8 +112,6 @@ ZKOI: Inherits: DOG - Buildable: - Prerequisites: ~disabled Valued: Cost: 2000 Tooltip: @@ -161,8 +129,6 @@ VOLK: Inherits: GNRL - Buildable: - Prerequisites: ~disabled Valued: Cost: 3000 Tooltip: @@ -189,8 +155,6 @@ VoiceSet: GenericVoice Armament: Weapon: VolkovWeapon - DetectCloaked: - CloakTypes: Cloak, Thief RenderSprites: Image: GNRL diff -Nru openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/scu35ea-AI.lua openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/scu35ea-AI.lua --- openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/scu35ea-AI.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/scu35ea-AI.lua 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ ---[[ - Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - This file is part of OpenRA, which is free software. It is made - available to you under the terms of the GNU General Public License - as published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. For more - information, see COPYING. -]] - -AlliedInfantryTypes = { "e1", "e3" } -if Map.LobbyOption("difficulty") == "easy" then - AlliedArmorTypes = { "1tnk", "1tnk" } -else - AlliedArmorTypes = { "1tnk", "2tnk" } -end -if Map.LobbyOption("difficulty") == "hard" then - AlliedNavyGuard = { "ca", "ca" } -else - AlliedNavyGuard = { "ca" } -end -ArmorAttackNumbers = -{ - easy = 2, - normal = 5, - hard = 8 -} -ArmorAttackDelays = -{ - easy = DateTime.Seconds(45), - normal = DateTime.Seconds(30), - hard = DateTime.Seconds(10) -} -AlliedWarFactRally = { waypoint2, waypoint9, waypoint10, waypoint11 } -InfAttack = { } -ArmorAttack = { } - -SendAttackToBase = function(units) - Utils.Do(units, function(unit) - if not unit.IsDead and unit.HasProperty("Hunt") then - unit.AttackMove(waypoint77.Location, 2) - Trigger.OnIdle(unit, unit.Hunt) - end - end) -end - -UnitsJustHunt = function(units) - Utils.Do(units, function(unit) - if not unit.IsDead and unit.HasProperty("Hunt") then - Trigger.OnIdle(unit, unit.Hunt) - end - end) -end - -ProduceInfantry = function() - if AlliedBarracks01.IsDead then - return - elseif (OreRefinery01.IsDead and OreRefinery02.IsDead or GreeceHarvestersAreDead) and greece.Resources <= 299 then - return - end - - local delay = Utils.RandomInteger(DateTime.Seconds(1), DateTime.Seconds(2)) - local toBuild = { Utils.Random(AlliedInfantryTypes) } - greece.Build(toBuild, function(unit) - InfAttack[#InfAttack + 1] = unit[1] - - if #InfAttack >= 5 then - UnitsJustHunt(InfAttack) - InfAttack = { } - Trigger.AfterDelay(DateTime.Seconds(1), ProduceInfantry) - else - Trigger.AfterDelay(delay, ProduceInfantry) - end - end) -end - -ProduceArmor = function() - if AlliedWarFact01.IsDead and AlliedWarFact02.IsDead then - return - elseif (OreRefinery01.IsDead and OreRefinery02.IsDead or GreeceHarvestersAreDead) and greece.Resources <= 699 then - return - end - - local delay = Utils.RandomInteger(DateTime.Seconds(7), DateTime.Seconds(10)) - local toBuild = { Utils.Random(AlliedArmorTypes) } - local Rally = Utils.Random(AlliedWarFactRally) - Utils.Do(AlliedWarFact, function(fact) fact.RallyPoint = Rally.Location end) - greece.Build(toBuild, function(unit) - ArmorAttack[#ArmorAttack + 1] = unit[1] - - if #ArmorAttack >= ArmorAttackNumbers[Map.LobbyOption("difficulty")] then - SendAttackToBase(ArmorAttack) - ArmorAttack = { } - Trigger.AfterDelay(ArmorAttackDelays[Map.LobbyOption("difficulty")], ProduceArmor) - else - Trigger.AfterDelay(delay, ProduceArmor) - end - end) -end - -ProduceNavyGuard = function() - if NavalYard01.IsDead then - return - elseif (OreRefinery01.IsDead and OreRefinery02.IsDead or GreeceHarvestersAreDead) and greece.Resources <= 2399 then - return - end - NavalYard01.RallyPoint = waypoint26.Location - greece.Build(AlliedNavyGuard, function(nvgrd) - Utils.Do(nvgrd, function(unit) - Trigger.OnKilled(unit, ProduceNavyGuard) - end) - end) -end diff -Nru openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/scu35ea.lua openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/scu35ea.lua --- openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/scu35ea.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/scu35ea.lua 1970-01-01 00:00:00.000000000 +0000 @@ -1,380 +0,0 @@ ---[[ - Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - This file is part of OpenRA, which is free software. It is made - available to you under the terms of the GNU General Public License - as published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. For more - information, see COPYING. -]] --- Unit Groups Setup -SuperTeam = { "zkoi", "volk" } -PlayerTankDivision = { PlyrHvyTnk01, PlyrHvyTnk02, PlyrHvyTnk03, PlyrHvyTnk04, PlyrHvyTnk05, PlyrMthTnk01, PlyrMthTnk02, PlyrV2RL01, PlyrV2RL02, PlyrV2RL03, PlyrV2RL04 } -InitialHuntTeam = { InitialHuntUnit01, InitialHuntUnit02, InitialHuntUnit03, InitialHuntUnit04, InitialHuntUnit05, InitialHuntUnit06, InitialHuntUnit07, InitialHuntUnit08, InitialHuntUnit09 } -BarrelsShooter = { InitialRifleman01, InitialRifleman02 } -TownPeoples = { TownDude01, TownDude02, TownDude03, TownDude04, TownMedic01, TownMedic02, TownMedic03 } -CivTeam01 = { "c1", "c3", "c4" } -CivTeam02 = { "c4", "c5", "c6" } -InfGuardSquad01 = { InfGuardSquad01Unit01, InfGuardSquad01Unit02, InfGuardSquad01Unit03, InfGuardSquad01Unit04, InfGuardSquad01Unit05, MediumTankGuard01 } -InfGuardSquad02 = { InfGuardSquad02Unit01, InfGuardSquad02Unit02, InfGuardSquad02Unit03, RangerGuard02 } -InfGuardSquad03 = { InfGuardSquad03Unit01, InfGuardSquad03Unit02, InfGuardSquad03Unit03, InfGuardSquad03Unit04, InfGuardSquad03Unit05, RangerGuard04 } -TanyaSquad = { TanyaSquadUnit01, TanyaSquadUnit02, TanyaSquadUnit03, TanyaSquadUnit04, TanyaSquadUnit05, TanyaSquadUnit06, TanyaSquadTanya } - --- Building Group Setup -AlliedOreRef = { OreRefinery01, OreRefinery02 } -AlliedWarFact = { AlliedWarFact01, AlliedWarFact02 } -HeavyTurrets = { HTurret01, HTurret02, HTurret03 } - --- Area Triggers Setup -SuperTeamLandCell = { CPos.New(21, 82), CPos.New(20, 81), CPos.New(21, 81), CPos.New(22, 81), CPos.New(20, 82), CPos.New(22, 82), CPos.New(21, 83), CPos.New(20, 83), CPos.New(22, 83) } -CivTeam01Trigger = { CPos.New(21, 58), CPos.New(21, 59), CPos.New(21, 60), CPos.New(22, 60), CPos.New(23, 60), CPos.New(22, 61), CPos.New(23, 61), CPos.New(24, 60), CPos.New(25, 60), CPos.New(24, 59), CPos.New(24, 58), CPos.New(23, 58), CPos.New(22, 58) } -CivTeam02Trigger = { CPos.New(33, 62), CPos.New(33, 63), CPos.New(32, 62), CPos.New(32, 63), CPos.New(31, 62), CPos.New(31, 63), CPos.New(31, 61), CPos.New(31, 60), CPos.New(30, 62), CPos.New(30, 61), CPos.New(30, 60), CPos.New(32, 60), CPos.New(33, 60) } -MineSoldierTrigger = { CPos.New(32, 58), CPos.New(32, 59), CPos.New(33, 58), CPos.New(33, 59), CPos.New(31, 59), CPos.New(30, 59), CPos.New(29, 59), CPos.New(29, 58), CPos.New(28, 59), CPos.New(27, 59), CPos.New(26, 59), CPos.New(25, 59), CPos.New(27, 58), CPos.New(26, 58), CPos.New(25, 58), CPos.New(24, 58), CPos.New(23, 58), CPos.New(26, 57), CPos.New(24, 57), CPos.New(24, 56), CPos.New(24, 55), CPos.New(24, 54), CPos.New(23, 57), CPos.New(23, 56), CPos.New(23, 55), CPos.New(23, 54), CPos.New(22, 57) } -MineRevealTrigger = { CPos.New(30, 46), CPos.New(31, 46), CPos.New(32, 46), CPos.New(33, 46), CPos.New(34, 46), CPos.New(35, 46), CPos.New(36, 46), CPos.New(37, 46) } -ParaTrigger = { CPos.New(18, 34), CPos.New(19, 34), CPos.New(20, 34), CPos.New(21, 34), CPos.New(22, 34), CPos.New(23, 34), CPos.New(24, 34), CPos.New(25, 34), CPos.New(18, 35), CPos.New(19, 35), CPos.New(20, 35), CPos.New(21, 35), CPos.New(22, 35), CPos.New(23, 35), CPos.New(24, 35), CPos.New(25, 35) } -TanyaTrigger = { CPos.New(59, 43), CPos.New(60, 43), CPos.New(61, 43), CPos.New(62, 43), CPos.New(63, 43), CPos.New(64, 43), CPos.New(65, 43), CPos.New(66, 43), CPos.New(67, 43), CPos.New(68, 43), CPos.New(69, 43), CPos.New(59, 44), CPos.New(60, 44), CPos.New(61, 44), CPos.New(62, 44), CPos.New(63, 44), CPos.New(64, 44), CPos.New(65, 44), CPos.New(66, 44), CPos.New(67, 44), CPos.New(68, 44), CPos.New(69, 44) } - --- Mission Variables Setup -GreeceHarvestersAreDead = false -AlloyFacilityDestroyed = false - -IdleHunt = function(actor) - Trigger.OnIdle(actor, function(a) - if a.IsInWorld then - a.Hunt() - end - end) -end - -WorldLoaded = function() - ---Players Setup - player = Player.GetPlayer("USSR") - greece = Player.GetPlayer("Greece") - goodguy = Player.GetPlayer("GoodGuy") - spain = Player.GetPlayer("Spain") - france = Player.GetPlayer("France") - - greece.Cash = 20000 - - Camera.Position = DefaultCameraPosition.CenterPosition - ---AI Production Setup - ProduceArmor() - - if Map.LobbyOption("difficulty") == "easy" then - Trigger.AfterDelay(DateTime.Minutes(10), ProduceNavyGuard) - elseif Map.LobbyOption("difficulty") == "normal" then - Trigger.AfterDelay(DateTime.Minutes(5), ProduceNavyGuard) - elseif Map.LobbyOption("difficulty") == "hard" then - ProduceNavyGuard() - end - ---Objectives Setup - Trigger.OnObjectiveAdded(player, function(p, id) - Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") - end) - Trigger.OnObjectiveCompleted(player, function(p, id) - Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") - end) - Trigger.OnObjectiveFailed(player, function(p, id) - Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") - end) - - DestroyControlCenter = player.AddPrimaryObjective("Destroy the Control Center.") - KeepTanksAlive = player.AddPrimaryObjective("Your tank division must not be destroyed before\n the alloy facility is dealt with.") - KeepVolkovAlive = player.AddPrimaryObjective("Keep Volkov Alive.") - KeepChitzkoiAlive = player.AddSecondaryObjective("Keep Chitzkoi Alive.") - - Trigger.OnPlayerWon(player, function() - Media.PlaySpeechNotification(player, "MissionAccomplished") - end) - Trigger.OnPlayerLost(player, function() - Media.PlaySpeechNotification(player, "MissionFailed") - end) - - Trigger.OnKilled(ControlCenter, function() - Utils.Do(HeavyTurrets, function(struc) - if not struc.IsDead then struc.Kill() end - end) - player.MarkCompletedObjective(DestroyControlCenter) - DestroyAlloyFacility = player.AddPrimaryObjective("Destroy the Alloy Facility.") - Media.PlaySpeechNotification(player, "FirstObjectiveMet") - Media.DisplayMessage("Excellent! The heavy turret control center is destroyed\n and now we can deal with the alloy facility.") - end) - - Trigger.OnKilled(AlloyFacility, function() - if not player.IsObjectiveCompleted(DestroyControlCenter) then --Prevent a crash if the player somehow manage to cheese the mission and destroy - player.MarkCompletedObjective(DestroyControlCenter) --the Alloy Facility without destroying the Control Center. - DestroyAlloyFacility = player.AddPrimaryObjective("Destroy the Alloy Facility.") - end - Trigger.AfterDelay(DateTime.Seconds(2), function() - player.MarkCompletedObjective(DestroyAlloyFacility) - player.MarkCompletedObjective(KeepTanksAlive) - player.MarkCompletedObjective(KeepVolkovAlive) - player.MarkCompletedObjective(KeepChitzkoiAlive) - end) - AlloyFacilityDestroyed = true - Media.PlaySpeechNotification(player, "SecondObjectiveMet") - end) - - Trigger.OnAllKilled(PlayerTankDivision, function() - if not AlloyFacilityDestroyed then player.MarkFailedObjective(KeepTanksAlive) end - end) - - Trigger.AfterDelay(0, function() - local AlliedBaseCamera = Actor.Create("camera", true, { Owner = player, Location = waypoint12.Location }) - local SuperTeamCamera = Actor.Create("camera", true, { Owner = player, Location = DefaultCameraPosition.Location }) - Trigger.AfterDelay(1, function() - if AlliedBaseCamera.IsInWorld then AlliedBaseCamera.Destroy() end - end) - Trigger.AfterDelay(DateTime.Seconds(20), function() - if SuperTeamCamera.IsInWorld then SuperTeamCamera.Destroy() end - end) - end) - ---Super Team Setup - Trigger.AfterDelay(DateTime.Seconds(2), function() - local spawn = superteamspawn.CenterPosition + WVec.New(0, 0, Actor.CruiseAltitude("badr")) - local transport = Actor.Create("badr", true, { CenterPosition = spawn, Owner = player, Facing = (superteamdrop.CenterPosition - spawn).Facing, Health = 3 }) - Utils.Do(SuperTeam, function(type) - local a = Actor.Create(type, false, { Owner = player }) - transport.LoadPassenger(a) - if a.Type == "volk" then - VolkovIsDead(a) - end - if a.Type == "zkoi" then - ChitzkoiIsDead(a) - end - end) - Media.PlaySpeechNotification(player, "ReinforcementsArrived") - transport.Paradrop(CPos.New(21, 82)) - end) - - Trigger.OnEnteredFootprint(SuperTeamLandCell, function(unit, id) - if unit.Owner == player then - Trigger.RemoveFootprintTrigger(id) - Trigger.AfterDelay(DateTime.Seconds(2), function() - if not BarrelsShooter[1].IsDead then - BarrelsShooter[1].Attack(Barrel, true, true) - elseif not BarrelsShooter[2].IsDead then - BarrelsShooter[2].Attack(Barrel, true, true) - end - Utils.Do(InitialHuntTeam, function(actor) - if not actor.IsDead then - Trigger.OnIdle(actor, actor.Hunt) - end - end) - end) - end - end) - ---Guards Squads Setup -- I used proximity triggers to make them hunt you down in order to mimic their behavior from the original mission - Trigger.OnEnteredProximityTrigger(RangerGuard01.CenterPosition, WDist.New(70 * 70), function(unit, id) - if not RangerGuard01.IsDead and unit.Owner == player then - Trigger.OnIdle(RangerGuard01, RangerGuard01.Hunt) - Trigger.RemoveProximityTrigger(id) - end - end) - - Trigger.OnEnteredProximityTrigger(waypoint7.CenterPosition, WDist.FromCells(6), function(unit, id) - if unit.Owner == player then - Utils.Do(InfGuardSquad01, function(actor) - if not actor.IsDead then - Trigger.OnIdle(actor, actor.Hunt) - end - end) - Trigger.RemoveProximityTrigger(id) - end - end) - - Trigger.OnEnteredProximityTrigger(InfGuardSquad02Unit01.CenterPosition, WDist.FromCells(6), function(unit, id) - if unit.Owner == player and (unit.Type == "volk" or unit.Type == "zkoi") then - Utils.Do(InfGuardSquad02, function(actor) - if not actor.IsDead then - Trigger.OnIdle(actor, actor.Hunt) - end - end) - Trigger.RemoveProximityTrigger(id) - end - end) - - Trigger.OnEnteredProximityTrigger(InfGuardSquad03Unit05.CenterPosition, WDist.FromCells(8), function(unit, id) - if unit.Owner == player then - local HospitalCamera = Actor.Create("camera", true, { Owner = player, Location = waypoint13.Location }) - Utils.Do(InfGuardSquad03, function(actor) - if not actor.IsDead then - Trigger.OnIdle(actor, actor.Hunt) - end - end) - if not SupplyTruck01.IsDead then - SupplyTruck01.Move(waypoint14.Location) - Trigger.AfterDelay(DateTime.Seconds(8), function() - if not SupplyTruck01.IsDead then - SupplyTruck01.Move(waypoint15.Location) - end - end) - end - Trigger.AfterDelay(DateTime.Seconds(15), function() - if HospitalCamera.IsInWorld then HospitalCamera.Destroy() end - end) - Trigger.RemoveProximityTrigger(id) - end - end) - - Trigger.OnEnteredProximityTrigger(LightTankGuard02.CenterPosition, WDist.FromCells(8), function(unit, id) - if not LightTankGuard02.IsDead and unit.Owner == player and (unit.Type == "volk" or unit.Type == "zkoi") then - Trigger.OnIdle(LightTankGuard02, LightTankGuard02.Hunt) - Trigger.RemoveProximityTrigger(id) - end - end) - ---Tanya Squad Setup - Trigger.OnEnteredFootprint(TanyaTrigger, function(unit, id) - if unit.Owner == player then - if not TanyaSquadTanya.IsDead then - local TanyaSquadCamera = Actor.Create("camera", true, { Owner = player, Location = waypoint85.Location }) - Media.PlaySoundNotification(player, "rokroll") - Utils.Do(TanyaSquad, function(actor) - if not actor.IsDead then - Trigger.OnIdle(actor, actor.Hunt) - end - end) - Trigger.OnKilled(TanyaSquadTanya, function() - if TanyaSquadCamera.IsInWorld then - TanyaSquadCamera.Destroy() - end - end) - end - Trigger.RemoveFootprintTrigger(id) - end - end) - ---Town Setup - Utils.Do(TownPeoples, function(actor) - Trigger.OnDamaged(actor, function() - if not TownMedic01.IsDead then - TownMedic01.Patrol({ waypoint5.Location, waypoint6.Location, waypoint7.Location }, true, 0) - end - if not TownMedic02.IsDead then - TownMedic02.Patrol({ waypoint8.Location, waypoint7.Location, waypoint5.Location, waypoint6.Location }, true, 0) - end - end) - end) - - Trigger.OnEnteredFootprint(CivTeam01Trigger, function(unit, id) - if unit.Owner == player then - if not TownHouse03.IsDead then - local civ01 = Reinforcements.Reinforce(spain, CivTeam01, { civteam01spawn.Location }, 0) - Utils.Do(civ01, function(actor) - if not actor.IsDead then - Trigger.OnIdle(actor, actor.Hunt) - end - end) - end - Trigger.RemoveFootprintTrigger(id) - end - end) - - Trigger.OnEnteredFootprint(CivTeam02Trigger, function(unit, id) - if unit.Owner == player then - if not TownHouse04.IsDead then - local civ02 = Reinforcements.Reinforce(spain, CivTeam02, { civteam02spawn.Location }, 0) - Utils.Do(civ02, function(actor) - if not actor.IsDead then - Trigger.OnIdle(actor, actor.Hunt) - end - end) - end - Trigger.RemoveFootprintTrigger(id) - end - end) - ---Minefield Setup - Trigger.OnEnteredFootprint(MineSoldierTrigger, function(unit, id) - if unit.Owner == player then - local MineSoldierCamera1 = Actor.Create("camera", true, { Owner = player, Location = waypoint96.Location }) - Trigger.AfterDelay(DateTime.Seconds(10), function() - if MineSoldierCamera1.IsInWorld then MineSoldierCamera1.Destroy() end - end) - if not MineSoldier01.IsDead then - MineSoldier01.Patrol({ waypoint91.Location, waypoint95.Location, waypoint76.Location, waypoint93.Location }, false, 0) - end - if not MineSoldier02.IsDead then - MineSoldier02.Patrol({ waypoint92.Location, waypoint91.Location, waypoint76.Location, waypoint93.Location }, false, 0) - end - if not MineSoldier03.IsDead then - MineSoldier03.Patrol({ waypoint91.Location, waypoint95.Location, waypoint76.Location, waypoint93.Location }, false, 0) - end - if not MineSoldier04.IsDead then - MineSoldier04.Patrol({ waypoint92.Location, waypoint95.Location, waypoint76.Location, waypoint93.Location }, false, 0) - end - if not MineSoldier05.IsDead then - MineSoldier05.Patrol({ waypoint90.Location, waypoint91.Location, waypoint95.Location, waypoint76.Location, waypoint93.Location }, false, 0) - end - if not MineSoldier06.IsDead then - MineSoldier06.Patrol({ waypoint92.Location, waypoint91.Location, waypoint93.Location }, false, 0) - end - Trigger.RemoveFootprintTrigger(id) - end - end) - - Trigger.OnEnteredFootprint(MineRevealTrigger, function(unit, id) - if unit.Owner == goodguy then - local MineSoldierCamera2 = Actor.Create("camera", true, { Owner = player, Location = waypoint76.Location }) - Trigger.AfterDelay(DateTime.Seconds(12), function() - if MineSoldierCamera2.IsInWorld then MineSoldierCamera2.Destroy() end - end) - Trigger.RemoveFootprintTrigger(id) - end - end) - ---Paradrop Rifle Team Setup - Trigger.OnEnteredFootprint(ParaTrigger, function(unit, id) - if unit.Owner == player then - local powerproxy = Actor.Create("powerproxy.pararifles", true, { Owner = greece }) - local aircraft = powerproxy.ActivateParatroopers(waypoint89.CenterPosition, Facing.South) - local prtcamera = Actor.Create("camera", true, { Owner = player, Location = waypoint89.Location }) - Utils.Do(aircraft, function(a) - Trigger.OnPassengerExited(a, function(t, p) - IdleHunt(p) - end) - end) - Trigger.AfterDelay(DateTime.Seconds(10), function() - if prtcamera.IsInWorld then prtcamera.Destroy() end - end) - if Map.LobbyOption("difficulty") == "hard" and not RiflemanGuard01.IsDead then - Trigger.ClearAll(RiflemanGuard01) - ProduceInfantry() --Greece will start infantry production right away if the difficulty is set to hard - end - Trigger.RemoveFootprintTrigger(id) - end - end) - - Trigger.OnKilled(RiflemanGuard01, function() - ProduceInfantry() --Greece will start infantry production once this unit is dead just like in the original mission - end) - - Trigger.AfterDelay(DateTime.Seconds(1), function() - local GreeceHarvesters = greece.GetActorsByType("harv") - Trigger.OnAllKilled(GreeceHarvesters, function() - GreeceHarvestersAreDead = true - end) - end) - -end - -VolkovIsDead = function(a) - Trigger.OnKilled(a, function() - player.MarkFailedObjective(KeepVolkovAlive) - end) -end - -ChitzkoiIsDead = function(a) - Trigger.OnKilled(a, function() - player.MarkFailedObjective(KeepChitzkoiAlive) - Media.DisplayMessage("We can rebuild Chitzkoi. We have the technology.") - Trigger.AfterDelay(DateTime.Seconds(1), function() - Media.PlaySpeechNotification(player, "ObjectiveNotMet") - end) - end) -end diff -Nru openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/soviet-soldier-volkov-n-chitzkoi-AI.lua openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/soviet-soldier-volkov-n-chitzkoi-AI.lua --- openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/soviet-soldier-volkov-n-chitzkoi-AI.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/soviet-soldier-volkov-n-chitzkoi-AI.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,112 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] + +AlliedInfantryTypes = { "e1", "e3" } +if Map.LobbyOption("difficulty") == "easy" then + AlliedArmorTypes = { "1tnk", "1tnk" } +else + AlliedArmorTypes = { "1tnk", "2tnk" } +end +if Map.LobbyOption("difficulty") == "hard" then + AlliedNavyGuard = { "ca", "ca" } +else + AlliedNavyGuard = { "ca" } +end +ArmorAttackNumbers = +{ + easy = 2, + normal = 5, + hard = 8 +} +ArmorAttackDelays = +{ + easy = DateTime.Seconds(45), + normal = DateTime.Seconds(30), + hard = DateTime.Seconds(10) +} +AlliedWarFactRally = { waypoint2, waypoint9, waypoint10, waypoint11 } +InfAttack = { } +ArmorAttack = { } + +SendAttackToBase = function(units) + Utils.Do(units, function(unit) + if not unit.IsDead and unit.HasProperty("Hunt") then + unit.AttackMove(waypoint77.Location, 2) + Trigger.OnIdle(unit, unit.Hunt) + end + end) +end + +UnitsJustHunt = function(units) + Utils.Do(units, function(unit) + if not unit.IsDead and unit.HasProperty("Hunt") then + Trigger.OnIdle(unit, unit.Hunt) + end + end) +end + +ProduceInfantry = function() + if AlliedBarracks01.IsDead then + return + elseif (OreRefinery01.IsDead and OreRefinery02.IsDead or GreeceHarvestersAreDead) and greece.Resources <= 299 then + return + end + + local delay = Utils.RandomInteger(DateTime.Seconds(1), DateTime.Seconds(2)) + local toBuild = { Utils.Random(AlliedInfantryTypes) } + greece.Build(toBuild, function(unit) + InfAttack[#InfAttack + 1] = unit[1] + + if #InfAttack >= 5 then + UnitsJustHunt(InfAttack) + InfAttack = { } + Trigger.AfterDelay(DateTime.Seconds(1), ProduceInfantry) + else + Trigger.AfterDelay(delay, ProduceInfantry) + end + end) +end + +ProduceArmor = function() + if AlliedWarFact01.IsDead and AlliedWarFact02.IsDead then + return + elseif (OreRefinery01.IsDead and OreRefinery02.IsDead or GreeceHarvestersAreDead) and greece.Resources <= 699 then + return + end + + local delay = Utils.RandomInteger(DateTime.Seconds(7), DateTime.Seconds(10)) + local toBuild = { Utils.Random(AlliedArmorTypes) } + local Rally = Utils.Random(AlliedWarFactRally) + Utils.Do(AlliedWarFact, function(fact) fact.RallyPoint = Rally.Location end) + greece.Build(toBuild, function(unit) + ArmorAttack[#ArmorAttack + 1] = unit[1] + + if #ArmorAttack >= ArmorAttackNumbers[Map.LobbyOption("difficulty")] then + SendAttackToBase(ArmorAttack) + ArmorAttack = { } + Trigger.AfterDelay(ArmorAttackDelays[Map.LobbyOption("difficulty")], ProduceArmor) + else + Trigger.AfterDelay(delay, ProduceArmor) + end + end) +end + +ProduceNavyGuard = function() + if NavalYard01.IsDead then + return + elseif (OreRefinery01.IsDead and OreRefinery02.IsDead or GreeceHarvestersAreDead) and greece.Resources <= 2399 then + return + end + NavalYard01.RallyPoint = waypoint26.Location + greece.Build(AlliedNavyGuard, function(nvgrd) + Utils.Do(nvgrd, function(unit) + Trigger.OnKilled(unit, ProduceNavyGuard) + end) + end) +end diff -Nru openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/soviet-soldier-volkov-n-chitzkoi.lua openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/soviet-soldier-volkov-n-chitzkoi.lua --- openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/soviet-soldier-volkov-n-chitzkoi.lua 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/soviet-soldier-volkov-n-chitzkoi.lua 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,380 @@ +--[[ + Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] +-- Unit Groups Setup +SuperTeam = { "zkoi", "volk" } +PlayerTankDivision = { PlyrHvyTnk01, PlyrHvyTnk02, PlyrHvyTnk03, PlyrHvyTnk04, PlyrHvyTnk05, PlyrMthTnk01, PlyrMthTnk02, PlyrV2RL01, PlyrV2RL02, PlyrV2RL03, PlyrV2RL04 } +InitialHuntTeam = { InitialHuntUnit01, InitialHuntUnit02, InitialHuntUnit03, InitialHuntUnit04, InitialHuntUnit05, InitialHuntUnit06, InitialHuntUnit07, InitialHuntUnit08, InitialHuntUnit09 } +BarrelsShooter = { InitialRifleman01, InitialRifleman02 } +TownPeoples = { TownDude01, TownDude02, TownDude03, TownDude04, TownMedic01, TownMedic02, TownMedic03 } +CivTeam01 = { "c1", "c3", "c4" } +CivTeam02 = { "c4", "c5", "c6" } +InfGuardSquad01 = { InfGuardSquad01Unit01, InfGuardSquad01Unit02, InfGuardSquad01Unit03, InfGuardSquad01Unit04, InfGuardSquad01Unit05, MediumTankGuard01 } +InfGuardSquad02 = { InfGuardSquad02Unit01, InfGuardSquad02Unit02, InfGuardSquad02Unit03, RangerGuard02 } +InfGuardSquad03 = { InfGuardSquad03Unit01, InfGuardSquad03Unit02, InfGuardSquad03Unit03, InfGuardSquad03Unit04, InfGuardSquad03Unit05, RangerGuard04 } +TanyaSquad = { TanyaSquadUnit01, TanyaSquadUnit02, TanyaSquadUnit03, TanyaSquadUnit04, TanyaSquadUnit05, TanyaSquadUnit06, TanyaSquadTanya } + +-- Building Group Setup +AlliedOreRef = { OreRefinery01, OreRefinery02 } +AlliedWarFact = { AlliedWarFact01, AlliedWarFact02 } +HeavyTurrets = { HTurret01, HTurret02, HTurret03 } + +-- Area Triggers Setup +SuperTeamLandCell = { CPos.New(21, 82), CPos.New(20, 81), CPos.New(21, 81), CPos.New(22, 81), CPos.New(20, 82), CPos.New(22, 82), CPos.New(21, 83), CPos.New(20, 83), CPos.New(22, 83) } +CivTeam01Trigger = { CPos.New(21, 58), CPos.New(21, 59), CPos.New(21, 60), CPos.New(22, 60), CPos.New(23, 60), CPos.New(22, 61), CPos.New(23, 61), CPos.New(24, 60), CPos.New(25, 60), CPos.New(24, 59), CPos.New(24, 58), CPos.New(23, 58), CPos.New(22, 58) } +CivTeam02Trigger = { CPos.New(33, 62), CPos.New(33, 63), CPos.New(32, 62), CPos.New(32, 63), CPos.New(31, 62), CPos.New(31, 63), CPos.New(31, 61), CPos.New(31, 60), CPos.New(30, 62), CPos.New(30, 61), CPos.New(30, 60), CPos.New(32, 60), CPos.New(33, 60) } +MineSoldierTrigger = { CPos.New(32, 58), CPos.New(32, 59), CPos.New(33, 58), CPos.New(33, 59), CPos.New(31, 59), CPos.New(30, 59), CPos.New(29, 59), CPos.New(29, 58), CPos.New(28, 59), CPos.New(27, 59), CPos.New(26, 59), CPos.New(25, 59), CPos.New(27, 58), CPos.New(26, 58), CPos.New(25, 58), CPos.New(24, 58), CPos.New(23, 58), CPos.New(26, 57), CPos.New(24, 57), CPos.New(24, 56), CPos.New(24, 55), CPos.New(24, 54), CPos.New(23, 57), CPos.New(23, 56), CPos.New(23, 55), CPos.New(23, 54), CPos.New(22, 57) } +MineRevealTrigger = { CPos.New(30, 46), CPos.New(31, 46), CPos.New(32, 46), CPos.New(33, 46), CPos.New(34, 46), CPos.New(35, 46), CPos.New(36, 46), CPos.New(37, 46) } +ParaTrigger = { CPos.New(18, 34), CPos.New(19, 34), CPos.New(20, 34), CPos.New(21, 34), CPos.New(22, 34), CPos.New(23, 34), CPos.New(24, 34), CPos.New(25, 34), CPos.New(18, 35), CPos.New(19, 35), CPos.New(20, 35), CPos.New(21, 35), CPos.New(22, 35), CPos.New(23, 35), CPos.New(24, 35), CPos.New(25, 35) } +TanyaTrigger = { CPos.New(59, 43), CPos.New(60, 43), CPos.New(61, 43), CPos.New(62, 43), CPos.New(63, 43), CPos.New(64, 43), CPos.New(65, 43), CPos.New(66, 43), CPos.New(67, 43), CPos.New(68, 43), CPos.New(69, 43), CPos.New(59, 44), CPos.New(60, 44), CPos.New(61, 44), CPos.New(62, 44), CPos.New(63, 44), CPos.New(64, 44), CPos.New(65, 44), CPos.New(66, 44), CPos.New(67, 44), CPos.New(68, 44), CPos.New(69, 44) } + +-- Mission Variables Setup +GreeceHarvestersAreDead = false +AlloyFacilityDestroyed = false + +IdleHunt = function(actor) + Trigger.OnIdle(actor, function(a) + if a.IsInWorld then + a.Hunt() + end + end) +end + +WorldLoaded = function() + +--Players Setup + player = Player.GetPlayer("USSR") + greece = Player.GetPlayer("Greece") + goodguy = Player.GetPlayer("GoodGuy") + spain = Player.GetPlayer("Spain") + france = Player.GetPlayer("France") + + greece.Cash = 20000 + + Camera.Position = DefaultCameraPosition.CenterPosition + +--AI Production Setup + ProduceArmor() + + if Map.LobbyOption("difficulty") == "easy" then + Trigger.AfterDelay(DateTime.Minutes(10), ProduceNavyGuard) + elseif Map.LobbyOption("difficulty") == "normal" then + Trigger.AfterDelay(DateTime.Minutes(5), ProduceNavyGuard) + elseif Map.LobbyOption("difficulty") == "hard" then + ProduceNavyGuard() + end + +--Objectives Setup + Trigger.OnObjectiveAdded(player, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") + end) + Trigger.OnObjectiveCompleted(player, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed") + end) + Trigger.OnObjectiveFailed(player, function(p, id) + Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed") + end) + + DestroyControlCenter = player.AddPrimaryObjective("Destroy the Control Center.") + KeepTanksAlive = player.AddPrimaryObjective("Your tank division must not be destroyed before\n the alloy facility is dealt with.") + KeepVolkovAlive = player.AddPrimaryObjective("Keep Volkov Alive.") + KeepChitzkoiAlive = player.AddSecondaryObjective("Keep Chitzkoi Alive.") + + Trigger.OnPlayerWon(player, function() + Media.PlaySpeechNotification(player, "MissionAccomplished") + end) + Trigger.OnPlayerLost(player, function() + Media.PlaySpeechNotification(player, "MissionFailed") + end) + + Trigger.OnKilled(ControlCenter, function() + Utils.Do(HeavyTurrets, function(struc) + if not struc.IsDead then struc.Kill() end + end) + player.MarkCompletedObjective(DestroyControlCenter) + DestroyAlloyFacility = player.AddPrimaryObjective("Destroy the Alloy Facility.") + Media.PlaySpeechNotification(player, "FirstObjectiveMet") + Media.DisplayMessage("Excellent! The heavy turret control center is destroyed\n and now we can deal with the alloy facility.") + end) + + Trigger.OnKilled(AlloyFacility, function() + if not player.IsObjectiveCompleted(DestroyControlCenter) then --Prevent a crash if the player somehow manage to cheese the mission and destroy + player.MarkCompletedObjective(DestroyControlCenter) --the Alloy Facility without destroying the Control Center. + DestroyAlloyFacility = player.AddPrimaryObjective("Destroy the Alloy Facility.") + end + Trigger.AfterDelay(DateTime.Seconds(2), function() + player.MarkCompletedObjective(DestroyAlloyFacility) + player.MarkCompletedObjective(KeepTanksAlive) + player.MarkCompletedObjective(KeepVolkovAlive) + player.MarkCompletedObjective(KeepChitzkoiAlive) + end) + AlloyFacilityDestroyed = true + Media.PlaySpeechNotification(player, "SecondObjectiveMet") + end) + + Trigger.OnAllKilled(PlayerTankDivision, function() + if not AlloyFacilityDestroyed then player.MarkFailedObjective(KeepTanksAlive) end + end) + + Trigger.AfterDelay(0, function() + local AlliedBaseCamera = Actor.Create("camera", true, { Owner = player, Location = waypoint12.Location }) + local SuperTeamCamera = Actor.Create("camera", true, { Owner = player, Location = DefaultCameraPosition.Location }) + Trigger.AfterDelay(1, function() + if AlliedBaseCamera.IsInWorld then AlliedBaseCamera.Destroy() end + end) + Trigger.AfterDelay(DateTime.Seconds(20), function() + if SuperTeamCamera.IsInWorld then SuperTeamCamera.Destroy() end + end) + end) + +--Super Team Setup + Trigger.AfterDelay(DateTime.Seconds(2), function() + local spawn = superteamspawn.CenterPosition + WVec.New(0, 0, Actor.CruiseAltitude("badr")) + local transport = Actor.Create("badr", true, { CenterPosition = spawn, Owner = player, Facing = (superteamdrop.CenterPosition - spawn).Facing, Health = 3 }) + Utils.Do(SuperTeam, function(type) + local a = Actor.Create(type, false, { Owner = player }) + transport.LoadPassenger(a) + if a.Type == "volk" then + VolkovIsDead(a) + end + if a.Type == "zkoi" then + ChitzkoiIsDead(a) + end + end) + Media.PlaySpeechNotification(player, "ReinforcementsArrived") + transport.Paradrop(CPos.New(21, 82)) + end) + + Trigger.OnEnteredFootprint(SuperTeamLandCell, function(unit, id) + if unit.Owner == player then + Trigger.RemoveFootprintTrigger(id) + Trigger.AfterDelay(DateTime.Seconds(2), function() + if not BarrelsShooter[1].IsDead then + BarrelsShooter[1].Attack(Barrel, true, true) + elseif not BarrelsShooter[2].IsDead then + BarrelsShooter[2].Attack(Barrel, true, true) + end + Utils.Do(InitialHuntTeam, function(actor) + if not actor.IsDead then + Trigger.OnIdle(actor, actor.Hunt) + end + end) + end) + end + end) + +--Guards Squads Setup -- I used proximity triggers to make them hunt you down in order to mimic their behavior from the original mission + Trigger.OnEnteredProximityTrigger(RangerGuard01.CenterPosition, WDist.New(70 * 70), function(unit, id) + if not RangerGuard01.IsDead and unit.Owner == player then + Trigger.OnIdle(RangerGuard01, RangerGuard01.Hunt) + Trigger.RemoveProximityTrigger(id) + end + end) + + Trigger.OnEnteredProximityTrigger(waypoint7.CenterPosition, WDist.FromCells(6), function(unit, id) + if unit.Owner == player then + Utils.Do(InfGuardSquad01, function(actor) + if not actor.IsDead then + Trigger.OnIdle(actor, actor.Hunt) + end + end) + Trigger.RemoveProximityTrigger(id) + end + end) + + Trigger.OnEnteredProximityTrigger(InfGuardSquad02Unit01.CenterPosition, WDist.FromCells(6), function(unit, id) + if unit.Owner == player and (unit.Type == "volk" or unit.Type == "zkoi") then + Utils.Do(InfGuardSquad02, function(actor) + if not actor.IsDead then + Trigger.OnIdle(actor, actor.Hunt) + end + end) + Trigger.RemoveProximityTrigger(id) + end + end) + + Trigger.OnEnteredProximityTrigger(InfGuardSquad03Unit05.CenterPosition, WDist.FromCells(8), function(unit, id) + if unit.Owner == player then + local HospitalCamera = Actor.Create("camera", true, { Owner = player, Location = waypoint13.Location }) + Utils.Do(InfGuardSquad03, function(actor) + if not actor.IsDead then + Trigger.OnIdle(actor, actor.Hunt) + end + end) + if not SupplyTruck01.IsDead then + SupplyTruck01.Move(waypoint14.Location) + Trigger.AfterDelay(DateTime.Seconds(8), function() + if not SupplyTruck01.IsDead then + SupplyTruck01.Move(waypoint15.Location) + end + end) + end + Trigger.AfterDelay(DateTime.Seconds(15), function() + if HospitalCamera.IsInWorld then HospitalCamera.Destroy() end + end) + Trigger.RemoveProximityTrigger(id) + end + end) + + Trigger.OnEnteredProximityTrigger(LightTankGuard02.CenterPosition, WDist.FromCells(8), function(unit, id) + if not LightTankGuard02.IsDead and unit.Owner == player and (unit.Type == "volk" or unit.Type == "zkoi") then + Trigger.OnIdle(LightTankGuard02, LightTankGuard02.Hunt) + Trigger.RemoveProximityTrigger(id) + end + end) + +--Tanya Squad Setup + Trigger.OnEnteredFootprint(TanyaTrigger, function(unit, id) + if unit.Owner == player then + if not TanyaSquadTanya.IsDead then + local TanyaSquadCamera = Actor.Create("camera", true, { Owner = player, Location = waypoint85.Location }) + Media.PlaySoundNotification(player, "rokroll") + Utils.Do(TanyaSquad, function(actor) + if not actor.IsDead then + Trigger.OnIdle(actor, actor.Hunt) + end + end) + Trigger.OnKilled(TanyaSquadTanya, function() + if TanyaSquadCamera.IsInWorld then + TanyaSquadCamera.Destroy() + end + end) + end + Trigger.RemoveFootprintTrigger(id) + end + end) + +--Town Setup + Utils.Do(TownPeoples, function(actor) + Trigger.OnDamaged(actor, function() + if not TownMedic01.IsDead then + TownMedic01.Patrol({ waypoint5.Location, waypoint6.Location, waypoint7.Location }, true, 0) + end + if not TownMedic02.IsDead then + TownMedic02.Patrol({ waypoint8.Location, waypoint7.Location, waypoint5.Location, waypoint6.Location }, true, 0) + end + end) + end) + + Trigger.OnEnteredFootprint(CivTeam01Trigger, function(unit, id) + if unit.Owner == player then + if not TownHouse03.IsDead then + local civ01 = Reinforcements.Reinforce(spain, CivTeam01, { civteam01spawn.Location }, 0) + Utils.Do(civ01, function(actor) + if not actor.IsDead then + Trigger.OnIdle(actor, actor.Hunt) + end + end) + end + Trigger.RemoveFootprintTrigger(id) + end + end) + + Trigger.OnEnteredFootprint(CivTeam02Trigger, function(unit, id) + if unit.Owner == player then + if not TownHouse04.IsDead then + local civ02 = Reinforcements.Reinforce(spain, CivTeam02, { civteam02spawn.Location }, 0) + Utils.Do(civ02, function(actor) + if not actor.IsDead then + Trigger.OnIdle(actor, actor.Hunt) + end + end) + end + Trigger.RemoveFootprintTrigger(id) + end + end) + +--Minefield Setup + Trigger.OnEnteredFootprint(MineSoldierTrigger, function(unit, id) + if unit.Owner == player then + local MineSoldierCamera1 = Actor.Create("camera", true, { Owner = player, Location = waypoint96.Location }) + Trigger.AfterDelay(DateTime.Seconds(10), function() + if MineSoldierCamera1.IsInWorld then MineSoldierCamera1.Destroy() end + end) + if not MineSoldier01.IsDead then + MineSoldier01.Patrol({ waypoint91.Location, waypoint95.Location, waypoint76.Location, waypoint93.Location }, false, 0) + end + if not MineSoldier02.IsDead then + MineSoldier02.Patrol({ waypoint92.Location, waypoint91.Location, waypoint76.Location, waypoint93.Location }, false, 0) + end + if not MineSoldier03.IsDead then + MineSoldier03.Patrol({ waypoint91.Location, waypoint95.Location, waypoint76.Location, waypoint93.Location }, false, 0) + end + if not MineSoldier04.IsDead then + MineSoldier04.Patrol({ waypoint92.Location, waypoint95.Location, waypoint76.Location, waypoint93.Location }, false, 0) + end + if not MineSoldier05.IsDead then + MineSoldier05.Patrol({ waypoint90.Location, waypoint91.Location, waypoint95.Location, waypoint76.Location, waypoint93.Location }, false, 0) + end + if not MineSoldier06.IsDead then + MineSoldier06.Patrol({ waypoint92.Location, waypoint91.Location, waypoint93.Location }, false, 0) + end + Trigger.RemoveFootprintTrigger(id) + end + end) + + Trigger.OnEnteredFootprint(MineRevealTrigger, function(unit, id) + if unit.Owner == goodguy then + local MineSoldierCamera2 = Actor.Create("camera", true, { Owner = player, Location = waypoint76.Location }) + Trigger.AfterDelay(DateTime.Seconds(12), function() + if MineSoldierCamera2.IsInWorld then MineSoldierCamera2.Destroy() end + end) + Trigger.RemoveFootprintTrigger(id) + end + end) + +--Paradrop Rifle Team Setup + Trigger.OnEnteredFootprint(ParaTrigger, function(unit, id) + if unit.Owner == player then + local powerproxy = Actor.Create("powerproxy.pararifles", true, { Owner = greece }) + local aircraft = powerproxy.TargetParatroopers(waypoint89.CenterPosition, Angle.South) + local prtcamera = Actor.Create("camera", true, { Owner = player, Location = waypoint89.Location }) + Utils.Do(aircraft, function(a) + Trigger.OnPassengerExited(a, function(t, p) + IdleHunt(p) + end) + end) + Trigger.AfterDelay(DateTime.Seconds(10), function() + if prtcamera.IsInWorld then prtcamera.Destroy() end + end) + if Map.LobbyOption("difficulty") == "hard" and not RiflemanGuard01.IsDead then + Trigger.ClearAll(RiflemanGuard01) + ProduceInfantry() --Greece will start infantry production right away if the difficulty is set to hard + end + Trigger.RemoveFootprintTrigger(id) + end + end) + + Trigger.OnKilled(RiflemanGuard01, function() + ProduceInfantry() --Greece will start infantry production once this unit is dead just like in the original mission + end) + + Trigger.AfterDelay(DateTime.Seconds(1), function() + local GreeceHarvesters = greece.GetActorsByType("harv") + Trigger.OnAllKilled(GreeceHarvesters, function() + GreeceHarvestersAreDead = true + end) + end) + +end + +VolkovIsDead = function(a) + Trigger.OnKilled(a, function() + player.MarkFailedObjective(KeepVolkovAlive) + end) +end + +ChitzkoiIsDead = function(a) + Trigger.OnKilled(a, function() + player.MarkFailedObjective(KeepChitzkoiAlive) + Media.DisplayMessage("We can rebuild Chitzkoi. We have the technology.") + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(player, "ObjectiveNotMet") + end) + end) +end diff -Nru openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/weapons.yaml openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/weapons.yaml --- openra-20200503/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/weapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/soviet-soldier-volkov-n-chitzkoi/weapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -10,8 +10,8 @@ Inherits: SilencedPPK ReloadDelay: 25 Range: 6c0 - -ValidTargets: - InvalidTargets: Air, Bridge, Structure + ValidTargets: Ground, GroundActor, Water, WaterActor + InvalidTargets: Bridge, Structure, Wall Warhead@1Dam: SpreadDamage Spread: 256 Versus: @@ -20,7 +20,7 @@ Light: 60 Heavy: 25 Concrete: 50 - -ValidTargets: + ValidTargets: Barrel, Infantry, Vehicle, Mine DamageTypes: Prone50Percent, TriggerProne, SmallExplosionDeath Warhead@2Smu: LeaveSmudge SmudgeType: Crater @@ -28,7 +28,7 @@ Warhead@3Eff: CreateEffect Explosions: artillery_explosion ImpactSounds: kaboom25.aud - ValidTargets: Ground, Ship, Trees + ValidTargets: Ground, GroundActor, Ship, Trees Warhead@4EffWater: CreateEffect Explosions: small_splash ImpactSounds: splash9.aud diff -Nru openra-20200503/mods/ra/maps/survival01/survival01.lua openra-20210321/mods/ra/maps/survival01/survival01.lua --- openra-20200503/mods/ra/maps/survival01/survival01.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/survival01/survival01.lua 2021-03-21 11:10:05.000000000 +0000 @@ -53,10 +53,10 @@ ParadropTicks = DateTime.Seconds(30) ParadropWaypoints = { - { 192 + 4, ParaDrop1}, - { 192 - 4, ParaDrop2}, - { 192 + 4, Alliesbase2}, - { 192 - 4, Alliesbase1} + { Angle.East + Angle.New(16), ParaDrop1}, + { Angle.East - Angle.New(16), ParaDrop2}, + { Angle.East + Angle.New(16), Alliesbase2}, + { Angle.East - Angle.New(16), Alliesbase1} } NavalTransportPassengers = { "e1", "e1", "e2", "e4", "e4" } NavalReinforcementsWaypoints = { NavalWaypoint1, NavalWaypoint2, NavalWaypoint2, NavalWaypoint3 } @@ -191,7 +191,7 @@ end SendSovietParadrops = function(table) - local aircraft = powerproxy.ActivateParatroopers(table[2].CenterPosition, table[1]) + local aircraft = powerproxy.TargetParatroopers(table[2].CenterPosition, table[1]) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) @@ -290,7 +290,7 @@ DropAlliedArtillery = function(facing, dropzone) local proxy = Actor.Create("powerproxy.allied", true, { Owner = allies }) - proxy.ActivateParatroopers(dropzone, facing) + proxy.TargetParatroopers(dropzone, facing) proxy.Destroy() end @@ -300,7 +300,7 @@ Reinforcements.Reinforce(allies, LongBowReinforcements, AlliedAirReinforcementsWaypoints[2]) if ParadropArtillery then - local facing = Utils.RandomInteger(Facing.NorthWest, Facing.SouthWest) + local facing = Angle.New(Utils.RandomInteger(128, 384)) DropAlliedArtillery(facing, Alliesbase.CenterPosition) end end diff -Nru openra-20200503/mods/ra/maps/survival02/map.yaml openra-20210321/mods/ra/maps/survival02/map.yaml --- openra-20200503/mods/ra/maps/survival02/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/survival02/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -305,18 +305,18 @@ Actor96: e1 Location: 13,13 Owner: Soviets - Facing: 160 + Facing: 640 Actor92: fenc Location: 55,69 Owner: Soviets Actor103: e4 Location: 8,12 Owner: Soviets - Facing: 160 + Facing: 640 Actor102: 3tnk Location: 14,11 Owner: Soviets - Facing: 160 + Facing: 640 Actor105: tc04 Location: 23,29 Owner: Neutral @@ -525,7 +525,7 @@ Actor167: e1 Location: 35,33 Owner: Allies - Facing: 64 + Facing: 256 Actor168: e1 Location: 43,32 Owner: Allies @@ -547,7 +547,7 @@ Actor174: 2tnk Location: 37,46 Owner: Allies - Facing: 160 + Facing: 640 Actor64: barb Location: 15,15 Owner: Soviets @@ -557,7 +557,7 @@ Actor100: e2 Location: 16,10 Owner: Soviets - Facing: 160 + Facing: 640 Actor180: fenc Location: 53,72 Owner: Soviets @@ -585,26 +585,26 @@ Actor223: e2 Location: 37,43 Owner: Soviets - Facing: 192 + Facing: 768 Actor220: e1 Location: 32,38 Owner: Soviets - Facing: 192 + Facing: 768 Actor222: e2 Location: 40,35 Owner: Soviets - Facing: 192 + Facing: 768 Actor221: e1 Location: 42,40 Owner: Soviets - Facing: 192 + Facing: 768 Actor70: mine Location: 38,50 Owner: Neutral Actor175: e1 Location: 63,72 Owner: Soviets - Facing: 32 + Facing: 128 Actor184: e2 Location: 61,74 Owner: Soviets @@ -794,23 +794,23 @@ Actor211: 3tnk Location: 58,6 Owner: Soviets - Facing: 160 + Facing: 640 Actor212: 3tnk Location: 65,10 Owner: Soviets - Facing: 96 + Facing: 384 Actor214: e1 Location: 73,9 Owner: Soviets - Facing: 96 + Facing: 384 Actor215: e3 Location: 76,4 Owner: Soviets - Facing: 32 + Facing: 128 Actor216: e4 Location: 66,3 Owner: Soviets - Facing: 96 + Facing: 384 Actor234: minv Location: 16,17 Owner: Soviets @@ -882,23 +882,23 @@ Harvester1: harv Location: 61,6 Owner: Soviets - Facing: 128 + Facing: 512 Harvester2: harv Location: 15,5 Owner: Soviets - Facing: 150 + Facing: 600 HarvGuard1: apc Location: 68,7 Owner: Soviets - Facing: 100 + Facing: 400 HarvGuard2: 3tnk Location: 69,8 Owner: Soviets - Facing: 127 + Facing: 508 HarvGuard3: 3tnk Location: 67,8 Owner: Soviets - Facing: 96 + Facing: 384 drum1: brl3 Location: 63,70 Owner: Soviets @@ -920,11 +920,11 @@ boom4: 3tnk Location: 61,70 Owner: Soviets - Facing: 32 + Facing: 128 boom5: 3tnk Location: 59,74 Owner: Soviets - Facing: 224 + Facing: 896 Factory: weap Location: 7,6 Owner: Soviets diff -Nru openra-20200503/mods/ra/maps/survival02/survival02.lua openra-20210321/mods/ra/maps/survival02/survival02.lua --- openra-20200503/mods/ra/maps/survival02/survival02.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/survival02/survival02.lua 2021-03-21 11:10:05.000000000 +0000 @@ -129,7 +129,7 @@ SendSovietParadrops = function(table) local paraproxy = Actor.Create(table.type, false, { Owner = soviets }) - local aircraft = paraproxy.ActivateParatroopers(table.target.CenterPosition) + local aircraft = paraproxy.TargetParatroopers(table.target.CenterPosition) Utils.Do(aircraft, function(a) Trigger.OnPassengerExited(a, function(t, p) IdleHunt(p) @@ -185,9 +185,9 @@ end powerproxy = Actor.Create("powerproxy.parabombs", false, { Owner = allies }) - powerproxy.SendAirstrike(drum1.CenterPosition, false, Facing.NorthEast + 4) - powerproxy.SendAirstrike(drum2.CenterPosition, false, Facing.NorthEast) - powerproxy.SendAirstrike(drum3.CenterPosition, false, Facing.NorthEast - 4) + powerproxy.TargetAirstrike(drum1.CenterPosition, Angle.NorthEast + Angle.New(16)) + powerproxy.TargetAirstrike(drum2.CenterPosition, Angle.NorthEast) + powerproxy.TargetAirstrike(drum3.CenterPosition, Angle.NorthEast - Angle.New(16)) powerproxy.Destroy() Trigger.AfterDelay(DateTime.Seconds(3), function() Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/tabula-rasa.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/tabula-rasa.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/tainted-peak.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/tainted-peak.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/temperal.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/temperal.oramap differ diff -Nru openra-20200503/mods/ra/maps/top-o-the-world/map.yaml openra-20210321/mods/ra/maps/top-o-the-world/map.yaml --- openra-20200503/mods/ra/maps/top-o-the-world/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/top-o-the-world/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -458,11 +458,11 @@ Actor130: gun Location: 43,40 Owner: Greece - Facing: 223 + Facing: 892 Actor131: gun Location: 40,41 Owner: Greece - Facing: 95 + Facing: 380 Actor132: gap Location: 42,42 Owner: Greece @@ -475,62 +475,62 @@ Actor135: gun Location: 44,43 Owner: Greece - Facing: 223 + Facing: 892 Actor136: gun Location: 40,44 Owner: Greece - Facing: 95 + Facing: 380 Actor137: gun Location: 44,46 Owner: Greece - Facing: 223 + Facing: 892 Actor138: gun Location: 41,47 Owner: Greece - Facing: 95 + Facing: 380 Actor139: hbox Location: 87,47 Owner: Greece AAGun01: agun Location: 53,61 Owner: GoodGuy - Facing: 95 + Facing: 380 AAGun02: agun Location: 67,62 Owner: GoodGuy - Facing: 95 + Facing: 380 Actor142: gun Location: 73,67 Owner: GoodGuy - Facing: 95 + Facing: 380 AAGun03: agun Location: 62,69 Owner: GoodGuy - Facing: 223 + Facing: 892 AAGun04: agun Location: 59,73 Owner: GoodGuy - Facing: 63 + Facing: 252 Actor145: gun Location: 94,73 Owner: GoodGuy - Facing: 127 + Facing: 508 AAGun05: agun Location: 70,75 Owner: GoodGuy - Facing: 159 + Facing: 636 Actor147: gun Location: 92,77 Owner: GoodGuy - Facing: 127 + Facing: 508 Actor148: gun Location: 97,77 Owner: GoodGuy - Facing: 127 + Facing: 508 AAGun06: agun Location: 39,78 Owner: GoodGuy - Facing: 159 + Facing: 636 Actor150: brl3 Location: 77,82 Owner: GoodGuy @@ -549,70 +549,70 @@ Actor155: 2tnk Location: 94,46 Owner: Greece - Facing: 95 + Facing: 380 AlliedSquad05MTank01: 2tnk Location: 57,56 Owner: GoodGuy - Facing: 31 + Facing: 124 AlliedSquad05MTank02: 2tnk Location: 63,56 Owner: GoodGuy - Facing: 31 + Facing: 124 AlliedSquad04MGG01: mgg Location: 34,61 Owner: Greece - Facing: 127 + Facing: 508 AlliedSquad04MTank01: 2tnk Location: 31,63 Owner: GoodGuy - Facing: 127 + Facing: 508 AlliedSquad04Arty01: arty Location: 33,63 Owner: Greece - Facing: 127 + Facing: 508 AlliedSquad04Arty02: arty Location: 35,63 Owner: Greece - Facing: 127 + Facing: 508 AlliedSquad04MTank02: 2tnk Location: 37,63 Owner: GoodGuy - Facing: 127 + Facing: 508 AlliedSquad03LTank01: 1tnk Location: 78,63 Owner: GoodGuy - Facing: 159 + Facing: 636 AlliedSquad04MTank03: 2tnk Location: 33,64 Owner: GoodGuy - Facing: 127 + Facing: 508 AlliedSquad04Arty03: arty Location: 34,64 Owner: GoodGuy - Facing: 127 + Facing: 508 AlliedSquad04MTank04: 2tnk Location: 35,64 Owner: GoodGuy - Facing: 127 + Facing: 508 AlliedSquad04MTank05: 2tnk Location: 34,65 Owner: GoodGuy - Facing: 127 + Facing: 508 Actor168: 1tnk Location: 66,65 Owner: GoodGuy - Facing: 127 + Facing: 508 Actor169: 2tnk Location: 75,78 Owner: GoodGuy - Facing: 191 + Facing: 764 Actor170: 2tnk Location: 78,82 Owner: GoodGuy Actor171: 2tnk Location: 55,83 Owner: GoodGuy - Facing: 95 + Facing: 380 USSRHTank01: 3tnk Location: 35,87 Owner: USSR @@ -643,22 +643,22 @@ Actor181: e3 Location: 47,33 Owner: GoodGuy - Facing: 63 + Facing: 252 SubCell: 1 Actor182: e3 Location: 47,34 Owner: GoodGuy - Facing: 63 + Facing: 252 SubCell: 1 AlliedSquad03RocketInf01: e3 Location: 78,61 Owner: Greece - Facing: 127 + Facing: 508 SubCell: 1 AlliedSquad03RocketInf02: e3 Location: 84,61 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 3 Actor185: e3 Location: 72,62 @@ -667,27 +667,27 @@ AlliedSquad03RocketInf03: e3 Location: 80,64 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 3 Actor187: e3 Location: 72,66 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 0 Actor188: e3 Location: 74,68 Owner: Greece - Facing: 95 + Facing: 380 SubCell: 2 Actor189: e3 Location: 60,69 Owner: GoodGuy - Facing: 191 + Facing: 764 SubCell: 4 Actor190: e3 Location: 60,71 Owner: GoodGuy - Facing: 191 + Facing: 764 SubCell: 0 Actor191: e3 Location: 69,78 @@ -784,27 +784,27 @@ AlliedSquad01RocketInf01: e3 Location: 90,92 Owner: GoodGuy - Facing: 31 + Facing: 124 SubCell: 5 AlliedSquad01RocketInf02: e3 Location: 88,93 Owner: GoodGuy - Facing: 31 + Facing: 124 SubCell: 1 AlliedSquad01RocketInf03: e3 Location: 89,93 Owner: GoodGuy - Facing: 31 + Facing: 124 SubCell: 2 AlliedSquad01RocketInf04: e3 Location: 87,94 Owner: GoodGuy - Facing: 31 + Facing: 124 SubCell: 4 AlliedSquad01RocketInf05: e3 Location: 88,94 Owner: GoodGuy - Facing: 31 + Facing: 124 SubCell: 4 Actor219: e3 Location: 74,95 diff -Nru openra-20200503/mods/ra/maps/top-o-the-world/scu36ea.lua openra-20210321/mods/ra/maps/top-o-the-world/scu36ea.lua --- openra-20200503/mods/ra/maps/top-o-the-world/scu36ea.lua 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/maps/top-o-the-world/scu36ea.lua 2021-03-21 11:10:05.000000000 +0000 @@ -216,7 +216,7 @@ Trigger.AfterDelay(DateTime.Minutes(9), function() local powerproxy01 = Actor.Create("powerproxy.paratroopers", true, { Owner = greece }) - local aircraft01 = powerproxy01.ActivateParatroopers(AlliedParadropLZ01.CenterPosition, Facing.SouthWest) + local aircraft01 = powerproxy01.TargetParatroopers(AlliedParadropLZ01.CenterPosition, Angle.SouthWest) Utils.Do(aircraft01, function(a) Trigger.OnPassengerExited(a, function(t, p) HuntObjectiveTruck(p) @@ -224,7 +224,7 @@ end) local powerproxy02 = Actor.Create("powerproxy.paratroopers", true, { Owner = goodguy }) - local aircraft02 = powerproxy02.ActivateParatroopers(AlliedParadropLZ02.CenterPosition, Facing.SouthWest) + local aircraft02 = powerproxy02.TargetParatroopers(AlliedParadropLZ02.CenterPosition, Angle.SouthWest) Utils.Do(aircraft02, function(a) Trigger.OnPassengerExited(a, function(t, p) HuntObjectiveTruck(p) @@ -285,59 +285,59 @@ --Units Death Setup Trigger.AfterDelay(DateTime.Seconds(660), function() Utils.Do(USSRDie01, function(actor) - if not actor.IsDead then actor.Kill() end + if not actor.IsDead then actor.Kill("DefaultDeath") end end) end) Trigger.AfterDelay(DateTime.Seconds(744), function() Utils.Do(USSRDie02, function(actor) - if not actor.IsDead then actor.Kill() end + if not actor.IsDead then actor.Kill("DefaultDeath") end end) end) Trigger.AfterDelay(DateTime.Seconds(1122), function() - if not USSRHTank03.IsDead then USSRHTank03.Kill() end + if not USSRHTank03.IsDead then USSRHTank03.Kill("DefaultDeath") end end) Trigger.AfterDelay(DateTime.Seconds(1230), function() Utils.Do(USSRDie03, function(actor) - if not actor.IsDead then actor.Kill() end + if not actor.IsDead then actor.Kill("DefaultDeath") end end) end) Trigger.AfterDelay(DateTime.Seconds(1338), function() Utils.Do(USSRDie04, function(actor) - if not actor.IsDead then actor.Kill() end + if not actor.IsDead then actor.Kill("DefaultDeath") end end) end) Trigger.AfterDelay(DateTime.Seconds(1416), function() Utils.Do(USSRDie05, function(actor) - if not actor.IsDead then actor.Kill() end + if not actor.IsDead then actor.Kill("DefaultDeath") end end) end) Trigger.AfterDelay(DateTime.Seconds(1668), function() - if not USSRV201.IsDead then USSRV201.Kill() end + if not USSRV201.IsDead then USSRV201.Kill("DefaultDeath") end end) Trigger.AfterDelay(DateTime.Seconds(1746), function() Utils.Do(USSRDie06, function(actor) - if not actor.IsDead then actor.Kill() end + if not actor.IsDead then actor.Kill("DefaultDeath") end end) end) Trigger.AfterDelay(DateTime.Seconds(2034), function() - if not USSRMTank02.IsDead then USSRMTank02.Kill() end + if not USSRMTank02.IsDead then USSRMTank02.Kill("DefaultDeath") end end) Trigger.AfterDelay(DateTime.Seconds(2142), function() - if not USSRMTank01.IsDead then USSRMTank01.Kill() end + if not USSRMTank01.IsDead then USSRMTank01.Kill("DefaultDeath") end end) Trigger.OnTimerExpired(function() if not ObjectiveTruck01.IsDead then - ObjectiveTruck01.Kill() + ObjectiveTruck01.Kill("DefaultDeath") -- Set the limit to one so that the timer displays 0 and never ends -- (which would display the game time instead of 0) Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/trapped.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/trapped.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/union-sacree.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/union-sacree.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/vihaan-lunta.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/vihaan-lunta.oramap differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/maps/winter-storm.oramap and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/maps/winter-storm.oramap differ diff -Nru openra-20200503/mods/ra/metrics.yaml openra-20210321/mods/ra/metrics.yaml --- openra-20200503/mods/ra/metrics.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/metrics.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -16,11 +16,3 @@ IncompatibleProtectedGameColor: B22222 IncompatibleVersionColor: D3D3D3 TextfieldColorHighlight: 562020 - ChatLineSound: ChatLine - ClickDisabledSound: ClickDisabledSound - ClickSound: ClickSound - ChatMessageColor: FFFFFF - SystemMessageColor: FFFF00 - NormalSelectionColor: FFFFFF - AltSelectionColor: 00FFFF - CtrlSelectionColor: FFFF00 diff -Nru openra-20200503/mods/ra/missions.yaml openra-20210321/mods/ra/missions.yaml --- openra-20200503/mods/ra/missions.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/missions.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -10,6 +10,7 @@ allies-07 allies-08a allies-08b + allies-09a Soviet Campaign: soviet-01 soviet-02a @@ -22,13 +23,21 @@ soviet-06b soviet-07 soviet-08a + soviet-08b + soviet-09 Counterstrike: sarin-gas-1-crackdown sarin-gas-2-down-under + sarin-gas-3-controlled-burn + fall-of-greece-1-personal-war + siberian-conflict-1-fresh-tracks soviet-soldier-volkov-n-chitzkoi top-o-the-world Aftermath: + production-disruption monster-tank-madness + shock-therapy + situation-critical OpenRA Originals: evacuation exodus diff -Nru openra-20200503/mods/ra/mod.yaml openra-20210321/mods/ra/mod.yaml --- openra-20200503/mods/ra/mod.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/mod.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,13 +7,13 @@ PackageFormats: Mix Packages: - ~^Content/ra/v2/ - ~^Content/ra/v2/expand - ~^Content/ra/v2/cnc - ~^Content/ra/v2/movies - . + ~^SupportDir|Content/ra/v2/ + ~^SupportDir|Content/ra/v2/expand + ~^SupportDir|Content/ra/v2/cnc + ~^SupportDir|Content/ra/v2/movies + ^EngineDir $ra: ra - ./mods/common: common + ^EngineDir|mods/common: common ~main.mix ~conquer.mix ~lores.mix: lores @@ -32,11 +32,12 @@ ~desert.mix ra|bits ra|bits/desert + ra|bits/scripts ra|uibits MapFolders: ra|maps: System - ~^maps/ra/{DEV_VERSION}: User + ~^SupportDir|maps/ra/{DEV_VERSION}: User Rules: ra|rules/misc.yaml @@ -77,8 +78,8 @@ ra|chrome.yaml Assemblies: - common|OpenRA.Mods.Common.dll - common|OpenRA.Mods.Cnc.dll + ^BinDir|OpenRA.Mods.Common.dll + ^BinDir|OpenRA.Mods.Cnc.dll ChromeLayout: common|chrome/ingame.yaml @@ -133,7 +134,7 @@ ra|weapons/other.yaml ra|weapons/smallcaliber.yaml ra|weapons/superweapons.yaml - + Voices: ra|audio/voices.yaml @@ -217,7 +218,7 @@ SpriteFormats: ShpD2, ShpTD, TmpRA, TmpTD, ShpTS -SpriteSequenceFormat: TilesetSpecificSpriteSequence +SpriteSequenceFormat: ClassicTilesetSpecificSpriteSequence TilesetExtensions: TEMPERAT: .tem SNOW: .sno @@ -259,40 +260,39 @@ TeamColorPresets: f7b3b3, f50606, 98331f, f57606, f7bb06, f861a4, da06f3, ddb8ff, 06f739, cef7b2, 200738, 280df6, 2f86f2, 76d2f8, 34ba93, 391d1d ModContent: - InstallPromptMessage: Red Alert requires artwork and audio from the original game.\n\nQuick Install will automatically download this content (without music\nor videos) from a mirror of the 2008 Red Alert freeware release.\n\nAdvanced Install includes options for downloading the music and for\ncopying the videos and other content from an original game disc. + InstallPromptMessage: Red Alert requires artwork and audio from the original game.\n\nQuick Install will automatically download this content (without music\nor videos) from a mirror of the 2008 Red Alert freeware release.\n\nAdvanced Install includes options for copying the music, videos, and\nother content from an original game disc or digital installation. QuickDownload: quickinstall HeaderMessage: Game content may be extracted from the original game discs or an\nexisting digital install. OpenRA can also download the base game\nfiles from an online mirror of the 2008 freeware release of RA. Packages: base: Base Game Files - TestFiles: ^Content/ra/v2/allies.mix, ^Content/ra/v2/conquer.mix, ^Content/ra/v2/interior.mix, ^Content/ra/v2/hires.mix, ^Content/ra/v2/lores.mix, ^Content/ra/v2/local.mix, ^Content/ra/v2/speech.mix, ^Content/ra/v2/russian.mix, ^Content/ra/v2/snow.mix, ^Content/ra/v2/sounds.mix, ^Content/ra/v2/temperat.mix + TestFiles: ^SupportDir|Content/ra/v2/allies.mix, ^SupportDir|Content/ra/v2/conquer.mix, ^SupportDir|Content/ra/v2/interior.mix, ^SupportDir|Content/ra/v2/hires.mix, ^SupportDir|Content/ra/v2/lores.mix, ^SupportDir|Content/ra/v2/local.mix, ^SupportDir|Content/ra/v2/speech.mix, ^SupportDir|Content/ra/v2/russian.mix, ^SupportDir|Content/ra/v2/snow.mix, ^SupportDir|Content/ra/v2/sounds.mix, ^SupportDir|Content/ra/v2/temperat.mix Sources: allied, allied-linux, soviet, soviet-linux, tfd, ra-origin Required: true Download: basefiles aftermathbase: Aftermath Expansion Files - TestFiles: ^Content/ra/v2/expand/expand2.mix, ^Content/ra/v2/expand/hires1.mix, ^Content/ra/v2/expand/lores1.mix, ^Content/ra/v2/expand/chrotnk1.aud, ^Content/ra/v2/expand/fixit1.aud, ^Content/ra/v2/expand/jburn1.aud, ^Content/ra/v2/expand/jchrge1.aud, ^Content/ra/v2/expand/jcrisp1.aud, ^Content/ra/v2/expand/jdance1.aud, ^Content/ra/v2/expand/jjuice1.aud, ^Content/ra/v2/expand/jjump1.aud, ^Content/ra/v2/expand/jlight1.aud, ^Content/ra/v2/expand/jpower1.aud, ^Content/ra/v2/expand/jshock1.aud, ^Content/ra/v2/expand/jyes1.aud, ^Content/ra/v2/expand/madchrg2.aud, ^Content/ra/v2/expand/madexplo.aud, ^Content/ra/v2/expand/mboss1.aud, ^Content/ra/v2/expand/mhear1.aud, ^Content/ra/v2/expand/mhotdig1.aud, ^Content/ra/v2/expand/mhowdy1.aud, ^Content/ra/v2/expand/mhuh1.aud, ^Content/ra/v2/expand/mlaff1.aud, ^Content/ra/v2/expand/mrise1.aud, ^Content/ra/v2/expand/mwrench1.aud, ^Content/ra/v2/expand/myeehaw1.aud, ^Content/ra/v2/expand/myes1.aud + TestFiles: ^SupportDir|Content/ra/v2/expand/expand2.mix, ^SupportDir|Content/ra/v2/expand/hires1.mix, ^SupportDir|Content/ra/v2/expand/lores1.mix, ^SupportDir|Content/ra/v2/expand/chrotnk1.aud, ^SupportDir|Content/ra/v2/expand/fixit1.aud, ^SupportDir|Content/ra/v2/expand/jburn1.aud, ^SupportDir|Content/ra/v2/expand/jchrge1.aud, ^SupportDir|Content/ra/v2/expand/jcrisp1.aud, ^SupportDir|Content/ra/v2/expand/jdance1.aud, ^SupportDir|Content/ra/v2/expand/jjuice1.aud, ^SupportDir|Content/ra/v2/expand/jjump1.aud, ^SupportDir|Content/ra/v2/expand/jlight1.aud, ^SupportDir|Content/ra/v2/expand/jpower1.aud, ^SupportDir|Content/ra/v2/expand/jshock1.aud, ^SupportDir|Content/ra/v2/expand/jyes1.aud, ^SupportDir|Content/ra/v2/expand/madchrg2.aud, ^SupportDir|Content/ra/v2/expand/madexplo.aud, ^SupportDir|Content/ra/v2/expand/mboss1.aud, ^SupportDir|Content/ra/v2/expand/mhear1.aud, ^SupportDir|Content/ra/v2/expand/mhotdig1.aud, ^SupportDir|Content/ra/v2/expand/mhowdy1.aud, ^SupportDir|Content/ra/v2/expand/mhuh1.aud, ^SupportDir|Content/ra/v2/expand/mlaff1.aud, ^SupportDir|Content/ra/v2/expand/mrise1.aud, ^SupportDir|Content/ra/v2/expand/mwrench1.aud, ^SupportDir|Content/ra/v2/expand/myeehaw1.aud, ^SupportDir|Content/ra/v2/expand/myes1.aud Sources: aftermath, aftermath-linux, tfd, ra-origin Required: true Download: aftermath cncdesert: C&C Desert Tileset - TestFiles: ^Content/ra/v2/cnc/desert.mix + TestFiles: ^SupportDir|Content/ra/v2/cnc/desert.mix Sources: tfd, cnc-origin, cnc95, cnc95-linux Required: true Download: cncdesert music: Base Game Music - TestFiles: ^Content/ra/v2/scores.mix + TestFiles: ^SupportDir|Content/ra/v2/scores.mix Sources: allied, allied-linux, soviet, soviet-linux, tfd, ra-origin - Download: music movies-allied: Allied Campaign Briefings - TestFiles: ^Content/ra/v2/movies/aagun.vqa, ^Content/ra/v2/movies/aftrmath.vqa, ^Content/ra/v2/movies/ally1.vqa, ^Content/ra/v2/movies/ally10.vqa, ^Content/ra/v2/movies/ally10b.vqa, ^Content/ra/v2/movies/ally11.vqa, ^Content/ra/v2/movies/ally12.vqa, ^Content/ra/v2/movies/ally14.vqa, ^Content/ra/v2/movies/ally2.vqa, ^Content/ra/v2/movies/ally4.vqa, ^Content/ra/v2/movies/ally5.vqa, ^Content/ra/v2/movies/ally6.vqa, ^Content/ra/v2/movies/ally8.vqa, ^Content/ra/v2/movies/ally9.vqa, ^Content/ra/v2/movies/allyend.vqa, ^Content/ra/v2/movies/allymorf.vqa, ^Content/ra/v2/movies/apcescpe.vqa, ^Content/ra/v2/movies/assess.vqa, ^Content/ra/v2/movies/battle.vqa, ^Content/ra/v2/movies/binoc.vqa, ^Content/ra/v2/movies/bmap.vqa, ^Content/ra/v2/movies/brdgtilt.vqa, ^Content/ra/v2/movies/crontest.vqa, ^Content/ra/v2/movies/cronfail.vqa, ^Content/ra/v2/movies/destroyr.vqa, ^Content/ra/v2/movies/dud.vqa, ^Content/ra/v2/movies/elevator.vqa, ^Content/ra/v2/movies/flare.vqa, ^Content/ra/v2/movies/frozen.vqa, ^Content/ra/v2/movies/grvestne.vqa, ^Content/ra/v2/movies/landing.vqa, ^Content/ra/v2/movies/masasslt.vqa, ^Content/ra/v2/movies/mcv.vqa, ^Content/ra/v2/movies/mcv_land.vqa, ^Content/ra/v2/movies/montpass.vqa, ^Content/ra/v2/movies/oildrum.vqa, ^Content/ra/v2/movies/overrun.vqa, ^Content/ra/v2/movies/prolog.vqa, ^Content/ra/v2/movies/redintro.vqa, ^Content/ra/v2/movies/shipsink.vqa, ^Content/ra/v2/movies/shorbom1.vqa, ^Content/ra/v2/movies/shorbom2.vqa, ^Content/ra/v2/movies/shorbomb.vqa, ^Content/ra/v2/movies/snowbomb.vqa, ^Content/ra/v2/movies/soviet1.vqa, ^Content/ra/v2/movies/sovtstar.vqa, ^Content/ra/v2/movies/spy.vqa, ^Content/ra/v2/movies/tanya1.vqa, ^Content/ra/v2/movies/tanya2.vqa, ^Content/ra/v2/movies/toofar.vqa, ^Content/ra/v2/movies/trinity.vqa + TestFiles: ^SupportDir|Content/ra/v2/movies/aagun.vqa, ^SupportDir|Content/ra/v2/movies/aftrmath.vqa, ^SupportDir|Content/ra/v2/movies/ally1.vqa, ^SupportDir|Content/ra/v2/movies/ally10.vqa, ^SupportDir|Content/ra/v2/movies/ally10b.vqa, ^SupportDir|Content/ra/v2/movies/ally11.vqa, ^SupportDir|Content/ra/v2/movies/ally12.vqa, ^SupportDir|Content/ra/v2/movies/ally14.vqa, ^SupportDir|Content/ra/v2/movies/ally2.vqa, ^SupportDir|Content/ra/v2/movies/ally4.vqa, ^SupportDir|Content/ra/v2/movies/ally5.vqa, ^SupportDir|Content/ra/v2/movies/ally6.vqa, ^SupportDir|Content/ra/v2/movies/ally8.vqa, ^SupportDir|Content/ra/v2/movies/ally9.vqa, ^SupportDir|Content/ra/v2/movies/allyend.vqa, ^SupportDir|Content/ra/v2/movies/allymorf.vqa, ^SupportDir|Content/ra/v2/movies/apcescpe.vqa, ^SupportDir|Content/ra/v2/movies/assess.vqa, ^SupportDir|Content/ra/v2/movies/battle.vqa, ^SupportDir|Content/ra/v2/movies/binoc.vqa, ^SupportDir|Content/ra/v2/movies/bmap.vqa, ^SupportDir|Content/ra/v2/movies/brdgtilt.vqa, ^SupportDir|Content/ra/v2/movies/crontest.vqa, ^SupportDir|Content/ra/v2/movies/cronfail.vqa, ^SupportDir|Content/ra/v2/movies/destroyr.vqa, ^SupportDir|Content/ra/v2/movies/dud.vqa, ^SupportDir|Content/ra/v2/movies/elevator.vqa, ^SupportDir|Content/ra/v2/movies/flare.vqa, ^SupportDir|Content/ra/v2/movies/frozen.vqa, ^SupportDir|Content/ra/v2/movies/grvestne.vqa, ^SupportDir|Content/ra/v2/movies/landing.vqa, ^SupportDir|Content/ra/v2/movies/masasslt.vqa, ^SupportDir|Content/ra/v2/movies/mcv.vqa, ^SupportDir|Content/ra/v2/movies/mcv_land.vqa, ^SupportDir|Content/ra/v2/movies/montpass.vqa, ^SupportDir|Content/ra/v2/movies/oildrum.vqa, ^SupportDir|Content/ra/v2/movies/overrun.vqa, ^SupportDir|Content/ra/v2/movies/prolog.vqa, ^SupportDir|Content/ra/v2/movies/redintro.vqa, ^SupportDir|Content/ra/v2/movies/shipsink.vqa, ^SupportDir|Content/ra/v2/movies/shorbom1.vqa, ^SupportDir|Content/ra/v2/movies/shorbom2.vqa, ^SupportDir|Content/ra/v2/movies/shorbomb.vqa, ^SupportDir|Content/ra/v2/movies/snowbomb.vqa, ^SupportDir|Content/ra/v2/movies/soviet1.vqa, ^SupportDir|Content/ra/v2/movies/sovtstar.vqa, ^SupportDir|Content/ra/v2/movies/spy.vqa, ^SupportDir|Content/ra/v2/movies/tanya1.vqa, ^SupportDir|Content/ra/v2/movies/tanya2.vqa, ^SupportDir|Content/ra/v2/movies/toofar.vqa, ^SupportDir|Content/ra/v2/movies/trinity.vqa Sources: allied, allied-linux, tfd, ra-origin movies-soviet: Soviet Campaign Briefings - TestFiles: ^Content/ra/v2/movies/aagun.vqa, ^Content/ra/v2/movies/cronfail.vqa, ^Content/ra/v2/movies/airfield.vqa, ^Content/ra/v2/movies/ally1.vqa, ^Content/ra/v2/movies/allymorf.vqa, ^Content/ra/v2/movies/averted.vqa, ^Content/ra/v2/movies/beachead.vqa, ^Content/ra/v2/movies/bmap.vqa, ^Content/ra/v2/movies/bombrun.vqa, ^Content/ra/v2/movies/countdwn.vqa, ^Content/ra/v2/movies/double.vqa, ^Content/ra/v2/movies/dpthchrg.vqa, ^Content/ra/v2/movies/execute.vqa, ^Content/ra/v2/movies/flare.vqa, ^Content/ra/v2/movies/landing.vqa, ^Content/ra/v2/movies/mcvbrdge.vqa, ^Content/ra/v2/movies/mig.vqa, ^Content/ra/v2/movies/movingin.vqa, ^Content/ra/v2/movies/mtnkfact.vqa, ^Content/ra/v2/movies/nukestok.vqa, ^Content/ra/v2/movies/onthprwl.vqa, ^Content/ra/v2/movies/periscop.vqa, ^Content/ra/v2/movies/prolog.vqa, ^Content/ra/v2/movies/radrraid.vqa, ^Content/ra/v2/movies/redintro.vqa, ^Content/ra/v2/movies/search.vqa, ^Content/ra/v2/movies/sfrozen.vqa, ^Content/ra/v2/movies/sitduck.vqa, ^Content/ra/v2/movies/slntsrvc.vqa, ^Content/ra/v2/movies/snowbomb.vqa, ^Content/ra/v2/movies/snstrafe.vqa, ^Content/ra/v2/movies/sovbatl.vqa, ^Content/ra/v2/movies/sovcemet.vqa, ^Content/ra/v2/movies/sovfinal.vqa, ^Content/ra/v2/movies/soviet1.vqa, ^Content/ra/v2/movies/soviet10.vqa, ^Content/ra/v2/movies/soviet11.vqa, ^Content/ra/v2/movies/soviet12.vqa, ^Content/ra/v2/movies/soviet13.vqa, ^Content/ra/v2/movies/soviet14.vqa, ^Content/ra/v2/movies/soviet2.vqa, ^Content/ra/v2/movies/soviet3.vqa, ^Content/ra/v2/movies/soviet4.vqa, ^Content/ra/v2/movies/soviet5.vqa, ^Content/ra/v2/movies/soviet6.vqa, ^Content/ra/v2/movies/soviet7.vqa, ^Content/ra/v2/movies/soviet8.vqa, ^Content/ra/v2/movies/soviet9.vqa, ^Content/ra/v2/movies/sovmcv.vqa, ^Content/ra/v2/movies/sovtstar.vqa, ^Content/ra/v2/movies/spotter.vqa, ^Content/ra/v2/movies/strafe.vqa, ^Content/ra/v2/movies/take_off.vqa, ^Content/ra/v2/movies/tesla.vqa, ^Content/ra/v2/movies/v2rocket.vqa + TestFiles: ^SupportDir|Content/ra/v2/movies/aagun.vqa, ^SupportDir|Content/ra/v2/movies/cronfail.vqa, ^SupportDir|Content/ra/v2/movies/airfield.vqa, ^SupportDir|Content/ra/v2/movies/ally1.vqa, ^SupportDir|Content/ra/v2/movies/allymorf.vqa, ^SupportDir|Content/ra/v2/movies/averted.vqa, ^SupportDir|Content/ra/v2/movies/beachead.vqa, ^SupportDir|Content/ra/v2/movies/bmap.vqa, ^SupportDir|Content/ra/v2/movies/bombrun.vqa, ^SupportDir|Content/ra/v2/movies/countdwn.vqa, ^SupportDir|Content/ra/v2/movies/double.vqa, ^SupportDir|Content/ra/v2/movies/dpthchrg.vqa, ^SupportDir|Content/ra/v2/movies/execute.vqa, ^SupportDir|Content/ra/v2/movies/flare.vqa, ^SupportDir|Content/ra/v2/movies/landing.vqa, ^SupportDir|Content/ra/v2/movies/mcvbrdge.vqa, ^SupportDir|Content/ra/v2/movies/mig.vqa, ^SupportDir|Content/ra/v2/movies/movingin.vqa, ^SupportDir|Content/ra/v2/movies/mtnkfact.vqa, ^SupportDir|Content/ra/v2/movies/nukestok.vqa, ^SupportDir|Content/ra/v2/movies/onthprwl.vqa, ^SupportDir|Content/ra/v2/movies/periscop.vqa, ^SupportDir|Content/ra/v2/movies/prolog.vqa, ^SupportDir|Content/ra/v2/movies/radrraid.vqa, ^SupportDir|Content/ra/v2/movies/redintro.vqa, ^SupportDir|Content/ra/v2/movies/search.vqa, ^SupportDir|Content/ra/v2/movies/sfrozen.vqa, ^SupportDir|Content/ra/v2/movies/sitduck.vqa, ^SupportDir|Content/ra/v2/movies/slntsrvc.vqa, ^SupportDir|Content/ra/v2/movies/snowbomb.vqa, ^SupportDir|Content/ra/v2/movies/snstrafe.vqa, ^SupportDir|Content/ra/v2/movies/sovbatl.vqa, ^SupportDir|Content/ra/v2/movies/sovcemet.vqa, ^SupportDir|Content/ra/v2/movies/sovfinal.vqa, ^SupportDir|Content/ra/v2/movies/soviet1.vqa, ^SupportDir|Content/ra/v2/movies/soviet10.vqa, ^SupportDir|Content/ra/v2/movies/soviet11.vqa, ^SupportDir|Content/ra/v2/movies/soviet12.vqa, ^SupportDir|Content/ra/v2/movies/soviet13.vqa, ^SupportDir|Content/ra/v2/movies/soviet14.vqa, ^SupportDir|Content/ra/v2/movies/soviet2.vqa, ^SupportDir|Content/ra/v2/movies/soviet3.vqa, ^SupportDir|Content/ra/v2/movies/soviet4.vqa, ^SupportDir|Content/ra/v2/movies/soviet5.vqa, ^SupportDir|Content/ra/v2/movies/soviet6.vqa, ^SupportDir|Content/ra/v2/movies/soviet7.vqa, ^SupportDir|Content/ra/v2/movies/soviet8.vqa, ^SupportDir|Content/ra/v2/movies/soviet9.vqa, ^SupportDir|Content/ra/v2/movies/sovmcv.vqa, ^SupportDir|Content/ra/v2/movies/sovtstar.vqa, ^SupportDir|Content/ra/v2/movies/spotter.vqa, ^SupportDir|Content/ra/v2/movies/strafe.vqa, ^SupportDir|Content/ra/v2/movies/take_off.vqa, ^SupportDir|Content/ra/v2/movies/tesla.vqa, ^SupportDir|Content/ra/v2/movies/v2rocket.vqa Sources: soviet, soviet-linux, tfd, ra-origin music-counterstrike: Counterstrike Music - TestFiles: ^Content/ra/v2/expand/araziod.aud, ^Content/ra/v2/expand/backstab.aud, ^Content/ra/v2/expand/chaos2.aud, ^Content/ra/v2/expand/shut_it.aud, ^Content/ra/v2/expand/2nd_hand.aud, ^Content/ra/v2/expand/twinmix1.aud, ^Content/ra/v2/expand/under3.aud, ^Content/ra/v2/expand/vr2.aud, + TestFiles: ^SupportDir|Content/ra/v2/expand/araziod.aud, ^SupportDir|Content/ra/v2/expand/backstab.aud, ^SupportDir|Content/ra/v2/expand/chaos2.aud, ^SupportDir|Content/ra/v2/expand/shut_it.aud, ^SupportDir|Content/ra/v2/expand/2nd_hand.aud, ^SupportDir|Content/ra/v2/expand/twinmix1.aud, ^SupportDir|Content/ra/v2/expand/under3.aud, ^SupportDir|Content/ra/v2/expand/vr2.aud, Sources: counterstrike, counterstrike-linux, ra-origin music-aftermath: Aftermath Music - TestFiles: ^Content/ra/v2/expand/await.aud, ^Content/ra/v2/expand/bog.aud, ^Content/ra/v2/expand/float_v2.aud, ^Content/ra/v2/expand/gloom.aud, ^Content/ra/v2/expand/grndwire.aud, ^Content/ra/v2/expand/rpt.aud, ^Content/ra/v2/expand/search.aud, ^Content/ra/v2/expand/traction.aud, ^Content/ra/v2/expand/wastelnd.aud + TestFiles: ^SupportDir|Content/ra/v2/expand/await.aud, ^SupportDir|Content/ra/v2/expand/bog.aud, ^SupportDir|Content/ra/v2/expand/float_v2.aud, ^SupportDir|Content/ra/v2/expand/gloom.aud, ^SupportDir|Content/ra/v2/expand/grndwire.aud, ^SupportDir|Content/ra/v2/expand/rpt.aud, ^SupportDir|Content/ra/v2/expand/search.aud, ^SupportDir|Content/ra/v2/expand/traction.aud, ^SupportDir|Content/ra/v2/expand/wastelnd.aud Sources: aftermath, aftermath-linux, ra-origin Downloads: ra|installer/downloads.yaml @@ -304,3 +304,6 @@ ra|installer/firstdecade.yaml ra|installer/origin.yaml ra|installer/soviet95.yaml + +DiscordService: + ApplicationId: 699222659766026240 diff -Nru openra-20200503/mods/ra/rules/aircraft.yaml openra-20210321/mods/ra/rules/aircraft.yaml --- openra-20200503/mods/ra/rules/aircraft.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/aircraft.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,15 +7,14 @@ HP: 30000 Aircraft: CruiseAltitude: 2560 - TurnSpeed: 5 + TurnSpeed: 20 Speed: 180 Repulsable: False MaximumPitch: 56 Cargo: MaxWeight: 10 -Selectable: - SelectionDecorations: - RenderSelectionBars: False + Interactable: -Voiced: Tooltip: Name: Badger @@ -35,49 +34,19 @@ RejectsOrders: GivesExperience: Experience: 1000 - Interactable: BADR.Bomber: - Inherits: ^NeutralPlane - AttackBomber: - Armament: - Weapon: ParaBomb - Health: - HP: 30000 - Aircraft: - CruiseAltitude: 2560 - TurnSpeed: 5 - Speed: 180 - Repulsable: False - MaximumPitch: 56 - AmmoPool: - Ammo: 5 - -Selectable: - SelectionDecorations: - RenderSelectionBars: False - -Voiced: - Tooltip: - Name: Badger - Contrail@1: - Offset: -432,560,0 - Contrail@2: - Offset: -432,-560,0 - SpawnActorOnDeath: - Actor: BADR.Husk - SmokeTrailWhenDamaged@0: - Offset: -432,560,0 - Interval: 2 - SmokeTrailWhenDamaged@1: - Offset: -432,-560,0 - Interval: 2 - -EjectOnDeath: + Inherits: BADR + -ParaDrop: + -Cargo: -MapEditorData: - RejectsOrders: RenderSprites: Image: badr - GivesExperience: - Experience: 1000 - Interactable: + AttackBomber: + AmmoPool: + Ammo: 5 + Armament: + Weapon: ParaBomb MIG: Inherits: ^Plane @@ -110,13 +79,12 @@ LocalYaw: -40, 24 PauseOnCondition: !ammo AttackAircraft: - FacingTolerance: 20 + FacingTolerance: 80 PersistentTargeting: false OpportunityFire: False Aircraft: CruiseAltitude: 2560 - InitialFacing: 192 - TurnSpeed: 4 + TurnSpeed: 16 Speed: 223 RepulsionSpeed: 40 MaximumPitch: 56 @@ -129,7 +97,6 @@ Selectable: Bounds: 36,28,0,2 DecorationBounds: 40,29,0,1 - SelectionDecorations: Contrail@1: Offset: -598,-683,0 Contrail@2: @@ -143,6 +110,10 @@ Prerequisites: aircraft.upgraded Rearmable: RearmActors: afld, afld.ukraine + WithAmmoPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true YAK: Inherits: ^Plane @@ -181,13 +152,12 @@ MuzzleSequence: muzzle PauseOnCondition: !ammo AttackAircraft: - FacingTolerance: 20 + FacingTolerance: 80 PersistentTargeting: false OpportunityFire: False Aircraft: CruiseAltitude: 2560 - InitialFacing: 192 - TurnSpeed: 4 + TurnSpeed: 16 Speed: 178 RepulsionSpeed: 40 MaximumPitch: 56 @@ -196,10 +166,8 @@ InitialStanceAI: HoldFire AmmoPool: Ammo: 18 - PipCount: 6 ReloadDelay: 11 AmmoCondition: ammo - SelectionDecorations: WithMuzzleOverlay: Contrail: Offset: -853,0,0 @@ -214,9 +182,15 @@ DecorationBounds: 30,28,0,2 Rearmable: RearmActors: afld, afld.ukraine + WithAmmoPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + PipCount: 6 TRAN: Inherits: ^Helicopter + Inherits@CARGOPIPS: ^CargoPips Buildable: Queue: Aircraft BuildAtProductionType: Helicopter @@ -230,7 +204,7 @@ UpdatesPlayerStatistics: AddToArmyValue: true Health: - HP: 20000 + HP: 14000 RevealsShroud: MinRange: 6c0 Range: 8c0 @@ -240,7 +214,7 @@ Range: 6c0 Type: GroundPosition Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 128 AltitudeVelocity: 0c58 WithIdleOverlay@ROTOR1AIR: @@ -262,11 +236,9 @@ Cargo: Types: Infantry MaxWeight: 8 - PipCount: 8 AfterUnloadDelay: 40 SpawnActorOnDeath: Actor: TRAN.Husk - SelectionDecorations: Selectable: DecorationBounds: 40,36 @@ -304,12 +276,12 @@ LocalOffset: 0,213,-85, 0,-213,-85 PauseOnCondition: !ammo AttackAircraft: - FacingTolerance: 20 + FacingTolerance: 80 PersistentTargeting: false AttackType: Hover OpportunityFire: False Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 149 AutoTarget: InitialStance: HoldFire @@ -325,7 +297,6 @@ AmmoPool: Ammo: 8 AmmoCondition: ammo - SelectionDecorations: SpawnActorOnDeath: Actor: HELI.Husk SmokeTrailWhenDamaged: @@ -336,6 +307,10 @@ DecorationBounds: 36,28 Rearmable: RearmActors: hpad + WithAmmoPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true HIND: Inherits: ^Helicopter @@ -374,12 +349,12 @@ MuzzleSequence: muzzle PauseOnCondition: !ammo AttackAircraft: - FacingTolerance: 20 + FacingTolerance: 80 PersistentTargeting: false AttackType: Hover OpportunityFire: False Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 112 AutoTarget: InitialStance: HoldFire @@ -392,10 +367,8 @@ RequiresCondition: !airborne AmmoPool: Ammo: 24 - PipCount: 6 ReloadDelay: 8 AmmoCondition: ammo - SelectionDecorations: WithMuzzleOverlay: SpawnActorOnDeath: Actor: HIND.Husk @@ -407,6 +380,11 @@ DecorationBounds: 38,32 Rearmable: RearmActors: hpad + WithAmmoPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + PipCount: 6 U2: Inherits: ^NeutralPlane @@ -416,14 +394,12 @@ Name: Spy Plane Aircraft: CruiseAltitude: 2560 - TurnSpeed: 7 + TurnSpeed: 28 Speed: 373 Repulsable: False MaximumPitch: 56 AttackBomber: -Selectable: - SelectionDecorations: - RenderSelectionBars: False -Voiced: -Targetable@AIRBORNE: Contrail@1: @@ -476,11 +452,11 @@ MuzzleSequence: muzzle PauseOnCondition: !ammo AttackAircraft: - FacingTolerance: 20 + FacingTolerance: 80 PersistentTargeting: false AttackType: Hover Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 112 AutoTarget: InitialStance: HoldFire @@ -493,10 +469,8 @@ RequiresCondition: !airborne AmmoPool: Ammo: 24 - PipCount: 6 ReloadDelay: 8 AmmoCondition: ammo - SelectionDecorations: WithMuzzleOverlay: SpawnActorOnDeath: Actor: MH60.Husk @@ -508,3 +482,8 @@ DecorationBounds: 38,32 Rearmable: RearmActors: hpad + WithAmmoPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + PipCount: 6 diff -Nru openra-20200503/mods/ra/rules/campaign-palettes.yaml openra-20210321/mods/ra/rules/campaign-palettes.yaml --- openra-20200503/mods/ra/rules/campaign-palettes.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/campaign-palettes.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -10,6 +10,7 @@ USSR: 229, 230, 231, 232, 233, 234, 235, 8, 236, 237, 238, 239, 221, 222, 223, 223 Ukraine: 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223 Greece: 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175 + Allies: 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175 England: 208, 208, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 154, 155, 143 Germany: 128, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 121, 122, 122, 123, 123 France: 224, 224, 225, 225, 226, 184, 185, 186, 187, 188, 188, 189, 190, 190, 191, 191 diff -Nru openra-20200503/mods/ra/rules/campaign-rules.yaml openra-20210321/mods/ra/rules/campaign-rules.yaml --- openra-20200503/mods/ra/rules/campaign-rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/campaign-rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,6 +2,7 @@ -ConquestVictoryConditions: MissionObjectives: EarlyGameOver: true + GameOverDelay: 3000 Shroud: FogCheckboxLocked: True FogCheckboxEnabled: True @@ -48,6 +49,11 @@ ^Vehicle: Demolishable: +HARV: + Harvester: + SearchFromProcRadius: 50 + SearchFromHarvesterRadius: 50 + MONEYCRATE: Tooltip: Name: Crate @@ -62,6 +68,16 @@ -GivesBuildableArea: BaseProvider: Range: 0 + RepairableBuilding: + RepairStep: 700 + PlayerExperience: 25 + RepairingNotification: Repairing + WithBuildingRepairDecoration: + Image: allyrepair + Sequence: repair + Position: Center + Palette: player + IsPlayerPalette: True MISS: RevealsShroud: diff -Nru openra-20200503/mods/ra/rules/campaign-tooltips.yaml openra-20210321/mods/ra/rules/campaign-tooltips.yaml --- openra-20200503/mods/ra/rules/campaign-tooltips.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/campaign-tooltips.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -89,3 +89,9 @@ Name: Technology Center -TooltipDescription@ally: -TooltipDescription@other: + +HOSP: + Tooltip: + GenericVisibility: Enemy + -TooltipDescription@ally: + -TooltipDescription@other: diff -Nru openra-20200503/mods/ra/rules/civilian.yaml openra-20210321/mods/ra/rules/civilian.yaml --- openra-20200503/mods/ra/rules/civilian.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/civilian.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,11 +4,20 @@ C2: Inherits: ^CivInfantry - Voiced: - VoiceSet: CivilianFemaleVoice + RenderSprites: + Image: C1 + WithInfantryBody: + Palette: civilian2 + WithDeathAnimation: + DeathSequencePalette: civilian2 + DeathPaletteIsPlayerPalette: false C3: Inherits: ^CivInfantry + Voiced: + VoiceSet: CivilianFemaleVoice + RenderSprites: + Image: C2 C4: Inherits: ^CivInfantry @@ -16,43 +25,79 @@ Image: C2 Voiced: VoiceSet: CivilianFemaleVoice + WithInfantryBody: + Palette: civilian4 + WithDeathAnimation: + DeathSequencePalette: civilian4 + DeathPaletteIsPlayerPalette: false C5: Inherits: ^CivInfantry RenderSprites: - Image: C1 + Image: C2 + Voiced: + VoiceSet: CivilianFemaleVoice + WithInfantryBody: + Palette: civilian5 + WithDeathAnimation: + DeathSequencePalette: civilian5 + DeathPaletteIsPlayerPalette: false C6: Inherits: ^CivInfantry RenderSprites: - Image: C2 - Voiced: - VoiceSet: CivilianFemaleVoice + Image: C1 + WithInfantryBody: + Palette: civilian6 + WithDeathAnimation: + DeathSequencePalette: civilian6 + DeathPaletteIsPlayerPalette: false C7: Inherits@1: ^CivInfantry Inherits@2: ^ArmedCivilian RenderSprites: Image: C1 + WithInfantryBody: + Palette: civilian7 + WithDeathAnimation: + DeathSequencePalette: civilian7 + DeathPaletteIsPlayerPalette: false C8: Inherits: ^CivInfantry RenderSprites: - Image: C2 - Voiced: - VoiceSet: CivilianFemaleVoice + Image: C1 + WithInfantryBody: + Palette: civilian8 + WithDeathAnimation: + DeathSequencePalette: civilian8 + DeathPaletteIsPlayerPalette: false C9: Inherits: ^CivInfantry RenderSprites: Image: C1 + WithInfantryBody: + Palette: civilian9 + WithDeathAnimation: + DeathSequencePalette: civilian9 + DeathPaletteIsPlayerPalette: false C10: Inherits: ^CivInfantry RenderSprites: - Image: C2 - Voiced: - VoiceSet: CivilianFemaleVoice + Image: C1 + Tooltip: + Name: Scientist + WithInfantryBody: + Palette: civilian10 + WithDeathAnimation: + DeathSequencePalette: civilian10 + DeathPaletteIsPlayerPalette: false + +C11: + Inherits: ^CivInfantry TECN: Inherits@1: ^CivInfantry @@ -62,6 +107,19 @@ RenderSprites: Image: C1 +TECN2: + Inherits@1: ^CivInfantry + Inherits@2: ^ArmedCivilian + Tooltip: + Name: Technician + RenderSprites: + Image: C1 + WithInfantryBody: + Palette: civilian7 + WithDeathAnimation: + DeathSequencePalette: civilian7 + DeathPaletteIsPlayerPalette: false + FCOM: Inherits: ^TechBuilding Inherits@shape: ^2x2Shape @@ -81,10 +139,10 @@ Name: Forward Command TooltipDescription@ally: Description: Provides buildable area. - ValidStances: Ally + ValidRelationships: Ally TooltipDescription@other: Description: Capture to give buildable area. - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy RevealsShroud: MinRange: 4c0 Range: 5c0 @@ -134,10 +192,10 @@ Name: Hospital TooltipDescription@ally: Description: Provides infantry with self-healing. - ValidStances: Ally + ValidRelationships: Ally TooltipDescription@other: Description: Capture to enable self-healing for infantry. - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy RevealsShroud: Range: 4c0 WithBuildingBib: @@ -298,13 +356,10 @@ Palette: player Tooltip: Name: Oil Pump - -SpawnActorOnDeath@1: - -SpawnActorOnDeath@2: - -SpawnActorOnDeath@3: SpawnActorOnDeath: Actor: V19.Husk Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure, NoAutoTarget + TargetTypes: GroundActor, C4, DetonateAttack, Structure, NoAutoTarget V19.Husk: Inherits: ^CivBuilding @@ -317,8 +372,6 @@ StartSequence: fire-start Sequence: fire-loop -Selectable: - SelectionDecorations: - RenderSelectionBars: False -Targetable: -Demolishable: -HitShape: @@ -330,8 +383,6 @@ BARL: Inherits: ^TechBuilding -Selectable: - SelectionDecorations: - RenderSelectionBars: False Health: HP: 1000 Explodes: @@ -342,7 +393,7 @@ Armor: Type: None Targetable: - TargetTypes: Ground, DemoTruck, Barrel, NoAutoTarget + TargetTypes: GroundActor, DemoTruck, Barrel, NoAutoTarget -ShakeOnDeath: -SoundOnDamageTransition: -Demolishable: @@ -354,8 +405,6 @@ BRL3: Inherits: ^TechBuilding -Selectable: - SelectionDecorations: - RenderSelectionBars: False Health: HP: 1000 Explodes: @@ -366,7 +415,7 @@ Armor: Type: None Targetable: - TargetTypes: Ground, DemoTruck, Barrel, NoAutoTarget + TargetTypes: GroundActor, DemoTruck, Barrel, NoAutoTarget -ShakeOnDeath: -SoundOnDamageTransition: -Demolishable: @@ -413,10 +462,10 @@ Name: Communications Center TooltipDescription@ally: Description: Provides range of vision. - ValidStances: Ally + ValidRelationships: Ally TooltipDescription@other: Description: Capture to give visual range. - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy WithBuildingBib: CaptureManager: Capturable: @@ -454,10 +503,10 @@ Name: Biological Lab TooltipDescription@ally: Description: Provides prerequisite for Bio-Lab units. - ValidStances: Ally + ValidRelationships: Ally TooltipDescription@other: Description: Capture to produce Bio-Lab units. - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy WithDeathAnimation: DeathSequence: dead UseDeathTypeSuffix: false @@ -493,14 +542,15 @@ CashTrickler: Interval: 375 Amount: 100 + RequiresCondition: enabled Tooltip: Name: Oil Derrick TooltipDescription@ally: Description: Provides additional funds. - ValidStances: Ally + ValidRelationships: Ally TooltipDescription@other: Description: Capture to receive additional funds. - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy Explodes: Weapon: BarrelExplode GpsDot: @@ -509,6 +559,8 @@ GivesCashOnCapture: Amount: 100 UpdatesDerrickCount: + GrantConditionOnCombatantOwner: + Condition: enabled BR1: Inherits: ^Bridge @@ -887,7 +939,6 @@ Selectable: Bounds: 24,24,0,-14 DecorationBounds: 36,36,0,-14 - SelectionDecorations: Tooltip: Name: Windmill Building: diff -Nru openra-20200503/mods/ra/rules/defaults.yaml openra-20210321/mods/ra/rules/defaults.yaml --- openra-20200503/mods/ra/rules/defaults.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/defaults.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,7 +4,6 @@ GivesExperience: PlayerExperienceModifier: 1 ScriptTriggers: - ConditionManager: RenderDebugState: ^SpriteActor: @@ -12,6 +11,11 @@ QuantizeFacingsFromSequence: RenderSprites: +^ClassicFacingSpriteActor: + ClassicFacingBodyOrientation: + QuantizeFacingsFromSequence: + RenderSprites: + ^1x1Shape: HitShape: UseTargetableCellsOffsets: true @@ -100,45 +104,45 @@ ReloadDelayMultiplier@RANK-ELITE: RequiresCondition: rank-elite Modifier: 75 - SelfHealing@ELITE: + ChangesHealth@ELITE: Step: 0 PercentageStep: 5 Delay: 100 - HealIfBelow: 100 + StartIfBelow: 100 DamageCooldown: 125 RequiresCondition: rank-elite WithDecoration@RANK-1: Image: rank Sequence: rank-veteran-1 Palette: effect - ReferencePoint: Bottom, Right - ValidStances: Ally, Enemy, Neutral + Position: BottomRight + Margin: 5, 6 + ValidRelationships: Ally, Enemy, Neutral RequiresCondition: rank-veteran == 1 - ZOffset: 256 WithDecoration@RANK-2: Image: rank Sequence: rank-veteran-2 Palette: effect - ReferencePoint: Bottom, Right - ValidStances: Ally, Enemy, Neutral + Position: BottomRight + Margin: 5, 6 + ValidRelationships: Ally, Enemy, Neutral RequiresCondition: rank-veteran == 2 - ZOffset: 256 WithDecoration@RANK-3: Image: rank Sequence: rank-veteran-3 Palette: effect - ReferencePoint: Bottom, Right - ValidStances: Ally, Enemy, Neutral + Position: BottomRight + Margin: 5, 6 + ValidRelationships: Ally, Enemy, Neutral RequiresCondition: rank-veteran == 3 - ZOffset: 256 WithDecoration@RANK-ELITE: Image: rank Sequence: rank-elite Palette: effect - ReferencePoint: Bottom, Right - ValidStances: Ally, Enemy, Neutral + Position: BottomRight + Margin: 5, 6 + ValidRelationships: Ally, Enemy, Neutral RequiresCondition: rank-elite - ZOffset: 256 ^InfantryExperienceHospitalOverrides: WithDecoration@RANK-1: @@ -174,11 +178,11 @@ AttackAnythingCondition: stance-attackanything AutoTargetPriority@DEFAULT: RequiresCondition: !stance-attackanything - ValidTargets: Infantry, Vehicle, Water, Underwater, Defense, Mine - InvalidTargets: NoAutoTarget, WaterStructure + ValidTargets: Infantry, Vehicle, Ship, Underwater, Defense, Mine + InvalidTargets: NoAutoTarget AutoTargetPriority@ATTACKANYTHING: RequiresCondition: stance-attackanything - ValidTargets: Infantry, Vehicle, Water, Underwater, Structure, Defense, Mine + ValidTargets: Infantry, Vehicle, Ship, Underwater, Structure, Defense, Mine InvalidTargets: NoAutoTarget ^AutoTargetGroundAssaultMove: @@ -193,7 +197,7 @@ ^AutoTargetAir: AutoTarget: AutoTargetPriority@DEFAULT: - ValidTargets: Air + ValidTargets: AirborneActor InvalidTargets: NoAutoTarget ^AutoTargetAll: @@ -201,11 +205,11 @@ AttackAnythingCondition: stance-attackanything AutoTargetPriority@DEFAULT: RequiresCondition: !stance-attackanything - ValidTargets: Infantry, Vehicle, Water, Underwater, Air, Defense, Mine - InvalidTargets: NoAutoTarget, WaterStructure + ValidTargets: Infantry, Vehicle, Ship, Underwater, AirborneActor, Defense, Mine + InvalidTargets: NoAutoTarget AutoTargetPriority@ATTACKANYTHING: RequiresCondition: stance-attackanything - ValidTargets: Infantry, Vehicle, Water, Underwater, Air, Structure, Defense, Mine + ValidTargets: Infantry, Vehicle, Ship, Underwater, AirborneActor, Structure, Defense, Mine InvalidTargets: NoAutoTarget ^AutoTargetAllAssaultMove: @@ -217,6 +221,11 @@ AttackMove: AssaultMoveCondition: assault-move +^PlayerHandicaps: + HandicapFirepowerMultiplier: + HandicapDamageMultiplier: + HandicapProductionTimeMultiplier: + ^GlobalBounty: GrantConditionOnPrerequisite@GLOBALBOUNTY: Condition: global-bounty @@ -227,25 +236,23 @@ ^Vehicle: Inherits@1: ^ExistsInWorld Inherits@2: ^IronCurtainable - Inherits@3: ^SpriteActor + Inherits@3: ^ClassicFacingSpriteActor Inherits@bounty: ^GlobalBounty Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill - DrawLineToTarget: UpdatesPlayerStatistics: Mobile: PauseOnCondition: being-captured Locomotor: wheeled - TurnSpeed: 5 - SelectionDecorations: - WithSpriteControlGroupDecoration: + TurnSpeed: 20 Selectable: Bounds: 24, 24 Targetable: RequiresCondition: !parachute - TargetTypes: Ground, Vehicle + TargetTypes: GroundActor, Vehicle Targetable@REPAIR: RequiresCondition: !parachute && damaged TargetTypes: Repair @@ -296,8 +303,6 @@ OpeningSequence: open Offset: 0,0,200 RequiresCondition: parachute - BodyOrientation: - UseClassicFacingFudge: True HitShape: MapEditorData: Categories: Vehicle @@ -314,11 +319,11 @@ Inherits@4: ^SpriteActor Inherits@bounty: ^GlobalBounty Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill DeathTypes: DefaultDeath - DrawLineToTarget: Health: HP: 2500 Armor: @@ -327,15 +332,14 @@ Range: 4c0 Mobile: Speed: 56 + AlwaysTurnInPlace: true Locomotor: foot - SelectionDecorations: - WithSpriteControlGroupDecoration: Selectable: Bounds: 18,20,0,-6 DecorationBounds: 12,18,0,-8 Targetable: RequiresCondition: !parachute - TargetTypes: Ground, Infantry, Disguise + TargetTypes: GroundActor, Infantry, Disguise Targetable@HEAL: RequiresCondition: !parachute && damaged TargetTypes: Heal @@ -371,10 +375,10 @@ Guardable: Tooltip: GenericName: Soldier - SelfHealing@HOSPITAL: + ChangesHealth@HOSPITAL: Step: 500 Delay: 100 - HealIfBelow: 100 + StartIfBelow: 100 DamageCooldown: 125 RequiresCondition: hospitalheal GrantConditionOnPrerequisite@HOSPITAL: @@ -389,7 +393,8 @@ WithDecoration@REDCROSS: Image: pips Sequence: medic - ReferencePoint: Bottom, Right + Position: BottomRight + Margin: 17, 4 RequiresCondition: hospitalheal BlinkInterval: 32 BlinkPattern: Off, On @@ -458,7 +463,7 @@ RevealsShroud: Range: 3c0 Passenger: - PipType: Gray + CustomPipType: gray ProximityCaptor: Types: CivilianInfantry ScaredyCat: @@ -485,19 +490,17 @@ Inherits@4: ^SpriteActor Inherits@bounty: ^GlobalBounty Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill - DrawLineToTarget: UpdatesPlayerStatistics: Mobile: Locomotor: naval - SelectionDecorations: - WithSpriteControlGroupDecoration: Selectable: Bounds: 24,24 Targetable: - TargetTypes: Ground, Water, Ship + TargetTypes: WaterActor, Ship Targetable@REPAIR: RequiresCondition: damaged TargetTypes: Repair @@ -537,27 +540,25 @@ Inherits@4: ^SpriteActor Inherits@bounty: ^GlobalBounty Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill - DrawLineToTarget: Armor: Type: Light UpdatesPlayerStatistics: AppearsOnRadar: UseLocation: true - SelectionDecorations: - WithSpriteControlGroupDecoration: Selectable: Bounds: 24,24 Aircraft: AirborneCondition: airborne Targetable@GROUND: RequiresCondition: !airborne - TargetTypes: Ground, Vehicle + TargetTypes: GroundActor, Vehicle Targetable@AIRBORNE: RequiresCondition: airborne - TargetTypes: Air + TargetTypes: AirborneActor Targetable@REPAIR: RequiresCondition: !airborne && damaged TargetTypes: Repair @@ -599,6 +600,13 @@ Explodes: Weapon: UnitExplode RequiresCondition: !airborne + CaptureManager: + Capturable: + Types: aircraft + RequiresCondition: !airborne + CaptureNotification: + Notification: UnitStolen + LoseNotification: UnitLost ^Plane: Inherits: ^NeutralPlane @@ -618,14 +626,13 @@ VTOL: true LandableTerrainTypes: Clear, Rough, Road, Ore, Beach, Gems Crushes: crate, mine, infantry - InitialFacing: 224 CanSlide: True GpsDot: String: Helicopter Hovers@CRUISING: RequiresCondition: cruising - BodyOrientation: - UseClassicFacingFudge: True + -BodyOrientation: + ClassicFacingBodyOrientation: ^BasicBuilding: Inherits@1: ^ExistsInWorld @@ -634,10 +641,9 @@ Inherits@shape: ^1x1Shape Inherits@bounty: ^GlobalBounty Inherits@selection: ^SelectableBuilding - SelectionDecorations: - WithSpriteControlGroupDecoration: + Inherits@handicaps: ^PlayerHandicaps Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure + TargetTypes: GroundActor, C4, DetonateAttack, Structure Building: Dimensions: 1,1 Footprint: x @@ -696,7 +702,7 @@ CapturableProgressBar: CapturableProgressBlink: SpawnActorsOnSell: - ActorTypes: e1,e1,e1,tecn,tecn + ActorTypes: e1,e1,e1,tecn,tecn2 MustBeDestroyed: RequiredForShortGame: true GpsDot: @@ -709,14 +715,14 @@ WithBuildingRepairDecoration: Image: allyrepair Sequence: repair - ReferencePoint: Center + Position: Center Palette: player IsPlayerPalette: True ^ScienceBuilding: Inherits: ^Building SpawnActorsOnSell: - ActorTypes: e1,e1,e1,e1,tecn,tecn,tecn,tecn,tecn,tecn,tecn,tecn,tecn,tecn,e6,e6,e6,e6,e6,chan,chan,chan,chan + ActorTypes: e1,e1,e1,e1,tecn,tecn2,tecn,tecn2,tecn,tecn2,tecn,tecn2,tecn,tecn2,e6,e6,e6,e6,e6,c10,c10,c10,c10 ^Defense: Inherits: ^Building @@ -724,12 +730,11 @@ Selectable: Bounds: 24,24 Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure, Defense + TargetTypes: GroundActor, C4, DetonateAttack, Structure, Defense MustBeDestroyed: RequiredForShortGame: false -GivesBuildableArea: -AcceptsDeliveredCash: - DrawLineToTarget: RenderRangeCircle: Explodes: Weapon: SmallBuildingExplode @@ -742,6 +747,7 @@ Inherits@1: ^ExistsInWorld Inherits@2: ^SpriteActor Inherits@shape: ^1x1Shape + Inherits@handicaps: ^PlayerHandicaps Interactable: Bounds: 24,24 OwnerLostAction: @@ -768,7 +774,7 @@ LineBuildNode: Types: wall Targetable: - TargetTypes: Ground, DetonateAttack, Wall, NoAutoTarget + TargetTypes: GroundActor, DetonateAttack, Wall, NoAutoTarget -GivesExperience: RenderSprites: Palette: effect @@ -786,6 +792,8 @@ Terrain: Wall MapEditorData: Categories: Wall + UpdatesPlayerStatistics: + AddToAssetsValue: false ^TechBuilding: Inherits: ^BasicBuilding @@ -815,11 +823,11 @@ RevealsShroud: Range: 1c0 WithDecoration@fake: - RequiresSelection: true + Position: Top + Margin: 0, 4 + RequiresSelection: false Image: pips Sequence: tag-fake - ReferencePoint: Top - ZOffset: 256 -SpawnActorsOnSell: -MustBeDestroyed: MapEditorData: @@ -827,20 +835,18 @@ ^InfiltratableFake: Targetable: - TargetTypes: Ground, Structure, C4, DetonateAttack, SpyInfiltrate + TargetTypes: GroundActor, Structure, C4, DetonateAttack, SpyInfiltrate InfiltrateForDecoration: Types: SpyInfiltrate + Position: Top + Margin: 0, 4 RequiresSelection: true Image: pips Sequence: tag-fake - ReferencePoint: Top - ZOffset: 256 ^AmmoBox: Inherits: ^TechBuilding -Selectable: - SelectionDecorations: - RenderSelectionBars: False Health: HP: 1000 Explodes: @@ -848,7 +854,7 @@ Tooltip: Name: Ammo Box Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure, NoAutoTarget + TargetTypes: GroundActor, C4, DetonateAttack, Structure, NoAutoTarget Armor: Type: Light MapEditorData: @@ -863,15 +869,6 @@ MapEditorData: ExcludeTilesets: INTERIOR Categories: Civilian building - SpawnActorOnDeath@1: - Actor: c1 - Probability: 40 - SpawnActorOnDeath@2: - Actor: c4 - Probability: 20 - SpawnActorOnDeath@3: - Actor: c3 - Probability: 15 Explodes: Weapon: SmallBuildingExplode Explodes@CIVPANIC: @@ -884,7 +881,6 @@ -Explodes: -Explodes@CIVPANIC: -Selectable: - -SelectionDecorations: Tooltip: Name: Field -Targetable: @@ -914,7 +910,7 @@ Health: HP: 50000 Armor: - Type: Wood + Type: Tree Targetable: TargetTypes: Trees WithDamageOverlay@SmallBurn: @@ -978,7 +974,6 @@ Categories: Decoration ^BasicHusk: - Inherits@1: ^SpriteActor Interactable: Health: HP: 28000 @@ -986,7 +981,7 @@ Type: Heavy HiddenUnderFog: Type: CenterPosition - AlwaysVisibleStances: None + AlwaysVisibleRelationships: None ScriptTriggers: WithFacingSpriteBody: HitShape: @@ -995,16 +990,23 @@ ^Husk: Inherits: ^BasicHusk + Inherits@2: ^ClassicFacingSpriteActor Husk: AllowedTerrain: Clear, Rough, Road, Ore, Gems, Beach - Burns: - Damage: 200 + WithIdleOverlay@Burns: + Image: fire + Sequence: 1 + IsDecoration: true + ChangesHealth: + Step: -200 + StartIfBelow: 101 + Delay: 8 OwnerLostAction: Action: ChangeOwner CaptureManager: Capturable: Types: husk - ValidStances: Enemy, Neutral + ValidRelationships: Enemy, Neutral TransformOnCapture: ForceHealthPercentage: 25 InfiltrateForTransform: @@ -1013,16 +1015,17 @@ WithColoredOverlay@IDISABLE: Palette: disabled Targetable: - TargetTypes: Ground, Husk, NoAutoTarget + TargetTypes: GroundActor, Husk, NoAutoTarget RequiresForceFire: true Chronoshiftable: Tooltip: GenericName: Destroyed Vehicle - BodyOrientation: - UseClassicFacingFudge: True ^PlaneHusk: Inherits: ^BasicHusk + Inherits@2: ^SpriteActor + Targetable: + TargetTypes: AirborneActor, Husk, NoAutoTarget WithShadow: Offset: 43, 128, 0 ZOffset: -129 @@ -1041,6 +1044,9 @@ ^HelicopterHusk: Inherits: ^BasicHusk + Inherits@2: ^ClassicFacingSpriteActor + Targetable: + TargetTypes: AirborneActor, Husk, NoAutoTarget WithShadow: Offset: 43, 128, 0 ZOffset: -129 @@ -1052,8 +1058,6 @@ CanSlide: True FallsToEarth: Explosion: UnitExplodeHeli - BodyOrientation: - UseClassicFacingFudge: True -MapEditorData: RevealOnDeath: Duration: 60 @@ -1066,7 +1070,7 @@ Name: Bridge ShowOwnerRow: false Targetable: - TargetTypes: Ground, Water, Bridge + TargetTypes: GroundActor, WaterActor, Bridge RequiresForceFire: true Building: Footprint: ____ ____ @@ -1147,7 +1151,6 @@ ShadowImage: parach-shadow ShadowSequence: idle RequiresCondition: parachute - ConditionManager: MapEditorData: Categories: System @@ -1176,7 +1179,7 @@ Tooltip: Name: Mine Targetable: - TargetTypes: Ground, Mine + TargetTypes: GroundActor, Mine Immobile: OccupiesSpace: true HitShape: @@ -1209,7 +1212,7 @@ Sequence: offline Palette: chrome RequiresCondition: powerdown - ReferencePoint: Center + Position: Center Offsets: repairing: 10, 0 PowerMultiplier@POWERDOWN: @@ -1235,25 +1238,60 @@ Power: RequiresCondition: !disabled +^Selectable: + Selectable: + SelectionDecorations: + WithSpriteControlGroupDecoration: + Margin: -2, 0 + DrawLineToTarget: + ^SelectableCombatUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 10 PriorityModifiers: Ctrl ^SelectableSupportUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 8 PriorityModifiers: Ctrl, Alt ^SelectableEconomicUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 6 PriorityModifiers: Ctrl, Alt ^SelectableCombatBuilding: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 4 ^SelectableBuilding: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 2 + +^CargoPips: + WithCargoPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + CustomPipSequences: + gray: pip-gray + yellow: pip-yellow + blue: pip-blue + red: pip-red + +^PrimaryBuilding: + PrimaryBuilding: + PrimaryCondition: primary + SelectionNotification: PrimaryBuildingSelected + WithDecoration@primary: + RequiresCondition: primary + Position: Top + Margin: 0, 4 + RequiresSelection: true + Image: pips + Sequence: tag-primary diff -Nru openra-20200503/mods/ra/rules/fakes.yaml openra-20210321/mods/ra/rules/fakes.yaml --- openra-20200503/mods/ra/rules/fakes.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/fakes.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -83,7 +83,7 @@ GenericVisibility: Enemy GenericStancePrefix: False Targetable: - TargetTypes: Ground, Water, Structure, SpyInfiltrate + TargetTypes: WaterActor, Structure, SpyInfiltrate Building: Footprint: XXX xxx XXX Dimensions: 3,3 @@ -117,7 +117,7 @@ Selectable: Bounds: 72,48 Targetable: - TargetTypes: Ground, Water, Structure, SpyInfiltrate + TargetTypes: WaterActor, Structure, SpyInfiltrate Buildable: BuildPaletteOrder: 890 Queue: Defense @@ -293,7 +293,6 @@ Selectable: Bounds: 72,48 DecorationBounds: 72,68,0,-10 - SelectionDecorations: Valued: Cost: 50 diff -Nru openra-20200503/mods/ra/rules/husks.yaml openra-20210321/mods/ra/rules/husks.yaml --- openra-20200503/mods/ra/rules/husks.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/husks.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,16 +1,3 @@ -1TNK.Husk: - Inherits: ^Husk - Tooltip: - Name: Husk (Light Tank) - ThrowsParticle@turret: - Anim: turret - TransformOnCapture: - IntoActor: 1tnk - InfiltrateForTransform: - IntoActor: 1tnk - RenderSprites: - Image: 1tnk.destroyed - 2TNK.Husk: Inherits: ^Husk Tooltip: @@ -102,7 +89,7 @@ Tooltip: Name: Chinook Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 149 WithIdleOverlay@PRIMARY: Offset: -597,0,341 @@ -146,7 +133,7 @@ Tooltip: Name: Badger Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 149 SmokeTrailWhenDamaged@0: Offset: -432,560,0 @@ -169,7 +156,7 @@ Contrail@2: Offset: -598,683,0 Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 186 SmokeTrailWhenDamaged: Offset: -853,0,171 @@ -193,7 +180,7 @@ Contrail: Offset: -853,0,0 Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 149 SmokeTrailWhenDamaged: Offset: -853,0,0 @@ -215,7 +202,7 @@ Tooltip: Name: Longbow Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 149 WithIdleOverlay: Offset: 0,0,85 @@ -239,7 +226,7 @@ Tooltip: Name: Hind Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 112 WithIdleOverlay: Sequence: rotor @@ -262,7 +249,7 @@ Tooltip: Name: Husk (Spy Plane) Aircraft: - TurnSpeed: 7 + TurnSpeed: 28 Speed: 373 Contrail@1: Offset: -725,683,0 @@ -451,7 +438,7 @@ Tooltip: Name: Black Hawk Aircraft: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 112 WithIdleOverlay: Sequence: rotor diff -Nru openra-20200503/mods/ra/rules/infantry.yaml openra-20210321/mods/ra/rules/infantry.yaml --- openra-20200503/mods/ra/rules/infantry.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/infantry.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,6 @@ Selectable: Bounds: 12,17,-1,-4 DecorationBounds: 12,17,-1,-4 - SelectionDecorations: Health: HP: 1800 Mobile: @@ -48,7 +47,7 @@ AutoTargetPriority@DEFAULT: ValidTargets: Infantry Targetable: - TargetTypes: Ground, Infantry + TargetTypes: GroundActor, Infantry WithInfantryBody: MoveSequence: walk StandSequences: stand @@ -265,7 +264,7 @@ StandSequences: parachute RequiresCondition: parachute Passenger: - PipType: Yellow + CustomPipType: yellow EngineerRepair: RepairsBridges: CaptureManager: @@ -312,7 +311,7 @@ RevealsShroud: Range: 5c0 Passenger: - PipType: Blue + CustomPipType: blue Voice: Move Disguise: DisguisedCondition: disguise @@ -330,11 +329,11 @@ IdleSequences: idle1,idle2 StandSequences: stand,stand2 WithDecoration@disguise: + Position: Top + Margin: 0, -6 Image: pips - Sequence: pip-disguise + Sequence: tag-spy Palette: effect - ReferencePoint: Top, Right - ZOffset: 256 RequiresCondition: disguise IgnoresDisguise: Armament: @@ -386,18 +385,21 @@ DetonationDelay: 45 Voice: Demolish Passenger: - PipType: Red + CustomPipType: red Voice: Move Armament@PRIMARY: Weapon: Colt45 + LocalOffset: 0,0,0, 0,0,0 Armament@SECONDARY: Weapon: Colt45 + LocalOffset: 0,0,0, 0,0,0 Armament@GARRISONED: Name: garrisoned Weapon: Colt45 MuzzleSequence: garrison-muzzle WithInfantryBody: - DefaultAttackSequence: shoot + AttackSequences: + primary: shoot-left, shoot-right StandSequences: stand ExternalCondition@PRODUCED: Condition: produced @@ -431,13 +433,13 @@ RevealsShroud: Range: 3c0 Passenger: - PipType: Blue + CustomPipType: blue Armament: Weapon: Heal Cursor: heal OutsideRangeCursor: heal - TargetStances: Ally - ForceTargetStances: None + TargetRelationships: Ally + ForceTargetRelationships: None WithInfantryBody: IdleSequences: idle StandSequences: stand @@ -470,14 +472,14 @@ RevealsShroud: Range: 3c0 Passenger: - PipType: Blue + CustomPipType: blue Voice: Move Armament: Weapon: Repair Cursor: repair OutsideRangeCursor: repair - TargetStances: Ally - ForceTargetStances: None + TargetRelationships: Ally + ForceTargetRelationships: None AttackFrontal: Voice: Action CaptureManager: @@ -486,7 +488,7 @@ PlayerExperience: 25 Infiltrates: Types: Husk - ValidStances: Ally + ValidRelationships: Ally EnterCursor: goldwrench PlayerExperience: 25 WithInfantryBody: @@ -573,10 +575,10 @@ RevealsShroud: Range: 5c0 Passenger: - PipType: Blue + CustomPipType: blue CaptureManager: Captures: - CaptureTypes: vehicle + CaptureTypes: vehicle, aircraft PlayerExperience: 50 Infiltrates: Types: ThiefInfiltrate @@ -669,7 +671,7 @@ Health: HP: 8000 Passenger: - PipType: Red + CustomPipType: red RevealsShroud: Range: 6c0 AutoTarget: @@ -749,12 +751,11 @@ Selectable: Bounds: 24,24,0,-5 DecorationBounds: 30,30,0,-2 - SelectionDecorations: Health: HP: 75000 Mobile: Speed: 99 - TurnSpeed: 12 + TurnSpeed: 48 Locomotor: lighttracked -Crushable: AutoTarget: @@ -765,7 +766,7 @@ Armament: Weapon: mandible Targetable: - TargetTypes: Ground, Infantry, Ant + TargetTypes: GroundActor, Infantry, Ant WithDeathAnimation: UseDeathTypeSuffix: false Voiced: diff -Nru openra-20200503/mods/ra/rules/misc.yaml openra-20210321/mods/ra/rules/misc.yaml --- openra-20200503/mods/ra/rules/misc.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/misc.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -32,7 +32,7 @@ HideMapCrateAction: SelectionShares: 5 Sequence: hide-map - HealUnitsCrateAction: + HealActorsCrateAction: Sound: heal2.aud SelectionShares: 2 Sequence: heal @@ -124,7 +124,7 @@ Inherits: ^Crate Tooltip: Name: Heal Crate - HealUnitsCrateAction: + HealActorsCrateAction: Sound: heal2.aud SelectionShares: 1 Sequence: heal @@ -339,6 +339,7 @@ EffectImage: moveflsh EffectPalette: moveflash SupportPowerPaletteOrder: 80 + EffectSequence: idle powerproxy.paratroopers: AlwaysVisible: @@ -420,7 +421,6 @@ -Health: -Explodes: -Selectable: - -SelectionDecorations: -Targetable: MapEditorData: Categories: Decoration diff -Nru openra-20200503/mods/ra/rules/palettes.yaml openra-20210321/mods/ra/rules/palettes.yaml --- openra-20200503/mods/ra/rules/palettes.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/palettes.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -127,3 +127,43 @@ BaseName: placebuilding BasePalette: player Alpha: 0.65 + IndexedPalette@CIV2: + Name: civilian2 + BasePalette: player + Index: 7, 14, 118, 119, 159, 187, 188 + ReplaceIndex: 209, 12, 187, 188, 209, 167, 13 + IndexedPalette@CIV4: + Name: civilian4 + BasePalette: player + Index: 7, 109, 111, 206, 210 + ReplaceIndex: 187, 118, 119, 188, 182 + IndexedPalette@CIV5: + Name: civilian5 + BasePalette: player + Index: 7, 12, 109, 111, 200, 206, 210 + ReplaceIndex: 109, 131, 177, 178, 111, 111, 182 + IndexedPalette@CIV6: + Name: civilian6 + BasePalette: player + Index: 7, 14, 118, 119, 159 + ReplaceIndex: 120, 238, 236, 206, 111 + IndexedPalette@CIV7: + Name: civilian7 + BasePalette: player + Index: 14, 118, 119, 159, 187, 188 + ReplaceIndex: 131, 157, 212, 7, 118, 119 + IndexedPalette@CIV8: + Name: civilian8 + BasePalette: player + Index: 7, 14, 118, 119, 159, 187, 188, 200 + ReplaceIndex: 182, 131, 215, 7, 182, 198, 199, 111 + IndexedPalette@CIV9: + Name: civilian9 + BasePalette: player + Index: 14, 118, 119, 159, 187, 188 + ReplaceIndex: 7, 163, 165, 200, 111, 13 + IndexedPalette@CIV10: + Name: civilian10 + BasePalette: player + Index: 7, 14, 118, 119, 159, 187, 188 + ReplaceIndex: 137, 15, 129, 131, 137, 163, 165 diff -Nru openra-20200503/mods/ra/rules/player.yaml openra-20210321/mods/ra/rules/player.yaml --- openra-20200503/mods/ra/rules/player.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/player.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -149,6 +149,5 @@ Sequence: veteran ResourceStorageWarning: PlayerExperience: - ConditionManager: GameSaveViewportManager: PlayerRadarTerrain: diff -Nru openra-20200503/mods/ra/rules/ships.yaml openra-20210321/mods/ra/rules/ships.yaml --- openra-20200503/mods/ra/rules/ships.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/ships.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ Armor: Type: Light Mobile: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 71 RevealsShroud: MinRange: 5c0 @@ -27,7 +27,7 @@ RevealsShroud@GAPGEN: Range: 5c0 Targetable: - TargetTypes: Ground, Water, Ship, Submarine, Repair + TargetTypes: WaterActor, Ship, Submarine, Repair RequiresCondition: !underwater Targetable@UNDERWATER: TargetTypes: Underwater, Submarine @@ -49,14 +49,11 @@ LocalOffset: 0,-171,0, 0,171,0 FireDelay: 2 AttackFrontal: - SelectionDecorations: - AutoTarget: - InitialStance: HoldFire - InitialStanceAI: ReturnFire AutoTargetPriority@DEFAULT: - ValidTargets: Water, Underwater + ValidTargets: WaterActor, Underwater + InvalidTargets: NoAutoTarget, Structure AutoTargetPriority@ATTACKANYTHING: - ValidTargets: Water, Underwater + ValidTargets: WaterActor, Underwater DetectCloaked: CloakTypes: Underwater Range: 4c0 @@ -88,7 +85,7 @@ Armor: Type: Light Mobile: - TurnSpeed: 3 + TurnSpeed: 12 Speed: 42 RevealsShroud: MinRange: 5c0 @@ -97,7 +94,7 @@ RevealsShroud@GAPGEN: Range: 5c0 Targetable: - TargetTypes: Ground, Water, Ship, Submarine, Repair + TargetTypes: WaterActor, Ship, Submarine, Repair RequiresCondition: !underwater Targetable@UNDERWATER: TargetTypes: Underwater, Submarine @@ -125,7 +122,6 @@ AttackFrontal: TargetFrozenActors: True ForceFireIgnoresActors: True - SelectionDecorations: AutoTarget: InitialStance: HoldFire InitialStanceAI: ReturnFire @@ -160,7 +156,7 @@ Armor: Type: Heavy Mobile: - TurnSpeed: 7 + TurnSpeed: 28 Speed: 85 RevealsShroud: MinRange: 5c0 @@ -169,7 +165,7 @@ RevealsShroud@GAPGEN: Range: 5c0 Turreted: - TurnSpeed: 7 + TurnSpeed: 28 Offset: 469,0,128 Armament@PRIMARY: Weapon: Stinger @@ -184,7 +180,6 @@ LocalOffset: 0,-100,0, 0,100,0 LocalYaw: 64, -64 AttackTurreted: - SelectionDecorations: WithSpriteTurret: DetectCloaked: CloakTypes: Underwater @@ -213,7 +208,7 @@ Armor: Type: Heavy Mobile: - TurnSpeed: 3 + TurnSpeed: 12 Speed: 42 RevealsShroud: MinRange: 5c0 @@ -224,11 +219,11 @@ Turreted@PRIMARY: Turret: primary Offset: -896,0,128 - TurnSpeed: 3 + TurnSpeed: 12 Turreted@SECONDARY: Turret: secondary Offset: 768,0,128 - TurnSpeed: 3 + TurnSpeed: 12 Armament@PRIMARY: Turret: primary Weapon: 8Inch @@ -249,7 +244,6 @@ TargetFrozenActors: True ForceFireIgnoresActors: True WithMuzzleOverlay: - SelectionDecorations: WithSpriteTurret@PRIMARY: Turret: primary WithSpriteTurret@SECONDARY: @@ -259,6 +253,7 @@ LST: Inherits: ^Ship + Inherits@CARGOPIPS: ^CargoPips Buildable: Queue: Ship BuildPaletteOrder: 10 @@ -284,13 +279,11 @@ RevealGeneratedShroud: False RevealsShroud@GAPGEN: Range: 5c0 - SelectionDecorations: WithLandingCraftAnimation: OpenTerrainTypes: Clear, Rough, Road, Ore, Gems, Beach Cargo: Types: Infantry, Vehicle MaxWeight: 5 - PipCount: 5 PassengerFacing: 0 LoadingCondition: notmobile -Chronoshiftable: @@ -317,7 +310,7 @@ Armor: Type: Heavy Mobile: - TurnSpeed: 7 + TurnSpeed: 28 Speed: 128 RevealsShroud: MinRange: 5c0 @@ -326,7 +319,7 @@ RevealsShroud@GAPGEN: Range: 5c0 Turreted: - TurnSpeed: 7 + TurnSpeed: 28 Offset: 512,0,0 Armament@PRIMARY: Weapon: 2Inch @@ -338,7 +331,6 @@ MuzzleSequence: muzzle AttackTurreted: WithMuzzleOverlay: - SelectionDecorations: WithSpriteTurret: DetectCloaked: CloakTypes: Underwater diff -Nru openra-20200503/mods/ra/rules/structures.yaml openra-20210321/mods/ra/rules/structures.yaml --- openra-20200503/mods/ra/rules/structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -47,22 +47,25 @@ MissileWeapon: atomic MissileDelay: 5 SpawnOffset: 1c0,427,0 - DisplayTimerStances: Ally, Neutral, Enemy + DisplayTimerRelationships: Ally, Neutral, Enemy DisplayBeacon: True DisplayRadarPing: True BeaconPoster: atomicon - FlashType: Nuke CameraRange: 10c0 ArrowSequence: arrow ClockSequence: clock CircleSequence: circles SupportPowerPaletteOrder: 70 SupportPowerChargeBar: + InfiltrateForSupportPowerReset: + Types: SpyInfiltrate + Targetable: + TargetTypes: GroundActor, C4, DetonateAttack, Structure, SpyInfiltrate Power: Amount: -150 MustBeDestroyed: RequiredForShortGame: false - WithNukeLaunchAnimation: + WithSupportPowerActivationAnimation: RequiresCondition: !build-incomplete GAP: @@ -80,7 +83,6 @@ Selectable: Bounds: 24,24 DecorationBounds: 24,48,0,-12 - SelectionDecorations: WithSpriteBody: PauseOnCondition: disabled Health: @@ -114,6 +116,7 @@ SPEN: Inherits: ^Building + Inherits@PRIMARY: ^PrimaryBuilding Selectable: Bounds: 72,48 InfiltrateForSupportPower: @@ -129,7 +132,7 @@ Prerequisites: anypower, ~structures.soviet, ~techlevel.low Description: Produces and repairs\nsubmarines and transports. Targetable: - TargetTypes: Ground, Water, Structure, WaterStructure, C4, DetonateAttack, SpyInfiltrate + TargetTypes: WaterActor, Structure, C4, DetonateAttack, SpyInfiltrate Building: Footprint: XXX xxx XXX Dimensions: 3,3 @@ -151,56 +154,53 @@ Exit@1: RequiresCondition: !being-captured SpawnOffset: 0,-213,0 - Facing: 96 + Facing: 384 ExitCell: -1,2 ProductionTypes: Submarine Exit@2: RequiresCondition: !being-captured SpawnOffset: 0,-213,0 - Facing: 160 + Facing: 640 ExitCell: 3,2 ProductionTypes: Submarine Exit@3: RequiresCondition: !being-captured SpawnOffset: 0,0,0 - Facing: 32 + Facing: 128 ExitCell: 0,0 ProductionTypes: Submarine Exit@4: RequiresCondition: !being-captured SpawnOffset: 0,0,0 - Facing: 224 + Facing: 896 ExitCell: 2,0 ProductionTypes: Submarine Exit@b1: RequiresCondition: !being-captured SpawnOffset: -1024,1024,0 - Facing: 160 + Facing: 640 ExitCell: 0,2 ProductionTypes: Ship Exit@b2: RequiresCondition: !being-captured SpawnOffset: 1024,1024,0 - Facing: 224 + Facing: 896 ExitCell: 2,2 ProductionTypes: Ship Exit@b3: RequiresCondition: !being-captured SpawnOffset: -1024,-1024,0 - Facing: 96 + Facing: 384 ExitCell: 0,0 ProductionTypes: Ship Exit@b4: RequiresCondition: !being-captured SpawnOffset: 1024,-1024,0 - Facing: 32 + Facing: 128 ExitCell: 2,0 ProductionTypes: Ship Production: Produces: Ship, Submarine - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected -SpawnActorsOnSell: RepairsUnits: HpPerStep: 1000 @@ -243,13 +243,6 @@ ProvidesPrerequisite@buildingname: MapEditorData: ExcludeTilesets: INTERIOR - WithDecoration@primary: - RequiresSelection: true - Image: pips - Sequence: tag-primary - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary HitShape: Type: Rectangle TopLeft: -1536, -598 @@ -262,6 +255,7 @@ SYRD: Inherits: ^Building + Inherits@PRIMARY: ^PrimaryBuilding Selectable: Bounds: 72,48 InfiltrateForSupportPower: @@ -277,7 +271,7 @@ Tooltip: Name: Naval Yard Targetable: - TargetTypes: Ground, Water, Structure, WaterStructure, C4, DetonateAttack, SpyInfiltrate + TargetTypes: WaterActor, Structure, C4, DetonateAttack, SpyInfiltrate Building: Footprint: XXX xxx XXX Dimensions: 3,3 @@ -298,32 +292,29 @@ Exit@1: RequiresCondition: !being-captured SpawnOffset: -1024,1024,0 - Facing: 160 + Facing: 640 ExitCell: 0,2 ProductionTypes: Ship, Boat Exit@2: RequiresCondition: !being-captured SpawnOffset: 1024,1024,0 - Facing: 224 + Facing: 896 ExitCell: 2,2 ProductionTypes: Ship, Boat Exit@3: RequiresCondition: !being-captured SpawnOffset: -1024,-1024,0 - Facing: 96 + Facing: 384 ExitCell: 0,0 ProductionTypes: Ship, Boat Exit@4: RequiresCondition: !being-captured SpawnOffset: 1024,-1024,0 - Facing: 32 + Facing: 128 ExitCell: 2,0 ProductionTypes: Ship, Boat Production: Produces: Ship, Boat - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected -SpawnActorsOnSell: RepairsUnits: HpPerStep: 1000 @@ -372,13 +363,6 @@ ProvidesPrerequisite@buildingname: MapEditorData: ExcludeTilesets: INTERIOR - WithDecoration@primary: - RequiresSelection: true - Image: pips - Sequence: tag-primary - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary HitShape: TargetableOffsets: 768,0,0, 768,-1024,0, 768,1024,0 Type: Rectangle @@ -410,7 +394,6 @@ Selectable: Bounds: 48,28,0,2 DecorationBounds: 50,50,0,-12 - SelectionDecorations: Health: HP: 100000 Armor: @@ -443,7 +426,13 @@ Condition: invulnerability OnFireSound: ironcur9.aud SupportPowerPaletteOrder: 10 + Dimensions: 3, 3 + Footprint: _x_ xxx _x_ SupportPowerChargeBar: + InfiltrateForSupportPowerReset: + Types: SpyInfiltrate + Targetable: + TargetTypes: GroundActor, C4, DetonateAttack, Structure, SpyInfiltrate Power: Amount: -200 MustBeDestroyed: @@ -507,6 +496,8 @@ KillCargo: true DisplayRadarPing: True SupportPowerPaletteOrder: 20 + Dimensions: 3, 3 + Footprint: _x_ xxx _x_ ChronoshiftPower@advancedchronoshift: OrderName: AdvancedChronoshift PauseOnCondition: disabled @@ -522,9 +513,14 @@ Duration: 400 KillCargo: true DisplayRadarPing: True - Range: 2 SupportPowerPaletteOrder: 30 + Dimensions: 5, 5 + Footprint: __x__ _xxx_ xxxxx _xxx_ __x__ SupportPowerChargeBar: + InfiltrateForSupportPowerReset: + Types: SpyInfiltrate + Targetable: + TargetTypes: GroundActor, C4, DetonateAttack, Structure, SpyInfiltrate Power: Amount: -200 MustBeDestroyed: @@ -547,14 +543,13 @@ Selectable: Bounds: 24,24 DecorationBounds: 24,40,0,-8 - SelectionDecorations: Health: HP: 40000 Armor: Type: Heavy RevealsShroud: MinRange: 6c0 - Range: 8c0 + Range: 7c0 RevealGeneratedShroud: False RevealsShroud@GAPGEN: Range: 6c0 @@ -593,7 +588,6 @@ Selectable: Bounds: 24,24 DecorationBounds: 24,32,0,-4 - SelectionDecorations: Health: HP: 40000 Armor: @@ -607,10 +601,13 @@ WithBuildingBib: HasMinibib: true Turreted: - TurnSpeed: 15 - InitialFacing: 224 - -WithSpriteBody: - WithEmbeddedTurretSpriteBody: + TurnSpeed: 60 + InitialFacing: 832 + RealignDelay: -1 + RequiresCondition: !build-incomplete + WithSpriteTurret: + RequiresCondition: !build-incomplete + Recoils: false Armament: Weapon: ZSU-23 LocalOffset: 520,100,450, 520,-150,450 @@ -623,8 +620,8 @@ RangeCircleType: aa Power: Amount: -50 - BodyOrientation: - UseClassicFacingFudge: True + -BodyOrientation: + ClassicFacingBodyOrientation: DOME: Inherits: ^Building @@ -649,7 +646,7 @@ Dimensions: 2,3 LocalCenterOffset: 0,-512,0 Targetable: - TargetTypes: Ground, Structure, C4, DetonateAttack, SpyInfiltrate + TargetTypes: GroundActor, Structure, C4, DetonateAttack, SpyInfiltrate Health: HP: 100000 Armor: @@ -679,6 +676,7 @@ PBOX: Inherits: ^Defense Inherits@AUTOTARGET: ^AutoTargetAll + Inherits@CARGOPIPS: ^CargoPips Tooltip: Name: Pillbox Building: @@ -704,14 +702,18 @@ WithBuildingBib: HasMinibib: true Turreted: - TurnSpeed: 255 + TurnSpeed: 512 -QuantizeFacingsFromSequence: BodyOrientation: QuantizedFacings: 8 + EngineerRepairable: + RequiresCondition: damaged + GrantConditionOnDamageState@DAMAGED: + Condition: damaged + ValidDamageStates: Light, Medium, Heavy, Critical Cargo: Types: Infantry MaxWeight: 1 - PipCount: 1 InitialUnits: e1 -SpawnActorsOnSell: AttackGarrisoned: @@ -730,6 +732,7 @@ HBOX: Inherits: ^Defense Inherits@AUTOTARGET: ^AutoTargetAll + Inherits@CARGOPIPS: ^CargoPips Tooltip: Name: Camo Pillbox Building: @@ -761,14 +764,18 @@ Condition: cloak-force-disabled ValidDamageStates: Critical Turreted: - TurnSpeed: 255 + TurnSpeed: 512 -QuantizeFacingsFromSequence: BodyOrientation: QuantizedFacings: 8 + EngineerRepairable: + RequiresCondition: damaged + GrantConditionOnDamageState@DAMAGED: + Condition: damaged + ValidDamageStates: Light, Medium, Heavy, Critical Cargo: Types: Infantry MaxWeight: 1 - PipCount: 1 InitialUnits: e1 -SpawnActorsOnSell: DetectCloaked: @@ -804,17 +811,22 @@ Type: Heavy RevealsShroud: MinRange: 5c0 - Range: 7c0 + Range: 6c512 RevealGeneratedShroud: False RevealsShroud@GAPGEN: Range: 5c0 WithBuildingBib: HasMinibib: true Turreted: - TurnSpeed: 12 - InitialFacing: 56 - -WithSpriteBody: - WithEmbeddedTurretSpriteBody: + TurnSpeed: 48 + InitialFacing: 192 + RealignDelay: -1 + RequiresCondition: !build-incomplete + WithSpriteTurret: + RequiresCondition: !build-incomplete + Recoils: false + WithTurretAttackAnimation: + Sequence: recoil Armament: Weapon: TurretGun LocalOffset: 512,0,112 @@ -826,8 +838,8 @@ Amount: -40 DetectCloaked: Range: 6c0 - BodyOrientation: - UseClassicFacingFudge: True + -BodyOrientation: + ClassicFacingBodyOrientation: FTUR: Inherits: ^Defense @@ -855,7 +867,7 @@ WithBuildingBib: HasMinibib: true Turreted: - TurnSpeed: 255 + TurnSpeed: 512 Offset: 0,0,112 Armament: Weapon: FireballLauncher @@ -910,10 +922,13 @@ WithBuildingBib: HasMinibib: true Turreted: - TurnSpeed: 30 + TurnSpeed: 120 InitialFacing: 0 - -WithSpriteBody: - WithEmbeddedTurretSpriteBody: + RealignDelay: -1 + RequiresCondition: !build-incomplete + WithSpriteTurret: + RequiresCondition: !build-incomplete + Recoils: false Armament: Weapon: Nike LocalOffset: 0,0,320 @@ -926,8 +941,8 @@ RangeCircleType: aa Power: Amount: -40 - BodyOrientation: - UseClassicFacingFudge: True + -BodyOrientation: + ClassicFacingBodyOrientation: ATEK: Inherits: ^ScienceBuilding @@ -970,9 +985,13 @@ LongDesc: Reveals map terrain and provides tactical\ninformation. Requires power and active radar. RevealDelay: 375 LaunchSpeechNotification: SatelliteLaunched - DisplayTimerStances: Ally, Neutral, Enemy + DisplayTimerRelationships: Ally, Neutral, Enemy SupportPowerPaletteOrder: 90 SupportPowerChargeBar: + InfiltrateForSupportPowerReset: + Types: SpyInfiltrate + Targetable: + TargetTypes: GroundActor, C4, DetonateAttack, Structure, SpyInfiltrate Power: Amount: -200 ProvidesPrerequisite@buildingname: @@ -980,6 +999,7 @@ WEAP: Inherits: ^Building Inherits@shape: ^3x2Shape + Inherits@PRIMARY: ^PrimaryBuilding Selectable: Bounds: 72,48 Buildable: @@ -1070,26 +1090,16 @@ ProvidesPrerequisite@ukrainianstructure: RequiresPrerequisites: structures.ukraine Prerequisite: vehicles.ukraine - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Vehicle Power: Amount: -30 ProvidesPrerequisite@buildingname: Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure, SpyInfiltrate + TargetTypes: GroundActor, C4, DetonateAttack, Structure, SpyInfiltrate InfiltrateForSupportPower: Proxy: vehicles.upgraded Types: SpyInfiltrate - WithDecoration@primary: - RequiresSelection: true - Image: pips - Sequence: tag-primary - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary -ActorPreviewPlaceBuildingPreview: SequencePlaceBuildingPreview: Sequence: place @@ -1152,14 +1162,14 @@ Tooltip: Name: Construction Yard SpawnActorsOnSell: - ActorTypes: e1,e1,e1,tecn,tecn,e6 + ActorTypes: e1,e1,e1,tecn,tecn2,e6 BaseBuilding: Transforms: RequiresCondition: factundeploy PauseOnCondition: chrono-vortex || being-captured || being-demolished || build-incomplete IntoActor: mcv Offset: 1,1 - Facing: 96 + Facing: 384 TransformsIntoMobile: RequiresCondition: factundeploy Locomotor: heavywheeled @@ -1226,9 +1236,8 @@ Selectable: Bounds: 72,50,0,4 DecorationBounds: 72,70,0,-2 - SelectionDecorations: Targetable: - TargetTypes: Ground, Structure, C4, DetonateAttack, ThiefInfiltrate, SpyInfiltrate + TargetTypes: GroundActor, Structure, C4, DetonateAttack, ThiefInfiltrate, SpyInfiltrate Health: HP: 90000 Armor: @@ -1240,22 +1249,20 @@ RevealsShroud@GAPGEN: Range: 4c0 Refinery: - DockAngle: 64 + DockAngle: 256 DockOffset: 1,2 StoresResources: - PipCount: 17 Capacity: 2000 - DrawLineToTarget: CustomSellValue: Value: 300 FreeActor: Actor: HARV SpawnOffset: 1,2 - Facing: 64 + Facing: 256 InfiltrateForCash: Percentage: 50 Types: SpyInfiltrate, ThiefInfiltrate - Notification: CreditsStolen + InfiltratedNotification: CreditsStolen WithBuildingBib: WithIdleOverlay@TOP: RequiresCondition: !build-incomplete @@ -1284,6 +1291,12 @@ SequencePlaceBuildingPreview: Sequence: idle SequencePalette: placebuilding + WithResourceStoragePipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + PipCount: 17 + FullSequence: pip-yellow SILO: Inherits: ^Building @@ -1297,7 +1310,7 @@ Valued: Cost: 150 Targetable: - TargetTypes: Ground, Structure, C4, DetonateAttack, ThiefInfiltrate + TargetTypes: GroundActor, Structure, C4, DetonateAttack, ThiefInfiltrate Tooltip: Name: Silo -GivesBuildableArea: @@ -1311,14 +1324,13 @@ InfiltrateForCash: Percentage: 50 Types: ThiefInfiltrate - Notification: CreditsStolen + InfiltratedNotification: CreditsStolen WithBuildingBib: HasMinibib: true -WithSpriteBody: WithResourceLevelSpriteBody: Sequence: stages StoresResources: - PipCount: 5 Capacity: 3000 -SpawnActorsOnSell: Power: @@ -1326,10 +1338,17 @@ Explodes: Weapon: SmallBuildingExplode EmptyWeapon: SmallBuildingExplode + WithResourceStoragePipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + PipCount: 5 + FullSequence: pip-yellow HPAD: Inherits: ^Building Inherits@shape: ^2x2Shape + Inherits@PRIMARY: ^PrimaryBuilding Selectable: Bounds: 48,48 HitShape: @@ -1365,16 +1384,13 @@ RequiresCondition: !being-captured SpawnOffset: 0,-256,0 ExitCell: 0,0 - Facing: 224 + Facing: 896 RallyPoint: Production: Produces: Aircraft, Helicopter Reservable: ProductionBar: ProductionType: Aircraft - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected Power: Amount: -10 ProvidesPrerequisite@allies: @@ -1409,21 +1425,15 @@ Prerequisite: aircraft.germany ProvidesPrerequisite@buildingname: Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure, SpyInfiltrate + TargetTypes: GroundActor, C4, DetonateAttack, Structure, SpyInfiltrate InfiltrateForSupportPower: Proxy: aircraft.upgraded Types: SpyInfiltrate - WithDecoration@primary: - RequiresSelection: true - Image: pips - Sequence: tag-primary - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary AFLD: Inherits: ^Building Inherits@shape: ^3x2Shape + Inherits@PRIMARY: ^PrimaryBuilding HitShape: UseTargetableCellsOffsets: false TargetableOffsets: 0,0,0, 420,0,0, 420,-1024,0, 420,1024,0, -777,0,0, -777,-1024,0, -777,1024,0 @@ -1455,7 +1465,7 @@ Exit@1: RequiresCondition: !being-captured ExitCell: 1,1 - Facing: 192 + Facing: 768 RallyPoint: Production: Produces: Aircraft, Plane @@ -1551,25 +1561,15 @@ ProductionBar: ProductionType: Aircraft SupportPowerChargeBar: - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected Power: Amount: -20 ProvidesPrerequisite@buildingname: Prerequisite: afld Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure, SpyInfiltrate + TargetTypes: GroundActor, C4, DetonateAttack, Structure, SpyInfiltrate InfiltrateForSupportPower: Proxy: aircraft.upgraded Types: SpyInfiltrate - WithDecoration@primary: - RequiresSelection: true - Image: pips - Sequence: tag-primary - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary WithResupplyAnimation: RequiresCondition: !build-incomplete @@ -1615,7 +1615,7 @@ Power: Amount: 100 Targetable: - TargetTypes: Ground, Structure, C4, DetonateAttack, SpyInfiltrate + TargetTypes: GroundActor, Structure, C4, DetonateAttack, SpyInfiltrate ScalePowerWithHealth: WithDeathAnimation: DeathSequence: dead @@ -1645,7 +1645,6 @@ Selectable: Bounds: 72,48 DecorationBounds: 72,68,0,-10 - SelectionDecorations: Health: HP: 70000 Armor: @@ -1656,7 +1655,7 @@ Power: Amount: 200 Targetable: - TargetTypes: Ground, Structure, C4, DetonateAttack, SpyInfiltrate + TargetTypes: GroundActor, Structure, C4, DetonateAttack, SpyInfiltrate ScalePowerWithHealth: WithDeathAnimation: DeathSequence: dead @@ -1702,6 +1701,7 @@ BARR: Inherits: ^Building Inherits@shape: ^2x2Shape + Inherits@PRIMARY: ^PrimaryBuilding Selectable: Bounds: 48,48 HitShape: @@ -1746,9 +1746,6 @@ Produces: Infantry, Soldier GrantExternalConditionToProduced: Condition: produced - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Infantry ProvidesPrerequisite: @@ -1784,17 +1781,11 @@ Proxy: barracks.upgraded Types: SpyInfiltrate Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure, SpyInfiltrate - WithDecoration@primary: - RequiresSelection: true - Image: pips - Sequence: tag-primary - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary + TargetTypes: GroundActor, C4, DetonateAttack, Structure, SpyInfiltrate KENN: Inherits: ^Building + Inherits@PRIMARY: ^PrimaryBuilding Selectable: Bounds: 24,24 Buildable: @@ -1861,26 +1852,17 @@ ProductionTypes: Dog, Infantry Production: Produces: Infantry, Dog - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Infantry -SpawnActorsOnSell: Power: Amount: -10 ProvidesPrerequisite@buildingname: - WithDecoration@primary: - RequiresSelection: true - Image: pips - Sequence: tag-primary - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary TENT: Inherits: ^Building Inherits@shape: ^2x2Shape + Inherits@PRIMARY: ^PrimaryBuilding Selectable: Bounds: 48,48 HitShape: @@ -1925,9 +1907,6 @@ Produces: Infantry, Soldier GrantExternalConditionToProduced: Condition: produced - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Infantry ProvidesPrerequisite@barracks: @@ -1969,14 +1948,7 @@ Proxy: barracks.upgraded Types: SpyInfiltrate Targetable: - TargetTypes: Ground, C4, DetonateAttack, Structure, SpyInfiltrate - WithDecoration@primary: - RequiresSelection: true - Image: pips - Sequence: tag-primary - ReferencePoint: Top - ZOffset: 256 - RequiresCondition: primary + TargetTypes: GroundActor, C4, DetonateAttack, Structure, SpyInfiltrate FIX: Inherits: ^Building @@ -1995,7 +1967,6 @@ Selectable: Bounds: 68,34,0,3 DecorationBounds: 72,48 - SelectionDecorations: Health: HP: 80000 Armor: diff -Nru openra-20200503/mods/ra/rules/vehicles.yaml openra-20210321/mods/ra/rules/vehicles.yaml --- openra-20200503/mods/ra/rules/vehicles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/vehicles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -40,7 +40,6 @@ RequiresCondition: reloading Sequence: empty-idle Name: reloading - SelectionDecorations: Explodes: Weapon: V2Explode ProducibleWithLevel: @@ -65,7 +64,7 @@ UpdatesPlayerStatistics: AddToArmyValue: true Health: - HP: 22000 + HP: 26000 Armor: Type: Heavy Mobile: @@ -77,7 +76,7 @@ RevealsShroud@GAPGEN: Range: 4c0 Turreted: - TurnSpeed: 7 + TurnSpeed: 28 Armament: Weapon: 25mm Recoil: 85 @@ -87,8 +86,6 @@ AttackTurreted: WithMuzzleOverlay: WithSpriteTurret: - SpawnActorOnDeath: - Actor: 1TNK.Husk ProducibleWithLevel: Prerequisites: vehicles.upgraded @@ -109,7 +106,7 @@ UpdatesPlayerStatistics: AddToArmyValue: true Health: - HP: 45000 + HP: 46000 Armor: Type: Heavy Mobile: @@ -121,7 +118,7 @@ RevealsShroud@GAPGEN: Range: 4c0 Turreted: - TurnSpeed: 5 + TurnSpeed: 20 Armament: Weapon: 90mm Recoil: 128 @@ -133,7 +130,6 @@ WithSpriteTurret: SpawnActorOnDeath: Actor: 2TNK.Husk - SelectionDecorations: ProducibleWithLevel: Prerequisites: vehicles.upgraded Selectable: @@ -168,7 +164,7 @@ RevealsShroud@GAPGEN: Range: 4c0 Turreted: - TurnSpeed: 5 + TurnSpeed: 20 Armament: Weapon: 105mm Recoil: 128 @@ -180,7 +176,6 @@ WithSpriteTurret: SpawnActorOnDeath: Actor: 3TNK.Husk - SelectionDecorations: ProducibleWithLevel: Prerequisites: vehicles.upgraded Selectable: @@ -216,7 +211,7 @@ RevealsShroud@GAPGEN: Range: 4c0 Turreted: - TurnSpeed: 2 + TurnSpeed: 8 Armament@PRIMARY: Weapon: 120mm LocalOffset: 900,180,340, 900,-180,340 @@ -235,12 +230,11 @@ WithSpriteTurret: SpawnActorOnDeath: Actor: 4TNK.Husk - SelfHealing: + ChangesHealth: Step: 100 Delay: 3 - HealIfBelow: 50 + StartIfBelow: 50 DamageCooldown: 150 - SelectionDecorations: ProducibleWithLevel: Prerequisites: vehicles.upgraded Selectable: @@ -266,7 +260,7 @@ Armor: Type: Light Mobile: - TurnSpeed: 2 + TurnSpeed: 8 Speed: 85 Locomotor: lighttracked RevealsShroud: @@ -305,13 +299,13 @@ GenericName: Harvester Selectable: DecorationBounds: 42,42 - SelectionDecorations: Harvester: Capacity: 20 Resources: Ore,Gems BaleUnloadDelay: 1 SearchFromProcRadius: 15 SearchFromHarvesterRadius: 8 + HarvestFacings: 8 EmptyCondition: no-ore Health: HP: 60000 @@ -331,10 +325,10 @@ HarvesterHuskModifier: FullHuskActor: HARV.FullHusk FullnessThreshold: 50 - SelfHealing: + ChangesHealth: Step: 100 Delay: 25 - HealIfBelow: 50 + StartIfBelow: 50 DamageCooldown: 500 Explodes: RequiresCondition: !no-ore @@ -342,6 +336,14 @@ WithHarvesterSpriteBody: ImageByFullness: harvempty, harvhalf, harv -WithFacingSpriteBody: + WithHarvesterPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true + PipCount: 7 + ResourceSequences: + Ore: pip-yellow + Gems: pip-red MCV: Inherits: ^Vehicle @@ -358,7 +360,6 @@ Name: Mobile Construction Vehicle Selectable: DecorationBounds: 42,42 - SelectionDecorations: Health: HP: 60000 Armor: @@ -371,7 +372,7 @@ Transforms: IntoActor: fact Offset: -1,-1 - Facing: 96 + Facing: 384 TransformSounds: placbldg.aud, build5.aud NoTransformNotification: BuildingCannotPlaceAudio MustBeDestroyed: @@ -386,6 +387,7 @@ Inherits: ^Vehicle Inherits@GAINSEXPERIENCE: ^GainsExperience Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove + Inherits@CARGOPIPS: ^CargoPips Buildable: Queue: Vehicle BuildPaletteOrder: 130 @@ -402,7 +404,7 @@ Armor: Type: Light Mobile: - TurnSpeed: 10 + TurnSpeed: 40 Speed: 170 PauseOnCondition: notmobile || being-captured RevealsShroud: @@ -412,7 +414,7 @@ RevealsShroud@GAPGEN: Range: 4c0 Turreted: - TurnSpeed: 10 + TurnSpeed: 40 Offset: 0,0,128 Armament: Weapon: M60mg @@ -424,7 +426,6 @@ Cargo: Types: Infantry MaxWeight: 1 - PipCount: 1 LoadingCondition: notmobile ProducibleWithLevel: Prerequisites: vehicles.upgraded @@ -433,6 +434,7 @@ Inherits: ^TrackedVehicle Inherits@GAINSEXPERIENCE: ^GainsExperience Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove + Inherits@CARGOPIPS: ^CargoPips Buildable: Queue: Vehicle BuildPaletteOrder: 120 @@ -466,7 +468,6 @@ Cargo: Types: Infantry MaxWeight: 5 - PipCount: 5 LoadingCondition: notmobile ProducibleWithLevel: Prerequisites: vehicles.upgraded @@ -500,6 +501,7 @@ Minelayer: Mine: MINV TileUnknownName: build-valid + TerrainTypes: Clear, Road, Beach, Ore, Gems, Rough, Bridge MineImmune: AmmoPool: Ammo: 5 @@ -515,7 +517,11 @@ Rearmable: RearmActors: fix Targetable: - TargetTypes: Ground, Vehicle, Mine + TargetTypes: GroundActor, Vehicle, Mine + WithAmmoPipsDecoration: + Position: BottomLeft + Margin: 4, 3 + RequiresSelection: true TRUK: Inherits: ^Vehicle @@ -595,7 +601,7 @@ Armor: Type: Heavy Mobile: - Speed: 85 + Speed: 78 RevealsShroud: Range: 7c0 WithIdleOverlay@SPINNER: @@ -603,7 +609,7 @@ Offset: -256,0,256 ProximityExternalCondition@JAMMER: Range: 18c0 - ValidStances: Enemy, Neutral + ValidRelationships: Enemy, Neutral Condition: jammed WithRangeCircle@JAMMER: Type: jammer @@ -611,7 +617,7 @@ Color: 0000FF80 JamsMissiles: Range: 5c0 - DeflectionStances: Neutral, Enemy + DeflectionRelationships: Neutral, Enemy RenderJammerCircle: TTNK: @@ -649,7 +655,6 @@ Turreted: WithIdleOverlay@SPINNER: Sequence: spinner - SelectionDecorations: ProducibleWithLevel: Prerequisites: vehicles.upgraded Selectable: @@ -675,7 +680,7 @@ Armor: Type: Light Mobile: - TurnSpeed: 10 + TurnSpeed: 40 Speed: 118 RevealsShroud: MinRange: 4c0 @@ -684,7 +689,7 @@ RevealsShroud@GAPGEN: Range: 4c0 Turreted: - TurnSpeed: 10 + TurnSpeed: 40 Offset: -298,0,298 Armament@AA: Weapon: FLAK-23-AA @@ -699,7 +704,6 @@ AttackTurreted: WithMuzzleOverlay: WithSpriteTurret: - SelectionDecorations: ProducibleWithLevel: Prerequisites: vehicles.upgraded Selectable: @@ -731,7 +735,7 @@ EmptyWeapon: MiniNuke DamageSource: Killer AttackFrontal: - FacingTolerance: 128 + FacingTolerance: 512 Armament@PRIMARY: Weapon: DemoTruckTargeting GrantConditionOnAttack: @@ -760,7 +764,6 @@ GenericName: Tank UpdatesPlayerStatistics: AddToArmyValue: true - SelectionDecorations: Health: HP: 40000 Armor: @@ -820,14 +823,13 @@ RevealGeneratedShroud: False RevealsShroud@GAPGEN: Range: 4c0 - SelectionDecorations: MadTank: DeployedCondition: deployed WithRangeCircle: Color: FFFF0080 Range: 7c0 Targetable: - TargetTypes: Ground, MADTank, Vehicle + TargetTypes: GroundActor, MADTank, Vehicle Selectable: DecorationBounds: 44,38,0,-4 @@ -835,6 +837,7 @@ Inherits: ^Vehicle Inherits@GAINSEXPERIENCE: ^GainsExperience Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove + Inherits@CARGOPIPS: ^CargoPips Buildable: Queue: Vehicle BuildPaletteOrder: 330 @@ -867,13 +870,12 @@ Weapon: APTusk.stnk LocalOffset: 192,0,176 Turreted: - TurnSpeed: 5 + TurnSpeed: 20 AttackTurreted: WithSpriteTurret: Cargo: Types: Infantry MaxWeight: 5 - PipCount: 4 LoadingCondition: notmobile Cloak: InitialDelay: 125 @@ -882,6 +884,7 @@ UncloakSound: appear1.aud IsPlayerPalette: true PauseOnCondition: cloak-force-disabled + UncloakOn: Attack, Heal, Dock GrantConditionOnDamageState@UNCLOAK: Condition: cloak-force-disabled ValidDamageStates: Critical diff -Nru openra-20200503/mods/ra/rules/world.yaml openra-20210321/mods/ra/rules/world.yaml --- openra-20200503/mods/ra/rules/world.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/rules/world.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -151,7 +151,6 @@ ResourceType@ore: Type: Ore Name: Valuable Minerals - PipColor: Yellow ResourceType: 1 TerrainType: Ore Palette: player @@ -163,7 +162,6 @@ ResourceType@gem: Type: Gems Name: Valuable Minerals - PipColor: Red ResourceType: 2 TerrainType: Gems Palette: player @@ -172,6 +170,8 @@ ValuePerUnit: 50 AllowedTerrainTypes: Clear,Road AllowUnderActors: true + ResourceRenderer: + RenderTypes: Ore, Gems World: Inherits: ^BaseWorld @@ -200,13 +200,16 @@ SmudgeLayer@SCORCH: Type: Scorch Sequence: scorches - SmokePercentage: 50 + SmokeChance: 50 + SmokeImage: smoke_m + SmokeSequences: idle SmudgeLayer@CRATER: Type: Crater Sequence: craters + SmokeChance: 25 + SmokeImage: smoke_m + SmokeSequences: idle ResourceLayer: - ResourceRenderer: - RenderTypes: Ore, Gems ResourceClaimLayer: WarheadDebugOverlay: SpawnMapActors: diff -Nru openra-20200503/mods/ra/sequences/aircraft.yaml openra-20210321/mods/ra/sequences/aircraft.yaml --- openra-20200503/mods/ra/sequences/aircraft.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/sequences/aircraft.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ heli: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True rotor: lrotor Length: 4 slow-rotor: lrotor @@ -25,7 +25,7 @@ hind: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True rotor: lrotorlg Length: 4 slow-rotor: lrotorlg @@ -39,7 +39,7 @@ tran: idle: tran2 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True rotor: lrotor Length: 4 rotor2: rrotor @@ -74,7 +74,7 @@ mh60: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True rotor: yrotorlg Length: 4 slow-rotor: yrotorlg diff -Nru openra-20200503/mods/ra/sequences/infantry.yaml openra-20210321/mods/ra/sequences/infantry.yaml --- openra-20200503/mods/ra/sequences/infantry.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/sequences/infantry.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -51,21 +51,27 @@ die1: Start: 288 Length: 8 + Tick: 80 die2: Start: 296 Length: 8 + Tick: 80 die3: Start: 304 Length: 8 + Tick: 80 die4: Start: 312 Length: 12 + Tick: 80 die5: Start: 324 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -79,8 +85,33 @@ DESERT: TEMPERAT INTERIOR: TEMPERAT garrison-muzzle: minigun - Length: 6 + Length: 12 Facings: 8 + Combine: + minigun: + Length: 12 + Frames: 0,1,2,3,4,5,0,1,2,3,4,5 + minigun: + Length: 12 + Frames: 6,7,8,9,10,11,6,7,8,9,10,11 + minigun: + Length: 12 + Frames: 12,13,14,15,16,17,12,13,14,15,16,17 + minigun: + Length: 12 + Frames: 18,19,20,21,22,23,18,19,20,21,22,23 + minigun: + Length: 12 + Frames: 24,25,26,27,28,29,24,25,26,27,28,29 + minigun: + Length: 12 + Frames: 30,31,32,33,34,35,30,31,32,33,34,35 + minigun: + Length: 12 + Frames: 36,37,38,39,40,41,36,37,38,39,40,41 + minigun: + Length: 12 + Frames: 42,43,44,45,46,47,42,43,44,45,46,47 icon: e1icon sniper: @@ -134,21 +165,27 @@ die1: Start: 416 Length: 8 + Tick: 80 die2: Start: 424 Length: 8 + Tick: 80 die3: Start: 432 Length: 8 + Tick: 80 die4: Start: 440 Length: 12 + Tick: 80 die5: Start: 452 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -195,21 +232,27 @@ die1: Start: 304 Length: 8 + Tick: 80 die2: Start: 312 Length: 8 + Tick: 80 die3: Start: 320 Length: 8 + Tick: 80 die4: Start: 328 Length: 12 + Tick: 80 die5: Start: 340 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -265,21 +308,27 @@ die1: Start: 146 Length: 8 + Tick: 80 die2: Start: 154 Length: 8 + Tick: 80 die3: Start: 162 Length: 8 + Tick: 80 die4: Start: 170 Length: 12 + Tick: 80 die5: Start: 182 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -329,22 +378,28 @@ Tick: 120 die1: Start: 193 - Length: 7 + Length: 8 + Tick: 80 die2: Start: 201 Length: 8 + Tick: 80 die3: Start: 209 Length: 8 + Tick: 80 die4: Start: 217 Length: 12 + Tick: 80 die5: Start: 229 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -390,22 +445,28 @@ Tick: 120 die1: Start: 193 - Length: 7 + Length: 8 + Tick: 80 die2: Start: 201 Length: 8 + Tick: 80 die3: Start: 209 Length: 8 + Tick: 80 die4: Start: 217 Length: 12 + Tick: 80 die5: Start: 229 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -457,21 +518,27 @@ die1: Start: 416 Length: 8 + Tick: 80 die2: Start: 424 Length: 8 + Tick: 80 die3: Start: 432 Length: 8 + Tick: 80 die4: Start: 440 Length: 12 + Tick: 80 die5: Start: 452 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -532,20 +599,26 @@ die1: Start: 236 Length: 6 + Tick: 80 die2: Start: 242 Length: 9 + Tick: 80 die3: Start: 236 Length: 6 + Tick: 80 die4: Start: 242 Length: 9 + Tick: 80 die5: Start: 251 Length: 14 + Tick: 80 die6: electdog Length: * + Tick: 80 die-crushed: corpse1 Length: 6 Tick: 1600 @@ -585,21 +658,27 @@ die1: Start: 288 Length: 8 + Tick: 80 die2: Start: 296 Length: 8 + Tick: 80 die3: Start: 304 Length: 8 + Tick: 80 die4: Start: 312 Length: 12 + Tick: 80 die5: Start: 324 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -646,21 +725,27 @@ die1: Start: 139 Length: 8 + Tick: 80 die2: Start: 147 Length: 8 + Tick: 80 die3: Start: 155 Length: 8 + Tick: 80 die4: Start: 163 Length: 12 + Tick: 80 die5: Start: 175 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -692,9 +777,49 @@ Length: 6 Facings: 8 Tick: 80 - shoot: - Start: 56 - Length: 7 + shoot-left: + Combine: + e7: + Length: 8 + Frames: 58, 56, 64, 63, 71, 70, 79, 77 + e7: + Length: 2 + Frames: 85, 84 + Offset: 1, 0 + e7: + Length: 2 + Frames: 92, 91 + e7: + Length: 2 + Frames: 99, 98 + Offset: 1, -2 + e7: + Length: 2 + Frames: 107, 105 + Offset: 0, -2 + Length: 2 + Facings: 8 + shoot-right: + Combine: + e7: + Length: 8 + Frames: 57, 56, 65, 63, 72, 70, 78, 77 + e7: + Length: 2 + Frames: 86, 84 + Offset: 1, 0 + e7: + Length: 2 + Frames: 93, 91 + e7: + Length: 2 + Frames: 100, 98 + Offset: 1, -2 + e7: + Length: 2 + Frames: 106, 105 + Offset: 0, -2 + Length: 2 Facings: 8 idle1: Start: 233 @@ -707,21 +832,27 @@ die1: Start: 262 Length: 8 + Tick: 80 die2: Start: 270 Length: 8 + Tick: 80 die3: Start: 278 Length: 8 + Tick: 80 die4: Start: 286 Length: 12 + Tick: 80 die5: Start: 298 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -743,9 +874,13 @@ Length: 4 Facings: 8 Tick: 80 - prone-shoot: - Start: 176 - Length: 7 + prone-shoot-left: + Frames: 179, 177, 185, 184, 192, 191, 200, 198, 206, 205, 213, 212, 220, 219, 228, 226 + Length: 2 + Facings: 8 + prone-shoot-right: + Frames: 178, 177, 186, 184, 193, 191, 199, 198, 207, 205, 214, 212, 221, 219, 227, 226 + Length: 2 Facings: 8 garrison-muzzle: minigun Length: 3 @@ -781,21 +916,27 @@ die1: Start: 416 Length: 8 + Tick: 80 die2: Start: 424 Length: 8 + Tick: 80 die3: Start: 432 Length: 8 + Tick: 80 die4: Start: 440 Length: 12 + Tick: 80 die5: Start: 452 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -863,21 +1004,27 @@ die1: Start: 210 Length: 8 + Tick: 80 die2: Start: 218 Length: 8 + Tick: 80 die3: Start: 226 Length: 8 + Tick: 80 die4: Start: 234 Length: 12 + Tick: 80 die5: Start: 246 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -944,21 +1091,27 @@ die1: Start: 416 Length: 8 + Tick: 80 die2: Start: 424 Length: 8 + Tick: 80 die3: Start: 432 Length: 8 + Tick: 80 die4: Start: 440 Length: 12 + Tick: 80 die5: Start: 452 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -989,21 +1142,27 @@ die1: Start: 152 Length: 8 + Tick: 80 die2: Start: 160 Length: 8 + Tick: 80 die3: Start: 168 Length: 12 + Tick: 80 die4: Start: 168 Length: 12 + Tick: 80 die5: Start: 180 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -1038,21 +1197,27 @@ die1: Start: 152 Length: 8 + Tick: 80 die2: Start: 160 Length: 8 + Tick: 80 die3: Start: 168 Length: 12 + Tick: 80 die4: Start: 168 Length: 12 + Tick: 80 die5: Start: 180 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -1071,7 +1236,7 @@ Facings: 8 Tick: 80 -c3: +c11: stand: Facings: 8 panic-stand: @@ -1087,21 +1252,27 @@ die1: Start: 152 Length: 8 + Tick: 80 die2: Start: 160 Length: 8 + Tick: 80 die3: Start: 168 Length: 12 + Tick: 80 die4: Start: 168 Length: 12 + Tick: 80 die5: Start: 180 Length: 18 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -1137,21 +1308,27 @@ die1: Start: 120 Length: 8 + Tick: 80 die2: Start: 128 Length: 8 + Tick: 80 die3: Start: 136 Length: 12 + Tick: 80 die4: Start: 136 Length: 12 + Tick: 80 die5: Start: 148 Length: 17 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -1182,21 +1359,27 @@ die1: Start: 329 Length: 8 + Tick: 80 die2: Start: 337 Length: 8 + Tick: 80 die3: Start: 345 Length: 12 + Tick: 80 die4: Start: 345 Length: 12 + Tick: 80 die5: Start: 357 Length: 17 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -1227,21 +1410,27 @@ die1: Start: 120 Length: 8 + Tick: 80 die2: Start: 128 Length: 8 + Tick: 80 die3: Start: 136 Length: 12 + Tick: 80 die4: Start: 136 Length: 12 + Tick: 80 die5: Start: 148 Length: 17 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT @@ -1277,21 +1466,27 @@ die1: Start: 106 Length: 8 + Tick: 80 die2: Start: 106 Length: 8 + Tick: 80 die3: Start: 106 Length: 8 + Tick: 80 die4: Start: 106 Length: 8 + Tick: 80 die5: Start: 114 Length: 19 + Tick: 80 die6: electro Frames: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 Length: * + Tick: 80 UseTilesetExtension: true TilesetOverrides: DESERT: TEMPERAT diff -Nru openra-20200503/mods/ra/sequences/misc.yaml openra-20210321/mods/ra/sequences/misc.yaml --- openra-20200503/mods/ra/sequences/misc.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/sequences/misc.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -44,7 +44,7 @@ large_explosion: frag1 Offset: -2,0 small_napalm: napalm1 - offseted_napalm: napalm1 # Used for E4 Explosion + offset_napalm: napalm1 # Used for E4 Explosion Offset: 0, -6 large_napalm: napalm3 corpse: corpse1 @@ -112,6 +112,7 @@ tag-primary: Start: 2 Offset: 0, 2 + tag-spy: tag-spy pip-empty: pips2 pip-green: pips2 Start: 1 diff -Nru openra-20200503/mods/ra/sequences/structures.yaml openra-20210321/mods/ra/sequences/structures.yaml --- openra-20200503/mods/ra/sequences/structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/sequences/structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -378,23 +378,24 @@ fake-icon: fixficon gun: - idle: + idle: gunmake # Empty first frame. We need WithSpriteBody for the make anim, and WSB needs at least a placeholder default sequence to work + make: gunmake + Length: * + turret: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True recoil: Start: 32 Facings: 32 - UseClassicFacingFudge: True - make: gunmake - Length: * - damaged-idle: + UseClassicFacings: True + damaged-turret: Start: 64 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True damaged-recoil: Start: 96 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: 5 bib: mbGUN @@ -404,27 +405,28 @@ icon: gunicon agun: - idle: + idle: gunmake # Empty first frame (agunmake has no empty frames). We need WithSpriteBody for the make anim, and WSB needs at least a placeholder default sequence to work + make: agunmake + Length: * + Offset: 0,-13 + turret: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True Offset: 0,-13 recoil: Start: 32 Facings: 32 - UseClassicFacingFudge: True - Offset: 0,-13 - make: agunmake - Length: * + UseClassicFacings: True Offset: 0,-13 - damaged-idle: + damaged-turret: Start: 64 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True Offset: 0,-13 damaged-recoil: Start: 96 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True Offset: 0,-13 muzzle: gunfire2 Start: 1 @@ -435,14 +437,15 @@ icon: agunicon sam: - idle: sam2 + idle: gunmake # Empty first frame (sammake has no empty frames). We need WithSpriteBody for the make anim, and WSB needs at least a placeholder default sequence to work + turret: sam2 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True Offset: -1,-2 - damaged-idle: sam2 + damaged-turret: sam2 Start: 34 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True Offset: -1,-2 make: sammake Length: * diff -Nru openra-20200503/mods/ra/sequences/vehicles.yaml openra-20210321/mods/ra/sequences/vehicles.yaml --- openra-20200503/mods/ra/sequences/vehicles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/sequences/vehicles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,25 +1,25 @@ mcv: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: mcvicon mcvhusk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -1023 truk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: trukicon harv: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True harvest: Start: 32 Length: 8 @@ -42,23 +42,23 @@ hhusk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -1023 hhusk2: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -1023 1tnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: 2 icon: 1tnkicon @@ -66,22 +66,22 @@ 1tnk.destroyed: idle: 1tnk Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: 1tnk Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 2tnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: 5 icon: 2tnkicon @@ -89,22 +89,22 @@ 2tnk.destroyed: idle: 2tnk Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: 2tnk Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 3tnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: 5 icon: 3tnkicon @@ -112,22 +112,22 @@ 3tnk.destroyed: idle: 3tnk Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: 3tnk Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 4tnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: 5 icon: 4tnkicon @@ -135,28 +135,28 @@ 4tnk.destroyed: idle: 4tnk Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 turret: 4tnk Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 v2rl: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True empty-idle: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: v2rlicon arty: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: 5 icon: artyicon @@ -164,11 +164,11 @@ jeep: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: minigun Length: 6 Facings: 8 @@ -177,7 +177,7 @@ apc: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: minigun Length: 6 Facings: 8 @@ -191,13 +191,13 @@ mnly: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: mnlyicon mrj: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True spinner: Start: 32 Length: 32 @@ -206,7 +206,7 @@ mgg: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True spinner: Start: 32 Length: 8 @@ -218,7 +218,7 @@ mgg.destroyed: idle: mgg Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True ZOffset: -512 spinner: mgg Start: 32 @@ -230,7 +230,7 @@ ttnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True spinner: Start: 32 Length: 32 @@ -239,11 +239,11 @@ ftrk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 32 Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: 2 icon: ftrkicon @@ -251,13 +251,13 @@ dtrk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True icon: dtrkicon ctnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True muzzle: gunfire2 Length: 5 icon: ctnkicon @@ -265,7 +265,7 @@ qtnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True piston: Start: 32 Facings: 8 @@ -275,8 +275,9 @@ stnk: idle: Facings: 32 - UseClassicFacingFudge: True + UseClassicFacings: True turret: Start: 38 Facings: 32 + UseClassicFacings: True icon: stnkicon diff -Nru openra-20200503/mods/ra/tilesets/desert.yaml openra-20210321/mods/ra/tilesets/desert.yaml --- openra-20200503/mods/ra/tilesets/desert.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/tilesets/desert.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -14,10 +14,6 @@ TargetTypes: Ground, Bridge AcceptsSmudgeType: Crater, Scorch Color: 606060 - TerrainType@Brush: - Type: Brush - TargetTypes: Ground - Color: 1C2024 TerrainType@Clear: Type: Clear TargetTypes: Ground Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/uibits/glyphs-2x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/uibits/glyphs-2x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/uibits/glyphs-3x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/uibits/glyphs-3x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ra/uibits/glyphs.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ra/uibits/glyphs.png differ diff -Nru openra-20200503/mods/ra/weapons/ballistics.yaml openra-20210321/mods/ra/weapons/ballistics.yaml --- openra-20200503/mods/ra/weapons/ballistics.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/weapons/ballistics.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,6 +2,7 @@ ReloadDelay: 50 Range: 4c768 Report: cannon1.aud + ValidTargets: Ground, Water, GroundActor, WaterActor Projectile: Bullet Speed: 682 Image: 120MM @@ -9,6 +10,7 @@ Warhead@1Dam: SpreadDamage Spread: 128 Damage: 4000 + ValidTargets: GroundActor, WaterActor Versus: None: 30 Wood: 75 @@ -17,16 +19,16 @@ DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath Warhead@2Smu: LeaveSmudge SmudgeType: Crater - InvalidTargets: Vehicle, Structure, Wall, Husk, Trees + ValidTargets: Ground, Infantry Warhead@3Eff: CreateEffect Explosions: small_explosion ImpactSounds: kaboom12.aud - ValidTargets: Ground, Ship, Trees + ValidTargets: Ground, GroundActor, WaterActor, Trees Warhead@4EffWater: CreateEffect Explosions: small_splash ImpactSounds: splash9.aud ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge + InvalidTargets: Bridge 25mm: Inherits: ^Cannon @@ -78,7 +80,7 @@ TurretGun: Inherits: ^Cannon ReloadDelay: 30 - Range: 7c0 + Range: 6c512 Report: turret1.aud Warhead@1Dam: SpreadDamage Damage: 6000 @@ -205,11 +207,15 @@ Versus: Light: 75 DamageTypes: ExplosionDeath - Warhead@4EffWater: CreateEffect - Explosions: large_splash - ImpactSounds: h2obomb2.aud - ValidTargets: Water, Underwater Warhead@3Eff: CreateEffect - Explosions: small_explosion + Explosions: med_explosion ImpactSounds: kaboom15.aud ValidTargets: Submarine + InvalidTargets: Underwater + Warhead@4EffWater: CreateEffect + Explosions: large_splash + ImpactSounds: splash9.aud + ValidTargets: Water, Underwater + Warhead@5EffSubmergedHitSound: CreateEffect + ImpactSounds: h2obomb2.aud + ValidTargets: Underwater diff -Nru openra-20200503/mods/ra/weapons/explosions.yaml openra-20210321/mods/ra/weapons/explosions.yaml --- openra-20200503/mods/ra/weapons/explosions.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/weapons/explosions.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,8 +1,9 @@ ^Explosion: - ValidTargets: Ground, Water, Air + ValidTargets: Ground, Water, Air, GroundActor, WaterActor, AirborneActor Warhead@1Dam: SpreadDamage Spread: 426 Damage: 5000 + ValidTargets: GroundActor, WaterActor Versus: None: 90 Wood: 75 @@ -12,25 +13,25 @@ DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath Warhead@Smu: LeaveSmudge SmudgeType: Crater - InvalidTargets: Structure, Wall, Trees + ValidTargets: Ground, Vehicle, Infantry Warhead@2Eff: CreateEffect Explosions: self_destruct ImpactSounds: kaboom22.aud - ValidTargets: Ground, Air, Ship, Trees + ValidTargets: Ground, Air, GroundActor, AirborneActor, WaterActor, Trees Warhead@3EffWater: CreateEffect Explosions: large_splash ImpactSounds: splash9.aud ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge + InvalidTargets: Bridge CrateNapalm: Inherits: ^Explosion - ValidTargets: Ground, Trees + ValidTargets: Ground, GroundActor, WaterActor, Trees Warhead@1Dam: SpreadDamage Spread: 170 Damage: 6000 Falloff: 1000, 368, 135, 50, 18, 7, 0 - ValidTargets: Ground, Trees + ValidTargets: GroundActor, WaterActor, Trees Versus: Wood: 100 Concrete: 50 @@ -39,7 +40,7 @@ Warhead@2Eff: CreateEffect Explosions: napalm ImpactSounds: firebl3.aud - ValidTargets: Ground, Water, Air, Trees + ValidTargets: Ground, Water, Air, GroundActor, AirborneActor, WaterActor, Trees -Warhead@3EffWater: Warhead@Smu: LeaveSmudge SmudgeType: Scorch @@ -50,7 +51,7 @@ Falloff: 1000, 368, 135, 50, 18, 7, 0 AffectsParent: true Warhead@2Eff: CreateEffect - ValidTargets: Ground, Water, Air + ValidTargets: Ground, Water, Air, GroundActor, AirborneActor, WaterActor, Trees -Warhead@3EffWater: UnitExplode: @@ -72,7 +73,7 @@ Inherits: ^Explosion -Warhead@1Dam: Warhead@2Eff: CreateEffect - Explosions: offseted_napalm + Explosions: offset_napalm ImpactSounds: firebl3.aud UnitExplodeShip: @@ -82,6 +83,10 @@ Explosions: building ImpactSounds: kaboom25.aud ValidTargets: Ground, Water + ImpactActors: false + Warhead@3EffWater: CreateEffect + ValidTargets: Water + ImpactActors: false UnitExplodeSubmarine: Inherits: ^Explosion @@ -89,7 +94,9 @@ Warhead@2Eff: CreateEffect Explosions: large_splash ImpactSounds: splash9.aud - ValidTargets: Ground, Water + ValidTargets: Water + ImpactActors: false + -Warhead@3EffWater: UnitExplodeSmall: Inherits: ^Explosion @@ -112,11 +119,13 @@ -Report: BuildingExplode: + ValidTargets: Ground, Water, GroundActor, WaterActor Warhead@2Eff: CreateEffect Explosions: building, building_napalm, large_explosion, self_destruct, large_napalm Warhead@Smu: LeaveSmudge SmudgeType: Crater - InvalidTargets: Wall, Trees + ValidTargets: GroundActor + InvalidTargets: Wall SmallBuildingExplode: Inherits: BuildingExplode @@ -124,7 +133,9 @@ Explosions: building, building_napalm, large_explosion, self_destruct CivPanicExplosion: + ValidTargets: Ground, GroundActor Warhead@1Dam: SpreadDamage # Used to panic civilians which are emitted from a killed CivBuilding + ValidTargets: Infantry Falloff: 100, 100 Range: 0, 128 Damage: 1 @@ -135,7 +146,7 @@ Warhead@1Dam: SpreadDamage Falloff: 1000, 368, 135, 50, 18, 7, 0 Delay: 5 - ValidTargets: Ground, Trees + ValidTargets: GroundActor, Trees Versus: None: 120 Wood: 100 @@ -153,18 +164,22 @@ Delay: 5 ATMine: + ValidTargets: Ground, Water, GroundActor, WaterActor Warhead@1Dam: SpreadDamage Spread: 256 Damage: 40000 AffectsParent: true + ValidTargets: GroundActor, WaterActor InvalidTargets: Mine DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath Warhead@2Eff: CreateEffect Explosions: large_explosion ImpactSounds: mineblo1.aud + ImpactActors: false Warhead@Smu: LeaveSmudge SmudgeType: Crater - InvalidTargets: Structure, Wall, Trees + ValidTargets: Ground, GroundActor + InvalidTargets: Structure, Wall APMine: Inherits: ATMine @@ -177,9 +192,11 @@ SmudgeType: Scorch OreExplosion: + ValidTargets: Ground, Water, GroundActor, WaterActor Warhead@1Dam: SpreadDamage Spread: 9 Damage: 1000 + ValidTargets: GroundActor, WaterActor Versus: None: 90 Wood: 70 @@ -192,14 +209,15 @@ Warhead@2Eff: CreateEffect Explosions: med_explosion ImpactSounds: kaboom25.aud + ImpactActors: false CrateNuke: - ValidTargets: Ground, Trees, Water, Air + ValidTargets: Ground, GroundActor, Trees, Water, WaterActor, Underwater, Air, AirborneActor Warhead@1Dam_impact: SpreadDamage Spread: 1c0 Damage: 10000 Falloff: 1000, 368, 135, 50, 18, 7, 0 - ValidTargets: Ground, Trees, Water, Air + ValidTargets: GroundActor, Trees, WaterActor, AirborneActor Versus: Concrete: 25 AffectsParent: true @@ -214,8 +232,9 @@ Damage: 6000 Falloff: 1000, 600, 400, 250, 150, 100, 0 Delay: 5 - ValidTargets: Ground, Water, Air + ValidTargets: GroundActor, Trees, WaterActor, AirborneActor Versus: + Tree: 200 Concrete: 25 AffectsParent: true DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary @@ -228,24 +247,20 @@ ImpactActors: false Warhead@6Smu_areanuke1: LeaveSmudge SmudgeType: Scorch - InvalidTargets: Vehicle, Structure, Wall, Trees + ValidTargets: Ground, Infantry Size: 4 Delay: 5 - Warhead@TREEKILL: SpreadDamage - Spread: 1c0 - Damage: 12000 - Falloff: 1000, 600, 400, 250, 150, 100, 0 - Delay: 5 - ValidTargets: Trees - DamageTypes: Incendiary + Warhead@7FlashEffect: FlashPaletteEffect + Duration: 20 + FlashType: Nuke MiniNuke: - ValidTargets: Ground, Trees, Water, Underwater, Air + ValidTargets: Ground, GroundActor, Trees, Water, WaterActor, Underwater, Air, AirborneActor Warhead@1Dam_impact: SpreadDamage Spread: 1c0 Damage: 15000 Falloff: 1000, 368, 135, 50, 18, 7, 0 - ValidTargets: Ground, Trees, Water, Air + ValidTargets: GroundActor, Trees, WaterActor, Underwater, AirborneActor Versus: Wood: 25 Concrete: 25 @@ -262,7 +277,7 @@ Damage: 6000 Falloff: 1000, 368, 135, 50, 18, 7, 0 Delay: 5 - ValidTargets: Ground, Trees, Water, Underwater, Air + ValidTargets: GroundActor, Trees, WaterActor, Underwater, AirborneActor Versus: Wood: 50 Concrete: 25 @@ -280,19 +295,13 @@ Damage: 6000 Falloff: 1000, 368, 135, 50, 18, 7, 0 Delay: 10 - ValidTargets: Ground, Water, Underwater, Air + ValidTargets: GroundActor, Trees, WaterActor, Underwater, AirborneActor Versus: Wood: 50 + Tree: 200 Concrete: 25 AffectsParent: true DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary - Warhead@8Dam_areanuke2: SpreadDamage - Spread: 3c0 - Damage: 12000 - Falloff: 1000, 368, 135, 50, 18, 7, 0 - Delay: 10 - ValidTargets: Trees - DamageTypes: Incendiary Warhead@9Res_areanuke2: DestroyResource Size: 3 Delay: 10 @@ -301,23 +310,20 @@ Damage: 6000 Falloff: 1000, 368, 135, 50, 18, 7, 0 Delay: 15 - ValidTargets: Ground, Water, Underwater + ValidTargets: GroundActor, Trees, WaterActor, Underwater Versus: + Tree: 300 Concrete: 25 AffectsParent: true DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary - Warhead@11Dam_areanuke3: SpreadDamage - Spread: 4c0 - Damage: 18000 - Falloff: 1000, 368, 135, 50, 18, 7, 0 - Delay: 15 - ValidTargets: Trees - DamageTypes: Incendiary Warhead@12Res_areanuke3: DestroyResource Size: 4 Delay: 15 Warhead@13Smu_areanuke3: LeaveSmudge SmudgeType: Scorch - InvalidTargets: Vehicle, Structure, Wall, Trees + ValidTargets: Ground, Infantry Size: 4 Delay: 15 + Warhead@14FlashEffect: FlashPaletteEffect + Duration: 20 + FlashType: Nuke diff -Nru openra-20200503/mods/ra/weapons/missiles.yaml openra-20210321/mods/ra/weapons/missiles.yaml --- openra-20200503/mods/ra/weapons/missiles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/weapons/missiles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -3,6 +3,7 @@ Range: 5c0 MinRange: 0c512 Report: missile6.aud + ValidTargets: Ground, Water, GroundActor, WaterActor Projectile: Missile Speed: 213 Arm: 2 @@ -11,12 +12,12 @@ Inaccuracy: 128 Image: DRAGON Shadow: True - HorizontalRateOfTurn: 5 + HorizontalRateOfTurn: 20 RangeLimit: 6c0 Warhead@1Dam: SpreadDamage Spread: 128 Damage: 5000 - ValidTargets: Ground, Water, Air + ValidTargets: GroundActor, WaterActor, AirborneActor Versus: None: 10 Wood: 74 @@ -26,20 +27,20 @@ DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath Warhead@2Smu: LeaveSmudge SmudgeType: Crater - InvalidTargets: Vehicle, Structure, Wall, Husk, Trees + ValidTargets: Ground, Infantry Warhead@3Eff: CreateEffect Explosions: med_explosion ImpactSounds: kaboom25.aud - ValidTargets: Ground, Air, Ship, Trees + ValidTargets: Ground, Air, GroundActor, AirborneActor, WaterActor, Trees Warhead@4EffWater: CreateEffect Explosions: med_splash ImpactSounds: splash9.aud ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge + InvalidTargets: Bridge ^AntiAirMissile: Inherits: ^AntiGroundMissile - ValidTargets: Air + ValidTargets: AirborneActor Warhead@3Eff: CreateEffect ImpactActors: false @@ -57,6 +58,7 @@ CruiseAltitude: 2c0 RangeLimit: 14c410 Warhead@1Dam: SpreadDamage + InvalidTargets: AirborneActor Damage: 7000 Versus: None: 30 @@ -78,7 +80,7 @@ BurstDelays: 7 Projectile: Missile Speed: 256 - HorizontalRateOfTurn: 10 + HorizontalRateOfTurn: 40 RangeLimit: 8c512 Warhead@1Dam: SpreadDamage Damage: 6000 @@ -98,12 +100,12 @@ Projectile: Missile Speed: 492 Inaccuracy: 128 - HorizontalRateOfTurn: 25 + HorizontalRateOfTurn: 100 RangeLimit: 7c0 CloseEnough: 0c600 Warhead@1Dam: SpreadDamage Damage: 4000 - ValidTargets: Air + ValidTargets: AirborneActor Versus: Wood: 75 Light: 75 @@ -115,10 +117,10 @@ ReloadDelay: 60 Range: 6c512 Burst: 2 - ValidTargets: Air, Infantry + ValidTargets: AirborneActor, Infantry Projectile: Missile Speed: 341 - HorizontalRateOfTurn: 15 + HorizontalRateOfTurn: 60 RangeLimit: 9c614 Warhead@1Dam: SpreadDamage Spread: 256 @@ -131,11 +133,11 @@ DamageTypes: Prone50Percent, TriggerProne, SmallExplosionDeath Warhead@3Eff: CreateEffect ImpactSounds: kaboom12.aud - ValidTargets: Ground, Trees + ValidTargets: Ground, GroundActor, Trees Warhead@5EffAir: CreateEffect Explosions: med_explosion_air ImpactSounds: kaboom25.aud - ValidTargets: Air + ValidTargets: Air, AirborneActor Nike: Inherits: ^AntiAirMissile @@ -146,12 +148,12 @@ Arm: 3 Inaccuracy: 0 Image: MISSILE - HorizontalRateOfTurn: 25 + HorizontalRateOfTurn: 100 RangeLimit: 9c0 Speed: 341 Warhead@1Dam: SpreadDamage Damage: 5000 - ValidTargets: Air + ValidTargets: AirborneActor Versus: Light: 90 Warhead@3Eff: CreateEffect @@ -163,11 +165,11 @@ ReloadDelay: 50 Projectile: Missile Inaccuracy: 0 - HorizontalRateOfTurn: 20 + HorizontalRateOfTurn: 80 Speed: 298 Warhead@1Dam: SpreadDamage Damage: 4000 - ValidTargets: Air + ValidTargets: AirborneActor Versus: Light: 60 @@ -181,7 +183,7 @@ Projectile: Missile Arm: 3 Inaccuracy: 0 - HorizontalRateOfTurn: 20 + HorizontalRateOfTurn: 80 RangeLimit: 9c512 Speed: 170 CloseEnough: 149 @@ -196,7 +198,7 @@ StingerAA: Inherits: Stinger - ValidTargets: Air + ValidTargets: AirborneActor Projectile: Missile Speed: 255 CloseEnough: 298 @@ -211,7 +213,7 @@ Projectile: Missile Speed: 298 TrailImage: smokey - HorizontalRateOfTurn: 10 + HorizontalRateOfTurn: 40 RangeLimit: 7c204 APTusk.stnk: @@ -222,7 +224,7 @@ ReloadDelay: 100 Range: 9c0 Report: torpedo1.aud - ValidTargets: Water, Underwater, Bridge + ValidTargets: Water, WaterActor, Underwater, Bridge Burst: 2 BurstDelays: 20 Projectile: Missile @@ -230,7 +232,7 @@ Arm: 3 Speed: 85 TrailImage: bubbles - HorizontalRateOfTurn: 1 + HorizontalRateOfTurn: 4 RangeLimit: 10c819 BoundToTerrainType: Water Palette: shadow @@ -239,7 +241,7 @@ Warhead@1Dam: SpreadDamage Spread: 426 Damage: 18000 - ValidTargets: Water, Underwater, Bridge + ValidTargets: WaterActor, Underwater, Bridge Versus: Wood: 75 Light: 75 @@ -249,12 +251,12 @@ Warhead@3Eff: CreateEffect Explosions: artillery_explosion ImpactSounds: kaboom15.aud - ValidTargets: Ship, Structure, Underwater, Ground, Bridge + ValidTargets: Ground, WaterActor, Underwater, GroundActor, Bridge Warhead@4EffWater: CreateEffect Explosions: large_splash ImpactSounds: splash9.aud ValidTargets: Water - InvalidTargets: Ship, Structure, Underwater, Bridge + InvalidTargets: Bridge ^SubMissileDefault: Inherits: ^AntiGroundMissile @@ -264,7 +266,7 @@ Projectile: Missile Speed: 234 Inaccuracy: 0c614 - HorizontalRateOfTurn: 15 + HorizontalRateOfTurn: 60 RangeLimit: 9c0 Image: MISSILE TrailImage: smokey @@ -304,7 +306,7 @@ SubMissileAA: Inherits: ^SubMissileDefault - ValidTargets: Air + ValidTargets: AirborneActor Warhead@1Dam: SpreadDamage Damage: 1500 @@ -328,10 +330,11 @@ Spread: 341 Damage: 4500 Falloff: 1000, 368, 135, 50, 18, 7, 0 - ValidTargets: Ground, Water, Trees + ValidTargets: GroundActor, WaterActor, Trees Versus: None: 90 Wood: 75 + Tree: 75 Light: 70 Heavy: 40 Concrete: 100 diff -Nru openra-20200503/mods/ra/weapons/other.yaml openra-20210321/mods/ra/weapons/other.yaml --- openra-20200503/mods/ra/weapons/other.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/weapons/other.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,14 +1,15 @@ ^FireWeapon: - ValidTargets: Ground, Water, Trees + ValidTargets: Ground, Water, GroundActor, WaterActor, Trees ReloadDelay: 65 Range: 5c0 Warhead@1Dam: SpreadDamage Spread: 213 Damage: 15000 - ValidTargets: Ground, Water, Trees + ValidTargets: GroundActor, WaterActor, Trees Versus: None: 90 Wood: 50 + Tree: 50 Light: 60 Heavy: 25 Concrete: 20 @@ -50,6 +51,7 @@ Versus: None: 70 Wood: 80 + Tree: 80 Light: 40 Heavy: 20 Concrete: 10 @@ -73,12 +75,14 @@ ^TeslaWeapon: ReloadDelay: 3 - Range: 8c0 + Range: 7c0 Report: tesla1.aud Projectile: TeslaZap + ValidTargets: Ground, Water, GroundActor, WaterActor Warhead@1Dam: SpreadDamage Spread: 42 Damage: 10000 + ValidTargets: GroundActor, WaterActor Versus: None: 1000 DamageTypes: Prone50Percent, TriggerProne, ElectricityDeath @@ -127,7 +131,7 @@ Warhead@1Dam: SpreadDamage Spread: 213 Damage: -5000 - ValidStances: Ally + ValidRelationships: Ally ValidTargets: Heal DebugOverlayColor: 00FF00 @@ -140,8 +144,10 @@ ValidTargets: Repair Demolish: + ValidTargets: GroundActor, WaterActor Warhead@1Dam: SpreadDamage DamageTypes: DefaultDeath + ValidTargets: GroundActor, WaterActor Warhead@2Eff: CreateEffect Explosions: building ImpactSounds: kaboom25.aud @@ -149,11 +155,13 @@ Claw: ReloadDelay: 30 Range: 1c512 + ValidTargets: Ground, Water, GroundActor, WaterActor Projectile: Bullet Speed: 1c682 Warhead@1Dam: SpreadDamage Spread: 213 Damage: 3000 + ValidTargets: GroundActor, WaterActor Versus: None: 97 Wood: 10 @@ -216,10 +224,12 @@ ValidTargets: DetonateAttack MADTankThump: + ValidTargets: GroundActor, WaterActor InvalidTargets: MADTank, Infantry Warhead@1Dam: HealthPercentageDamage Spread: 7c0 Damage: 1 + ValidTargets: GroundActor, WaterActor InvalidTargets: MADTank, Infantry Warhead@Shake: ShakeScreen Duration: 10 @@ -227,10 +237,12 @@ Multiplier: 1,0 MADTankDetonate: + ValidTargets: GroundActor, WaterActor InvalidTargets: MADTank, Infantry Warhead@1Dam: HealthPercentageDamage Spread: 7c0 Damage: 19 + ValidTargets: GroundActor, WaterActor InvalidTargets: MADTank, Infantry Warhead@2Smu: LeaveSmudge SmudgeType: Crater diff -Nru openra-20200503/mods/ra/weapons/smallcaliber.yaml openra-20210321/mods/ra/weapons/smallcaliber.yaml --- openra-20200503/mods/ra/weapons/smallcaliber.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/weapons/smallcaliber.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,12 +2,12 @@ ReloadDelay: 10 Range: 8c0 Report: aacanon3.aud - ValidTargets: Air + ValidTargets: AirborneActor Projectile: InstantHit Warhead@1Dam: SpreadDamage Spread: 213 Damage: 2000 - ValidTargets: Air + ValidTargets: AirborneActor Versus: None: 40 Wood: 10 @@ -37,33 +37,35 @@ FLAK-23-AA: Inherits: ^AACannon Warhead@1Dam: SpreadDamage - ValidTargets: Air, Ground, Water + ValidTargets: AirborneActor, GroundActor, WaterActor FLAK-23-AG: Inherits: ^AACannon Range: 6c0 - ValidTargets: Ground, Water + ValidTargets: Ground, Water, GroundActor, WaterActor Projectile: InstantHit Blockable: true Warhead@1Dam: SpreadDamage - ValidTargets: Air, Ground, Water + ValidTargets: AirborneActor, GroundActor, WaterActor Warhead@2Eff: CreateEffect Explosions: flak_explosion_ground - ValidTargets: Ground, Ship, Air, Trees + ValidTargets: Ground, GroundActor, Air, AirborneActor, WaterActor, Trees Warhead@3EffWater: CreateEffect Explosions: small_splash ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge + InvalidTargets: Bridge ^HeavyMG: ReloadDelay: 30 Range: 6c0 Report: gun13.aud + ValidTargets: Ground, Water, GroundActor, WaterActor Projectile: InstantHit Blockable: true Warhead@1Dam: SpreadDamage Spread: 128 Damage: 2500 + ValidTargets: GroundActor, WaterActor Versus: None: 120 Wood: 60 @@ -73,11 +75,11 @@ DamageTypes: Prone50Percent, TriggerProne, BulletDeath Warhead@2Eff: CreateEffect Explosions: piffs - ValidTargets: Ground, Ship, Air, Trees + ValidTargets: Ground, GroundActor, Air, AirborneActor, WaterActor, Trees Warhead@3EffWater: CreateEffect Explosions: water_piffs ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge + InvalidTargets: Bridge ^LightMG: Inherits: ^HeavyMG @@ -90,6 +92,12 @@ Heavy: 10 Concrete: 10 DamageTypes: Prone50Percent, TriggerProne, DefaultDeath + Warhead@2Eff: CreateEffect + Explosions: piff + Inaccuracy: 171 + Warhead@3EffWater: CreateEffect + Explosions: water_piff + Inaccuracy: 171 Vulcan: Inherits: ^HeavyMG @@ -105,6 +113,7 @@ Spread: 128 Damage: 1000 Delay: 2 + ValidTargets: GroundActor, WaterActor Versus: None: 200 Wood: 50 @@ -114,17 +123,18 @@ DamageTypes: Prone50Percent, TriggerProne, BulletDeath Warhead@4Eff_2: CreateEffect Explosions: piffs - ValidTargets: Ground, Ship, Trees + ValidTargets: Ground, GroundActor, Air, AirborneActor, WaterActor, Trees Delay: 2 Warhead@4Eff_2Water: CreateEffect Explosions: water_piffs ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge + InvalidTargets: Bridge Delay: 2 Warhead@5Dam_3: SpreadDamage Spread: 128 Damage: 1000 Delay: 4 + ValidTargets: GroundActor, WaterActor Versus: None: 200 Wood: 50 @@ -134,17 +144,18 @@ DamageTypes: Prone50Percent, TriggerProne, BulletDeath Warhead@6Eff_3: CreateEffect Explosions: piffs - ValidTargets: Ground, Ship, Trees + ValidTargets: Ground, GroundActor, Air, AirborneActor, WaterActor, Trees Delay: 4 Warhead@6Eff_3Water: CreateEffect Explosions: water_piffs ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge + InvalidTargets: Bridge Delay: 4 Warhead@7Dam_4: SpreadDamage Spread: 128 Damage: 1000 Delay: 6 + ValidTargets: GroundActor, WaterActor Versus: None: 200 Wood: 50 @@ -154,17 +165,18 @@ DamageTypes: Prone50Percent, TriggerProne, BulletDeath Warhead@8Eff_4: CreateEffect Explosions: piffs - ValidTargets: Ground, Ship, Trees + ValidTargets: Ground, GroundActor, Air, AirborneActor, WaterActor, Trees Delay: 6 Warhead@8Eff_4Water: CreateEffect Explosions: water_piffs ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge + InvalidTargets: Bridge Delay: 6 Warhead@9Dam_5: SpreadDamage Spread: 128 Damage: 1000 Delay: 8 + ValidTargets: GroundActor, WaterActor Versus: None: 200 Wood: 50 @@ -174,17 +186,18 @@ DamageTypes: Prone50Percent, TriggerProne, BulletDeath Warhead@10Eff_5: CreateEffect Explosions: piffs - ValidTargets: Ground, Ship, Trees + ValidTargets: Ground, GroundActor, Air, AirborneActor, WaterActor, Trees Delay: 8 Warhead@10Eff_5Water: CreateEffect Explosions: water_piffs ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge + InvalidTargets: Bridge Delay: 8 Warhead@11Dam_6: SpreadDamage Spread: 128 Damage: 1000 Delay: 10 + ValidTargets: GroundActor, WaterActor Versus: None: 200 Wood: 50 @@ -194,12 +207,12 @@ DamageTypes: Prone50Percent, TriggerProne, BulletDeath Warhead@12Eff_6: CreateEffect Explosions: piffs - ValidTargets: Ground, Ship, Trees + ValidTargets: Ground, GroundActor, Air, AirborneActor, WaterActor, Trees Delay: 10 Warhead@12Eff_6Water: CreateEffect Explosions: water_piffs ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge + InvalidTargets: Bridge Delay: 10 ChainGun: @@ -239,9 +252,9 @@ Versus: None: 100 Warhead@2Eff: CreateEffect - Explosions: piff + Inaccuracy: 128 Warhead@3EffWater: CreateEffect - Explosions: water_piff + Inaccuracy: 128 M1Carbine: Inherits: ^LightMG @@ -251,6 +264,28 @@ Warhead@1Dam: SpreadDamage Versus: Wood: 30 + Warhead@2Eff2: CreateEffect + Delay: 2 + Explosions: piff + ValidTargets: Ground, GroundActor, Air, AirborneActor, WaterActor, Trees + Inaccuracy: 171 + Warhead@3EffWater2: CreateEffect + Delay: 2 + ValidTargets: Water, Underwater + InvalidTargets: Bridge + Explosions: water_piff + Inaccuracy: 171 + Warhead@2Eff3: CreateEffect + Delay: 4 + Explosions: piff + ValidTargets: Ground, GroundActor, Air, AirborneActor, WaterActor, Trees + Inaccuracy: 171 + Warhead@3EffWater3: CreateEffect + Delay: 4 + ValidTargets: Water, Underwater + InvalidTargets: Bridge + Explosions: water_piff + Inaccuracy: 171 M60mg: Inherits: ^LightMG @@ -261,13 +296,16 @@ Warhead@1Dam: SpreadDamage Versus: Light: 30 + Warhead@2Eff: CreateEffect + Inaccuracy: 213 + Warhead@3EffWater: CreateEffect + Inaccuracy: 213 ^SnipeWeapon: ReloadDelay: 80 Range: 2c512 Report: gun5.aud - ValidTargets: Ground, Infantry - InvalidTargets: Vehicle, Water, Structure, Wall, Husk, Mine + ValidTargets: Ground, Infantry, Barrel Projectile: InstantHit Blockable: true Warhead@1Dam: SpreadDamage @@ -275,33 +313,26 @@ Damage: 15000 ValidTargets: Barrel, Infantry DamageTypes: Prone50Percent, TriggerProne, DefaultDeath + Warhead@2Eff: CreateEffect + Explosions: piff + ValidTargets: Ground, GroundActor, Air, AirborneActor, WaterActor, Trees + Warhead@3EffWater: CreateEffect + Explosions: water_piff + ValidTargets: Water, Underwater + InvalidTargets: Ship, Structure, Bridge SilencedPPK: Inherits: ^SnipeWeapon Report: silppk.aud Warhead@1Dam: SpreadDamage Spread: 128 - Warhead@2Eff: CreateEffect - Explosions: piffs - ValidTargets: Ground, Ship, Air, Trees - Warhead@3EffWater: CreateEffect - Explosions: water_piffs - ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge Colt45: Inherits: ^SnipeWeapon - ReloadDelay: 5 + ReloadDelay: 7 Range: 7c0 Warhead@1Dam: SpreadDamage Damage: 5000 - Warhead@2Eff: CreateEffect - Explosions: piff - ValidTargets: Ground, Ship, Air, Trees - Warhead@3EffWater: CreateEffect - Explosions: water_piff - ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure, Bridge Sniper: Inherits: ^SnipeWeapon diff -Nru openra-20200503/mods/ra/weapons/superweapons.yaml openra-20210321/mods/ra/weapons/superweapons.yaml --- openra-20200503/mods/ra/weapons/superweapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ra/weapons/superweapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,6 +2,7 @@ ReloadDelay: 8 Range: 3c0 Report: chute1.aud + ValidTargets: Ground, Water, GroundActor, WaterActor Projectile: GravityBomb Image: PARABOMB OpenSequence: open @@ -11,6 +12,7 @@ Warhead@1Dam: SpreadDamage Spread: 768 Damage: 30000 + ValidTargets: GroundActor, WaterActor Versus: None: 30 Wood: 30 @@ -19,24 +21,23 @@ DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath Warhead@2Smu: LeaveSmudge SmudgeType: Crater - InvalidTargets: Vehicle, Structure, Wall, Husk, Trees + ValidTargets: Ground, Infantry Warhead@3Eff: CreateEffect Explosions: artillery_explosion ImpactSounds: kaboom15.aud - ValidTargets: Ground, Ship, Trees + ValidTargets: Ground, GroundActor, WaterActor, Trees Warhead@4EffWater: CreateEffect Explosions: small_splash ImpactSounds: splash9.aud ValidTargets: Water, Underwater - InvalidTargets: Ship, Structure Atomic: - ValidTargets: Ground, Trees, Water, Underwater, Air + ValidTargets: Ground, Water, GroundActor, WaterActor, Underwater, AirborneActor, Trees Warhead@1Dam_impact: SpreadDamage Spread: 1c0 Damage: 15000 Falloff: 1000, 368, 135, 50, 18, 7, 0 - ValidTargets: Ground, Trees, Water, Underwater, Air + ValidTargets: GroundActor, WaterActor, Underwater, AirborneActor, Trees Versus: Wood: 25 Concrete: 25 @@ -45,7 +46,7 @@ Size: 1 Warhead@3Smu_impact: LeaveSmudge SmudgeType: Scorch - InvalidTargets: Vehicle, Structure, Wall + ValidTargets: Ground, Infantry Size: 1 Warhead@4Eff_impact: CreateEffect Explosions: nuke @@ -57,7 +58,7 @@ Damage: 6000 Falloff: 1000, 368, 135, 50, 18, 7, 0 Delay: 5 - ValidTargets: Ground, Trees, Water, Underwater, Air + ValidTargets: GroundActor, WaterActor, Underwater, AirborneActor, Trees Versus: Wood: 25 Concrete: 25 @@ -67,7 +68,7 @@ Delay: 5 Warhead@7Smu_areanuke1: LeaveSmudge SmudgeType: Scorch - InvalidTargets: Vehicle, Structure, Wall, Husk, Trees + ValidTargets: Ground, Infantry Size: 2 Delay: 5 Warhead@8Eff_areanuke1: CreateEffect @@ -79,24 +80,18 @@ Damage: 6000 Falloff: 1000, 368, 135, 50, 18, 7, 0 Delay: 10 - ValidTargets: Ground, Water, Underwater, Air + ValidTargets: GroundActor, Trees, WaterActor, Underwater, AirborneActor Versus: Wood: 50 + Tree: 200 Concrete: 25 DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary - Warhead@10Dam_areanuke2: SpreadDamage - Spread: 3c0 - Damage: 12000 - Falloff: 1000, 368, 135, 50, 18, 7, 0 - Delay: 15 - ValidTargets: Trees - DamageTypes: Incendiary Warhead@11Res_areanuke2: DestroyResource Size: 3 Delay: 10 Warhead@12Smu_areanuke2: LeaveSmudge SmudgeType: Scorch - InvalidTargets: Vehicle, Structure, Wall, Husk, Trees + ValidTargets: Ground, Infantry Size: 3 Delay: 10 Warhead@13Dam_areanuke3: SpreadDamage @@ -104,23 +99,17 @@ Damage: 6000 Falloff: 1000, 368, 135, 50, 18, 7, 0 Delay: 15 - ValidTargets: Ground, Water, Underwater, Air + ValidTargets: GroundActor, Trees, WaterActor, Underwater, AirborneActor Versus: + Tree: 200 Concrete: 25 DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary - Warhead@14Dam_areanuke3: SpreadDamage - Spread: 4c0 - Damage: 12000 - Falloff: 1000, 368, 135, 50, 18, 7, 0 - Delay: 15 - ValidTargets: Trees - DamageTypes: Incendiary Warhead@15Res_areanuke3: DestroyResource Size: 4 Delay: 15 Warhead@16Smu_areanuke3: LeaveSmudge SmudgeType: Scorch - InvalidTargets: Vehicle, Structure, Wall, Husk, Trees + ValidTargets: Ground, Infantry Size: 4 Delay: 15 Warhead@17Dam_areanuke4: SpreadDamage @@ -128,26 +117,23 @@ Damage: 6000 Falloff: 1000, 368, 135, 50, 18, 7, 0 Delay: 20 - ValidTargets: Ground, Water, Underwater, Air + ValidTargets: GroundActor, Trees, WaterActor, Underwater, AirborneActor Versus: + Tree: 200 Concrete: 25 DamageTypes: Prone50Percent, TriggerProne, FireDeath, Incendiary - Warhead@18Dam_areanuke4: SpreadDamage - Spread: 5c0 - Damage: 12000 - Falloff: 1000, 368, 135, 50, 18, 7, 0 - Delay: 20 - ValidTargets: Trees - DamageTypes: Incendiary Warhead@19Res_areanuke4: DestroyResource Size: 5 Delay: 20 Warhead@20Smu_areanuke4: LeaveSmudge SmudgeType: Scorch - InvalidTargets: Vehicle, Structure, Wall, Husk, Trees + ValidTargets: Ground, Infantry Size: 5 Delay: 20 Warhead@21Shake: ShakeScreen Duration: 20 Intensity: 5 Multiplier: 1,1 + Warhead@22FlashEffect: FlashPaletteEffect + Duration: 20 + FlashType: Nuke diff -Nru openra-20200503/mods/ts/audio/voices.yaml openra-20210321/mods/ts/audio/voices.yaml --- openra-20200503/mods/ts/audio/voices.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/audio/voices.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -196,6 +196,31 @@ Zapped: electro1 Explode: expnew10 +Civilian1: + Inherits: Civilian + Voices: + Select: 67-n100, 67-n102 + Move: 67-n104, 67-n106, 67-n108 + +Civilian2: + Inherits: Civilian + Voices: + Select: 68-n100, 68-n102, 68-n104 + Move: 68-n106, 68-n108, 68-n110 + +Civilian3: + Inherits: Civilian + Voices: + Select: 69-n100, 69-b102, 69-n104 + Move: 69-n106, 69-n108, 69-n110 + +CivilianTechnician: + Inherits: Civilian + Voices: + Select: 70-n000, 70-n002, 70-n004 + Move: 70-n006, 70-n008, 70-n010 + Attack: 70-n014, 70-n016, 70-n018 + CivilianFemale: #can be used for female mutant as well Voices: Select: Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/bits/harpyrotor.shp and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/bits/harpyrotor.shp differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/bits/lrotor.shp and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/bits/lrotor.shp differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/bits/typeglyphs.shp and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/bits/typeglyphs.shp differ diff -Nru openra-20200503/mods/ts/chrome/dropdowns.yaml openra-20210321/mods/ts/chrome/dropdowns.yaml --- openra-20200503/mods/ts/chrome/dropdowns.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/chrome/dropdowns.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -104,7 +104,7 @@ Height: 16 Label@LABEL: X: 40 - Width: 60 + Width: PARENT_RIGHT Height: 25 Shadow: True Label@NOFLAG_LABEL: diff -Nru openra-20200503/mods/ts/chrome/ingame-observer.yaml openra-20210321/mods/ts/chrome/ingame-observer.yaml --- openra-20200503/mods/ts/chrome/ingame-observer.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/chrome/ingame-observer.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -94,7 +94,7 @@ Y: 5 Label@LABEL: X: 34 - Width: 60 + Width: PARENT_RIGHT Height: 25 Shadow: True Label@NOFLAG_LABEL: @@ -871,7 +871,7 @@ X: PARENT_RIGHT - 200 Y: 0 Width: 200 - Height: PARENT_BOTTOM + Height: PARENT_BOTTOM Image@FLAG: X: 5 Y: 4 diff -Nru openra-20200503/mods/ts/chrome/ingame-player.yaml openra-20210321/mods/ts/chrome/ingame-player.yaml --- openra-20200503/mods/ts/chrome/ingame-player.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/chrome/ingame-player.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -523,7 +523,7 @@ Height: 31 VisualHeight: 0 Background: sidebar-button - TooltipText: Defense + TooltipText: Support TooltipContainer: TOOLTIP_CONTAINER ProductionGroup: Defense Key: ProductionTypeDefense diff -Nru openra-20200503/mods/ts/chrome.yaml openra-20210321/mods/ts/chrome.yaml --- openra-20200503/mods/ts/chrome.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/chrome.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -458,10 +458,11 @@ lobby-bits: Inherits: ^Glyphs Regions: - spawn-unclaimed: 91, 119, 22, 22 - spawn-claimed: 68, 119, 22, 22 + spawn-claimed: 27, 119, 22, 22 + spawn-unclaimed: 50, 119, 22, 22 + spawn-disabled: 73, 119, 22, 22 admin: 170, 0, 6, 5 - colorpicker: 68, 119, 22, 22 + colorpicker: 27, 119, 22, 22 huepicker: 136, 0, 7, 15 kick: 153, 0, 11, 11 protected: 0, 17, 12, 13 @@ -500,18 +501,6 @@ prev: 68, 0, 16, 16 fastforward: 85, 0, 16, 16 -scrollbar: - Inherits: ^Glyphs - Regions: - down_arrow: 68, 17, 16, 16 - down_pressed: 85, 17, 16, 16 - up_arrow: 102, 17, 16, 16 - up_pressed: 119, 17, 16, 16 - right_arrow: 136, 17, 16, 16 - right_pressed: 153, 17, 16, 16 - left_arrow: 170, 17, 16, 16 - left_pressed: 187, 17, 16, 16 - # ---------------------------------------------------------------------- # Other UI stuff # ---------------------------------------------------------------------- @@ -666,6 +655,12 @@ Inherits: ^Dialog PanelRegion: 897, 1, 2, 2, 122, 122, 2, 2 +checkbox-highlighted-hover: + Inherits: checkbox-highlighted + +checkbox-highlighted-disabled: + Inherits: checkbox-disabled + scrollitem-selected: Inherits: button-pressed @@ -681,10 +676,36 @@ mainmenu-border: Inherits: ^Dialog -dropdown: +scrollpanel-decorations: + Inherits: ^Glyphs + Regions: + down: 68, 17, 16, 16 + down-pressed: 68, 17, 16, 16 + down-disabled: 85, 17, 16, 16 + up: 102, 17, 16, 16 + up-pressed: 102, 17, 16, 16 + up-disabled: 119, 17, 16, 16 + right: 136, 17, 16, 16 + right-pressed: 136, 17, 16, 16 + right-disabled: 153, 17, 16, 16 + left: 170, 17, 16, 16 + left-pressed: 170, 17, 16, 16 + left-disabled: 187, 17, 16, 16 + +dropdown-decorations: + Inherits: ^Glyphs + Regions: + marker: 68, 17, 16, 16 + marker-pressed: 68, 17, 16, 16 + marker-disabled: 85, 17, 16, 16 + +dropdown-separators: Inherits: ^Dialog Regions: - separator: 513, 1, 1, 19 + separator: 513, 2, 1, 19 + separator-hover: 513, 130, 1, 19 + separator-pressed: 766, 2, 1, 19 + separator-disabled: 513, 258, 1, 19 logos: Inherits: ^LoadScreen diff -Nru openra-20200503/mods/ts/installer/downloads.yaml openra-20210321/mods/ts/installer/downloads.yaml --- openra-20200503/mods/ts/installer/downloads.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/installer/downloads.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -2,418 +2,397 @@ SHA1: 824df30de0004ad13fac29cf16450caafee9fb1b MirrorList: http://www.openra.net/packages/ts-mirrors.txt Extract: - ^Content/ts/cache.mix: cache.mix - ^Content/ts/conquer.mix: conquer.mix - ^Content/ts/isosnow.mix: isosnow.mix - ^Content/ts/isotemp.mix: isotemp.mix - ^Content/ts/local.mix: local.mix - ^Content/ts/sidec01.mix: sidec01.mix - ^Content/ts/sidec02.mix: sidec02.mix - ^Content/ts/sno.mix: sno.mix - ^Content/ts/snow.mix: snow.mix - ^Content/ts/sounds.mix: sounds.mix - ^Content/ts/speech01.mix: speech01.mix - ^Content/ts/speech02.mix: speech02.mix - ^Content/ts/tem.mix: tem.mix - ^Content/ts/temperat.mix: temperat.mix - -tibsun-music: Base Freeware Music - SHA1: f445cf47ffa343d9e211ec31f29fb45c8aefac80 - MirrorList: http://www.openra.net/packages/ts-music-mirrors.txt - Extract: - ^Content/ts/scores.mix: scores.mix + ^SupportDir|Content/ts/cache.mix: cache.mix + ^SupportDir|Content/ts/conquer.mix: conquer.mix + ^SupportDir|Content/ts/isosnow.mix: isosnow.mix + ^SupportDir|Content/ts/isotemp.mix: isotemp.mix + ^SupportDir|Content/ts/local.mix: local.mix + ^SupportDir|Content/ts/sidec01.mix: sidec01.mix + ^SupportDir|Content/ts/sidec02.mix: sidec02.mix + ^SupportDir|Content/ts/sno.mix: sno.mix + ^SupportDir|Content/ts/snow.mix: snow.mix + ^SupportDir|Content/ts/sounds.mix: sounds.mix + ^SupportDir|Content/ts/speech01.mix: speech01.mix + ^SupportDir|Content/ts/speech02.mix: speech02.mix + ^SupportDir|Content/ts/tem.mix: tem.mix + ^SupportDir|Content/ts/temperat.mix: temperat.mix fstorm: Expansion Freeware Content SHA1: 8bff90870a9348b72cbe91314aec7d3a50311aa9 MirrorList: http://www.openra.net/packages/fs-mirrors.txt Extract: - ^Content/ts/firestorm/c_kodiak.shp: firestorm/c_kodiak.shp - ^Content/ts/firestorm/coremk.shp: firestorm/coremk.shp - ^Content/ts/firestorm/defdmk.shp: firestorm/defdmk.shp - ^Content/ts/firestorm/k_light1.shp: firestorm/k_light1.shp - ^Content/ts/firestorm/k_light2.shp: firestorm/k_light2.shp - ^Content/ts/firestorm/mstlmk.shp: firestorm/mstlmk.shp - ^Content/ts/firestorm/mwarmk.shp: firestorm/mwarmk.shp - ^Content/ts/firestorm/djuggbar.hva: firestorm/djuggbar.hva - ^Content/ts/firestorm/m_emp.hva: firestorm/m_emp.hva - ^Content/ts/firestorm/mwar_nod.hva: firestorm/mwar_nod.hva - ^Content/ts/firestorm/sgen.hva: firestorm/sgen.hva - ^Content/ts/firestorm/djuggbar.vxl: firestorm/djuggbar.vxl - ^Content/ts/firestorm/m_emp.vxl: firestorm/m_emp.vxl - ^Content/ts/firestorm/mwar_nod.vxl: firestorm/mwar_nod.vxl - ^Content/ts/firestorm/sgen.vxl: firestorm/sgen.vxl - ^Content/ts/firestorm/e01sc01.mix: firestorm/e01sc01.mix - ^Content/ts/firestorm/e01sc02.mix: firestorm/e01sc02.mix - ^Content/ts/firestorm/e01vox01.mix: firestorm/e01vox01.mix - ^Content/ts/firestorm/e01vox02.mix: firestorm/e01vox02.mix - ^Content/ts/firestorm/ecache01.mix: firestorm/ecache01.mix - ^Content/ts/firestorm/sounds01.mix: firestorm/sounds01.mix - ^Content/ts/firestorm/blat01.tem: firestorm/blat01.tem - ^Content/ts/firestorm/blat01a.tem: firestorm/blat01a.tem - ^Content/ts/firestorm/blat02.tem: firestorm/blat02.tem - ^Content/ts/firestorm/blat02a.tem: firestorm/blat02a.tem - ^Content/ts/firestorm/blat03.tem: firestorm/blat03.tem - ^Content/ts/firestorm/blat03a.tem: firestorm/blat03a.tem - ^Content/ts/firestorm/blat04.tem: firestorm/blat04.tem - ^Content/ts/firestorm/blat04a.tem: firestorm/blat04a.tem - ^Content/ts/firestorm/blat05.tem: firestorm/blat05.tem - ^Content/ts/firestorm/blat05a.tem: firestorm/blat05a.tem - ^Content/ts/firestorm/blat06.tem: firestorm/blat06.tem - ^Content/ts/firestorm/blat06a.tem: firestorm/blat06a.tem - ^Content/ts/firestorm/blat07.tem: firestorm/blat07.tem - ^Content/ts/firestorm/blat07a.tem: firestorm/blat07a.tem - ^Content/ts/firestorm/blat08.tem: firestorm/blat08.tem - ^Content/ts/firestorm/blat08a.tem: firestorm/blat08a.tem - ^Content/ts/firestorm/blat09.tem: firestorm/blat09.tem - ^Content/ts/firestorm/blat09a.tem: firestorm/blat09a.tem - ^Content/ts/firestorm/blat10.tem: firestorm/blat10.tem - ^Content/ts/firestorm/blat10a.tem: firestorm/blat10a.tem - ^Content/ts/firestorm/blat11.tem: firestorm/blat11.tem - ^Content/ts/firestorm/blat11a.tem: firestorm/blat11a.tem - ^Content/ts/firestorm/blat12.tem: firestorm/blat12.tem - ^Content/ts/firestorm/blat12a.tem: firestorm/blat12a.tem - ^Content/ts/firestorm/blat13.tem: firestorm/blat13.tem - ^Content/ts/firestorm/blat13a.tem: firestorm/blat13a.tem - ^Content/ts/firestorm/blat14.tem: firestorm/blat14.tem - ^Content/ts/firestorm/blat14a.tem: firestorm/blat14a.tem - ^Content/ts/firestorm/blat15.tem: firestorm/blat15.tem - ^Content/ts/firestorm/blat15a.tem: firestorm/blat15a.tem - ^Content/ts/firestorm/blat16.tem: firestorm/blat16.tem - ^Content/ts/firestorm/blat16a.tem: firestorm/blat16a.tem - ^Content/ts/firestorm/blue01.tem: firestorm/blue01.tem - ^Content/ts/firestorm/blue01a.tem: firestorm/blue01a.tem - ^Content/ts/firestorm/blue01b.tem: firestorm/blue01b.tem - ^Content/ts/firestorm/blue01c.tem: firestorm/blue01c.tem - ^Content/ts/firestorm/blue01d.tem: firestorm/blue01d.tem - ^Content/ts/firestorm/blue01e.tem: firestorm/blue01e.tem - ^Content/ts/firestorm/blue01f.tem: firestorm/blue01f.tem - ^Content/ts/firestorm/blue01g.tem: firestorm/blue01g.tem - ^Content/ts/firestorm/ccliff01.tem: firestorm/ccliff01.tem - ^Content/ts/firestorm/ccliff02.tem: firestorm/ccliff02.tem - ^Content/ts/firestorm/ccliff03.tem: firestorm/ccliff03.tem - ^Content/ts/firestorm/ccliff04.tem: firestorm/ccliff04.tem - ^Content/ts/firestorm/ccliff05.tem: firestorm/ccliff05.tem - ^Content/ts/firestorm/ccliff06.tem: firestorm/ccliff06.tem - ^Content/ts/firestorm/crash01.tem: firestorm/crash01.tem - ^Content/ts/firestorm/crash02.tem: firestorm/crash02.tem - ^Content/ts/firestorm/crash03.tem: firestorm/crash03.tem - ^Content/ts/firestorm/crash04.tem: firestorm/crash04.tem - ^Content/ts/firestorm/crash05.tem: firestorm/crash05.tem - ^Content/ts/firestorm/crash06.tem: firestorm/crash06.tem - ^Content/ts/firestorm/crash07.tem: firestorm/crash07.tem - ^Content/ts/firestorm/crys01.tem: firestorm/crys01.tem - ^Content/ts/firestorm/crys01a.tem: firestorm/crys01a.tem - ^Content/ts/firestorm/crys01b.tem: firestorm/crys01b.tem - ^Content/ts/firestorm/crys01c.tem: firestorm/crys01c.tem - ^Content/ts/firestorm/crys01d.tem: firestorm/crys01d.tem - ^Content/ts/firestorm/crys01e.tem: firestorm/crys01e.tem - ^Content/ts/firestorm/crys01f.tem: firestorm/crys01f.tem - ^Content/ts/firestorm/crys01g.tem: firestorm/crys01g.tem - ^Content/ts/firestorm/cylat01.tem: firestorm/cylat01.tem - ^Content/ts/firestorm/cylat01a.tem: firestorm/cylat01a.tem - ^Content/ts/firestorm/cylat02.tem: firestorm/cylat02.tem - ^Content/ts/firestorm/cylat02a.tem: firestorm/cylat02a.tem - ^Content/ts/firestorm/cylat03.tem: firestorm/cylat03.tem - ^Content/ts/firestorm/cylat03a.tem: firestorm/cylat03a.tem - ^Content/ts/firestorm/cylat04.tem: firestorm/cylat04.tem - ^Content/ts/firestorm/cylat04a.tem: firestorm/cylat04a.tem - ^Content/ts/firestorm/cylat05.tem: firestorm/cylat05.tem - ^Content/ts/firestorm/cylat05a.tem: firestorm/cylat05a.tem - ^Content/ts/firestorm/cylat06.tem: firestorm/cylat06.tem - ^Content/ts/firestorm/cylat06a.tem: firestorm/cylat06a.tem - ^Content/ts/firestorm/cylat07.tem: firestorm/cylat07.tem - ^Content/ts/firestorm/cylat07a.tem: firestorm/cylat07a.tem - ^Content/ts/firestorm/cylat08.tem: firestorm/cylat08.tem - ^Content/ts/firestorm/cylat08a.tem: firestorm/cylat08a.tem - ^Content/ts/firestorm/cylat09.tem: firestorm/cylat09.tem - ^Content/ts/firestorm/cylat09a.tem: firestorm/cylat09a.tem - ^Content/ts/firestorm/cylat10.tem: firestorm/cylat10.tem - ^Content/ts/firestorm/cylat10a.tem: firestorm/cylat10a.tem - ^Content/ts/firestorm/cylat11.tem: firestorm/cylat11.tem - ^Content/ts/firestorm/cylat11a.tem: firestorm/cylat11a.tem - ^Content/ts/firestorm/cylat12.tem: firestorm/cylat12.tem - ^Content/ts/firestorm/cylat12a.tem: firestorm/cylat12a.tem - ^Content/ts/firestorm/cylat13.tem: firestorm/cylat13.tem - ^Content/ts/firestorm/cylat13a.tem: firestorm/cylat13a.tem - ^Content/ts/firestorm/cylat14.tem: firestorm/cylat14.tem - ^Content/ts/firestorm/cylat14a.tem: firestorm/cylat14a.tem - ^Content/ts/firestorm/cylat15.tem: firestorm/cylat15.tem - ^Content/ts/firestorm/cylat15a.tem: firestorm/cylat15a.tem - ^Content/ts/firestorm/cylat16.tem: firestorm/cylat16.tem - ^Content/ts/firestorm/cylat16a.tem: firestorm/cylat16a.tem - ^Content/ts/firestorm/slat01.tem: firestorm/slat01.tem - ^Content/ts/firestorm/slat01a.tem: firestorm/slat01a.tem - ^Content/ts/firestorm/slat02.tem: firestorm/slat02.tem - ^Content/ts/firestorm/slat02a.tem: firestorm/slat02a.tem - ^Content/ts/firestorm/slat03.tem: firestorm/slat03.tem - ^Content/ts/firestorm/slat03a.tem: firestorm/slat03a.tem - ^Content/ts/firestorm/slat04.tem: firestorm/slat04.tem - ^Content/ts/firestorm/slat04a.tem: firestorm/slat04a.tem - ^Content/ts/firestorm/slat05.tem: firestorm/slat05.tem - ^Content/ts/firestorm/slat05a.tem: firestorm/slat05a.tem - ^Content/ts/firestorm/slat06.tem: firestorm/slat06.tem - ^Content/ts/firestorm/slat06a.tem: firestorm/slat06a.tem - ^Content/ts/firestorm/slat07.tem: firestorm/slat07.tem - ^Content/ts/firestorm/slat07a.tem: firestorm/slat07a.tem - ^Content/ts/firestorm/slat08.tem: firestorm/slat08.tem - ^Content/ts/firestorm/slat08a.tem: firestorm/slat08a.tem - ^Content/ts/firestorm/slat09.tem: firestorm/slat09.tem - ^Content/ts/firestorm/slat09a.tem: firestorm/slat09a.tem - ^Content/ts/firestorm/slat10.tem: firestorm/slat10.tem - ^Content/ts/firestorm/slat10a.tem: firestorm/slat10a.tem - ^Content/ts/firestorm/slat11.tem: firestorm/slat11.tem - ^Content/ts/firestorm/slat11a.tem: firestorm/slat11a.tem - ^Content/ts/firestorm/slat12.tem: firestorm/slat12.tem - ^Content/ts/firestorm/slat12a.tem: firestorm/slat12a.tem - ^Content/ts/firestorm/slat13.tem: firestorm/slat13.tem - ^Content/ts/firestorm/slat13a.tem: firestorm/slat13a.tem - ^Content/ts/firestorm/slat14.tem: firestorm/slat14.tem - ^Content/ts/firestorm/slat14a.tem: firestorm/slat14a.tem - ^Content/ts/firestorm/slat15.tem: firestorm/slat15.tem - ^Content/ts/firestorm/slat15a.tem: firestorm/slat15a.tem - ^Content/ts/firestorm/slat16.tem: firestorm/slat16.tem - ^Content/ts/firestorm/slat16a.tem: firestorm/slat16a.tem - ^Content/ts/firestorm/swamp01.tem: firestorm/swamp01.tem - ^Content/ts/firestorm/swamp01a.tem: firestorm/swamp01a.tem - ^Content/ts/firestorm/swamp01b.tem: firestorm/swamp01b.tem - ^Content/ts/firestorm/swamp01c.tem: firestorm/swamp01c.tem - ^Content/ts/firestorm/swamp01d.tem: firestorm/swamp01d.tem - ^Content/ts/firestorm/swamp01e.tem: firestorm/swamp01e.tem - ^Content/ts/firestorm/swamp01f.tem: firestorm/swamp01f.tem - ^Content/ts/firestorm/swamp01g.tem: firestorm/swamp01g.tem - ^Content/ts/firestorm/swamp02.tem: firestorm/swamp02.tem - ^Content/ts/firestorm/swamp03.tem: firestorm/swamp03.tem - ^Content/ts/firestorm/swamp04.tem: firestorm/swamp04.tem - ^Content/ts/firestorm/swamp05.tem: firestorm/swamp05.tem - ^Content/ts/firestorm/swamp06.tem: firestorm/swamp06.tem - ^Content/ts/firestorm/swamp07.tem: firestorm/swamp07.tem - ^Content/ts/firestorm/swamp08.tem: firestorm/swamp08.tem - ^Content/ts/firestorm/swamp09.tem: firestorm/swamp09.tem - ^Content/ts/firestorm/fona01.tem: firestorm/fona01.tem - ^Content/ts/firestorm/fona02.tem: firestorm/fona02.tem - ^Content/ts/firestorm/fona03.tem: firestorm/fona03.tem - ^Content/ts/firestorm/fona04.tem: firestorm/fona04.tem - ^Content/ts/firestorm/fona05.tem: firestorm/fona05.tem - ^Content/ts/firestorm/fona06.tem: firestorm/fona06.tem - ^Content/ts/firestorm/fona07.tem: firestorm/fona07.tem - ^Content/ts/firestorm/fona08.tem: firestorm/fona08.tem - ^Content/ts/firestorm/fona09.tem: firestorm/fona09.tem - ^Content/ts/firestorm/fona10.tem: firestorm/fona10.tem - ^Content/ts/firestorm/fona11.tem: firestorm/fona11.tem - ^Content/ts/firestorm/fona12.tem: firestorm/fona12.tem - ^Content/ts/firestorm/fona13.tem: firestorm/fona13.tem - ^Content/ts/firestorm/fona14.tem: firestorm/fona14.tem - ^Content/ts/firestorm/fona15.tem: firestorm/fona15.tem - ^Content/ts/firestorm/bigblue3.tem: firestorm/bigblue3.tem - -fstorm-music: Expansion Freeware Music - SHA1: 74b1ec47ea8c9815fb85c998963229aa0a8f8619 - MirrorList: http://www.openra.net/packages/fs-music-mirrors.txt - Extract: - ^Content/ts/firestorm/dmachine.aud: firestorm/dmachine.aud - ^Content/ts/firestorm/elusive.aud: firestorm/elusive.aud - ^Content/ts/firestorm/fsmap.aud: firestorm/fsmap.aud - ^Content/ts/firestorm/fsmenu.aud: firestorm/fsmenu.aud - ^Content/ts/firestorm/hacker.aud: firestorm/hacker.aud - ^Content/ts/firestorm/infiltra.aud: firestorm/infiltra.aud - ^Content/ts/firestorm/kmachine.aud: firestorm/kmachine.aud - ^Content/ts/firestorm/linkup.aud: firestorm/linkup.aud - ^Content/ts/firestorm/rainnite.aud: firestorm/rainnite.aud - ^Content/ts/firestorm/slavesys.aud: firestorm/slavesys.aud + ^SupportDir|Content/ts/firestorm/c_kodiak.shp: firestorm/c_kodiak.shp + ^SupportDir|Content/ts/firestorm/coremk.shp: firestorm/coremk.shp + ^SupportDir|Content/ts/firestorm/defdmk.shp: firestorm/defdmk.shp + ^SupportDir|Content/ts/firestorm/k_light1.shp: firestorm/k_light1.shp + ^SupportDir|Content/ts/firestorm/k_light2.shp: firestorm/k_light2.shp + ^SupportDir|Content/ts/firestorm/mstlmk.shp: firestorm/mstlmk.shp + ^SupportDir|Content/ts/firestorm/mwarmk.shp: firestorm/mwarmk.shp + ^SupportDir|Content/ts/firestorm/djuggbar.hva: firestorm/djuggbar.hva + ^SupportDir|Content/ts/firestorm/m_emp.hva: firestorm/m_emp.hva + ^SupportDir|Content/ts/firestorm/mwar_nod.hva: firestorm/mwar_nod.hva + ^SupportDir|Content/ts/firestorm/sgen.hva: firestorm/sgen.hva + ^SupportDir|Content/ts/firestorm/djuggbar.vxl: firestorm/djuggbar.vxl + ^SupportDir|Content/ts/firestorm/m_emp.vxl: firestorm/m_emp.vxl + ^SupportDir|Content/ts/firestorm/mwar_nod.vxl: firestorm/mwar_nod.vxl + ^SupportDir|Content/ts/firestorm/sgen.vxl: firestorm/sgen.vxl + ^SupportDir|Content/ts/firestorm/e01sc01.mix: firestorm/e01sc01.mix + ^SupportDir|Content/ts/firestorm/e01sc02.mix: firestorm/e01sc02.mix + ^SupportDir|Content/ts/firestorm/e01vox01.mix: firestorm/e01vox01.mix + ^SupportDir|Content/ts/firestorm/e01vox02.mix: firestorm/e01vox02.mix + ^SupportDir|Content/ts/firestorm/ecache01.mix: firestorm/ecache01.mix + ^SupportDir|Content/ts/firestorm/sounds01.mix: firestorm/sounds01.mix + ^SupportDir|Content/ts/firestorm/blat01.tem: firestorm/blat01.tem + ^SupportDir|Content/ts/firestorm/blat01a.tem: firestorm/blat01a.tem + ^SupportDir|Content/ts/firestorm/blat02.tem: firestorm/blat02.tem + ^SupportDir|Content/ts/firestorm/blat02a.tem: firestorm/blat02a.tem + ^SupportDir|Content/ts/firestorm/blat03.tem: firestorm/blat03.tem + ^SupportDir|Content/ts/firestorm/blat03a.tem: firestorm/blat03a.tem + ^SupportDir|Content/ts/firestorm/blat04.tem: firestorm/blat04.tem + ^SupportDir|Content/ts/firestorm/blat04a.tem: firestorm/blat04a.tem + ^SupportDir|Content/ts/firestorm/blat05.tem: firestorm/blat05.tem + ^SupportDir|Content/ts/firestorm/blat05a.tem: firestorm/blat05a.tem + ^SupportDir|Content/ts/firestorm/blat06.tem: firestorm/blat06.tem + ^SupportDir|Content/ts/firestorm/blat06a.tem: firestorm/blat06a.tem + ^SupportDir|Content/ts/firestorm/blat07.tem: firestorm/blat07.tem + ^SupportDir|Content/ts/firestorm/blat07a.tem: firestorm/blat07a.tem + ^SupportDir|Content/ts/firestorm/blat08.tem: firestorm/blat08.tem + ^SupportDir|Content/ts/firestorm/blat08a.tem: firestorm/blat08a.tem + ^SupportDir|Content/ts/firestorm/blat09.tem: firestorm/blat09.tem + ^SupportDir|Content/ts/firestorm/blat09a.tem: firestorm/blat09a.tem + ^SupportDir|Content/ts/firestorm/blat10.tem: firestorm/blat10.tem + ^SupportDir|Content/ts/firestorm/blat10a.tem: firestorm/blat10a.tem + ^SupportDir|Content/ts/firestorm/blat11.tem: firestorm/blat11.tem + ^SupportDir|Content/ts/firestorm/blat11a.tem: firestorm/blat11a.tem + ^SupportDir|Content/ts/firestorm/blat12.tem: firestorm/blat12.tem + ^SupportDir|Content/ts/firestorm/blat12a.tem: firestorm/blat12a.tem + ^SupportDir|Content/ts/firestorm/blat13.tem: firestorm/blat13.tem + ^SupportDir|Content/ts/firestorm/blat13a.tem: firestorm/blat13a.tem + ^SupportDir|Content/ts/firestorm/blat14.tem: firestorm/blat14.tem + ^SupportDir|Content/ts/firestorm/blat14a.tem: firestorm/blat14a.tem + ^SupportDir|Content/ts/firestorm/blat15.tem: firestorm/blat15.tem + ^SupportDir|Content/ts/firestorm/blat15a.tem: firestorm/blat15a.tem + ^SupportDir|Content/ts/firestorm/blat16.tem: firestorm/blat16.tem + ^SupportDir|Content/ts/firestorm/blat16a.tem: firestorm/blat16a.tem + ^SupportDir|Content/ts/firestorm/blue01.tem: firestorm/blue01.tem + ^SupportDir|Content/ts/firestorm/blue01a.tem: firestorm/blue01a.tem + ^SupportDir|Content/ts/firestorm/blue01b.tem: firestorm/blue01b.tem + ^SupportDir|Content/ts/firestorm/blue01c.tem: firestorm/blue01c.tem + ^SupportDir|Content/ts/firestorm/blue01d.tem: firestorm/blue01d.tem + ^SupportDir|Content/ts/firestorm/blue01e.tem: firestorm/blue01e.tem + ^SupportDir|Content/ts/firestorm/blue01f.tem: firestorm/blue01f.tem + ^SupportDir|Content/ts/firestorm/blue01g.tem: firestorm/blue01g.tem + ^SupportDir|Content/ts/firestorm/ccliff01.tem: firestorm/ccliff01.tem + ^SupportDir|Content/ts/firestorm/ccliff02.tem: firestorm/ccliff02.tem + ^SupportDir|Content/ts/firestorm/ccliff03.tem: firestorm/ccliff03.tem + ^SupportDir|Content/ts/firestorm/ccliff04.tem: firestorm/ccliff04.tem + ^SupportDir|Content/ts/firestorm/ccliff05.tem: firestorm/ccliff05.tem + ^SupportDir|Content/ts/firestorm/ccliff06.tem: firestorm/ccliff06.tem + ^SupportDir|Content/ts/firestorm/crash01.tem: firestorm/crash01.tem + ^SupportDir|Content/ts/firestorm/crash02.tem: firestorm/crash02.tem + ^SupportDir|Content/ts/firestorm/crash03.tem: firestorm/crash03.tem + ^SupportDir|Content/ts/firestorm/crash04.tem: firestorm/crash04.tem + ^SupportDir|Content/ts/firestorm/crash05.tem: firestorm/crash05.tem + ^SupportDir|Content/ts/firestorm/crash06.tem: firestorm/crash06.tem + ^SupportDir|Content/ts/firestorm/crash07.tem: firestorm/crash07.tem + ^SupportDir|Content/ts/firestorm/crys01.tem: firestorm/crys01.tem + ^SupportDir|Content/ts/firestorm/crys01a.tem: firestorm/crys01a.tem + ^SupportDir|Content/ts/firestorm/crys01b.tem: firestorm/crys01b.tem + ^SupportDir|Content/ts/firestorm/crys01c.tem: firestorm/crys01c.tem + ^SupportDir|Content/ts/firestorm/crys01d.tem: firestorm/crys01d.tem + ^SupportDir|Content/ts/firestorm/crys01e.tem: firestorm/crys01e.tem + ^SupportDir|Content/ts/firestorm/crys01f.tem: firestorm/crys01f.tem + ^SupportDir|Content/ts/firestorm/crys01g.tem: firestorm/crys01g.tem + ^SupportDir|Content/ts/firestorm/cylat01.tem: firestorm/cylat01.tem + ^SupportDir|Content/ts/firestorm/cylat01a.tem: firestorm/cylat01a.tem + ^SupportDir|Content/ts/firestorm/cylat02.tem: firestorm/cylat02.tem + ^SupportDir|Content/ts/firestorm/cylat02a.tem: firestorm/cylat02a.tem + ^SupportDir|Content/ts/firestorm/cylat03.tem: firestorm/cylat03.tem + ^SupportDir|Content/ts/firestorm/cylat03a.tem: firestorm/cylat03a.tem + ^SupportDir|Content/ts/firestorm/cylat04.tem: firestorm/cylat04.tem + ^SupportDir|Content/ts/firestorm/cylat04a.tem: firestorm/cylat04a.tem + ^SupportDir|Content/ts/firestorm/cylat05.tem: firestorm/cylat05.tem + ^SupportDir|Content/ts/firestorm/cylat05a.tem: firestorm/cylat05a.tem + ^SupportDir|Content/ts/firestorm/cylat06.tem: firestorm/cylat06.tem + ^SupportDir|Content/ts/firestorm/cylat06a.tem: firestorm/cylat06a.tem + ^SupportDir|Content/ts/firestorm/cylat07.tem: firestorm/cylat07.tem + ^SupportDir|Content/ts/firestorm/cylat07a.tem: firestorm/cylat07a.tem + ^SupportDir|Content/ts/firestorm/cylat08.tem: firestorm/cylat08.tem + ^SupportDir|Content/ts/firestorm/cylat08a.tem: firestorm/cylat08a.tem + ^SupportDir|Content/ts/firestorm/cylat09.tem: firestorm/cylat09.tem + ^SupportDir|Content/ts/firestorm/cylat09a.tem: firestorm/cylat09a.tem + ^SupportDir|Content/ts/firestorm/cylat10.tem: firestorm/cylat10.tem + ^SupportDir|Content/ts/firestorm/cylat10a.tem: firestorm/cylat10a.tem + ^SupportDir|Content/ts/firestorm/cylat11.tem: firestorm/cylat11.tem + ^SupportDir|Content/ts/firestorm/cylat11a.tem: firestorm/cylat11a.tem + ^SupportDir|Content/ts/firestorm/cylat12.tem: firestorm/cylat12.tem + ^SupportDir|Content/ts/firestorm/cylat12a.tem: firestorm/cylat12a.tem + ^SupportDir|Content/ts/firestorm/cylat13.tem: firestorm/cylat13.tem + ^SupportDir|Content/ts/firestorm/cylat13a.tem: firestorm/cylat13a.tem + ^SupportDir|Content/ts/firestorm/cylat14.tem: firestorm/cylat14.tem + ^SupportDir|Content/ts/firestorm/cylat14a.tem: firestorm/cylat14a.tem + ^SupportDir|Content/ts/firestorm/cylat15.tem: firestorm/cylat15.tem + ^SupportDir|Content/ts/firestorm/cylat15a.tem: firestorm/cylat15a.tem + ^SupportDir|Content/ts/firestorm/cylat16.tem: firestorm/cylat16.tem + ^SupportDir|Content/ts/firestorm/cylat16a.tem: firestorm/cylat16a.tem + ^SupportDir|Content/ts/firestorm/slat01.tem: firestorm/slat01.tem + ^SupportDir|Content/ts/firestorm/slat01a.tem: firestorm/slat01a.tem + ^SupportDir|Content/ts/firestorm/slat02.tem: firestorm/slat02.tem + ^SupportDir|Content/ts/firestorm/slat02a.tem: firestorm/slat02a.tem + ^SupportDir|Content/ts/firestorm/slat03.tem: firestorm/slat03.tem + ^SupportDir|Content/ts/firestorm/slat03a.tem: firestorm/slat03a.tem + ^SupportDir|Content/ts/firestorm/slat04.tem: firestorm/slat04.tem + ^SupportDir|Content/ts/firestorm/slat04a.tem: firestorm/slat04a.tem + ^SupportDir|Content/ts/firestorm/slat05.tem: firestorm/slat05.tem + ^SupportDir|Content/ts/firestorm/slat05a.tem: firestorm/slat05a.tem + ^SupportDir|Content/ts/firestorm/slat06.tem: firestorm/slat06.tem + ^SupportDir|Content/ts/firestorm/slat06a.tem: firestorm/slat06a.tem + ^SupportDir|Content/ts/firestorm/slat07.tem: firestorm/slat07.tem + ^SupportDir|Content/ts/firestorm/slat07a.tem: firestorm/slat07a.tem + ^SupportDir|Content/ts/firestorm/slat08.tem: firestorm/slat08.tem + ^SupportDir|Content/ts/firestorm/slat08a.tem: firestorm/slat08a.tem + ^SupportDir|Content/ts/firestorm/slat09.tem: firestorm/slat09.tem + ^SupportDir|Content/ts/firestorm/slat09a.tem: firestorm/slat09a.tem + ^SupportDir|Content/ts/firestorm/slat10.tem: firestorm/slat10.tem + ^SupportDir|Content/ts/firestorm/slat10a.tem: firestorm/slat10a.tem + ^SupportDir|Content/ts/firestorm/slat11.tem: firestorm/slat11.tem + ^SupportDir|Content/ts/firestorm/slat11a.tem: firestorm/slat11a.tem + ^SupportDir|Content/ts/firestorm/slat12.tem: firestorm/slat12.tem + ^SupportDir|Content/ts/firestorm/slat12a.tem: firestorm/slat12a.tem + ^SupportDir|Content/ts/firestorm/slat13.tem: firestorm/slat13.tem + ^SupportDir|Content/ts/firestorm/slat13a.tem: firestorm/slat13a.tem + ^SupportDir|Content/ts/firestorm/slat14.tem: firestorm/slat14.tem + ^SupportDir|Content/ts/firestorm/slat14a.tem: firestorm/slat14a.tem + ^SupportDir|Content/ts/firestorm/slat15.tem: firestorm/slat15.tem + ^SupportDir|Content/ts/firestorm/slat15a.tem: firestorm/slat15a.tem + ^SupportDir|Content/ts/firestorm/slat16.tem: firestorm/slat16.tem + ^SupportDir|Content/ts/firestorm/slat16a.tem: firestorm/slat16a.tem + ^SupportDir|Content/ts/firestorm/swamp01.tem: firestorm/swamp01.tem + ^SupportDir|Content/ts/firestorm/swamp01a.tem: firestorm/swamp01a.tem + ^SupportDir|Content/ts/firestorm/swamp01b.tem: firestorm/swamp01b.tem + ^SupportDir|Content/ts/firestorm/swamp01c.tem: firestorm/swamp01c.tem + ^SupportDir|Content/ts/firestorm/swamp01d.tem: firestorm/swamp01d.tem + ^SupportDir|Content/ts/firestorm/swamp01e.tem: firestorm/swamp01e.tem + ^SupportDir|Content/ts/firestorm/swamp01f.tem: firestorm/swamp01f.tem + ^SupportDir|Content/ts/firestorm/swamp01g.tem: firestorm/swamp01g.tem + ^SupportDir|Content/ts/firestorm/swamp02.tem: firestorm/swamp02.tem + ^SupportDir|Content/ts/firestorm/swamp03.tem: firestorm/swamp03.tem + ^SupportDir|Content/ts/firestorm/swamp04.tem: firestorm/swamp04.tem + ^SupportDir|Content/ts/firestorm/swamp05.tem: firestorm/swamp05.tem + ^SupportDir|Content/ts/firestorm/swamp06.tem: firestorm/swamp06.tem + ^SupportDir|Content/ts/firestorm/swamp07.tem: firestorm/swamp07.tem + ^SupportDir|Content/ts/firestorm/swamp08.tem: firestorm/swamp08.tem + ^SupportDir|Content/ts/firestorm/swamp09.tem: firestorm/swamp09.tem + ^SupportDir|Content/ts/firestorm/fona01.tem: firestorm/fona01.tem + ^SupportDir|Content/ts/firestorm/fona02.tem: firestorm/fona02.tem + ^SupportDir|Content/ts/firestorm/fona03.tem: firestorm/fona03.tem + ^SupportDir|Content/ts/firestorm/fona04.tem: firestorm/fona04.tem + ^SupportDir|Content/ts/firestorm/fona05.tem: firestorm/fona05.tem + ^SupportDir|Content/ts/firestorm/fona06.tem: firestorm/fona06.tem + ^SupportDir|Content/ts/firestorm/fona07.tem: firestorm/fona07.tem + ^SupportDir|Content/ts/firestorm/fona08.tem: firestorm/fona08.tem + ^SupportDir|Content/ts/firestorm/fona09.tem: firestorm/fona09.tem + ^SupportDir|Content/ts/firestorm/fona10.tem: firestorm/fona10.tem + ^SupportDir|Content/ts/firestorm/fona11.tem: firestorm/fona11.tem + ^SupportDir|Content/ts/firestorm/fona12.tem: firestorm/fona12.tem + ^SupportDir|Content/ts/firestorm/fona13.tem: firestorm/fona13.tem + ^SupportDir|Content/ts/firestorm/fona14.tem: firestorm/fona14.tem + ^SupportDir|Content/ts/firestorm/fona15.tem: firestorm/fona15.tem + ^SupportDir|Content/ts/firestorm/bigblue3.tem: firestorm/bigblue3.tem quickinstall: Quick Install Package SHA1: d9339e7b6ecf624ac6ca91d25c58b88fb88a49d2 MirrorList: http://www.openra.net/packages/ts-quickinstall-mirrors.txt Extract: - ^Content/ts/cache.mix: cache.mix - ^Content/ts/conquer.mix: conquer.mix - ^Content/ts/isosnow.mix: isosnow.mix - ^Content/ts/isotemp.mix: isotemp.mix - ^Content/ts/local.mix: local.mix - ^Content/ts/sidec01.mix: sidec01.mix - ^Content/ts/sidec02.mix: sidec02.mix - ^Content/ts/sno.mix: sno.mix - ^Content/ts/snow.mix: snow.mix - ^Content/ts/sounds.mix: sounds.mix - ^Content/ts/speech01.mix: speech01.mix - ^Content/ts/speech02.mix: speech02.mix - ^Content/ts/tem.mix: tem.mix - ^Content/ts/temperat.mix: temperat.mix - ^Content/ts/firestorm/c_kodiak.shp: firestorm/c_kodiak.shp - ^Content/ts/firestorm/coremk.shp: firestorm/coremk.shp - ^Content/ts/firestorm/defdmk.shp: firestorm/defdmk.shp - ^Content/ts/firestorm/k_light1.shp: firestorm/k_light1.shp - ^Content/ts/firestorm/k_light2.shp: firestorm/k_light2.shp - ^Content/ts/firestorm/mstlmk.shp: firestorm/mstlmk.shp - ^Content/ts/firestorm/mwarmk.shp: firestorm/mwarmk.shp - ^Content/ts/firestorm/djuggbar.hva: firestorm/djuggbar.hva - ^Content/ts/firestorm/m_emp.hva: firestorm/m_emp.hva - ^Content/ts/firestorm/mwar_nod.hva: firestorm/mwar_nod.hva - ^Content/ts/firestorm/sgen.hva: firestorm/sgen.hva - ^Content/ts/firestorm/djuggbar.vxl: firestorm/djuggbar.vxl - ^Content/ts/firestorm/m_emp.vxl: firestorm/m_emp.vxl - ^Content/ts/firestorm/mwar_nod.vxl: firestorm/mwar_nod.vxl - ^Content/ts/firestorm/sgen.vxl: firestorm/sgen.vxl - ^Content/ts/firestorm/e01sc01.mix: firestorm/e01sc01.mix - ^Content/ts/firestorm/e01sc02.mix: firestorm/e01sc02.mix - ^Content/ts/firestorm/e01vox01.mix: firestorm/e01vox01.mix - ^Content/ts/firestorm/e01vox02.mix: firestorm/e01vox02.mix - ^Content/ts/firestorm/ecache01.mix: firestorm/ecache01.mix - ^Content/ts/firestorm/sounds01.mix: firestorm/sounds01.mix - ^Content/ts/firestorm/blat01.tem: firestorm/blat01.tem - ^Content/ts/firestorm/blat01a.tem: firestorm/blat01a.tem - ^Content/ts/firestorm/blat02.tem: firestorm/blat02.tem - ^Content/ts/firestorm/blat02a.tem: firestorm/blat02a.tem - ^Content/ts/firestorm/blat03.tem: firestorm/blat03.tem - ^Content/ts/firestorm/blat03a.tem: firestorm/blat03a.tem - ^Content/ts/firestorm/blat04.tem: firestorm/blat04.tem - ^Content/ts/firestorm/blat04a.tem: firestorm/blat04a.tem - ^Content/ts/firestorm/blat05.tem: firestorm/blat05.tem - ^Content/ts/firestorm/blat05a.tem: firestorm/blat05a.tem - ^Content/ts/firestorm/blat06.tem: firestorm/blat06.tem - ^Content/ts/firestorm/blat06a.tem: firestorm/blat06a.tem - ^Content/ts/firestorm/blat07.tem: firestorm/blat07.tem - ^Content/ts/firestorm/blat07a.tem: firestorm/blat07a.tem - ^Content/ts/firestorm/blat08.tem: firestorm/blat08.tem - ^Content/ts/firestorm/blat08a.tem: firestorm/blat08a.tem - ^Content/ts/firestorm/blat09.tem: firestorm/blat09.tem - ^Content/ts/firestorm/blat09a.tem: firestorm/blat09a.tem - ^Content/ts/firestorm/blat10.tem: firestorm/blat10.tem - ^Content/ts/firestorm/blat10a.tem: firestorm/blat10a.tem - ^Content/ts/firestorm/blat11.tem: firestorm/blat11.tem - ^Content/ts/firestorm/blat11a.tem: firestorm/blat11a.tem - ^Content/ts/firestorm/blat12.tem: firestorm/blat12.tem - ^Content/ts/firestorm/blat12a.tem: firestorm/blat12a.tem - ^Content/ts/firestorm/blat13.tem: firestorm/blat13.tem - ^Content/ts/firestorm/blat13a.tem: firestorm/blat13a.tem - ^Content/ts/firestorm/blat14.tem: firestorm/blat14.tem - ^Content/ts/firestorm/blat14a.tem: firestorm/blat14a.tem - ^Content/ts/firestorm/blat15.tem: firestorm/blat15.tem - ^Content/ts/firestorm/blat15a.tem: firestorm/blat15a.tem - ^Content/ts/firestorm/blat16.tem: firestorm/blat16.tem - ^Content/ts/firestorm/blat16a.tem: firestorm/blat16a.tem - ^Content/ts/firestorm/blue01.tem: firestorm/blue01.tem - ^Content/ts/firestorm/blue01a.tem: firestorm/blue01a.tem - ^Content/ts/firestorm/blue01b.tem: firestorm/blue01b.tem - ^Content/ts/firestorm/blue01c.tem: firestorm/blue01c.tem - ^Content/ts/firestorm/blue01d.tem: firestorm/blue01d.tem - ^Content/ts/firestorm/blue01e.tem: firestorm/blue01e.tem - ^Content/ts/firestorm/blue01f.tem: firestorm/blue01f.tem - ^Content/ts/firestorm/blue01g.tem: firestorm/blue01g.tem - ^Content/ts/firestorm/ccliff01.tem: firestorm/ccliff01.tem - ^Content/ts/firestorm/ccliff02.tem: firestorm/ccliff02.tem - ^Content/ts/firestorm/ccliff03.tem: firestorm/ccliff03.tem - ^Content/ts/firestorm/ccliff04.tem: firestorm/ccliff04.tem - ^Content/ts/firestorm/ccliff05.tem: firestorm/ccliff05.tem - ^Content/ts/firestorm/ccliff06.tem: firestorm/ccliff06.tem - ^Content/ts/firestorm/crash01.tem: firestorm/crash01.tem - ^Content/ts/firestorm/crash02.tem: firestorm/crash02.tem - ^Content/ts/firestorm/crash03.tem: firestorm/crash03.tem - ^Content/ts/firestorm/crash04.tem: firestorm/crash04.tem - ^Content/ts/firestorm/crash05.tem: firestorm/crash05.tem - ^Content/ts/firestorm/crash06.tem: firestorm/crash06.tem - ^Content/ts/firestorm/crash07.tem: firestorm/crash07.tem - ^Content/ts/firestorm/crys01.tem: firestorm/crys01.tem - ^Content/ts/firestorm/crys01a.tem: firestorm/crys01a.tem - ^Content/ts/firestorm/crys01b.tem: firestorm/crys01b.tem - ^Content/ts/firestorm/crys01c.tem: firestorm/crys01c.tem - ^Content/ts/firestorm/crys01d.tem: firestorm/crys01d.tem - ^Content/ts/firestorm/crys01e.tem: firestorm/crys01e.tem - ^Content/ts/firestorm/crys01f.tem: firestorm/crys01f.tem - ^Content/ts/firestorm/crys01g.tem: firestorm/crys01g.tem - ^Content/ts/firestorm/cylat01.tem: firestorm/cylat01.tem - ^Content/ts/firestorm/cylat01a.tem: firestorm/cylat01a.tem - ^Content/ts/firestorm/cylat02.tem: firestorm/cylat02.tem - ^Content/ts/firestorm/cylat02a.tem: firestorm/cylat02a.tem - ^Content/ts/firestorm/cylat03.tem: firestorm/cylat03.tem - ^Content/ts/firestorm/cylat03a.tem: firestorm/cylat03a.tem - ^Content/ts/firestorm/cylat04.tem: firestorm/cylat04.tem - ^Content/ts/firestorm/cylat04a.tem: firestorm/cylat04a.tem - ^Content/ts/firestorm/cylat05.tem: firestorm/cylat05.tem - ^Content/ts/firestorm/cylat05a.tem: firestorm/cylat05a.tem - ^Content/ts/firestorm/cylat06.tem: firestorm/cylat06.tem - ^Content/ts/firestorm/cylat06a.tem: firestorm/cylat06a.tem - ^Content/ts/firestorm/cylat07.tem: firestorm/cylat07.tem - ^Content/ts/firestorm/cylat07a.tem: firestorm/cylat07a.tem - ^Content/ts/firestorm/cylat08.tem: firestorm/cylat08.tem - ^Content/ts/firestorm/cylat08a.tem: firestorm/cylat08a.tem - ^Content/ts/firestorm/cylat09.tem: firestorm/cylat09.tem - ^Content/ts/firestorm/cylat09a.tem: firestorm/cylat09a.tem - ^Content/ts/firestorm/cylat10.tem: firestorm/cylat10.tem - ^Content/ts/firestorm/cylat10a.tem: firestorm/cylat10a.tem - ^Content/ts/firestorm/cylat11.tem: firestorm/cylat11.tem - ^Content/ts/firestorm/cylat11a.tem: firestorm/cylat11a.tem - ^Content/ts/firestorm/cylat12.tem: firestorm/cylat12.tem - ^Content/ts/firestorm/cylat12a.tem: firestorm/cylat12a.tem - ^Content/ts/firestorm/cylat13.tem: firestorm/cylat13.tem - ^Content/ts/firestorm/cylat13a.tem: firestorm/cylat13a.tem - ^Content/ts/firestorm/cylat14.tem: firestorm/cylat14.tem - ^Content/ts/firestorm/cylat14a.tem: firestorm/cylat14a.tem - ^Content/ts/firestorm/cylat15.tem: firestorm/cylat15.tem - ^Content/ts/firestorm/cylat15a.tem: firestorm/cylat15a.tem - ^Content/ts/firestorm/cylat16.tem: firestorm/cylat16.tem - ^Content/ts/firestorm/cylat16a.tem: firestorm/cylat16a.tem - ^Content/ts/firestorm/slat01.tem: firestorm/slat01.tem - ^Content/ts/firestorm/slat01a.tem: firestorm/slat01a.tem - ^Content/ts/firestorm/slat02.tem: firestorm/slat02.tem - ^Content/ts/firestorm/slat02a.tem: firestorm/slat02a.tem - ^Content/ts/firestorm/slat03.tem: firestorm/slat03.tem - ^Content/ts/firestorm/slat03a.tem: firestorm/slat03a.tem - ^Content/ts/firestorm/slat04.tem: firestorm/slat04.tem - ^Content/ts/firestorm/slat04a.tem: firestorm/slat04a.tem - ^Content/ts/firestorm/slat05.tem: firestorm/slat05.tem - ^Content/ts/firestorm/slat05a.tem: firestorm/slat05a.tem - ^Content/ts/firestorm/slat06.tem: firestorm/slat06.tem - ^Content/ts/firestorm/slat06a.tem: firestorm/slat06a.tem - ^Content/ts/firestorm/slat07.tem: firestorm/slat07.tem - ^Content/ts/firestorm/slat07a.tem: firestorm/slat07a.tem - ^Content/ts/firestorm/slat08.tem: firestorm/slat08.tem - ^Content/ts/firestorm/slat08a.tem: firestorm/slat08a.tem - ^Content/ts/firestorm/slat09.tem: firestorm/slat09.tem - ^Content/ts/firestorm/slat09a.tem: firestorm/slat09a.tem - ^Content/ts/firestorm/slat10.tem: firestorm/slat10.tem - ^Content/ts/firestorm/slat10a.tem: firestorm/slat10a.tem - ^Content/ts/firestorm/slat11.tem: firestorm/slat11.tem - ^Content/ts/firestorm/slat11a.tem: firestorm/slat11a.tem - ^Content/ts/firestorm/slat12.tem: firestorm/slat12.tem - ^Content/ts/firestorm/slat12a.tem: firestorm/slat12a.tem - ^Content/ts/firestorm/slat13.tem: firestorm/slat13.tem - ^Content/ts/firestorm/slat13a.tem: firestorm/slat13a.tem - ^Content/ts/firestorm/slat14.tem: firestorm/slat14.tem - ^Content/ts/firestorm/slat14a.tem: firestorm/slat14a.tem - ^Content/ts/firestorm/slat15.tem: firestorm/slat15.tem - ^Content/ts/firestorm/slat15a.tem: firestorm/slat15a.tem - ^Content/ts/firestorm/slat16.tem: firestorm/slat16.tem - ^Content/ts/firestorm/slat16a.tem: firestorm/slat16a.tem - ^Content/ts/firestorm/swamp01.tem: firestorm/swamp01.tem - ^Content/ts/firestorm/swamp01a.tem: firestorm/swamp01a.tem - ^Content/ts/firestorm/swamp01b.tem: firestorm/swamp01b.tem - ^Content/ts/firestorm/swamp01c.tem: firestorm/swamp01c.tem - ^Content/ts/firestorm/swamp01d.tem: firestorm/swamp01d.tem - ^Content/ts/firestorm/swamp01e.tem: firestorm/swamp01e.tem - ^Content/ts/firestorm/swamp01f.tem: firestorm/swamp01f.tem - ^Content/ts/firestorm/swamp01g.tem: firestorm/swamp01g.tem - ^Content/ts/firestorm/swamp02.tem: firestorm/swamp02.tem - ^Content/ts/firestorm/swamp03.tem: firestorm/swamp03.tem - ^Content/ts/firestorm/swamp04.tem: firestorm/swamp04.tem - ^Content/ts/firestorm/swamp05.tem: firestorm/swamp05.tem - ^Content/ts/firestorm/swamp06.tem: firestorm/swamp06.tem - ^Content/ts/firestorm/swamp07.tem: firestorm/swamp07.tem - ^Content/ts/firestorm/swamp08.tem: firestorm/swamp08.tem - ^Content/ts/firestorm/swamp09.tem: firestorm/swamp09.tem - ^Content/ts/firestorm/fona01.tem: firestorm/fona01.tem - ^Content/ts/firestorm/fona02.tem: firestorm/fona02.tem - ^Content/ts/firestorm/fona03.tem: firestorm/fona03.tem - ^Content/ts/firestorm/fona04.tem: firestorm/fona04.tem - ^Content/ts/firestorm/fona05.tem: firestorm/fona05.tem - ^Content/ts/firestorm/fona06.tem: firestorm/fona06.tem - ^Content/ts/firestorm/fona07.tem: firestorm/fona07.tem - ^Content/ts/firestorm/fona08.tem: firestorm/fona08.tem - ^Content/ts/firestorm/fona09.tem: firestorm/fona09.tem - ^Content/ts/firestorm/fona10.tem: firestorm/fona10.tem - ^Content/ts/firestorm/fona11.tem: firestorm/fona11.tem - ^Content/ts/firestorm/fona12.tem: firestorm/fona12.tem - ^Content/ts/firestorm/fona13.tem: firestorm/fona13.tem - ^Content/ts/firestorm/fona14.tem: firestorm/fona14.tem - ^Content/ts/firestorm/fona15.tem: firestorm/fona15.tem - ^Content/ts/firestorm/bigblue3.tem: firestorm/bigblue3.tem + ^SupportDir|Content/ts/cache.mix: cache.mix + ^SupportDir|Content/ts/conquer.mix: conquer.mix + ^SupportDir|Content/ts/isosnow.mix: isosnow.mix + ^SupportDir|Content/ts/isotemp.mix: isotemp.mix + ^SupportDir|Content/ts/local.mix: local.mix + ^SupportDir|Content/ts/sidec01.mix: sidec01.mix + ^SupportDir|Content/ts/sidec02.mix: sidec02.mix + ^SupportDir|Content/ts/sno.mix: sno.mix + ^SupportDir|Content/ts/snow.mix: snow.mix + ^SupportDir|Content/ts/sounds.mix: sounds.mix + ^SupportDir|Content/ts/speech01.mix: speech01.mix + ^SupportDir|Content/ts/speech02.mix: speech02.mix + ^SupportDir|Content/ts/tem.mix: tem.mix + ^SupportDir|Content/ts/temperat.mix: temperat.mix + ^SupportDir|Content/ts/firestorm/c_kodiak.shp: firestorm/c_kodiak.shp + ^SupportDir|Content/ts/firestorm/coremk.shp: firestorm/coremk.shp + ^SupportDir|Content/ts/firestorm/defdmk.shp: firestorm/defdmk.shp + ^SupportDir|Content/ts/firestorm/k_light1.shp: firestorm/k_light1.shp + ^SupportDir|Content/ts/firestorm/k_light2.shp: firestorm/k_light2.shp + ^SupportDir|Content/ts/firestorm/mstlmk.shp: firestorm/mstlmk.shp + ^SupportDir|Content/ts/firestorm/mwarmk.shp: firestorm/mwarmk.shp + ^SupportDir|Content/ts/firestorm/djuggbar.hva: firestorm/djuggbar.hva + ^SupportDir|Content/ts/firestorm/m_emp.hva: firestorm/m_emp.hva + ^SupportDir|Content/ts/firestorm/mwar_nod.hva: firestorm/mwar_nod.hva + ^SupportDir|Content/ts/firestorm/sgen.hva: firestorm/sgen.hva + ^SupportDir|Content/ts/firestorm/djuggbar.vxl: firestorm/djuggbar.vxl + ^SupportDir|Content/ts/firestorm/m_emp.vxl: firestorm/m_emp.vxl + ^SupportDir|Content/ts/firestorm/mwar_nod.vxl: firestorm/mwar_nod.vxl + ^SupportDir|Content/ts/firestorm/sgen.vxl: firestorm/sgen.vxl + ^SupportDir|Content/ts/firestorm/e01sc01.mix: firestorm/e01sc01.mix + ^SupportDir|Content/ts/firestorm/e01sc02.mix: firestorm/e01sc02.mix + ^SupportDir|Content/ts/firestorm/e01vox01.mix: firestorm/e01vox01.mix + ^SupportDir|Content/ts/firestorm/e01vox02.mix: firestorm/e01vox02.mix + ^SupportDir|Content/ts/firestorm/ecache01.mix: firestorm/ecache01.mix + ^SupportDir|Content/ts/firestorm/sounds01.mix: firestorm/sounds01.mix + ^SupportDir|Content/ts/firestorm/blat01.tem: firestorm/blat01.tem + ^SupportDir|Content/ts/firestorm/blat01a.tem: firestorm/blat01a.tem + ^SupportDir|Content/ts/firestorm/blat02.tem: firestorm/blat02.tem + ^SupportDir|Content/ts/firestorm/blat02a.tem: firestorm/blat02a.tem + ^SupportDir|Content/ts/firestorm/blat03.tem: firestorm/blat03.tem + ^SupportDir|Content/ts/firestorm/blat03a.tem: firestorm/blat03a.tem + ^SupportDir|Content/ts/firestorm/blat04.tem: firestorm/blat04.tem + ^SupportDir|Content/ts/firestorm/blat04a.tem: firestorm/blat04a.tem + ^SupportDir|Content/ts/firestorm/blat05.tem: firestorm/blat05.tem + ^SupportDir|Content/ts/firestorm/blat05a.tem: firestorm/blat05a.tem + ^SupportDir|Content/ts/firestorm/blat06.tem: firestorm/blat06.tem + ^SupportDir|Content/ts/firestorm/blat06a.tem: firestorm/blat06a.tem + ^SupportDir|Content/ts/firestorm/blat07.tem: firestorm/blat07.tem + ^SupportDir|Content/ts/firestorm/blat07a.tem: firestorm/blat07a.tem + ^SupportDir|Content/ts/firestorm/blat08.tem: firestorm/blat08.tem + ^SupportDir|Content/ts/firestorm/blat08a.tem: firestorm/blat08a.tem + ^SupportDir|Content/ts/firestorm/blat09.tem: firestorm/blat09.tem + ^SupportDir|Content/ts/firestorm/blat09a.tem: firestorm/blat09a.tem + ^SupportDir|Content/ts/firestorm/blat10.tem: firestorm/blat10.tem + ^SupportDir|Content/ts/firestorm/blat10a.tem: firestorm/blat10a.tem + ^SupportDir|Content/ts/firestorm/blat11.tem: firestorm/blat11.tem + ^SupportDir|Content/ts/firestorm/blat11a.tem: firestorm/blat11a.tem + ^SupportDir|Content/ts/firestorm/blat12.tem: firestorm/blat12.tem + ^SupportDir|Content/ts/firestorm/blat12a.tem: firestorm/blat12a.tem + ^SupportDir|Content/ts/firestorm/blat13.tem: firestorm/blat13.tem + ^SupportDir|Content/ts/firestorm/blat13a.tem: firestorm/blat13a.tem + ^SupportDir|Content/ts/firestorm/blat14.tem: firestorm/blat14.tem + ^SupportDir|Content/ts/firestorm/blat14a.tem: firestorm/blat14a.tem + ^SupportDir|Content/ts/firestorm/blat15.tem: firestorm/blat15.tem + ^SupportDir|Content/ts/firestorm/blat15a.tem: firestorm/blat15a.tem + ^SupportDir|Content/ts/firestorm/blat16.tem: firestorm/blat16.tem + ^SupportDir|Content/ts/firestorm/blat16a.tem: firestorm/blat16a.tem + ^SupportDir|Content/ts/firestorm/blue01.tem: firestorm/blue01.tem + ^SupportDir|Content/ts/firestorm/blue01a.tem: firestorm/blue01a.tem + ^SupportDir|Content/ts/firestorm/blue01b.tem: firestorm/blue01b.tem + ^SupportDir|Content/ts/firestorm/blue01c.tem: firestorm/blue01c.tem + ^SupportDir|Content/ts/firestorm/blue01d.tem: firestorm/blue01d.tem + ^SupportDir|Content/ts/firestorm/blue01e.tem: firestorm/blue01e.tem + ^SupportDir|Content/ts/firestorm/blue01f.tem: firestorm/blue01f.tem + ^SupportDir|Content/ts/firestorm/blue01g.tem: firestorm/blue01g.tem + ^SupportDir|Content/ts/firestorm/ccliff01.tem: firestorm/ccliff01.tem + ^SupportDir|Content/ts/firestorm/ccliff02.tem: firestorm/ccliff02.tem + ^SupportDir|Content/ts/firestorm/ccliff03.tem: firestorm/ccliff03.tem + ^SupportDir|Content/ts/firestorm/ccliff04.tem: firestorm/ccliff04.tem + ^SupportDir|Content/ts/firestorm/ccliff05.tem: firestorm/ccliff05.tem + ^SupportDir|Content/ts/firestorm/ccliff06.tem: firestorm/ccliff06.tem + ^SupportDir|Content/ts/firestorm/crash01.tem: firestorm/crash01.tem + ^SupportDir|Content/ts/firestorm/crash02.tem: firestorm/crash02.tem + ^SupportDir|Content/ts/firestorm/crash03.tem: firestorm/crash03.tem + ^SupportDir|Content/ts/firestorm/crash04.tem: firestorm/crash04.tem + ^SupportDir|Content/ts/firestorm/crash05.tem: firestorm/crash05.tem + ^SupportDir|Content/ts/firestorm/crash06.tem: firestorm/crash06.tem + ^SupportDir|Content/ts/firestorm/crash07.tem: firestorm/crash07.tem + ^SupportDir|Content/ts/firestorm/crys01.tem: firestorm/crys01.tem + ^SupportDir|Content/ts/firestorm/crys01a.tem: firestorm/crys01a.tem + ^SupportDir|Content/ts/firestorm/crys01b.tem: firestorm/crys01b.tem + ^SupportDir|Content/ts/firestorm/crys01c.tem: firestorm/crys01c.tem + ^SupportDir|Content/ts/firestorm/crys01d.tem: firestorm/crys01d.tem + ^SupportDir|Content/ts/firestorm/crys01e.tem: firestorm/crys01e.tem + ^SupportDir|Content/ts/firestorm/crys01f.tem: firestorm/crys01f.tem + ^SupportDir|Content/ts/firestorm/crys01g.tem: firestorm/crys01g.tem + ^SupportDir|Content/ts/firestorm/cylat01.tem: firestorm/cylat01.tem + ^SupportDir|Content/ts/firestorm/cylat01a.tem: firestorm/cylat01a.tem + ^SupportDir|Content/ts/firestorm/cylat02.tem: firestorm/cylat02.tem + ^SupportDir|Content/ts/firestorm/cylat02a.tem: firestorm/cylat02a.tem + ^SupportDir|Content/ts/firestorm/cylat03.tem: firestorm/cylat03.tem + ^SupportDir|Content/ts/firestorm/cylat03a.tem: firestorm/cylat03a.tem + ^SupportDir|Content/ts/firestorm/cylat04.tem: firestorm/cylat04.tem + ^SupportDir|Content/ts/firestorm/cylat04a.tem: firestorm/cylat04a.tem + ^SupportDir|Content/ts/firestorm/cylat05.tem: firestorm/cylat05.tem + ^SupportDir|Content/ts/firestorm/cylat05a.tem: firestorm/cylat05a.tem + ^SupportDir|Content/ts/firestorm/cylat06.tem: firestorm/cylat06.tem + ^SupportDir|Content/ts/firestorm/cylat06a.tem: firestorm/cylat06a.tem + ^SupportDir|Content/ts/firestorm/cylat07.tem: firestorm/cylat07.tem + ^SupportDir|Content/ts/firestorm/cylat07a.tem: firestorm/cylat07a.tem + ^SupportDir|Content/ts/firestorm/cylat08.tem: firestorm/cylat08.tem + ^SupportDir|Content/ts/firestorm/cylat08a.tem: firestorm/cylat08a.tem + ^SupportDir|Content/ts/firestorm/cylat09.tem: firestorm/cylat09.tem + ^SupportDir|Content/ts/firestorm/cylat09a.tem: firestorm/cylat09a.tem + ^SupportDir|Content/ts/firestorm/cylat10.tem: firestorm/cylat10.tem + ^SupportDir|Content/ts/firestorm/cylat10a.tem: firestorm/cylat10a.tem + ^SupportDir|Content/ts/firestorm/cylat11.tem: firestorm/cylat11.tem + ^SupportDir|Content/ts/firestorm/cylat11a.tem: firestorm/cylat11a.tem + ^SupportDir|Content/ts/firestorm/cylat12.tem: firestorm/cylat12.tem + ^SupportDir|Content/ts/firestorm/cylat12a.tem: firestorm/cylat12a.tem + ^SupportDir|Content/ts/firestorm/cylat13.tem: firestorm/cylat13.tem + ^SupportDir|Content/ts/firestorm/cylat13a.tem: firestorm/cylat13a.tem + ^SupportDir|Content/ts/firestorm/cylat14.tem: firestorm/cylat14.tem + ^SupportDir|Content/ts/firestorm/cylat14a.tem: firestorm/cylat14a.tem + ^SupportDir|Content/ts/firestorm/cylat15.tem: firestorm/cylat15.tem + ^SupportDir|Content/ts/firestorm/cylat15a.tem: firestorm/cylat15a.tem + ^SupportDir|Content/ts/firestorm/cylat16.tem: firestorm/cylat16.tem + ^SupportDir|Content/ts/firestorm/cylat16a.tem: firestorm/cylat16a.tem + ^SupportDir|Content/ts/firestorm/slat01.tem: firestorm/slat01.tem + ^SupportDir|Content/ts/firestorm/slat01a.tem: firestorm/slat01a.tem + ^SupportDir|Content/ts/firestorm/slat02.tem: firestorm/slat02.tem + ^SupportDir|Content/ts/firestorm/slat02a.tem: firestorm/slat02a.tem + ^SupportDir|Content/ts/firestorm/slat03.tem: firestorm/slat03.tem + ^SupportDir|Content/ts/firestorm/slat03a.tem: firestorm/slat03a.tem + ^SupportDir|Content/ts/firestorm/slat04.tem: firestorm/slat04.tem + ^SupportDir|Content/ts/firestorm/slat04a.tem: firestorm/slat04a.tem + ^SupportDir|Content/ts/firestorm/slat05.tem: firestorm/slat05.tem + ^SupportDir|Content/ts/firestorm/slat05a.tem: firestorm/slat05a.tem + ^SupportDir|Content/ts/firestorm/slat06.tem: firestorm/slat06.tem + ^SupportDir|Content/ts/firestorm/slat06a.tem: firestorm/slat06a.tem + ^SupportDir|Content/ts/firestorm/slat07.tem: firestorm/slat07.tem + ^SupportDir|Content/ts/firestorm/slat07a.tem: firestorm/slat07a.tem + ^SupportDir|Content/ts/firestorm/slat08.tem: firestorm/slat08.tem + ^SupportDir|Content/ts/firestorm/slat08a.tem: firestorm/slat08a.tem + ^SupportDir|Content/ts/firestorm/slat09.tem: firestorm/slat09.tem + ^SupportDir|Content/ts/firestorm/slat09a.tem: firestorm/slat09a.tem + ^SupportDir|Content/ts/firestorm/slat10.tem: firestorm/slat10.tem + ^SupportDir|Content/ts/firestorm/slat10a.tem: firestorm/slat10a.tem + ^SupportDir|Content/ts/firestorm/slat11.tem: firestorm/slat11.tem + ^SupportDir|Content/ts/firestorm/slat11a.tem: firestorm/slat11a.tem + ^SupportDir|Content/ts/firestorm/slat12.tem: firestorm/slat12.tem + ^SupportDir|Content/ts/firestorm/slat12a.tem: firestorm/slat12a.tem + ^SupportDir|Content/ts/firestorm/slat13.tem: firestorm/slat13.tem + ^SupportDir|Content/ts/firestorm/slat13a.tem: firestorm/slat13a.tem + ^SupportDir|Content/ts/firestorm/slat14.tem: firestorm/slat14.tem + ^SupportDir|Content/ts/firestorm/slat14a.tem: firestorm/slat14a.tem + ^SupportDir|Content/ts/firestorm/slat15.tem: firestorm/slat15.tem + ^SupportDir|Content/ts/firestorm/slat15a.tem: firestorm/slat15a.tem + ^SupportDir|Content/ts/firestorm/slat16.tem: firestorm/slat16.tem + ^SupportDir|Content/ts/firestorm/slat16a.tem: firestorm/slat16a.tem + ^SupportDir|Content/ts/firestorm/swamp01.tem: firestorm/swamp01.tem + ^SupportDir|Content/ts/firestorm/swamp01a.tem: firestorm/swamp01a.tem + ^SupportDir|Content/ts/firestorm/swamp01b.tem: firestorm/swamp01b.tem + ^SupportDir|Content/ts/firestorm/swamp01c.tem: firestorm/swamp01c.tem + ^SupportDir|Content/ts/firestorm/swamp01d.tem: firestorm/swamp01d.tem + ^SupportDir|Content/ts/firestorm/swamp01e.tem: firestorm/swamp01e.tem + ^SupportDir|Content/ts/firestorm/swamp01f.tem: firestorm/swamp01f.tem + ^SupportDir|Content/ts/firestorm/swamp01g.tem: firestorm/swamp01g.tem + ^SupportDir|Content/ts/firestorm/swamp02.tem: firestorm/swamp02.tem + ^SupportDir|Content/ts/firestorm/swamp03.tem: firestorm/swamp03.tem + ^SupportDir|Content/ts/firestorm/swamp04.tem: firestorm/swamp04.tem + ^SupportDir|Content/ts/firestorm/swamp05.tem: firestorm/swamp05.tem + ^SupportDir|Content/ts/firestorm/swamp06.tem: firestorm/swamp06.tem + ^SupportDir|Content/ts/firestorm/swamp07.tem: firestorm/swamp07.tem + ^SupportDir|Content/ts/firestorm/swamp08.tem: firestorm/swamp08.tem + ^SupportDir|Content/ts/firestorm/swamp09.tem: firestorm/swamp09.tem + ^SupportDir|Content/ts/firestorm/fona01.tem: firestorm/fona01.tem + ^SupportDir|Content/ts/firestorm/fona02.tem: firestorm/fona02.tem + ^SupportDir|Content/ts/firestorm/fona03.tem: firestorm/fona03.tem + ^SupportDir|Content/ts/firestorm/fona04.tem: firestorm/fona04.tem + ^SupportDir|Content/ts/firestorm/fona05.tem: firestorm/fona05.tem + ^SupportDir|Content/ts/firestorm/fona06.tem: firestorm/fona06.tem + ^SupportDir|Content/ts/firestorm/fona07.tem: firestorm/fona07.tem + ^SupportDir|Content/ts/firestorm/fona08.tem: firestorm/fona08.tem + ^SupportDir|Content/ts/firestorm/fona09.tem: firestorm/fona09.tem + ^SupportDir|Content/ts/firestorm/fona10.tem: firestorm/fona10.tem + ^SupportDir|Content/ts/firestorm/fona11.tem: firestorm/fona11.tem + ^SupportDir|Content/ts/firestorm/fona12.tem: firestorm/fona12.tem + ^SupportDir|Content/ts/firestorm/fona13.tem: firestorm/fona13.tem + ^SupportDir|Content/ts/firestorm/fona14.tem: firestorm/fona14.tem + ^SupportDir|Content/ts/firestorm/fona15.tem: firestorm/fona15.tem + ^SupportDir|Content/ts/firestorm/bigblue3.tem: firestorm/bigblue3.tem diff -Nru openra-20200503/mods/ts/installer/firestorm.yaml openra-20210321/mods/ts/installer/firestorm.yaml --- openra-20200503/mods/ts/installer/firestorm.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/installer/firestorm.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -5,562 +5,562 @@ Install: copy: . extract-raw: Install/expand01.mix - ^Content/ts/firestorm/m_emp.vxl: + ^SupportDir|Content/ts/firestorm/m_emp.vxl: Offset: 2187652 Length: 24652 - ^Content/ts/firestorm/mwar_nod.vxl: + ^SupportDir|Content/ts/firestorm/mwar_nod.vxl: Offset: 2212308 Length: 31118 - ^Content/ts/firestorm/djuggbar.vxl: + ^SupportDir|Content/ts/firestorm/djuggbar.vxl: Offset: 2243428 Length: 18283 - ^Content/ts/firestorm/sgen.vxl: + ^SupportDir|Content/ts/firestorm/sgen.vxl: Offset: 2261716 Length: 24136 - ^Content/ts/firestorm/m_emp.hva: + ^SupportDir|Content/ts/firestorm/m_emp.hva: Offset: 2285860 Length: 88 - ^Content/ts/firestorm/mwar_nod.hva: + ^SupportDir|Content/ts/firestorm/mwar_nod.hva: Offset: 2285956 Length: 88 - ^Content/ts/firestorm/djuggbar.hva: + ^SupportDir|Content/ts/firestorm/djuggbar.hva: Offset: 2286052 Length: 88 - ^Content/ts/firestorm/sgen.hva: + ^SupportDir|Content/ts/firestorm/sgen.hva: Offset: 2286148 Length: 88 - ^Content/ts/firestorm/c_kodiak.shp: + ^SupportDir|Content/ts/firestorm/c_kodiak.shp: Offset: 2286244 Length: 24080 - ^Content/ts/firestorm/k_light1.shp: + ^SupportDir|Content/ts/firestorm/k_light1.shp: Offset: 2310324 Length: 12328 - ^Content/ts/firestorm/k_light2.shp: + ^SupportDir|Content/ts/firestorm/k_light2.shp: Offset: 2322660 Length: 5928 - ^Content/ts/firestorm/mwarmk.shp: + ^SupportDir|Content/ts/firestorm/mwarmk.shp: Offset: 2328596 Length: 129824 - ^Content/ts/firestorm/mstlmk.shp: + ^SupportDir|Content/ts/firestorm/mstlmk.shp: Offset: 2458420 Length: 26712 - ^Content/ts/firestorm/defdmk.shp: + ^SupportDir|Content/ts/firestorm/defdmk.shp: Offset: 2485140 Length: 80728 - ^Content/ts/firestorm/coremk.shp: + ^SupportDir|Content/ts/firestorm/coremk.shp: Offset: 2565876 Length: 155384 - ^Content/ts/firestorm/blat01.tem: + ^SupportDir|Content/ts/firestorm/blat01.tem: Offset: 12709962 Length: 1224 - ^Content/ts/firestorm/blat01a.tem: + ^SupportDir|Content/ts/firestorm/blat01a.tem: Offset: 12711194 Length: 1224 - ^Content/ts/firestorm/blat02.tem: + ^SupportDir|Content/ts/firestorm/blat02.tem: Offset: 12712426 Length: 1224 - ^Content/ts/firestorm/blat02a.tem: + ^SupportDir|Content/ts/firestorm/blat02a.tem: Offset: 12713658 Length: 1224 - ^Content/ts/firestorm/blat03.tem: + ^SupportDir|Content/ts/firestorm/blat03.tem: Offset: 12714890 Length: 1224 - ^Content/ts/firestorm/blat03a.tem: + ^SupportDir|Content/ts/firestorm/blat03a.tem: Offset: 12716122 Length: 1224 - ^Content/ts/firestorm/blat04.tem: + ^SupportDir|Content/ts/firestorm/blat04.tem: Offset: 12717354 Length: 1224 - ^Content/ts/firestorm/blat04a.tem: + ^SupportDir|Content/ts/firestorm/blat04a.tem: Offset: 12718586 Length: 1224 - ^Content/ts/firestorm/blat05.tem: + ^SupportDir|Content/ts/firestorm/blat05.tem: Offset: 12719818 Length: 1224 - ^Content/ts/firestorm/blat05a.tem: + ^SupportDir|Content/ts/firestorm/blat05a.tem: Offset: 12721050 Length: 1224 - ^Content/ts/firestorm/blat06.tem: + ^SupportDir|Content/ts/firestorm/blat06.tem: Offset: 12722282 Length: 1224 - ^Content/ts/firestorm/blat06a.tem: + ^SupportDir|Content/ts/firestorm/blat06a.tem: Offset: 12723514 Length: 1224 - ^Content/ts/firestorm/blat07.tem: + ^SupportDir|Content/ts/firestorm/blat07.tem: Offset: 12724746 Length: 1224 - ^Content/ts/firestorm/blat07a.tem: + ^SupportDir|Content/ts/firestorm/blat07a.tem: Offset: 12725978 Length: 1224 - ^Content/ts/firestorm/blat08.tem: + ^SupportDir|Content/ts/firestorm/blat08.tem: Offset: 12727210 Length: 1224 - ^Content/ts/firestorm/blat08a.tem: + ^SupportDir|Content/ts/firestorm/blat08a.tem: Offset: 12728442 Length: 1224 - ^Content/ts/firestorm/blat09.tem: + ^SupportDir|Content/ts/firestorm/blat09.tem: Offset: 12729674 Length: 1224 - ^Content/ts/firestorm/blat09a.tem: + ^SupportDir|Content/ts/firestorm/blat09a.tem: Offset: 12730906 Length: 1224 - ^Content/ts/firestorm/blat10.tem: + ^SupportDir|Content/ts/firestorm/blat10.tem: Offset: 12732138 Length: 1224 - ^Content/ts/firestorm/blat10a.tem: + ^SupportDir|Content/ts/firestorm/blat10a.tem: Offset: 12733370 Length: 1224 - ^Content/ts/firestorm/blat11.tem: + ^SupportDir|Content/ts/firestorm/blat11.tem: Offset: 12734602 Length: 1224 - ^Content/ts/firestorm/blat11a.tem: + ^SupportDir|Content/ts/firestorm/blat11a.tem: Offset: 12735834 Length: 1224 - ^Content/ts/firestorm/blat12.tem: + ^SupportDir|Content/ts/firestorm/blat12.tem: Offset: 12737066 Length: 1224 - ^Content/ts/firestorm/blat12a.tem: + ^SupportDir|Content/ts/firestorm/blat12a.tem: Offset: 12738298 Length: 1224 - ^Content/ts/firestorm/blat13.tem: + ^SupportDir|Content/ts/firestorm/blat13.tem: Offset: 12739530 Length: 1224 - ^Content/ts/firestorm/blat13a.tem: + ^SupportDir|Content/ts/firestorm/blat13a.tem: Offset: 12740762 Length: 1224 - ^Content/ts/firestorm/blat14.tem: + ^SupportDir|Content/ts/firestorm/blat14.tem: Offset: 12741994 Length: 1224 - ^Content/ts/firestorm/blat14a.tem: + ^SupportDir|Content/ts/firestorm/blat14a.tem: Offset: 12743226 Length: 1224 - ^Content/ts/firestorm/blat15.tem: + ^SupportDir|Content/ts/firestorm/blat15.tem: Offset: 12744458 Length: 1224 - ^Content/ts/firestorm/blat15a.tem: + ^SupportDir|Content/ts/firestorm/blat15a.tem: Offset: 12745690 Length: 1224 - ^Content/ts/firestorm/blat16.tem: + ^SupportDir|Content/ts/firestorm/blat16.tem: Offset: 12746922 Length: 1224 - ^Content/ts/firestorm/blat16a.tem: + ^SupportDir|Content/ts/firestorm/blat16a.tem: Offset: 12748154 Length: 1224 - ^Content/ts/firestorm/blue01.tem: + ^SupportDir|Content/ts/firestorm/blue01.tem: Offset: 12749386 Length: 1224 - ^Content/ts/firestorm/blue01a.tem: + ^SupportDir|Content/ts/firestorm/blue01a.tem: Offset: 12750618 Length: 1224 - ^Content/ts/firestorm/blue01b.tem: + ^SupportDir|Content/ts/firestorm/blue01b.tem: Offset: 12751850 Length: 1224 - ^Content/ts/firestorm/blue01c.tem: + ^SupportDir|Content/ts/firestorm/blue01c.tem: Offset: 12753082 Length: 1224 - ^Content/ts/firestorm/blue01d.tem: + ^SupportDir|Content/ts/firestorm/blue01d.tem: Offset: 12754314 Length: 1224 - ^Content/ts/firestorm/blue01e.tem: + ^SupportDir|Content/ts/firestorm/blue01e.tem: Offset: 12755546 Length: 1224 - ^Content/ts/firestorm/blue01f.tem: + ^SupportDir|Content/ts/firestorm/blue01f.tem: Offset: 12756778 Length: 1224 - ^Content/ts/firestorm/blue01g.tem: + ^SupportDir|Content/ts/firestorm/blue01g.tem: Offset: 12758010 Length: 1224 - ^Content/ts/firestorm/ccliff01.tem: + ^SupportDir|Content/ts/firestorm/ccliff01.tem: Offset: 12759242 Length: 10514 - ^Content/ts/firestorm/ccliff02.tem: + ^SupportDir|Content/ts/firestorm/ccliff02.tem: Offset: 12769770 Length: 10514 - ^Content/ts/firestorm/ccliff03.tem: + ^SupportDir|Content/ts/firestorm/ccliff03.tem: Offset: 12780298 Length: 14972 - ^Content/ts/firestorm/ccliff04.tem: + ^SupportDir|Content/ts/firestorm/ccliff04.tem: Offset: 12795274 Length: 6888 - ^Content/ts/firestorm/ccliff05.tem: + ^SupportDir|Content/ts/firestorm/ccliff05.tem: Offset: 12802170 Length: 10512 - ^Content/ts/firestorm/ccliff06.tem: + ^SupportDir|Content/ts/firestorm/ccliff06.tem: Offset: 12812682 Length: 10512 - ^Content/ts/firestorm/crash01.tem: + ^SupportDir|Content/ts/firestorm/crash01.tem: Offset: 12823194 Length: 52004 - ^Content/ts/firestorm/crash02.tem: + ^SupportDir|Content/ts/firestorm/crash02.tem: Offset: 12875210 Length: 14068 - ^Content/ts/firestorm/crash03.tem: + ^SupportDir|Content/ts/firestorm/crash03.tem: Offset: 12889290 Length: 95662 - ^Content/ts/firestorm/crash04.tem: + ^SupportDir|Content/ts/firestorm/crash04.tem: Offset: 12984954 Length: 21784 - ^Content/ts/firestorm/crash05.tem: + ^SupportDir|Content/ts/firestorm/crash05.tem: Offset: 13006746 Length: 38512 - ^Content/ts/firestorm/crash06.tem: + ^SupportDir|Content/ts/firestorm/crash06.tem: Offset: 13045258 Length: 36768 - ^Content/ts/firestorm/crash07.tem: + ^SupportDir|Content/ts/firestorm/crash07.tem: Offset: 13082026 Length: 37090 - ^Content/ts/firestorm/crys01.tem: + ^SupportDir|Content/ts/firestorm/crys01.tem: Offset: 13119130 Length: 1224 - ^Content/ts/firestorm/crys01a.tem: + ^SupportDir|Content/ts/firestorm/crys01a.tem: Offset: 13120362 Length: 1224 - ^Content/ts/firestorm/crys01b.tem: + ^SupportDir|Content/ts/firestorm/crys01b.tem: Offset: 13121594 Length: 1224 - ^Content/ts/firestorm/crys01c.tem: + ^SupportDir|Content/ts/firestorm/crys01c.tem: Offset: 13122826 Length: 1224 - ^Content/ts/firestorm/crys01d.tem: + ^SupportDir|Content/ts/firestorm/crys01d.tem: Offset: 13124058 Length: 1224 - ^Content/ts/firestorm/crys01e.tem: + ^SupportDir|Content/ts/firestorm/crys01e.tem: Offset: 13125290 Length: 1224 - ^Content/ts/firestorm/crys01f.tem: + ^SupportDir|Content/ts/firestorm/crys01f.tem: Offset: 13126522 Length: 1224 - ^Content/ts/firestorm/crys01g.tem: + ^SupportDir|Content/ts/firestorm/crys01g.tem: Offset: 13127754 Length: 1224 - ^Content/ts/firestorm/cylat01.tem: + ^SupportDir|Content/ts/firestorm/cylat01.tem: Offset: 13128986 Length: 1224 - ^Content/ts/firestorm/cylat01a.tem: + ^SupportDir|Content/ts/firestorm/cylat01a.tem: Offset: 13130218 Length: 1224 - ^Content/ts/firestorm/cylat02.tem: + ^SupportDir|Content/ts/firestorm/cylat02.tem: Offset: 13131450 Length: 1224 - ^Content/ts/firestorm/cylat02a.tem: + ^SupportDir|Content/ts/firestorm/cylat02a.tem: Offset: 13132682 Length: 1224 - ^Content/ts/firestorm/cylat03.tem: + ^SupportDir|Content/ts/firestorm/cylat03.tem: Offset: 13133914 Length: 1224 - ^Content/ts/firestorm/cylat03a.tem: + ^SupportDir|Content/ts/firestorm/cylat03a.tem: Offset: 13135146 Length: 1224 - ^Content/ts/firestorm/cylat04.tem: + ^SupportDir|Content/ts/firestorm/cylat04.tem: Offset: 13136378 Length: 1224 - ^Content/ts/firestorm/cylat04a.tem: + ^SupportDir|Content/ts/firestorm/cylat04a.tem: Offset: 13137610 Length: 1224 - ^Content/ts/firestorm/cylat05.tem: + ^SupportDir|Content/ts/firestorm/cylat05.tem: Offset: 13138842 Length: 1224 - ^Content/ts/firestorm/cylat05a.tem: + ^SupportDir|Content/ts/firestorm/cylat05a.tem: Offset: 13140074 Length: 1224 - ^Content/ts/firestorm/cylat06.tem: + ^SupportDir|Content/ts/firestorm/cylat06.tem: Offset: 13141306 Length: 1224 - ^Content/ts/firestorm/cylat06a.tem: + ^SupportDir|Content/ts/firestorm/cylat06a.tem: Offset: 13142538 Length: 1224 - ^Content/ts/firestorm/cylat07.tem: + ^SupportDir|Content/ts/firestorm/cylat07.tem: Offset: 13143770 Length: 1224 - ^Content/ts/firestorm/cylat07a.tem: + ^SupportDir|Content/ts/firestorm/cylat07a.tem: Offset: 13145002 Length: 1224 - ^Content/ts/firestorm/cylat08.tem: + ^SupportDir|Content/ts/firestorm/cylat08.tem: Offset: 13146234 Length: 1224 - ^Content/ts/firestorm/cylat08a.tem: + ^SupportDir|Content/ts/firestorm/cylat08a.tem: Offset: 13147466 Length: 1224 - ^Content/ts/firestorm/cylat09.tem: + ^SupportDir|Content/ts/firestorm/cylat09.tem: Offset: 13148698 Length: 1224 - ^Content/ts/firestorm/cylat09a.tem: + ^SupportDir|Content/ts/firestorm/cylat09a.tem: Offset: 13149930 Length: 1224 - ^Content/ts/firestorm/cylat10.tem: + ^SupportDir|Content/ts/firestorm/cylat10.tem: Offset: 13151162 Length: 1224 - ^Content/ts/firestorm/cylat10a.tem: + ^SupportDir|Content/ts/firestorm/cylat10a.tem: Offset: 13152394 Length: 1224 - ^Content/ts/firestorm/cylat11.tem: + ^SupportDir|Content/ts/firestorm/cylat11.tem: Offset: 13153626 Length: 1224 - ^Content/ts/firestorm/cylat11a.tem: + ^SupportDir|Content/ts/firestorm/cylat11a.tem: Offset: 13154858 Length: 1224 - ^Content/ts/firestorm/cylat12.tem: + ^SupportDir|Content/ts/firestorm/cylat12.tem: Offset: 13156090 Length: 1224 - ^Content/ts/firestorm/cylat12a.tem: + ^SupportDir|Content/ts/firestorm/cylat12a.tem: Offset: 13157322 Length: 1224 - ^Content/ts/firestorm/cylat13.tem: + ^SupportDir|Content/ts/firestorm/cylat13.tem: Offset: 13158554 Length: 1224 - ^Content/ts/firestorm/cylat13a.tem: + ^SupportDir|Content/ts/firestorm/cylat13a.tem: Offset: 13159786 Length: 1224 - ^Content/ts/firestorm/cylat14.tem: + ^SupportDir|Content/ts/firestorm/cylat14.tem: Offset: 13161018 Length: 1224 - ^Content/ts/firestorm/cylat14a.tem: + ^SupportDir|Content/ts/firestorm/cylat14a.tem: Offset: 13162250 Length: 1224 - ^Content/ts/firestorm/cylat15.tem: + ^SupportDir|Content/ts/firestorm/cylat15.tem: Offset: 13163482 Length: 1224 - ^Content/ts/firestorm/cylat15a.tem: + ^SupportDir|Content/ts/firestorm/cylat15a.tem: Offset: 13164714 Length: 1224 - ^Content/ts/firestorm/cylat16.tem: + ^SupportDir|Content/ts/firestorm/cylat16.tem: Offset: 13165946 Length: 1224 - ^Content/ts/firestorm/cylat16a.tem: + ^SupportDir|Content/ts/firestorm/cylat16a.tem: Offset: 13167178 Length: 1224 - ^Content/ts/firestorm/slat01.tem: + ^SupportDir|Content/ts/firestorm/slat01.tem: Offset: 13168410 Length: 1224 - ^Content/ts/firestorm/slat01a.tem: + ^SupportDir|Content/ts/firestorm/slat01a.tem: Offset: 13169642 Length: 1224 - ^Content/ts/firestorm/slat02.tem: + ^SupportDir|Content/ts/firestorm/slat02.tem: Offset: 13170874 Length: 1224 - ^Content/ts/firestorm/slat02a.tem: + ^SupportDir|Content/ts/firestorm/slat02a.tem: Offset: 13172106 Length: 1224 - ^Content/ts/firestorm/slat03.tem: + ^SupportDir|Content/ts/firestorm/slat03.tem: Offset: 13173338 Length: 1224 - ^Content/ts/firestorm/slat03a.tem: + ^SupportDir|Content/ts/firestorm/slat03a.tem: Offset: 13174570 Length: 1224 - ^Content/ts/firestorm/slat04.tem: + ^SupportDir|Content/ts/firestorm/slat04.tem: Offset: 13175802 Length: 1224 - ^Content/ts/firestorm/slat04a.tem: + ^SupportDir|Content/ts/firestorm/slat04a.tem: Offset: 13177034 Length: 1224 - ^Content/ts/firestorm/slat05.tem: + ^SupportDir|Content/ts/firestorm/slat05.tem: Offset: 13178266 Length: 1224 - ^Content/ts/firestorm/slat05a.tem: + ^SupportDir|Content/ts/firestorm/slat05a.tem: Offset: 13179498 Length: 1224 - ^Content/ts/firestorm/slat06.tem: + ^SupportDir|Content/ts/firestorm/slat06.tem: Offset: 13180730 Length: 1224 - ^Content/ts/firestorm/slat06a.tem: + ^SupportDir|Content/ts/firestorm/slat06a.tem: Offset: 13181962 Length: 1224 - ^Content/ts/firestorm/slat07.tem: + ^SupportDir|Content/ts/firestorm/slat07.tem: Offset: 13183194 Length: 1224 - ^Content/ts/firestorm/slat07a.tem: + ^SupportDir|Content/ts/firestorm/slat07a.tem: Offset: 13184426 Length: 1224 - ^Content/ts/firestorm/slat08.tem: + ^SupportDir|Content/ts/firestorm/slat08.tem: Offset: 13185658 Length: 1224 - ^Content/ts/firestorm/slat08a.tem: + ^SupportDir|Content/ts/firestorm/slat08a.tem: Offset: 13186890 Length: 1224 - ^Content/ts/firestorm/slat09.tem: + ^SupportDir|Content/ts/firestorm/slat09.tem: Offset: 13188122 Length: 1224 - ^Content/ts/firestorm/slat09a.tem: + ^SupportDir|Content/ts/firestorm/slat09a.tem: Offset: 13189354 Length: 1224 - ^Content/ts/firestorm/slat10.tem: + ^SupportDir|Content/ts/firestorm/slat10.tem: Offset: 13190586 Length: 1224 - ^Content/ts/firestorm/slat10a.tem: + ^SupportDir|Content/ts/firestorm/slat10a.tem: Offset: 13191818 Length: 1224 - ^Content/ts/firestorm/slat11.tem: + ^SupportDir|Content/ts/firestorm/slat11.tem: Offset: 13193050 Length: 1224 - ^Content/ts/firestorm/slat11a.tem: + ^SupportDir|Content/ts/firestorm/slat11a.tem: Offset: 13194282 Length: 1224 - ^Content/ts/firestorm/slat12.tem: + ^SupportDir|Content/ts/firestorm/slat12.tem: Offset: 13195514 Length: 1224 - ^Content/ts/firestorm/slat12a.tem: + ^SupportDir|Content/ts/firestorm/slat12a.tem: Offset: 13196746 Length: 1224 - ^Content/ts/firestorm/slat13.tem: + ^SupportDir|Content/ts/firestorm/slat13.tem: Offset: 13197978 Length: 1224 - ^Content/ts/firestorm/slat13a.tem: + ^SupportDir|Content/ts/firestorm/slat13a.tem: Offset: 13199210 Length: 1224 - ^Content/ts/firestorm/slat14.tem: + ^SupportDir|Content/ts/firestorm/slat14.tem: Offset: 13200442 Length: 1224 - ^Content/ts/firestorm/slat14a.tem: + ^SupportDir|Content/ts/firestorm/slat14a.tem: Offset: 13201674 Length: 1224 - ^Content/ts/firestorm/slat15.tem: + ^SupportDir|Content/ts/firestorm/slat15.tem: Offset: 13202906 Length: 1224 - ^Content/ts/firestorm/slat15a.tem: + ^SupportDir|Content/ts/firestorm/slat15a.tem: Offset: 13204138 Length: 1224 - ^Content/ts/firestorm/slat16.tem: + ^SupportDir|Content/ts/firestorm/slat16.tem: Offset: 13205370 Length: 1224 - ^Content/ts/firestorm/slat16a.tem: + ^SupportDir|Content/ts/firestorm/slat16a.tem: Offset: 13206602 Length: 1224 - ^Content/ts/firestorm/swamp01.tem: + ^SupportDir|Content/ts/firestorm/swamp01.tem: Offset: 13207834 Length: 1224 - ^Content/ts/firestorm/swamp01a.tem: + ^SupportDir|Content/ts/firestorm/swamp01a.tem: Offset: 13209066 Length: 1224 - ^Content/ts/firestorm/swamp01b.tem: + ^SupportDir|Content/ts/firestorm/swamp01b.tem: Offset: 13210298 Length: 1224 - ^Content/ts/firestorm/swamp01c.tem: + ^SupportDir|Content/ts/firestorm/swamp01c.tem: Offset: 13211530 Length: 1224 - ^Content/ts/firestorm/swamp01d.tem: + ^SupportDir|Content/ts/firestorm/swamp01d.tem: Offset: 13212762 Length: 1224 - ^Content/ts/firestorm/swamp01e.tem: + ^SupportDir|Content/ts/firestorm/swamp01e.tem: Offset: 13213994 Length: 1224 - ^Content/ts/firestorm/swamp01f.tem: + ^SupportDir|Content/ts/firestorm/swamp01f.tem: Offset: 13215226 Length: 1224 - ^Content/ts/firestorm/swamp01g.tem: + ^SupportDir|Content/ts/firestorm/swamp01g.tem: Offset: 13216458 Length: 1224 - ^Content/ts/firestorm/swamp02.tem: + ^SupportDir|Content/ts/firestorm/swamp02.tem: Offset: 13217690 Length: 4848 - ^Content/ts/firestorm/swamp03.tem: + ^SupportDir|Content/ts/firestorm/swamp03.tem: Offset: 13222538 Length: 4848 - ^Content/ts/firestorm/swamp04.tem: + ^SupportDir|Content/ts/firestorm/swamp04.tem: Offset: 13227386 Length: 4848 - ^Content/ts/firestorm/swamp05.tem: + ^SupportDir|Content/ts/firestorm/swamp05.tem: Offset: 13232234 Length: 1224 - ^Content/ts/firestorm/swamp06.tem: + ^SupportDir|Content/ts/firestorm/swamp06.tem: Offset: 13233466 Length: 1224 - ^Content/ts/firestorm/swamp07.tem: + ^SupportDir|Content/ts/firestorm/swamp07.tem: Offset: 13234698 Length: 1224 - ^Content/ts/firestorm/swamp08.tem: + ^SupportDir|Content/ts/firestorm/swamp08.tem: Offset: 13235930 Length: 1224 - ^Content/ts/firestorm/swamp09.tem: + ^SupportDir|Content/ts/firestorm/swamp09.tem: Offset: 13237162 Length: 1224 - ^Content/ts/firestorm/fona01.tem: + ^SupportDir|Content/ts/firestorm/fona01.tem: Offset: 15276198 Length: 2048 - ^Content/ts/firestorm/fona02.tem: + ^SupportDir|Content/ts/firestorm/fona02.tem: Offset: 15278246 Length: 1304 - ^Content/ts/firestorm/fona03.tem: + ^SupportDir|Content/ts/firestorm/fona03.tem: Offset: 15279558 Length: 1864 - ^Content/ts/firestorm/fona04.tem: + ^SupportDir|Content/ts/firestorm/fona04.tem: Offset: 15281430 Length: 1952 - ^Content/ts/firestorm/fona05.tem: + ^SupportDir|Content/ts/firestorm/fona05.tem: Offset: 15283382 Length: 1328 - ^Content/ts/firestorm/fona06.tem: + ^SupportDir|Content/ts/firestorm/fona06.tem: Offset: 15284710 Length: 1160 - ^Content/ts/firestorm/fona07.tem: + ^SupportDir|Content/ts/firestorm/fona07.tem: Offset: 15285878 Length: 1216 - ^Content/ts/firestorm/fona08.tem: + ^SupportDir|Content/ts/firestorm/fona08.tem: Offset: 15287094 Length: 872 - ^Content/ts/firestorm/fona09.tem: + ^SupportDir|Content/ts/firestorm/fona09.tem: Offset: 15287974 Length: 608 - ^Content/ts/firestorm/fona10.tem: + ^SupportDir|Content/ts/firestorm/fona10.tem: Offset: 15288582 Length: 616 - ^Content/ts/firestorm/fona11.tem: + ^SupportDir|Content/ts/firestorm/fona11.tem: Offset: 15289206 Length: 2448 - ^Content/ts/firestorm/fona12.tem: + ^SupportDir|Content/ts/firestorm/fona12.tem: Offset: 15291654 Length: 2360 - ^Content/ts/firestorm/fona13.tem: + ^SupportDir|Content/ts/firestorm/fona13.tem: Offset: 15294022 Length: 1608 - ^Content/ts/firestorm/fona14.tem: + ^SupportDir|Content/ts/firestorm/fona14.tem: Offset: 15295638 Length: 1544 - ^Content/ts/firestorm/fona15.tem: + ^SupportDir|Content/ts/firestorm/fona15.tem: Offset: 15297190 Length: 2496 - ^Content/ts/firestorm/bigblue3.tem: + ^SupportDir|Content/ts/firestorm/bigblue3.tem: Offset: 15299686 Length: 12808 - ^Content/ts/firestorm/ecache01.mix: + ^SupportDir|Content/ts/firestorm/ecache01.mix: Offset: 17400340 Length: 2229224 - ^Content/ts/firestorm/e01sc01.mix: + ^SupportDir|Content/ts/firestorm/e01sc01.mix: Offset: 19629572 Length: 6324 - ^Content/ts/firestorm/e01sc02.mix: + ^SupportDir|Content/ts/firestorm/e01sc02.mix: Offset: 19635908 Length: 6324 - ^Content/ts/firestorm/e01vox01.mix: + ^SupportDir|Content/ts/firestorm/e01vox01.mix: Offset: 19642244 Length: 6313740 - ^Content/ts/firestorm/e01vox02.mix: + ^SupportDir|Content/ts/firestorm/e01vox02.mix: Offset: 25955988 Length: 2273956 - ^Content/ts/firestorm/sounds01.mix: + ^SupportDir|Content/ts/firestorm/sounds01.mix: Offset: 28229956 Length: 990096 extract-raw: scores01.mix - ^Content/ts/firestorm/elusive.aud: + ^SupportDir|Content/ts/firestorm/elusive.aud: Offset: 188 Length: 2991051 - ^Content/ts/firestorm/hacker.aud: + ^SupportDir|Content/ts/firestorm/hacker.aud: Offset: 2991244 Length: 2719611 - ^Content/ts/firestorm/infiltra.aud: + ^SupportDir|Content/ts/firestorm/infiltra.aud: Offset: 5710860 Length: 2915781 - ^Content/ts/firestorm/linkup.aud: + ^SupportDir|Content/ts/firestorm/linkup.aud: Offset: 8626652 Length: 2210011 - ^Content/ts/firestorm/kmachine.aud: + ^SupportDir|Content/ts/firestorm/kmachine.aud: Offset: 10836668 Length: 2323371 - ^Content/ts/firestorm/rainnite.aud: + ^SupportDir|Content/ts/firestorm/rainnite.aud: Offset: 13160044 Length: 2679051 - ^Content/ts/firestorm/slavesys.aud: + ^SupportDir|Content/ts/firestorm/slavesys.aud: Offset: 15839100 Length: 1747576 - ^Content/ts/firestorm/dmachine.aud: + ^SupportDir|Content/ts/firestorm/dmachine.aud: Offset: 17586684 Length: 2492891 diff -Nru openra-20200503/mods/ts/installer/firstdecade.yaml openra-20210321/mods/ts/installer/firstdecade.yaml --- openra-20200503/mods/ts/installer/firstdecade.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/installer/firstdecade.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -8,613 +8,613 @@ 6: data6.cab 7: data7.cab Extract: - ^Content/ts/scores.mix: Tiberian Sun\SUN\SCORES.MIX - ^Content/ts/tibsun.mix: Tiberian Sun\SUN\TIBSUN.MIX - ^Content/ts/expand01.mix: Tiberian Sun\SUN\expand01.mix - ^Content/ts/scores01.mix: Tiberian Sun\SUN\scores01.mix - extract-raw: ^Content/ts/tibsun.mix - ^Content/ts/cache.mix: + ^SupportDir|Content/ts/scores.mix: Tiberian Sun\SUN\SCORES.MIX + ^SupportDir|Content/ts/tibsun.mix: Tiberian Sun\SUN\TIBSUN.MIX + ^SupportDir|Content/ts/expand01.mix: Tiberian Sun\SUN\expand01.mix + ^SupportDir|Content/ts/scores01.mix: Tiberian Sun\SUN\scores01.mix + extract-raw: ^SupportDir|Content/ts/tibsun.mix + ^SupportDir|Content/ts/cache.mix: Offset: 300 Length: 169176 - ^Content/ts/conquer.mix: + ^SupportDir|Content/ts/conquer.mix: Offset: 169484 Length: 5700088 - ^Content/ts/isosnow.mix: + ^SupportDir|Content/ts/isosnow.mix: Offset: 5869580 Length: 7624750 - ^Content/ts/isotemp.mix: + ^SupportDir|Content/ts/isotemp.mix: Offset: 13494332 Length: 8617646 - ^Content/ts/local.mix: + ^SupportDir|Content/ts/local.mix: Offset: 22111980 Length: 18044736 - ^Content/ts/sidec01.mix: + ^SupportDir|Content/ts/sidec01.mix: Offset: 40156716 Length: 998476 - ^Content/ts/sidec02.mix: + ^SupportDir|Content/ts/sidec02.mix: Offset: 41155196 Length: 1039996 - ^Content/ts/snow.mix: + ^SupportDir|Content/ts/snow.mix: Offset: 56104508 Length: 2087806 - ^Content/ts/sno.mix: + ^SupportDir|Content/ts/sno.mix: Offset: 58192316 Length: 7826 - ^Content/ts/sounds.mix: + ^SupportDir|Content/ts/sounds.mix: Offset: 58200156 Length: 3224136 - ^Content/ts/speech01.mix: + ^SupportDir|Content/ts/speech01.mix: Offset: 61424300 Length: 6028236 - ^Content/ts/speech02.mix: + ^SupportDir|Content/ts/speech02.mix: Offset: 67452540 Length: 5596628 - ^Content/ts/tem.mix: + ^SupportDir|Content/ts/tem.mix: Offset: 73049180 Length: 7746 - ^Content/ts/temperat.mix: + ^SupportDir|Content/ts/temperat.mix: Offset: 73056940 Length: 2037606 - delete: ^Content/ts/tibsun.mix - extract-raw: ^Content/ts/expand01.mix - ^Content/ts/firestorm/m_emp.vxl: + delete: ^SupportDir|Content/ts/tibsun.mix + extract-raw: ^SupportDir|Content/ts/expand01.mix + ^SupportDir|Content/ts/firestorm/m_emp.vxl: Offset: 2187652 Length: 24652 - ^Content/ts/firestorm/mwar_nod.vxl: + ^SupportDir|Content/ts/firestorm/mwar_nod.vxl: Offset: 2212308 Length: 31118 - ^Content/ts/firestorm/djuggbar.vxl: + ^SupportDir|Content/ts/firestorm/djuggbar.vxl: Offset: 2243428 Length: 18283 - ^Content/ts/firestorm/sgen.vxl: + ^SupportDir|Content/ts/firestorm/sgen.vxl: Offset: 2261716 Length: 24136 - ^Content/ts/firestorm/m_emp.hva: + ^SupportDir|Content/ts/firestorm/m_emp.hva: Offset: 2285860 Length: 88 - ^Content/ts/firestorm/mwar_nod.hva: + ^SupportDir|Content/ts/firestorm/mwar_nod.hva: Offset: 2285956 Length: 88 - ^Content/ts/firestorm/djuggbar.hva: + ^SupportDir|Content/ts/firestorm/djuggbar.hva: Offset: 2286052 Length: 88 - ^Content/ts/firestorm/sgen.hva: + ^SupportDir|Content/ts/firestorm/sgen.hva: Offset: 2286148 Length: 88 - ^Content/ts/firestorm/c_kodiak.shp: + ^SupportDir|Content/ts/firestorm/c_kodiak.shp: Offset: 2286244 Length: 24080 - ^Content/ts/firestorm/k_light1.shp: + ^SupportDir|Content/ts/firestorm/k_light1.shp: Offset: 2310324 Length: 12328 - ^Content/ts/firestorm/k_light2.shp: + ^SupportDir|Content/ts/firestorm/k_light2.shp: Offset: 2322660 Length: 5928 - ^Content/ts/firestorm/mwarmk.shp: + ^SupportDir|Content/ts/firestorm/mwarmk.shp: Offset: 2328596 Length: 129824 - ^Content/ts/firestorm/mstlmk.shp: + ^SupportDir|Content/ts/firestorm/mstlmk.shp: Offset: 2458420 Length: 26712 - ^Content/ts/firestorm/defdmk.shp: + ^SupportDir|Content/ts/firestorm/defdmk.shp: Offset: 2485140 Length: 80728 - ^Content/ts/firestorm/coremk.shp: + ^SupportDir|Content/ts/firestorm/coremk.shp: Offset: 2565876 Length: 155384 - ^Content/ts/firestorm/blat01.tem: + ^SupportDir|Content/ts/firestorm/blat01.tem: Offset: 12709962 Length: 1224 - ^Content/ts/firestorm/blat01a.tem: + ^SupportDir|Content/ts/firestorm/blat01a.tem: Offset: 12711194 Length: 1224 - ^Content/ts/firestorm/blat02.tem: + ^SupportDir|Content/ts/firestorm/blat02.tem: Offset: 12712426 Length: 1224 - ^Content/ts/firestorm/blat02a.tem: + ^SupportDir|Content/ts/firestorm/blat02a.tem: Offset: 12713658 Length: 1224 - ^Content/ts/firestorm/blat03.tem: + ^SupportDir|Content/ts/firestorm/blat03.tem: Offset: 12714890 Length: 1224 - ^Content/ts/firestorm/blat03a.tem: + ^SupportDir|Content/ts/firestorm/blat03a.tem: Offset: 12716122 Length: 1224 - ^Content/ts/firestorm/blat04.tem: + ^SupportDir|Content/ts/firestorm/blat04.tem: Offset: 12717354 Length: 1224 - ^Content/ts/firestorm/blat04a.tem: + ^SupportDir|Content/ts/firestorm/blat04a.tem: Offset: 12718586 Length: 1224 - ^Content/ts/firestorm/blat05.tem: + ^SupportDir|Content/ts/firestorm/blat05.tem: Offset: 12719818 Length: 1224 - ^Content/ts/firestorm/blat05a.tem: + ^SupportDir|Content/ts/firestorm/blat05a.tem: Offset: 12721050 Length: 1224 - ^Content/ts/firestorm/blat06.tem: + ^SupportDir|Content/ts/firestorm/blat06.tem: Offset: 12722282 Length: 1224 - ^Content/ts/firestorm/blat06a.tem: + ^SupportDir|Content/ts/firestorm/blat06a.tem: Offset: 12723514 Length: 1224 - ^Content/ts/firestorm/blat07.tem: + ^SupportDir|Content/ts/firestorm/blat07.tem: Offset: 12724746 Length: 1224 - ^Content/ts/firestorm/blat07a.tem: + ^SupportDir|Content/ts/firestorm/blat07a.tem: Offset: 12725978 Length: 1224 - ^Content/ts/firestorm/blat08.tem: + ^SupportDir|Content/ts/firestorm/blat08.tem: Offset: 12727210 Length: 1224 - ^Content/ts/firestorm/blat08a.tem: + ^SupportDir|Content/ts/firestorm/blat08a.tem: Offset: 12728442 Length: 1224 - ^Content/ts/firestorm/blat09.tem: + ^SupportDir|Content/ts/firestorm/blat09.tem: Offset: 12729674 Length: 1224 - ^Content/ts/firestorm/blat09a.tem: + ^SupportDir|Content/ts/firestorm/blat09a.tem: Offset: 12730906 Length: 1224 - ^Content/ts/firestorm/blat10.tem: + ^SupportDir|Content/ts/firestorm/blat10.tem: Offset: 12732138 Length: 1224 - ^Content/ts/firestorm/blat10a.tem: + ^SupportDir|Content/ts/firestorm/blat10a.tem: Offset: 12733370 Length: 1224 - ^Content/ts/firestorm/blat11.tem: + ^SupportDir|Content/ts/firestorm/blat11.tem: Offset: 12734602 Length: 1224 - ^Content/ts/firestorm/blat11a.tem: + ^SupportDir|Content/ts/firestorm/blat11a.tem: Offset: 12735834 Length: 1224 - ^Content/ts/firestorm/blat12.tem: + ^SupportDir|Content/ts/firestorm/blat12.tem: Offset: 12737066 Length: 1224 - ^Content/ts/firestorm/blat12a.tem: + ^SupportDir|Content/ts/firestorm/blat12a.tem: Offset: 12738298 Length: 1224 - ^Content/ts/firestorm/blat13.tem: + ^SupportDir|Content/ts/firestorm/blat13.tem: Offset: 12739530 Length: 1224 - ^Content/ts/firestorm/blat13a.tem: + ^SupportDir|Content/ts/firestorm/blat13a.tem: Offset: 12740762 Length: 1224 - ^Content/ts/firestorm/blat14.tem: + ^SupportDir|Content/ts/firestorm/blat14.tem: Offset: 12741994 Length: 1224 - ^Content/ts/firestorm/blat14a.tem: + ^SupportDir|Content/ts/firestorm/blat14a.tem: Offset: 12743226 Length: 1224 - ^Content/ts/firestorm/blat15.tem: + ^SupportDir|Content/ts/firestorm/blat15.tem: Offset: 12744458 Length: 1224 - ^Content/ts/firestorm/blat15a.tem: + ^SupportDir|Content/ts/firestorm/blat15a.tem: Offset: 12745690 Length: 1224 - ^Content/ts/firestorm/blat16.tem: + ^SupportDir|Content/ts/firestorm/blat16.tem: Offset: 12746922 Length: 1224 - ^Content/ts/firestorm/blat16a.tem: + ^SupportDir|Content/ts/firestorm/blat16a.tem: Offset: 12748154 Length: 1224 - ^Content/ts/firestorm/blue01.tem: + ^SupportDir|Content/ts/firestorm/blue01.tem: Offset: 12749386 Length: 1224 - ^Content/ts/firestorm/blue01a.tem: + ^SupportDir|Content/ts/firestorm/blue01a.tem: Offset: 12750618 Length: 1224 - ^Content/ts/firestorm/blue01b.tem: + ^SupportDir|Content/ts/firestorm/blue01b.tem: Offset: 12751850 Length: 1224 - ^Content/ts/firestorm/blue01c.tem: + ^SupportDir|Content/ts/firestorm/blue01c.tem: Offset: 12753082 Length: 1224 - ^Content/ts/firestorm/blue01d.tem: + ^SupportDir|Content/ts/firestorm/blue01d.tem: Offset: 12754314 Length: 1224 - ^Content/ts/firestorm/blue01e.tem: + ^SupportDir|Content/ts/firestorm/blue01e.tem: Offset: 12755546 Length: 1224 - ^Content/ts/firestorm/blue01f.tem: + ^SupportDir|Content/ts/firestorm/blue01f.tem: Offset: 12756778 Length: 1224 - ^Content/ts/firestorm/blue01g.tem: + ^SupportDir|Content/ts/firestorm/blue01g.tem: Offset: 12758010 Length: 1224 - ^Content/ts/firestorm/ccliff01.tem: + ^SupportDir|Content/ts/firestorm/ccliff01.tem: Offset: 12759242 Length: 10514 - ^Content/ts/firestorm/ccliff02.tem: + ^SupportDir|Content/ts/firestorm/ccliff02.tem: Offset: 12769770 Length: 10514 - ^Content/ts/firestorm/ccliff03.tem: + ^SupportDir|Content/ts/firestorm/ccliff03.tem: Offset: 12780298 Length: 14972 - ^Content/ts/firestorm/ccliff04.tem: + ^SupportDir|Content/ts/firestorm/ccliff04.tem: Offset: 12795274 Length: 6888 - ^Content/ts/firestorm/ccliff05.tem: + ^SupportDir|Content/ts/firestorm/ccliff05.tem: Offset: 12802170 Length: 10512 - ^Content/ts/firestorm/ccliff06.tem: + ^SupportDir|Content/ts/firestorm/ccliff06.tem: Offset: 12812682 Length: 10512 - ^Content/ts/firestorm/crash01.tem: + ^SupportDir|Content/ts/firestorm/crash01.tem: Offset: 12823194 Length: 52004 - ^Content/ts/firestorm/crash02.tem: + ^SupportDir|Content/ts/firestorm/crash02.tem: Offset: 12875210 Length: 14068 - ^Content/ts/firestorm/crash03.tem: + ^SupportDir|Content/ts/firestorm/crash03.tem: Offset: 12889290 Length: 95662 - ^Content/ts/firestorm/crash04.tem: + ^SupportDir|Content/ts/firestorm/crash04.tem: Offset: 12984954 Length: 21784 - ^Content/ts/firestorm/crash05.tem: + ^SupportDir|Content/ts/firestorm/crash05.tem: Offset: 13006746 Length: 38512 - ^Content/ts/firestorm/crash06.tem: + ^SupportDir|Content/ts/firestorm/crash06.tem: Offset: 13045258 Length: 36768 - ^Content/ts/firestorm/crash07.tem: + ^SupportDir|Content/ts/firestorm/crash07.tem: Offset: 13082026 Length: 37090 - ^Content/ts/firestorm/crys01.tem: + ^SupportDir|Content/ts/firestorm/crys01.tem: Offset: 13119130 Length: 1224 - ^Content/ts/firestorm/crys01a.tem: + ^SupportDir|Content/ts/firestorm/crys01a.tem: Offset: 13120362 Length: 1224 - ^Content/ts/firestorm/crys01b.tem: + ^SupportDir|Content/ts/firestorm/crys01b.tem: Offset: 13121594 Length: 1224 - ^Content/ts/firestorm/crys01c.tem: + ^SupportDir|Content/ts/firestorm/crys01c.tem: Offset: 13122826 Length: 1224 - ^Content/ts/firestorm/crys01d.tem: + ^SupportDir|Content/ts/firestorm/crys01d.tem: Offset: 13124058 Length: 1224 - ^Content/ts/firestorm/crys01e.tem: + ^SupportDir|Content/ts/firestorm/crys01e.tem: Offset: 13125290 Length: 1224 - ^Content/ts/firestorm/crys01f.tem: + ^SupportDir|Content/ts/firestorm/crys01f.tem: Offset: 13126522 Length: 1224 - ^Content/ts/firestorm/crys01g.tem: + ^SupportDir|Content/ts/firestorm/crys01g.tem: Offset: 13127754 Length: 1224 - ^Content/ts/firestorm/cylat01.tem: + ^SupportDir|Content/ts/firestorm/cylat01.tem: Offset: 13128986 Length: 1224 - ^Content/ts/firestorm/cylat01a.tem: + ^SupportDir|Content/ts/firestorm/cylat01a.tem: Offset: 13130218 Length: 1224 - ^Content/ts/firestorm/cylat02.tem: + ^SupportDir|Content/ts/firestorm/cylat02.tem: Offset: 13131450 Length: 1224 - ^Content/ts/firestorm/cylat02a.tem: + ^SupportDir|Content/ts/firestorm/cylat02a.tem: Offset: 13132682 Length: 1224 - ^Content/ts/firestorm/cylat03.tem: + ^SupportDir|Content/ts/firestorm/cylat03.tem: Offset: 13133914 Length: 1224 - ^Content/ts/firestorm/cylat03a.tem: + ^SupportDir|Content/ts/firestorm/cylat03a.tem: Offset: 13135146 Length: 1224 - ^Content/ts/firestorm/cylat04.tem: + ^SupportDir|Content/ts/firestorm/cylat04.tem: Offset: 13136378 Length: 1224 - ^Content/ts/firestorm/cylat04a.tem: + ^SupportDir|Content/ts/firestorm/cylat04a.tem: Offset: 13137610 Length: 1224 - ^Content/ts/firestorm/cylat05.tem: + ^SupportDir|Content/ts/firestorm/cylat05.tem: Offset: 13138842 Length: 1224 - ^Content/ts/firestorm/cylat05a.tem: + ^SupportDir|Content/ts/firestorm/cylat05a.tem: Offset: 13140074 Length: 1224 - ^Content/ts/firestorm/cylat06.tem: + ^SupportDir|Content/ts/firestorm/cylat06.tem: Offset: 13141306 Length: 1224 - ^Content/ts/firestorm/cylat06a.tem: + ^SupportDir|Content/ts/firestorm/cylat06a.tem: Offset: 13142538 Length: 1224 - ^Content/ts/firestorm/cylat07.tem: + ^SupportDir|Content/ts/firestorm/cylat07.tem: Offset: 13143770 Length: 1224 - ^Content/ts/firestorm/cylat07a.tem: + ^SupportDir|Content/ts/firestorm/cylat07a.tem: Offset: 13145002 Length: 1224 - ^Content/ts/firestorm/cylat08.tem: + ^SupportDir|Content/ts/firestorm/cylat08.tem: Offset: 13146234 Length: 1224 - ^Content/ts/firestorm/cylat08a.tem: + ^SupportDir|Content/ts/firestorm/cylat08a.tem: Offset: 13147466 Length: 1224 - ^Content/ts/firestorm/cylat09.tem: + ^SupportDir|Content/ts/firestorm/cylat09.tem: Offset: 13148698 Length: 1224 - ^Content/ts/firestorm/cylat09a.tem: + ^SupportDir|Content/ts/firestorm/cylat09a.tem: Offset: 13149930 Length: 1224 - ^Content/ts/firestorm/cylat10.tem: + ^SupportDir|Content/ts/firestorm/cylat10.tem: Offset: 13151162 Length: 1224 - ^Content/ts/firestorm/cylat10a.tem: + ^SupportDir|Content/ts/firestorm/cylat10a.tem: Offset: 13152394 Length: 1224 - ^Content/ts/firestorm/cylat11.tem: + ^SupportDir|Content/ts/firestorm/cylat11.tem: Offset: 13153626 Length: 1224 - ^Content/ts/firestorm/cylat11a.tem: + ^SupportDir|Content/ts/firestorm/cylat11a.tem: Offset: 13154858 Length: 1224 - ^Content/ts/firestorm/cylat12.tem: + ^SupportDir|Content/ts/firestorm/cylat12.tem: Offset: 13156090 Length: 1224 - ^Content/ts/firestorm/cylat12a.tem: + ^SupportDir|Content/ts/firestorm/cylat12a.tem: Offset: 13157322 Length: 1224 - ^Content/ts/firestorm/cylat13.tem: + ^SupportDir|Content/ts/firestorm/cylat13.tem: Offset: 13158554 Length: 1224 - ^Content/ts/firestorm/cylat13a.tem: + ^SupportDir|Content/ts/firestorm/cylat13a.tem: Offset: 13159786 Length: 1224 - ^Content/ts/firestorm/cylat14.tem: + ^SupportDir|Content/ts/firestorm/cylat14.tem: Offset: 13161018 Length: 1224 - ^Content/ts/firestorm/cylat14a.tem: + ^SupportDir|Content/ts/firestorm/cylat14a.tem: Offset: 13162250 Length: 1224 - ^Content/ts/firestorm/cylat15.tem: + ^SupportDir|Content/ts/firestorm/cylat15.tem: Offset: 13163482 Length: 1224 - ^Content/ts/firestorm/cylat15a.tem: + ^SupportDir|Content/ts/firestorm/cylat15a.tem: Offset: 13164714 Length: 1224 - ^Content/ts/firestorm/cylat16.tem: + ^SupportDir|Content/ts/firestorm/cylat16.tem: Offset: 13165946 Length: 1224 - ^Content/ts/firestorm/cylat16a.tem: + ^SupportDir|Content/ts/firestorm/cylat16a.tem: Offset: 13167178 Length: 1224 - ^Content/ts/firestorm/slat01.tem: + ^SupportDir|Content/ts/firestorm/slat01.tem: Offset: 13168410 Length: 1224 - ^Content/ts/firestorm/slat01a.tem: + ^SupportDir|Content/ts/firestorm/slat01a.tem: Offset: 13169642 Length: 1224 - ^Content/ts/firestorm/slat02.tem: + ^SupportDir|Content/ts/firestorm/slat02.tem: Offset: 13170874 Length: 1224 - ^Content/ts/firestorm/slat02a.tem: + ^SupportDir|Content/ts/firestorm/slat02a.tem: Offset: 13172106 Length: 1224 - ^Content/ts/firestorm/slat03.tem: + ^SupportDir|Content/ts/firestorm/slat03.tem: Offset: 13173338 Length: 1224 - ^Content/ts/firestorm/slat03a.tem: + ^SupportDir|Content/ts/firestorm/slat03a.tem: Offset: 13174570 Length: 1224 - ^Content/ts/firestorm/slat04.tem: + ^SupportDir|Content/ts/firestorm/slat04.tem: Offset: 13175802 Length: 1224 - ^Content/ts/firestorm/slat04a.tem: + ^SupportDir|Content/ts/firestorm/slat04a.tem: Offset: 13177034 Length: 1224 - ^Content/ts/firestorm/slat05.tem: + ^SupportDir|Content/ts/firestorm/slat05.tem: Offset: 13178266 Length: 1224 - ^Content/ts/firestorm/slat05a.tem: + ^SupportDir|Content/ts/firestorm/slat05a.tem: Offset: 13179498 Length: 1224 - ^Content/ts/firestorm/slat06.tem: + ^SupportDir|Content/ts/firestorm/slat06.tem: Offset: 13180730 Length: 1224 - ^Content/ts/firestorm/slat06a.tem: + ^SupportDir|Content/ts/firestorm/slat06a.tem: Offset: 13181962 Length: 1224 - ^Content/ts/firestorm/slat07.tem: + ^SupportDir|Content/ts/firestorm/slat07.tem: Offset: 13183194 Length: 1224 - ^Content/ts/firestorm/slat07a.tem: + ^SupportDir|Content/ts/firestorm/slat07a.tem: Offset: 13184426 Length: 1224 - ^Content/ts/firestorm/slat08.tem: + ^SupportDir|Content/ts/firestorm/slat08.tem: Offset: 13185658 Length: 1224 - ^Content/ts/firestorm/slat08a.tem: + ^SupportDir|Content/ts/firestorm/slat08a.tem: Offset: 13186890 Length: 1224 - ^Content/ts/firestorm/slat09.tem: + ^SupportDir|Content/ts/firestorm/slat09.tem: Offset: 13188122 Length: 1224 - ^Content/ts/firestorm/slat09a.tem: + ^SupportDir|Content/ts/firestorm/slat09a.tem: Offset: 13189354 Length: 1224 - ^Content/ts/firestorm/slat10.tem: + ^SupportDir|Content/ts/firestorm/slat10.tem: Offset: 13190586 Length: 1224 - ^Content/ts/firestorm/slat10a.tem: + ^SupportDir|Content/ts/firestorm/slat10a.tem: Offset: 13191818 Length: 1224 - ^Content/ts/firestorm/slat11.tem: + ^SupportDir|Content/ts/firestorm/slat11.tem: Offset: 13193050 Length: 1224 - ^Content/ts/firestorm/slat11a.tem: + ^SupportDir|Content/ts/firestorm/slat11a.tem: Offset: 13194282 Length: 1224 - ^Content/ts/firestorm/slat12.tem: + ^SupportDir|Content/ts/firestorm/slat12.tem: Offset: 13195514 Length: 1224 - ^Content/ts/firestorm/slat12a.tem: + ^SupportDir|Content/ts/firestorm/slat12a.tem: Offset: 13196746 Length: 1224 - ^Content/ts/firestorm/slat13.tem: + ^SupportDir|Content/ts/firestorm/slat13.tem: Offset: 13197978 Length: 1224 - ^Content/ts/firestorm/slat13a.tem: + ^SupportDir|Content/ts/firestorm/slat13a.tem: Offset: 13199210 Length: 1224 - ^Content/ts/firestorm/slat14.tem: + ^SupportDir|Content/ts/firestorm/slat14.tem: Offset: 13200442 Length: 1224 - ^Content/ts/firestorm/slat14a.tem: + ^SupportDir|Content/ts/firestorm/slat14a.tem: Offset: 13201674 Length: 1224 - ^Content/ts/firestorm/slat15.tem: + ^SupportDir|Content/ts/firestorm/slat15.tem: Offset: 13202906 Length: 1224 - ^Content/ts/firestorm/slat15a.tem: + ^SupportDir|Content/ts/firestorm/slat15a.tem: Offset: 13204138 Length: 1224 - ^Content/ts/firestorm/slat16.tem: + ^SupportDir|Content/ts/firestorm/slat16.tem: Offset: 13205370 Length: 1224 - ^Content/ts/firestorm/slat16a.tem: + ^SupportDir|Content/ts/firestorm/slat16a.tem: Offset: 13206602 Length: 1224 - ^Content/ts/firestorm/swamp01.tem: + ^SupportDir|Content/ts/firestorm/swamp01.tem: Offset: 13207834 Length: 1224 - ^Content/ts/firestorm/swamp01a.tem: + ^SupportDir|Content/ts/firestorm/swamp01a.tem: Offset: 13209066 Length: 1224 - ^Content/ts/firestorm/swamp01b.tem: + ^SupportDir|Content/ts/firestorm/swamp01b.tem: Offset: 13210298 Length: 1224 - ^Content/ts/firestorm/swamp01c.tem: + ^SupportDir|Content/ts/firestorm/swamp01c.tem: Offset: 13211530 Length: 1224 - ^Content/ts/firestorm/swamp01d.tem: + ^SupportDir|Content/ts/firestorm/swamp01d.tem: Offset: 13212762 Length: 1224 - ^Content/ts/firestorm/swamp01e.tem: + ^SupportDir|Content/ts/firestorm/swamp01e.tem: Offset: 13213994 Length: 1224 - ^Content/ts/firestorm/swamp01f.tem: + ^SupportDir|Content/ts/firestorm/swamp01f.tem: Offset: 13215226 Length: 1224 - ^Content/ts/firestorm/swamp01g.tem: + ^SupportDir|Content/ts/firestorm/swamp01g.tem: Offset: 13216458 Length: 1224 - ^Content/ts/firestorm/swamp02.tem: + ^SupportDir|Content/ts/firestorm/swamp02.tem: Offset: 13217690 Length: 4848 - ^Content/ts/firestorm/swamp03.tem: + ^SupportDir|Content/ts/firestorm/swamp03.tem: Offset: 13222538 Length: 4848 - ^Content/ts/firestorm/swamp04.tem: + ^SupportDir|Content/ts/firestorm/swamp04.tem: Offset: 13227386 Length: 4848 - ^Content/ts/firestorm/swamp05.tem: + ^SupportDir|Content/ts/firestorm/swamp05.tem: Offset: 13232234 Length: 1224 - ^Content/ts/firestorm/swamp06.tem: + ^SupportDir|Content/ts/firestorm/swamp06.tem: Offset: 13233466 Length: 1224 - ^Content/ts/firestorm/swamp07.tem: + ^SupportDir|Content/ts/firestorm/swamp07.tem: Offset: 13234698 Length: 1224 - ^Content/ts/firestorm/swamp08.tem: + ^SupportDir|Content/ts/firestorm/swamp08.tem: Offset: 13235930 Length: 1224 - ^Content/ts/firestorm/swamp09.tem: + ^SupportDir|Content/ts/firestorm/swamp09.tem: Offset: 13237162 Length: 1224 - ^Content/ts/firestorm/fona01.tem: + ^SupportDir|Content/ts/firestorm/fona01.tem: Offset: 15276198 Length: 2048 - ^Content/ts/firestorm/fona02.tem: + ^SupportDir|Content/ts/firestorm/fona02.tem: Offset: 15278246 Length: 1304 - ^Content/ts/firestorm/fona03.tem: + ^SupportDir|Content/ts/firestorm/fona03.tem: Offset: 15279558 Length: 1864 - ^Content/ts/firestorm/fona04.tem: + ^SupportDir|Content/ts/firestorm/fona04.tem: Offset: 15281430 Length: 1952 - ^Content/ts/firestorm/fona05.tem: + ^SupportDir|Content/ts/firestorm/fona05.tem: Offset: 15283382 Length: 1328 - ^Content/ts/firestorm/fona06.tem: + ^SupportDir|Content/ts/firestorm/fona06.tem: Offset: 15284710 Length: 1160 - ^Content/ts/firestorm/fona07.tem: + ^SupportDir|Content/ts/firestorm/fona07.tem: Offset: 15285878 Length: 1216 - ^Content/ts/firestorm/fona08.tem: + ^SupportDir|Content/ts/firestorm/fona08.tem: Offset: 15287094 Length: 872 - ^Content/ts/firestorm/fona09.tem: + ^SupportDir|Content/ts/firestorm/fona09.tem: Offset: 15287974 Length: 608 - ^Content/ts/firestorm/fona10.tem: + ^SupportDir|Content/ts/firestorm/fona10.tem: Offset: 15288582 Length: 616 - ^Content/ts/firestorm/fona11.tem: + ^SupportDir|Content/ts/firestorm/fona11.tem: Offset: 15289206 Length: 2448 - ^Content/ts/firestorm/fona12.tem: + ^SupportDir|Content/ts/firestorm/fona12.tem: Offset: 15291654 Length: 2360 - ^Content/ts/firestorm/fona13.tem: + ^SupportDir|Content/ts/firestorm/fona13.tem: Offset: 15294022 Length: 1608 - ^Content/ts/firestorm/fona14.tem: + ^SupportDir|Content/ts/firestorm/fona14.tem: Offset: 15295638 Length: 1544 - ^Content/ts/firestorm/fona15.tem: + ^SupportDir|Content/ts/firestorm/fona15.tem: Offset: 15297190 Length: 2496 - ^Content/ts/firestorm/bigblue3.tem: + ^SupportDir|Content/ts/firestorm/bigblue3.tem: Offset: 15299686 Length: 12808 - ^Content/ts/firestorm/ecache01.mix: + ^SupportDir|Content/ts/firestorm/ecache01.mix: Offset: 17400340 Length: 2229224 - ^Content/ts/firestorm/e01sc01.mix: + ^SupportDir|Content/ts/firestorm/e01sc01.mix: Offset: 19629572 Length: 6324 - ^Content/ts/firestorm/e01sc02.mix: + ^SupportDir|Content/ts/firestorm/e01sc02.mix: Offset: 19635908 Length: 6324 - ^Content/ts/firestorm/e01vox01.mix: + ^SupportDir|Content/ts/firestorm/e01vox01.mix: Offset: 19642244 Length: 6313740 - ^Content/ts/firestorm/e01vox02.mix: + ^SupportDir|Content/ts/firestorm/e01vox02.mix: Offset: 25955988 Length: 2273956 - ^Content/ts/firestorm/sounds01.mix: + ^SupportDir|Content/ts/firestorm/sounds01.mix: Offset: 28229956 Length: 990096 - delete: ^Content/ts/expand01.mix - extract-raw: ^Content/ts/scores01.mix - ^Content/ts/firestorm/elusive.aud: + delete: ^SupportDir|Content/ts/expand01.mix + extract-raw: ^SupportDir|Content/ts/scores01.mix + ^SupportDir|Content/ts/firestorm/elusive.aud: Offset: 188 Length: 2991051 - ^Content/ts/firestorm/hacker.aud: + ^SupportDir|Content/ts/firestorm/hacker.aud: Offset: 2991244 Length: 2719611 - ^Content/ts/firestorm/infiltra.aud: + ^SupportDir|Content/ts/firestorm/infiltra.aud: Offset: 5710860 Length: 2915781 - ^Content/ts/firestorm/linkup.aud: + ^SupportDir|Content/ts/firestorm/linkup.aud: Offset: 8626652 Length: 2210011 - ^Content/ts/firestorm/kmachine.aud: + ^SupportDir|Content/ts/firestorm/kmachine.aud: Offset: 10836668 Length: 2323371 - ^Content/ts/firestorm/rainnite.aud: + ^SupportDir|Content/ts/firestorm/rainnite.aud: Offset: 13160044 Length: 2679051 - ^Content/ts/firestorm/slavesys.aud: + ^SupportDir|Content/ts/firestorm/slavesys.aud: Offset: 15839100 Length: 1747576 - ^Content/ts/firestorm/dmachine.aud: + ^SupportDir|Content/ts/firestorm/dmachine.aud: Offset: 17586684 Length: 2492891 - delete: ^Content/ts/scores01.mix + delete: ^SupportDir|Content/ts/scores01.mix diff -Nru openra-20200503/mods/ts/installer/origin.yaml openra-20210321/mods/ts/installer/origin.yaml --- openra-20200503/mods/ts/installer/origin.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/installer/origin.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,47 +7,47 @@ GDFBinary_en_US.dll: 4bb56a449bd0003e7ae67625d90a11ae169319d6 Install: copy: . - ^Content/ts/scores.mix: SCORES.MIX + ^SupportDir|Content/ts/scores.mix: SCORES.MIX extract-raw: TIBSUN.MIX - ^Content/ts/cache.mix: + ^SupportDir|Content/ts/cache.mix: Offset: 300 Length: 169176 - ^Content/ts/conquer.mix: + ^SupportDir|Content/ts/conquer.mix: Offset: 169484 Length: 5700088 - ^Content/ts/isosnow.mix: + ^SupportDir|Content/ts/isosnow.mix: Offset: 5869580 Length: 7624750 - ^Content/ts/isotemp.mix: + ^SupportDir|Content/ts/isotemp.mix: Offset: 13494332 Length: 8617646 - ^Content/ts/local.mix: + ^SupportDir|Content/ts/local.mix: Offset: 22111980 Length: 18044736 - ^Content/ts/sidec01.mix: + ^SupportDir|Content/ts/sidec01.mix: Offset: 40156716 Length: 998476 - ^Content/ts/sidec02.mix: + ^SupportDir|Content/ts/sidec02.mix: Offset: 41155196 Length: 1039996 - ^Content/ts/snow.mix: + ^SupportDir|Content/ts/snow.mix: Offset: 56104508 Length: 2087806 - ^Content/ts/sno.mix: + ^SupportDir|Content/ts/sno.mix: Offset: 58192316 Length: 7826 - ^Content/ts/sounds.mix: + ^SupportDir|Content/ts/sounds.mix: Offset: 58200156 Length: 3224136 - ^Content/ts/speech01.mix: + ^SupportDir|Content/ts/speech01.mix: Offset: 61424300 Length: 6028236 - ^Content/ts/speech02.mix: + ^SupportDir|Content/ts/speech02.mix: Offset: 67452540 Length: 5596628 - ^Content/ts/tem.mix: + ^SupportDir|Content/ts/tem.mix: Offset: 73049180 Length: 7746 - ^Content/ts/temperat.mix: + ^SupportDir|Content/ts/temperat.mix: Offset: 73056940 Length: 2037606 diff -Nru openra-20200503/mods/ts/installer/tibsun.yaml openra-20210321/mods/ts/installer/tibsun.yaml --- openra-20200503/mods/ts/installer/tibsun.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/installer/tibsun.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -4,48 +4,48 @@ AUTOPLAY.WAV: 2dfce5d00f98b641849c29942b651f4e98d30e30 Install: copy: . - ^Content/ts/scores.mix: SCORES.MIX + ^SupportDir|Content/ts/scores.mix: SCORES.MIX extract-raw: INSTALL/TIBSUN.MIX - ^Content/ts/cache.mix: + ^SupportDir|Content/ts/cache.mix: Offset: 300 Length: 169176 - ^Content/ts/conquer.mix: + ^SupportDir|Content/ts/conquer.mix: Offset: 169484 Length: 5700088 - ^Content/ts/isosnow.mix: + ^SupportDir|Content/ts/isosnow.mix: Offset: 5869580 Length: 7624750 - ^Content/ts/isotemp.mix: + ^SupportDir|Content/ts/isotemp.mix: Offset: 13494332 Length: 8617646 - ^Content/ts/local.mix: + ^SupportDir|Content/ts/local.mix: Offset: 22111980 Length: 18044736 - ^Content/ts/sidec01.mix: + ^SupportDir|Content/ts/sidec01.mix: Offset: 40156716 Length: 998476 - ^Content/ts/sidec02.mix: + ^SupportDir|Content/ts/sidec02.mix: Offset: 41155196 Length: 1039996 - ^Content/ts/snow.mix: + ^SupportDir|Content/ts/snow.mix: Offset: 56104508 Length: 2087806 - ^Content/ts/sno.mix: + ^SupportDir|Content/ts/sno.mix: Offset: 58192316 Length: 7826 - ^Content/ts/sounds.mix: + ^SupportDir|Content/ts/sounds.mix: Offset: 58200156 Length: 3224136 - ^Content/ts/speech01.mix: + ^SupportDir|Content/ts/speech01.mix: Offset: 61424300 Length: 6028236 - ^Content/ts/speech02.mix: + ^SupportDir|Content/ts/speech02.mix: Offset: 67452540 Length: 5596628 - ^Content/ts/tem.mix: + ^SupportDir|Content/ts/tem.mix: Offset: 73049180 Length: 7746 - ^Content/ts/temperat.mix: + ^SupportDir|Content/ts/temperat.mix: Offset: 73056940 Length: 2037606 tibsun-linux: Tiberian Sun (GDI or Nod Disc, English) @@ -54,47 +54,47 @@ autoplay.wav: 2dfce5d00f98b641849c29942b651f4e98d30e30 Install: copy: . - ^Content/ts/scores.mix: scores.mix + ^SupportDir|Content/ts/scores.mix: scores.mix extract-raw: install/tibsun.mix - ^Content/ts/cache.mix: + ^SupportDir|Content/ts/cache.mix: Offset: 300 Length: 169176 - ^Content/ts/conquer.mix: + ^SupportDir|Content/ts/conquer.mix: Offset: 169484 Length: 5700088 - ^Content/ts/isosnow.mix: + ^SupportDir|Content/ts/isosnow.mix: Offset: 5869580 Length: 7624750 - ^Content/ts/isotemp.mix: + ^SupportDir|Content/ts/isotemp.mix: Offset: 13494332 Length: 8617646 - ^Content/ts/local.mix: + ^SupportDir|Content/ts/local.mix: Offset: 22111980 Length: 18044736 - ^Content/ts/sidec01.mix: + ^SupportDir|Content/ts/sidec01.mix: Offset: 40156716 Length: 998476 - ^Content/ts/sidec02.mix: + ^SupportDir|Content/ts/sidec02.mix: Offset: 41155196 Length: 1039996 - ^Content/ts/snow.mix: + ^SupportDir|Content/ts/snow.mix: Offset: 56104508 Length: 2087806 - ^Content/ts/sno.mix: + ^SupportDir|Content/ts/sno.mix: Offset: 58192316 Length: 7826 - ^Content/ts/sounds.mix: + ^SupportDir|Content/ts/sounds.mix: Offset: 58200156 Length: 3224136 - ^Content/ts/speech01.mix: + ^SupportDir|Content/ts/speech01.mix: Offset: 61424300 Length: 6028236 - ^Content/ts/speech02.mix: + ^SupportDir|Content/ts/speech02.mix: Offset: 67452540 Length: 5596628 - ^Content/ts/tem.mix: + ^SupportDir|Content/ts/tem.mix: Offset: 73049180 Length: 7746 - ^Content/ts/temperat.mix: + ^SupportDir|Content/ts/temperat.mix: Offset: 73056940 Length: 2037606 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/1ice6/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/1ice6/map.png differ diff -Nru openra-20200503/mods/ts/maps/1ice6/map.yaml openra-20210321/mods/ts/maps/1ice6/map.yaml --- openra-20200503/mods/ts/maps/1ice6/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/1ice6/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -63,776 +63,895 @@ Location: 85,5 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor1: aban07 Location: 77,3 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor2: aban08 Location: 85,-2 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor3: ca0006 Location: 76,-6 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor4: ca0007 Location: 80,-7 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor5: ca0008 Location: 70,-4 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor6: ca0001 Location: 74,10 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor7: ca0020 Location: 70,7 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor8: ca0020 Location: 70,5 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor9: ca0021 Location: 89,13 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor10: ca0021 Location: 89,11 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor11: aban06 Location: 97,-36 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor12: aban11 Location: 108,-37 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor13: ca0016 Location: 95,-25 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor14: ca0016 Location: 115,-18 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor15: ca0003 Location: 106,-16 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor16: ca0011 Location: 82,12 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor17: ca0004 Location: 114,-27 Owner: Neutral Health: 0 - Facing: 96 + Facing: 896 Actor18: ca0018 Location: 92,-39 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor19: ca0018 Location: 92,-41 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor20: ca0018 Location: 108,-41 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor21: ca0018 Location: 101,-14 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor22: ca0018 Location: 115,-13 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor23: ca0018 Location: 86,-6 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor24: aban08 Location: 104,-30 Owner: Neutral Health: 0 - Facing: 96 - Actor25: mutant + Facing: 896 + Actor25: inblulmp + Location: 110,71 + Owner: Neutral + Facing: 896 + Actor26: inblulmp + Location: 86,67 + Owner: Neutral + Facing: 896 + Actor27: inblulmp + Location: 90,49 + Owner: Neutral + Facing: 896 + Actor28: inblulmp + Location: 56,19 + Owner: Neutral + Facing: 896 + Actor29: inblulmp + Location: 56,-26 + Owner: Neutral + Facing: 896 + Actor30: inblulmp + Location: 79,-20 + Owner: Neutral + Facing: 896 + Actor31: inblulmp + Location: 75,-47 + Owner: Neutral + Facing: 896 + Actor32: inblulmp + Location: 101,-54 + Owner: Neutral + Facing: 896 + Actor33: inblulmp + Location: 117,46 + Owner: Neutral + Facing: 896 + Actor34: inblulmp + Location: 164,10 + Owner: Neutral + Facing: 896 + Actor35: ingrnlmp + Location: 96,80 + Owner: Neutral + Facing: 896 + Actor36: ingrnlmp + Location: 67,49 + Owner: Neutral + Facing: 896 + Actor37: ingrnlmp + Location: 30,18 + Owner: Neutral + Facing: 896 + Actor38: ingrnlmp + Location: 32,-9 + Owner: Neutral + Facing: 896 + Actor39: ingrnlmp + Location: 62,-36 + Owner: Neutral + Facing: 896 + Actor40: ingrnlmp + Location: 104,-85 + Owner: Neutral + Facing: 896 + Actor41: ingrnlmp + Location: 185,-4 + Owner: Neutral + Facing: 896 + Actor42: ingrnlmp + Location: 134,28 + Owner: Neutral + Facing: 896 + Actor43: ingrnlmp + Location: 98,38 + Owner: Neutral + Facing: 896 + Actor44: ingrnlmp + Location: 129,6 + Owner: Neutral + Facing: 896 + Actor45: ingrnlmp + Location: 143,-15 + Owner: Neutral + Facing: 896 + Actor46: ingrnlmp + Location: 109,-22 + Owner: Neutral + Facing: 896 + Actor47: ingrnlmp + Location: 102,-37 + Owner: Neutral + Facing: 896 + Actor48: ingrnlmp + Location: 84,1 + Owner: Neutral + Facing: 896 + Actor49: ingrnlmp + Location: 74,8 + Owner: Neutral + Facing: 896 + Actor50: ingrnlmp + Location: 128,-55 + Owner: Neutral + Facing: 896 + Actor51: inblulmp + Location: 143,-38 + Owner: Neutral + Facing: 896 + Actor52: ingrnlmp + Location: 82,-57 + Owner: Neutral + Facing: 896 + Actor53: mutant Location: 81,-3 Owner: Neutral - Health: 100 - Facing: 99 - Actor26: mutant + Facing: 884 + Actor54: mutant Location: 72,1 Owner: Neutral - Health: 100 - Facing: 99 - Actor27: mutant + Facing: 884 + Actor55: mutant Location: 76,9 Owner: Neutral - Health: 100 - Facing: 99 - Actor28: mutant + Facing: 884 + Actor56: mutant Location: 84,9 Owner: Neutral - Health: 100 - Facing: 99 - Actor29: mutant + Facing: 884 + Actor57: mutant Location: 89,6 Owner: Neutral - Health: 100 - Facing: 98 - Actor30: mutant + Facing: 888 + Actor58: mutant Location: 74,-3 Owner: Neutral - Health: 100 - Facing: 98 - Actor31: mutant + Facing: 888 + Actor59: mutant Location: 112,-23 Owner: Neutral - Health: 100 - Facing: 99 - Actor32: mutant + Facing: 884 + Actor60: mutant Location: 108,-19 Owner: Neutral - Health: 100 - Facing: 98 - Actor33: mutant + Facing: 888 + Actor61: mutant Location: 100,-24 Owner: Neutral - Health: 100 - Facing: 100 - Actor34: mutant + Facing: 880 + Actor62: mutant Location: 100,-31 Owner: Neutral - Health: 100 - Facing: 99 - Actor35: mutant + Facing: 884 + Actor63: mutant Location: 99,-38 Owner: Neutral - Health: 100 - Facing: 98 - Actor36: mutant + Facing: 888 + Actor64: mutant Location: 106,-38 Owner: Neutral - Health: 100 - Facing: 98 - Actor37: mutant + Facing: 888 + Actor65: mutant Location: 111,-32 Owner: Neutral - Health: 100 - Facing: 98 - Actor38: mutant3 + Facing: 888 + Actor66: mutant3 Location: 105,-27 Owner: Neutral - Health: 100 - Facing: 99 - Actor39: mutant3 + Facing: 884 + Actor67: mutant3 Location: 76,5 Owner: Neutral - Health: 100 - Facing: 98 - Actor40: mwmn + Facing: 888 + Actor68: mwmn Location: 80,0 Owner: Neutral - Health: 100 - Facing: 100 - Actor41: mwmn + Facing: 880 + Actor69: mwmn Location: 74,1 Owner: Neutral - Health: 100 - Facing: 98 - Actor42: mwmn + Facing: 888 + Actor70: mwmn Location: 79,8 Owner: Neutral - Health: 100 - Facing: 98 - Actor43: mwmn + Facing: 888 + Actor71: mwmn Location: 107,-31 Owner: Neutral - Health: 100 - Facing: 99 - Actor44: mwmn + Facing: 884 + Actor72: mwmn Location: 104,-34 Owner: Neutral - Health: 100 - Facing: 99 - Actor45: mwmn + Facing: 884 + Actor73: mwmn Location: 104,-24 Owner: Neutral - Health: 100 - Facing: 98 - Actor46: doggie + Facing: 888 + Actor74: doggie Location: 105,-37 - Owner: Neutral - Health: 100 - Facing: 98 - Actor47: doggie + Owner: Creeps + Facing: 888 + Actor75: doggie Location: 110,-21 - Owner: Neutral - Health: 100 - Facing: 99 - Actor48: doggie + Owner: Creeps + Facing: 884 + Actor76: doggie Location: 101,-30 - Owner: Neutral - Health: 100 - Facing: 98 - Actor49: doggie + Owner: Creeps + Facing: 888 + Actor77: doggie Location: 86,1 - Owner: Neutral - Health: 100 - Facing: 98 - Actor50: doggie + Owner: Creeps + Facing: 888 + Actor78: doggie Location: 80,-1 - Owner: Neutral - Health: 100 - Facing: 99 - Actor51: doggie + Owner: Creeps + Facing: 884 + Actor79: doggie Location: 73,6 - Owner: Neutral - Health: 100 - Facing: 98 - Actor52: doggie + Owner: Creeps + Facing: 888 + Actor80: doggie Location: 77,8 - Owner: Neutral - Health: 100 - Facing: 99 - Actor53: tree02 + Owner: Creeps + Facing: 884 + Actor81: tree02 Location: 51,24 Owner: Neutral - Actor54: tree04 + Actor82: tree04 Location: 63,36 Owner: Neutral - Actor55: tree05 + Actor83: tree05 Location: 62,20 Owner: Neutral - Actor56: tree06 + Actor84: tree06 Location: 26,14 Owner: Neutral - Actor57: tree07 + Actor85: tree07 Location: 29,9 Owner: Neutral - Actor58: tree08 + Actor86: tree08 Location: 28,21 Owner: Neutral - Actor59: tree10 + Actor87: tree10 Location: 26,-10 Owner: Neutral - Actor60: tree11 + Actor88: tree11 Location: 32,-2 Owner: Neutral - Actor61: tree12 + Actor89: tree12 Location: 32,1 Owner: Neutral - Actor62: tree13 + Actor90: tree13 Location: 34,7 Owner: Neutral - Actor63: tree17 + Actor91: tree17 Location: 26,-15 Owner: Neutral - Actor64: tree17 + Actor92: tree17 Location: 52,-31 Owner: Neutral - Actor65: tree12 + Actor93: tree12 Location: 71,-45 Owner: Neutral - Actor66: tree11 + Actor94: tree11 Location: 70,-28 Owner: Neutral - Actor67: tree10 + Actor95: tree10 Location: 69,-27 Owner: Neutral - Actor68: tree06 + Actor96: tree06 Location: 64,-49 Owner: Neutral - Actor69: tree05 + Actor97: tree05 Location: 53,-37 Owner: Neutral - Actor70: tree04 + Actor98: tree04 Location: 57,-31 Owner: Neutral - Actor71: tree02 + Actor99: tree02 Location: 63,14 Owner: Neutral - Actor72: tree01 + Actor100: tree01 Location: 83,10 Owner: Neutral - Actor73: tree05 + Actor101: tree05 Location: 92,-60 Owner: Neutral - Actor74: tree07 + Actor102: tree07 Location: 94,-50 Owner: Neutral - Actor75: tree12 + Actor103: tree12 Location: 105,-52 Owner: Neutral - Actor76: tree13 + Actor104: tree13 Location: 109,-64 Owner: Neutral - Actor77: tree15 + Actor105: tree15 Location: 108,-55 Owner: Neutral - Actor78: tree16 + Actor106: tree16 Location: 98,-29 Owner: Neutral - Actor79: tree17 + Actor107: tree17 Location: 113,-20 Owner: Neutral - Actor80: tree18 + Actor108: tree18 Location: 107,-35 Owner: Neutral - Actor81: tree20 + Actor109: tree20 Location: 127,-26 Owner: Neutral - Actor82: tree25 + Actor110: tree25 Location: 46,19 Owner: Neutral - Actor83: tree23 + Actor111: tree23 Location: 47,16 Owner: Neutral - Actor84: tree21 + Actor112: tree21 Location: 64,26 Owner: Neutral - Actor85: tree20 + Actor113: tree20 Location: 81,45 Owner: Neutral - Actor86: tree18 + Actor114: tree18 Location: 81,41 Owner: Neutral - Actor87: tree17 + Actor115: tree17 Location: 85,46 Owner: Neutral - Actor88: tree16 + Actor116: tree16 Location: 79,29 Owner: Neutral - Actor89: tree15 + Actor117: tree15 Location: 82,24 Owner: Neutral - Actor90: tree14 + Actor118: tree14 Location: 91,22 Owner: Neutral - Actor91: tree12 + Actor119: tree12 Location: 94,22 Owner: Neutral - Actor92: tree17 + Actor120: tree17 Location: 102,18 Owner: Neutral - Actor93: tree16 + Actor121: tree16 Location: 99,26 Owner: Neutral - Actor94: tree12 + Actor122: tree12 Location: 97,51 Owner: Neutral - Actor95: tree11 + Actor123: tree11 Location: 109,53 Owner: Neutral - Actor96: tree10 + Actor124: tree10 Location: 110,42 Owner: Neutral - Actor97: tree05 + Actor125: tree05 Location: 119,37 Owner: Neutral - Actor98: tree02 + Actor126: tree02 Location: 112,45 Owner: Neutral - Actor99: tree01 + Actor127: tree01 Location: 115,41 Owner: Neutral - Actor100: tree04 + Actor128: tree04 Location: 113,53 Owner: Neutral - Actor101: tree06 + Actor129: tree06 Location: 121,34 Owner: Neutral - Actor102: tree13 + Actor130: tree13 Location: 121,33 Owner: Neutral - Actor103: tree15 + Actor131: tree15 Location: 127,26 Owner: Neutral - Actor104: tree12 + Actor132: tree12 Location: 128,26 Owner: Neutral - Actor105: tree10 + Actor133: tree10 Location: 136,16 Owner: Neutral - Actor106: tree09 + Actor134: tree09 Location: 137,15 Owner: Neutral - Actor107: tree07 + Actor135: tree07 Location: 146,10 Owner: Neutral - Actor108: tree06 + Actor136: tree06 Location: 157,10 Owner: Neutral - Actor109: tree05 + Actor137: tree05 Location: 162,1 Owner: Neutral - Actor110: tree04 + Actor138: tree04 Location: 164,1 Owner: Neutral - Actor111: tree02 + Actor139: tree02 Location: 173,-7 Owner: Neutral - Actor112: tree13 + Actor140: tree13 Location: 173,-9 Owner: Neutral - Actor113: tree15 + Actor141: tree15 Location: 173,-1 Owner: Neutral - Actor114: tree16 + Actor142: tree16 Location: 170,-16 Owner: Neutral - Actor115: tree17 + Actor143: tree17 Location: 165,-16 Owner: Neutral - Actor116: tree17 + Actor144: tree17 Location: 157,11 Owner: Neutral - Actor117: tree18 + Actor145: tree18 Location: 170,-11 Owner: Neutral - Actor118: tree19 + Actor146: tree19 Location: 167,-1 Owner: Neutral - Actor119: tree20 + Actor147: tree20 Location: 166,-1 Owner: Neutral - Actor120: tree21 + Actor148: tree21 Location: 169,-3 Owner: Neutral - Actor121: tree07 + Actor149: tree07 Location: 169,-8 Owner: Neutral - Actor122: tree07 + Actor150: tree07 Location: 174,-11 Owner: Neutral - Actor123: tree07 + Actor151: tree07 Location: 174,-4 Owner: Neutral - Actor124: tree07 + Actor152: tree07 Location: 146,-25 Owner: Neutral - Actor125: tree11 + Actor153: tree11 Location: 159,-20 Owner: Neutral - Actor126: tree12 + Actor154: tree12 Location: 151,-20 Owner: Neutral - Actor127: tree13 + Actor155: tree13 Location: 160,-19 Owner: Neutral - Actor128: tree15 + Actor156: tree15 Location: 150,-22 Owner: Neutral - Actor129: tree16 + Actor157: tree16 Location: 133,-37 Owner: Neutral - Actor130: tree17 + Actor158: tree17 Location: 132,-39 Owner: Neutral - Actor131: tree18 + Actor159: tree18 Location: 136,-37 Owner: Neutral - Actor132: tree21 + Actor160: tree21 Location: 121,-40 Owner: Neutral - Actor133: tree22 + Actor161: tree22 Location: 120,-41 Owner: Neutral - Actor134: tree23 + Actor162: tree23 Location: 122,-28 Owner: Neutral - Actor135: tree24 + Actor163: tree24 Location: 121,-28 Owner: Neutral - Actor136: tree25 + Actor164: tree25 Location: 129,-19 Owner: Neutral - Actor137: tree17 + Actor165: tree17 Location: 123,-9 Owner: Neutral - Actor138: tree16 + Actor166: tree16 Location: 113,5 Owner: Neutral - Actor139: tree15 + Actor167: tree15 Location: 113,4 Owner: Neutral - Actor140: tree14 + Actor168: tree14 Location: 102,12 Owner: Neutral - Actor141: tree12 + Actor169: tree12 Location: 103,12 Owner: Neutral - Actor142: tree11 + Actor170: tree11 Location: 108,6 Owner: Neutral - Actor143: tree15 + Actor171: tree15 Location: 108,5 Owner: Neutral - Actor144: tree15 + Actor172: tree15 Location: 99,20 Owner: Neutral - Actor145: tree11 + Actor173: tree11 Location: 95,19 Owner: Neutral - Actor146: tree11 + Actor174: tree11 Location: 56,-2 Owner: Neutral - Actor147: tree10 + Actor175: tree10 Location: 48,5 Owner: Neutral - Actor148: tree09 + Actor176: tree09 Location: 47,5 Owner: Neutral - Actor149: tree07 + Actor177: tree07 Location: 47,11 Owner: Neutral - Actor150: tree15 + Actor178: tree15 Location: 60,3 Owner: Neutral - Actor151: tree16 + Actor179: tree16 Location: 53,10 Owner: Neutral - Actor152: tree17 + Actor180: tree17 Location: 56,26 Owner: Neutral - Actor153: tree15 + Actor181: tree15 Location: 51,26 Owner: Neutral - Actor154: tree14 + Actor182: tree14 Location: 54,34 Owner: Neutral - Actor155: tree16 + Actor183: tree16 Location: 55,35 Owner: Neutral - Actor156: tree16 + Actor184: tree16 Location: 27,15 Owner: Neutral - Actor157: tree17 + Actor185: tree17 Location: 27,20 Owner: Neutral - Actor158: tree19 + Actor186: tree19 Location: 29,10 Owner: Neutral - Actor159: tree19 + Actor187: tree19 Location: 108,52 Owner: Neutral - Actor160: tree12 + Actor188: tree12 Location: 128,-39 Owner: Neutral - Actor161: tree11 + Actor189: tree11 Location: 132,-22 Owner: Neutral - Actor162: tree07 + Actor190: tree07 Location: 130,-11 Owner: Neutral - Actor163: tree06 + Actor191: tree06 Location: 124,-3 Owner: Neutral - Actor164: tree05 + Actor192: tree05 Location: 125,-3 Owner: Neutral - Actor165: tree04 + Actor193: tree04 Location: 118,2 Owner: Neutral - Actor166: tree03 + Actor194: tree03 Location: 118,3 Owner: Neutral - Actor167: tree02 + Actor195: tree02 Location: 112,10 Owner: Neutral - Actor168: tree01 + Actor196: tree01 Location: 104,17 Owner: Neutral - Actor169: tree03 + Actor197: tree03 Location: 127,23 Owner: Neutral - Actor170: tree04 + Actor198: tree04 Location: 128,23 Owner: Neutral - Actor171: tree05 + Actor199: tree05 Location: 143,12 Owner: Neutral - Actor172: tree06 + Actor200: tree06 Location: 143,10 Owner: Neutral - Actor173: tree07 + Actor201: tree07 Location: 156,7 Owner: Neutral - Actor174: tree08 + Actor202: tree08 Location: 155,6 Owner: Neutral - Actor175: tree08 + Actor203: tree08 Location: 109,52 Owner: Neutral - Actor176: tibtre01 + Actor204: tibtre01 Location: 30,18 Owner: Neutral - Actor177: tibtre02 + Actor205: tibtre02 Location: 32,-9 Owner: Neutral - Actor178: tibtre03 + Actor206: tibtre03 Location: 62,-36 Owner: Neutral - Actor179: tibtre02 + Actor207: tibtre02 Location: 74,8 Owner: Neutral - Actor180: tibtre03 + Actor208: tibtre03 Location: 84,1 Owner: Neutral - Actor181: tibtre03 + Actor209: tibtre03 Location: 102,-37 Owner: Neutral - Actor182: tibtre02 + Actor210: tibtre02 Location: 109,-22 Owner: Neutral - Actor183: tibtre02 + Actor211: tibtre02 Location: 104,-85 Owner: Neutral - Actor184: tibtre01 + Actor212: tibtre01 Location: 82,-57 Owner: Neutral - Actor185: tibtre01 + Actor213: tibtre01 Location: 143,-15 Owner: Neutral - Actor186: tibtre02 + Actor214: tibtre02 Location: 129,6 Owner: Neutral - Actor187: tibtre03 + Actor215: tibtre03 Location: 98,38 Owner: Neutral - Actor188: tibtre03 + Actor216: tibtre03 Location: 96,80 Owner: Neutral - Actor189: tibtre02 + Actor217: tibtre02 Location: 185,-4 Owner: Neutral - Actor190: tibtre02 + Actor218: tibtre02 Location: 134,28 Owner: Neutral - Actor191: tibtre02 + Actor219: tibtre02 Location: 67,49 Owner: Neutral - Actor192: tibtre03 + Actor220: tibtre03 Location: 128,-55 Owner: Neutral - Actor193: mpspawn + Actor221: mpspawn Location: 53,-18 Owner: Neutral - Actor194: mpspawn + Actor222: mpspawn Location: 147,27 Owner: Neutral - Actor195: mpspawn + Actor223: mpspawn Location: 93,-73 Owner: Neutral - Actor196: mpspawn + Actor224: mpspawn Location: 156,-30 Owner: Neutral - Actor197: mpspawn + Actor225: mpspawn Location: 45,29 Owner: Neutral - Actor198: mpspawn + Actor226: mpspawn Location: 106,63 Owner: Neutral - Actor199: waypoint + Actor227: waypoint Location: 100,0 Owner: Neutral - Actor200: waypoint + Actor228: waypoint Location: 100,0 Owner: Neutral - Actor201: srock01 + Actor229: srock01 Location: 73,-58 Owner: Neutral - Actor202: trock04 + Actor230: trock04 Location: 45,-23 Owner: Neutral - Actor203: trock03 + Actor231: trock03 Location: 31,-6 Owner: Neutral - Actor204: srock02 + Actor232: srock02 Location: 70,-43 Owner: Neutral - Actor205: trock05 + Actor233: bigblue + Location: 75,-47 + Owner: Neutral + Actor234: bigblue + Location: 56,-26 + Owner: Neutral + Actor235: trock05 Location: 56,-23 Owner: Neutral - Actor206: srock03 + Actor236: srock03 Location: 75,-34 Owner: Neutral - Actor207: trock02 + Actor237: trock02 Location: 33,9 Owner: Neutral - Actor208: srock01 + Actor238: bigblue + Location: 101,-54 + Owner: Neutral + Actor239: srock01 Location: 103,-45 Owner: Neutral - Actor209: trock05 + Actor240: bigblue + Location: 79,-20 + Owner: Neutral + Actor241: trock05 Location: 82,-21 Owner: Neutral - Actor210: trock01 + Actor242: bigblue + Location: 56,19 + Owner: Neutral + Actor243: trock01 Location: 55,36 Owner: Neutral - Actor211: srock02 + Actor244: srock02 Location: 126,-24 Owner: Neutral - Actor212: srock03 + Actor245: bigblue + Location: 143,-38 + Owner: Neutral + Actor246: srock03 Location: 88,29 Owner: Neutral - Actor213: srock04 + Actor247: srock04 Location: 86,48 Owner: Neutral - Actor214: srock05 + Actor248: bigblue + Location: 90,49 + Owner: Neutral + Actor249: srock05 Location: 78,65 Owner: Neutral - Actor215: srock04 + Actor250: srock04 Location: 103,47 Owner: Neutral - Actor216: srock01 + Actor251: srock01 Location: 144,17 Owner: Neutral - Actor217: srock03 + Actor252: bigblue + Location: 117,46 + Owner: Neutral + Actor253: srock03 Location: 122,42 Owner: Neutral - Actor218: srock04 + Actor254: srock04 Location: 160,10 Owner: Neutral - Actor219: trock02 + Actor255: bigblue + Location: 164,10 + Owner: Neutral + Actor256: trock02 Location: 122,58 Owner: Neutral - Actor220: srock05 + Actor257: srock05 Location: 179,1 Owner: Neutral - Actor221: trock01 + Actor258: bigblue + Location: 110,71 + Owner: Neutral + Actor259: trock01 Location: 142,43 Owner: Neutral Rules: - World: - GlobalLightingPaletteEffect: - Ambient: 0.6 + ^BaseWorld: + TerrainLighting: + Intensity: 0.6 + HeightStep: 0.008 + INGRNLMP: + TerrainLightSource: + Range: 13c688 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.5 + BlueTint: 0.01 + INBLULMP: + TerrainLightSource: + Range: 15c640 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.01 + BlueTint: 0.7 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/2temp7/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/2temp7/map.png differ diff -Nru openra-20200503/mods/ts/maps/2temp7/map.yaml openra-20210321/mods/ts/maps/2temp7/map.yaml --- openra-20200503/mods/ts/maps/2temp7/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/2temp7/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -52,38 +52,31 @@ Actor0: cabhut Location: 141,0 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor1: cabhut Location: 137,-11 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor2: cabhut Location: 79,25 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor3: cabhut Location: 83,16 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor4: cabhut Location: 81,-15 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor5: cabhut Location: 77,-28 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor6: city22 Location: 175,8 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor7: tibtre01 Location: 45,0 Owner: Neutral @@ -597,12 +590,24 @@ Actor177: lobrdg_a Location: 138,-7 Owner: Neutral + Actor178: lobrdg_r_nw + Location: 125,7 + Owner: Neutral Actor179: lobrdg_a Location: 138,-6 Owner: Neutral + Actor180: lobrdg_b + Location: 126,7 + Owner: Neutral Actor181: lobrdg_a Location: 138,-5 Owner: Neutral + Actor182: lobrdg_r_nw + Location: 125,9 + Owner: Neutral + Actor183: lobrdg_b + Location: 127,7 + Owner: Neutral Actor184: lobrdg_a Location: 138,-4 Owner: Neutral Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/arivruns/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/arivruns/map.png differ diff -Nru openra-20200503/mods/ts/maps/arivruns/map.yaml openra-20210321/mods/ts/maps/arivruns/map.yaml --- openra-20200503/mods/ts/maps/arivruns/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/arivruns/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -62,990 +62,1120 @@ Actor0: cabhut Location: 104,-68 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor1: cabhut Location: 95,-72 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor2: cabhut Location: 169,68 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor3: cabhut Location: 158,64 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor4: cabhut Location: 116,56 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor5: cabhut Location: 120,43 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor6: cabhut Location: 179,-26 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor7: cabhut Location: 172,-30 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor8: cabhut Location: 145,-51 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor9: cabhut Location: 149,-57 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor10: cabhut Location: 95,28 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor11: cabhut Location: 87,24 Owner: Neutral - Health: 100 - Facing: 96 - Actor16: tibtre01 + Facing: 896 + Actor12: cabhut + Location: 174,2 + Owner: Neutral + Facing: 896 + Actor13: cabhut + Location: 183,6 + Owner: Neutral + Facing: 896 + Actor14: cabhut + Location: 239,2 + Owner: Neutral + Facing: 896 + Actor15: cabhut + Location: 229,-2 + Owner: Neutral + Facing: 896 + Actor16: ingrnlmp + Location: 134,-101 + Owner: Neutral + Facing: 896 + Actor17: ingrnlmp + Location: 75,-38 + Owner: Neutral + Facing: 896 + Actor18: ingrnlmp + Location: 53,22 + Owner: Neutral + Facing: 896 + Actor19: ingrnlmp + Location: 85,77 + Owner: Neutral + Facing: 896 + Actor20: ingrnlmp + Location: 92,63 + Owner: Neutral + Facing: 896 + Actor21: ingrnlmp + Location: 111,89 + Owner: Neutral + Facing: 896 + Actor22: ingrnlmp + Location: 178,40 + Owner: Neutral + Facing: 896 + Actor23: ingrnlmp + Location: 209,-36 + Owner: Neutral + Facing: 896 + Actor24: ingrnlmp + Location: 180,-72 + Owner: Neutral + Facing: 896 + Actor25: ingrnlmp + Location: 63,-6 + Owner: Neutral + Facing: 896 + Actor26: ingrnlmp + Location: 170,-62 + Owner: Neutral + Facing: 896 + Actor27: ingrnlmp + Location: 88,-65 + Owner: Neutral + Facing: 896 + Actor28: ingrnlmp + Location: 112,-76 + Owner: Neutral + Facing: 896 + Actor29: ingrnlmp + Location: 100,-5 + Owner: Neutral + Facing: 896 + Actor30: ingrnlmp + Location: 82,41 + Owner: Neutral + Facing: 896 + Actor31: ingrnlmp + Location: 164,56 + Owner: Neutral + Facing: 896 + Actor32: ingrnlmp + Location: 190,5 + Owner: Neutral + Facing: 896 + Actor33: ingrnlmp + Location: 182,-40 + Owner: Neutral + Facing: 896 + Actor34: ingrnlmp + Location: 139,-65 + Owner: Neutral + Facing: 896 + Actor35: inblulmp + Location: 160,72 + Owner: Neutral + Facing: 896 + Actor36: ingrnlmp + Location: 150,71 + Owner: Neutral + Facing: 896 + Actor37: ingrnlmp + Location: 126,114 + Owner: Neutral + Facing: 896 + Actor38: ingrnlmp + Location: 116,-23 + Owner: Neutral + Facing: 896 + Actor39: ingrnlmp + Location: 144,23 + Owner: Neutral + Facing: 896 + Actor40: ingrnlmp + Location: 116,24 + Owner: Neutral + Facing: 896 + Actor41: ingrnlmp + Location: 151,-24 + Owner: Neutral + Facing: 896 + Actor42: inblulmp + Location: 97,-62 + Owner: Neutral + Facing: 896 + Actor43: inblulmp + Location: 146,-6 + Owner: Neutral + Facing: 896 + Actor44: ingrnlmp + Location: 224,0 + Owner: Neutral + Facing: 896 + Actor45: ingrnlmp + Location: 24,11 + Owner: Neutral + Facing: 896 + Actor46: tibtre01 Location: 133,-102 Owner: Neutral - Actor17: tibtre02 + Actor47: tibtre02 Location: 74,-39 Owner: Neutral - Actor18: tibtre03 + Actor48: tibtre03 Location: 52,21 Owner: Neutral - Actor19: tibtre02 + Actor49: tibtre02 Location: 110,88 Owner: Neutral - Actor20: tibtre03 + Actor50: tibtre03 Location: 177,39 Owner: Neutral - Actor21: tibtre01 + Actor51: tibtre01 Location: 208,-37 Owner: Neutral - Actor22: tibtre02 + Actor52: tibtre02 Location: 91,62 Owner: Neutral - Actor23: tibtre03 + Actor53: tibtre03 Location: 84,76 Owner: Neutral - Actor24: tibtre03 + Actor54: tibtre03 Location: 62,-7 Owner: Neutral - Actor25: tibtre03 + Actor55: tibtre03 Location: 179,-73 Owner: Neutral - Actor26: tibtre02 + Actor56: tibtre02 Location: 169,-63 Owner: Neutral - Actor27: tibtre01 + Actor57: tibtre01 Location: 111,-77 Owner: Neutral - Actor28: tibtre02 + Actor58: tibtre02 Location: 87,-66 Owner: Neutral - Actor29: tibtre03 + Actor59: tibtre03 Location: 99,-6 Owner: Neutral - Actor30: tibtre01 + Actor60: tibtre01 Location: 81,40 Owner: Neutral - Actor31: tibtre01 + Actor61: tibtre01 Location: 125,114 Owner: Neutral - Actor32: tibtre01 + Actor62: tibtre01 Location: 150,71 Owner: Neutral - Actor33: tibtre03 + Actor63: tibtre03 Location: 164,56 Owner: Neutral - Actor34: tibtre03 + Actor64: tibtre03 Location: 190,5 Owner: Neutral - Actor35: tibtre02 + Actor65: tibtre02 Location: 138,-66 Owner: Neutral - Actor36: tibtre01 + Actor66: tibtre01 Location: 181,-41 Owner: Neutral - Actor37: tibtre01 + Actor67: tibtre01 Location: 115,23 Owner: Neutral - Actor38: tibtre02 + Actor68: tibtre02 Location: 144,23 Owner: Neutral - Actor39: tibtre01 + Actor69: tibtre01 Location: 115,-24 Owner: Neutral - Actor40: tibtre01 + Actor70: tibtre01 Location: 150,-25 Owner: Neutral - Actor41: tibtre01 + Actor71: tibtre01 Location: 23,10 Owner: Neutral - Actor42: tibtre01 + Actor72: tibtre01 Location: 223,-1 Owner: Neutral - Actor43: tree01 + Actor73: tree01 Location: 96,-61 Owner: Neutral - Actor44: tree02 + Actor74: tree02 Location: 96,-59 Owner: Neutral - Actor45: tree03 + Actor75: tree03 Location: 98,-54 Owner: Neutral - Actor46: tree04 + Actor76: tree04 Location: 100,-53 Owner: Neutral - Actor47: tree05 + Actor77: tree05 Location: 99,-53 Owner: Neutral - Actor48: tree06 + Actor78: tree06 Location: 111,-52 Owner: Neutral - Actor49: tree07 + Actor79: tree07 Location: 110,-54 Owner: Neutral - Actor50: tree08 + Actor80: tree08 Location: 109,-54 Owner: Neutral - Actor51: tree09 + Actor81: tree09 Location: 105,-61 Owner: Neutral - Actor52: tree10 + Actor82: tree10 Location: 105,-60 Owner: Neutral - Actor53: tree10 + Actor83: tree10 Location: 105,-49 Owner: Neutral - Actor54: tree11 + Actor84: tree11 Location: 111,-44 Owner: Neutral - Actor55: tree12 + Actor85: tree12 Location: 112,-44 Owner: Neutral - Actor56: tree13 + Actor86: tree13 Location: 113,-43 Owner: Neutral - Actor57: tree14 + Actor87: tree14 Location: 119,-48 Owner: Neutral - Actor58: tree15 + Actor88: tree15 Location: 120,-48 Owner: Neutral - Actor59: tree16 + Actor89: tree16 Location: 118,-49 Owner: Neutral - Actor60: tree17 + Actor90: tree17 Location: 124,-41 Owner: Neutral - Actor61: tree18 + Actor91: tree18 Location: 126,-41 Owner: Neutral - Actor62: tree19 + Actor92: tree19 Location: 129,-40 Owner: Neutral - Actor63: tree20 + Actor93: tree20 Location: 131,-42 Owner: Neutral - Actor64: tree21 + Actor94: tree21 Location: 134,-44 Owner: Neutral - Actor65: tree22 + Actor95: tree22 Location: 134,-45 Owner: Neutral - Actor66: tree19 + Actor96: tree19 Location: 131,-51 Owner: Neutral - Actor67: tree18 + Actor97: tree18 Location: 130,-51 Owner: Neutral - Actor68: tree17 + Actor98: tree17 Location: 129,-50 Owner: Neutral - Actor69: tree16 + Actor99: tree16 Location: 129,-49 Owner: Neutral - Actor70: tree15 + Actor100: tree15 Location: 137,-58 Owner: Neutral - Actor71: tree14 + Actor101: tree14 Location: 139,-58 Owner: Neutral - Actor72: tree13 + Actor102: tree13 Location: 140,-58 Owner: Neutral - Actor73: tree12 + Actor103: tree12 Location: 144,-58 Owner: Neutral - Actor74: tree11 + Actor104: tree11 Location: 142,-51 Owner: Neutral - Actor75: tree10 + Actor105: tree10 Location: 141,-51 Owner: Neutral - Actor76: tree10 + Actor106: tree10 Location: 153,-50 Owner: Neutral - Actor77: tree09 + Actor107: tree09 Location: 154,-49 Owner: Neutral - Actor78: tree08 + Actor108: tree08 Location: 155,-48 Owner: Neutral - Actor79: tree07 + Actor109: tree07 Location: 151,-50 Owner: Neutral - Actor80: tree07 + Actor110: tree07 Location: 154,-56 Owner: Neutral - Actor81: tree06 + Actor111: tree06 Location: 153,-56 Owner: Neutral - Actor82: tree06 + Actor112: tree06 Location: 167,-50 Owner: Neutral - Actor83: tree05 + Actor113: tree05 Location: 165,-51 Owner: Neutral - Actor84: tree04 + Actor114: tree04 Location: 165,-42 Owner: Neutral - Actor85: tree03 + Actor115: tree03 Location: 167,-41 Owner: Neutral - Actor86: tree02 + Actor116: tree02 Location: 169,-39 Owner: Neutral - Actor87: tree01 + Actor117: tree01 Location: 160,-46 Owner: Neutral - Actor88: tree01 + Actor118: tree01 Location: 175,-41 Owner: Neutral - Actor89: tree03 + Actor119: tree03 Location: 178,-36 Owner: Neutral - Actor90: tree04 + Actor120: tree04 Location: 179,-34 Owner: Neutral - Actor91: tree05 + Actor121: tree05 Location: 179,-32 Owner: Neutral - Actor92: tree05 + Actor122: tree05 Location: 172,-33 Owner: Neutral - Actor93: tree06 + Actor123: tree06 Location: 172,-32 Owner: Neutral - Actor94: tree06 + Actor124: tree06 Location: 171,-24 Owner: Neutral - Actor95: tree07 + Actor125: tree07 Location: 172,-23 Owner: Neutral - Actor96: tree08 + Actor126: tree08 Location: 171,-22 Owner: Neutral - Actor97: tree09 + Actor127: tree09 Location: 178,-21 Owner: Neutral - Actor98: tree10 + Actor128: tree10 Location: 178,-22 Owner: Neutral - Actor99: tree11 + Actor129: tree11 Location: 178,-19 Owner: Neutral - Actor100: tree11 + Actor130: tree11 Location: 167,-17 Owner: Neutral - Actor101: tree12 + Actor131: tree12 Location: 166,-17 Owner: Neutral - Actor102: tree13 + Actor132: tree13 Location: 165,-16 Owner: Neutral - Actor103: tree14 + Actor133: tree14 Location: 164,-16 Owner: Neutral - Actor104: tree15 + Actor134: tree15 Location: 174,-12 Owner: Neutral - Actor105: tree16 + Actor135: tree16 Location: 174,-11 Owner: Neutral - Actor106: tree17 + Actor136: tree17 Location: 173,-10 Owner: Neutral - Actor107: tree18 + Actor137: tree18 Location: 175,-12 Owner: Neutral - Actor108: tree16 + Actor138: tree16 Location: 170,-6 Owner: Neutral - Actor109: tree15 + Actor139: tree15 Location: 171,-7 Owner: Neutral - Actor110: tree13 + Actor140: tree13 Location: 170,-5 Owner: Neutral - Actor111: tree13 + Actor141: tree13 Location: 159,-8 Owner: Neutral - Actor112: tree12 + Actor142: tree12 Location: 158,-8 Owner: Neutral - Actor113: tree11 + Actor143: tree11 Location: 157,-8 Owner: Neutral - Actor114: tree10 + Actor144: tree10 Location: 160,-8 Owner: Neutral - Actor115: tree09 + Actor145: tree09 Location: 161,-10 Owner: Neutral - Actor116: tree11 + Actor146: tree11 Location: 163,1 Owner: Neutral - Actor117: tree12 + Actor147: tree12 Location: 165,1 Owner: Neutral - Actor118: tree13 + Actor148: tree13 Location: 164,-1 Owner: Neutral - Actor119: tree13 + Actor149: tree13 Location: 152,-1 Owner: Neutral - Actor120: tree14 + Actor150: tree14 Location: 150,-1 Owner: Neutral - Actor121: tree15 + Actor151: tree15 Location: 149,-1 Owner: Neutral - Actor122: tree16 + Actor152: tree16 Location: 139,-9 Owner: Neutral - Actor123: tree17 + Actor153: tree17 Location: 138,-9 Owner: Neutral - Actor124: tree18 + Actor154: tree18 Location: 141,-2 Owner: Neutral - Actor125: tree19 + Actor155: tree19 Location: 140,-2 Owner: Neutral - Actor126: tree19 + Actor156: tree19 Location: 146,-1 Owner: Neutral - Actor127: tree19 + Actor157: tree19 Location: 129,-5 Owner: Neutral - Actor128: tree20 + Actor158: tree20 Location: 130,-5 Owner: Neutral - Actor129: tree21 + Actor159: tree21 Location: 128,-6 Owner: Neutral - Actor130: tree19 + Actor160: tree19 Location: 130,3 Owner: Neutral - Actor131: tree18 + Actor161: tree18 Location: 129,3 Owner: Neutral - Actor132: tree17 + Actor162: tree17 Location: 130,4 Owner: Neutral - Actor133: tree16 + Actor163: tree16 Location: 128,4 Owner: Neutral - Actor134: tree16 + Actor164: tree16 Location: 120,-1 Owner: Neutral - Actor135: tree14 + Actor165: tree14 Location: 116,-2 Owner: Neutral - Actor136: tree13 + Actor166: tree13 Location: 119,-1 Owner: Neutral - Actor137: tree13 + Actor167: tree13 Location: 122,6 Owner: Neutral - Actor138: tree12 + Actor168: tree12 Location: 121,6 Owner: Neutral - Actor139: tree12 + Actor169: tree12 Location: 114,4 Owner: Neutral - Actor140: tree11 + Actor170: tree11 Location: 113,5 Owner: Neutral - Actor141: tree11 + Actor171: tree11 Location: 102,-1 Owner: Neutral - Actor142: tree10 + Actor172: tree10 Location: 100,0 Owner: Neutral - Actor143: tree09 + Actor173: tree09 Location: 105,6 Owner: Neutral - Actor144: tree08 + Actor174: tree08 Location: 105,7 Owner: Neutral - Actor145: tree07 + Actor175: tree07 Location: 103,8 Owner: Neutral - Actor146: tree06 + Actor176: tree06 Location: 96,3 Owner: Neutral - Actor147: tree05 + Actor177: tree05 Location: 95,3 Owner: Neutral - Actor148: tree04 + Actor178: tree04 Location: 92,5 Owner: Neutral - Actor149: tree03 + Actor179: tree03 Location: 99,18 Owner: Neutral - Actor150: tree01 + Actor180: tree01 Location: 98,20 Owner: Neutral - Actor151: tree01 + Actor181: tree01 Location: 87,21 Owner: Neutral - Actor152: tree02 + Actor182: tree02 Location: 87,20 Owner: Neutral - Actor153: tree03 + Actor183: tree03 Location: 87,19 Owner: Neutral - Actor155: tree04 + Actor184: tree03 + Location: 96,32 + Owner: Neutral + Actor185: tree04 Location: 96,33 Owner: Neutral - Actor156: tree05 + Actor186: tree05 Location: 96,35 Owner: Neutral - Actor157: tree06 + Actor187: tree06 Location: 86,36 Owner: Neutral - Actor158: tree07 + Actor188: tree07 Location: 90,48 Owner: Neutral - Actor159: tree09 + Actor189: tree09 Location: 93,50 Owner: Neutral - Actor160: tree09 + Actor190: tree09 Location: 91,49 Owner: Neutral - Actor161: tree02 + Actor191: tree02 Location: 100,54 Owner: Neutral - Actor162: tree02 + Actor192: tree02 Location: 109,58 Owner: Neutral - Actor163: tree03 + Actor193: tree03 Location: 113,58 Owner: Neutral - Actor164: tree05 + Actor194: tree05 Location: 124,53 Owner: Neutral - Actor165: tree06 + Actor195: tree06 Location: 124,52 Owner: Neutral - Actor166: tree06 + Actor196: tree06 Location: 108,48 Owner: Neutral - Actor167: tree07 + Actor197: tree07 Location: 106,48 Owner: Neutral - Actor168: tree08 + Actor198: tree08 Location: 104,47 Owner: Neutral - Actor169: tree09 + Actor199: tree09 Location: 100,46 Owner: Neutral - Actor170: tree09 + Actor200: tree09 Location: 116,47 Owner: Neutral - Actor171: tree10 + Actor201: tree10 Location: 115,47 Owner: Neutral - Actor172: tree10 + Actor202: tree10 Location: 133,50 Owner: Neutral - Actor173: tree11 + Actor203: tree11 Location: 132,50 Owner: Neutral - Actor174: tree12 + Actor204: tree12 Location: 139,49 Owner: Neutral - Actor175: tree13 + Actor205: tree13 Location: 141,50 Owner: Neutral - Actor176: tree13 + Actor206: tree13 Location: 151,54 Owner: Neutral - Actor177: tree14 + Actor207: tree14 Location: 152,56 Owner: Neutral - Actor178: tree15 + Actor208: tree15 Location: 145,43 Owner: Neutral - Actor179: tree16 + Actor209: tree16 Location: 144,43 Owner: Neutral - Actor180: tree17 + Actor210: tree17 Location: 130,41 Owner: Neutral - Actor181: tree18 + Actor211: tree18 Location: 129,41 Owner: Neutral - Actor182: tree19 + Actor212: tree19 Location: 129,40 Owner: Neutral - Actor183: tree19 + Actor213: tree19 Location: 122,42 Owner: Neutral - Actor184: tree20 + Actor214: tree20 Location: 121,41 Owner: Neutral - Actor185: tree01 + Actor215: tree01 Location: 160,56 Owner: Neutral - Actor186: tree04 + Actor216: tree04 Location: 155,60 Owner: Neutral - Actor187: tree05 + Actor217: tree05 Location: 158,62 Owner: Neutral - Actor188: tree06 + Actor218: tree06 Location: 159,70 Owner: Neutral - Actor189: tree07 + Actor219: tree07 Location: 156,72 Owner: Neutral - Actor190: tree08 + Actor220: tree08 Location: 170,72 Owner: Neutral - Actor191: tree09 + Actor221: tree09 Location: 172,72 Owner: Neutral - Actor192: tree10 + Actor222: tree10 Location: 173,71 Owner: Neutral - Actor193: tree11 + Actor223: tree11 Location: 168,69 Owner: Neutral - Actor194: tree11 + Actor224: tree11 Location: 156,79 Owner: Neutral - Actor195: tree12 + Actor225: tree12 Location: 155,80 Owner: Neutral - Actor196: tree13 + Actor226: tree13 Location: 155,82 Owner: Neutral - Actor197: tree14 + Actor227: tree14 Location: 155,85 Owner: Neutral - Actor198: tree15 + Actor228: tree15 Location: 155,83 Owner: Neutral - Actor199: tree16 + Actor229: tree16 Location: 157,88 Owner: Neutral - Actor200: tree16 + Actor230: tree16 Location: 153,47 Owner: Neutral - Actor201: tree17 + Actor231: tree17 Location: 151,47 Owner: Neutral - Actor202: tree18 + Actor232: tree18 Location: 125,42 Owner: Neutral - Actor203: tree19 + Actor233: tree19 Location: 127,50 Owner: Neutral - Actor204: tree20 + Actor234: tree20 Location: 111,47 Owner: Neutral - Actor205: tree24 + Actor235: tree24 Location: 86,41 Owner: Neutral - Actor206: tree21 + Actor236: tree21 Location: 87,29 Owner: Neutral - Actor207: tree20 + Actor237: tree20 Location: 86,29 Owner: Neutral - Actor208: tree20 + Actor238: tree20 Location: 90,14 Owner: Neutral - Actor209: tree21 + Actor239: tree21 Location: 91,13 Owner: Neutral - Actor210: tree02 + Actor240: tree02 Location: 95,-75 Owner: Neutral - Actor211: tree03 + Actor241: tree03 Location: 95,-74 Owner: Neutral - Actor212: tree04 + Actor242: tree04 Location: 95,-67 Owner: Neutral - Actor213: tree05 + Actor243: tree05 Location: 95,-65 Owner: Neutral - Actor214: tree05 + Actor244: tree05 Location: 105,-66 Owner: Neutral - Actor215: tree06 + Actor245: tree06 Location: 104,-73 Owner: Neutral - Actor216: tree07 + Actor246: tree07 Location: 103,-77 Owner: Neutral - Actor217: tree08 + Actor247: tree08 Location: 103,-81 Owner: Neutral - Actor218: tree01 + Actor248: tree01 Location: 146,-16 Owner: Neutral - Actor219: tree02 + Actor249: tree02 Location: 147,-16 Owner: Neutral - Actor220: tree03 + Actor250: tree03 Location: 147,-15 Owner: Neutral - Actor221: tree04 + Actor251: tree04 Location: 149,-15 Owner: Neutral - Actor222: tree05 + Actor252: tree05 Location: 149,-16 Owner: Neutral - Actor223: tree06 + Actor253: tree06 Location: 150,-16 Owner: Neutral - Actor224: tree07 + Actor254: tree07 Location: 151,-16 Owner: Neutral - Actor225: tree08 + Actor255: tree08 Location: 151,-14 Owner: Neutral - Actor226: tree12 + Actor256: tree12 Location: 116,-12 Owner: Neutral - Actor227: tree13 + Actor257: tree13 Location: 117,-12 Owner: Neutral - Actor228: tree14 + Actor258: tree14 Location: 118,-12 Owner: Neutral - Actor229: tree15 + Actor259: tree15 Location: 121,-12 Owner: Neutral - Actor230: tree16 + Actor260: tree16 Location: 119,-12 Owner: Neutral - Actor231: tree17 + Actor261: tree17 Location: 117,-10 Owner: Neutral - Actor232: tree18 + Actor262: tree18 Location: 118,-10 Owner: Neutral - Actor233: tree19 + Actor263: tree19 Location: 121,-8 Owner: Neutral - Actor234: tree20 + Actor264: tree20 Location: 120,-11 Owner: Neutral - Actor235: mpspawn + Actor265: mpspawn Location: 59,26 Owner: Neutral - Actor236: mpspawn + Actor266: mpspawn Location: 207,-31 Owner: Neutral - Actor237: mpspawn + Actor267: mpspawn Location: 82,-35 Owner: Neutral - Actor238: mpspawn + Actor268: mpspawn Location: 178,34 Owner: Neutral - Actor239: mpspawn + Actor269: mpspawn Location: 137,-94 Owner: Neutral - Actor240: mpspawn + Actor270: mpspawn Location: 115,85 Owner: Neutral - Actor241: waypoint + Actor271: waypoint Location: 132,-4 Owner: Neutral - Actor242: waypoint + Actor272: waypoint Location: 132,-4 Owner: Neutral - Actor243: trock05 + Actor273: trock05 Location: 76,-62 Owner: Neutral - Actor244: trock01 + Actor274: trock01 Location: 13,8 Owner: Neutral - Actor245: trock04 + Actor275: trock04 Location: 75,-52 Owner: Neutral - Actor246: trock05 - Location: 127,-102 + Actor276: trock01 + Location: 49,-25 Owner: Neutral - Actor247: lobrdg_b - Location: 96,-71 + Actor277: trock01 + Location: 84,-60 Owner: Neutral - Actor248: lobrdg_r_nw + Actor278: lobrdg_r_nw Location: 95,-71 Owner: Neutral - Actor250: trock01 - Location: 84,-60 - Owner: Neutral - Actor251: trock03 + Actor279: trock03 Location: 64,-39 Owner: Neutral - Actor252: trock01 - Location: 49,-25 - Owner: Neutral - Actor253: trock05 - Location: 114,-87 + Actor280: lobrdg_b + Location: 96,-71 Owner: Neutral - Actor254: lobrdg_b - Location: 98,-71 + Actor281: trock05 + Location: 127,-102 Owner: Neutral - Health: 25 - Actor255: lobrdg_b + Actor282: lobrdg_b Location: 97,-71 Owner: Neutral - Actor260: trock05 - Location: 33,-6 - Owner: Neutral - Actor261: trock04 + Actor283: trock04 Location: 25,2 Owner: Neutral - Actor262: trock02 - Location: 121,-92 + Actor284: trock05 + Location: 33,-6 Owner: Neutral - Actor263: lobrdg_b - Location: 100,-71 + Actor285: lobrdg_b + Location: 98,-71 Owner: Neutral Health: 25 - Actor264: lobrdg_b_d - Location: 99,-71 + Actor286: trock05 + Location: 114,-87 Owner: Neutral - Actor269: trock03 - Location: 75,-47 + Actor287: trock02 + Location: 41,-13 Owner: Neutral - Actor270: trock02 + Actor288: trock02 Location: 70,-42 Owner: Neutral - Actor271: trock01 - Location: 68,-39 + Actor289: trock03 + Location: 75,-47 Owner: Neutral - Actor272: trock02 - Location: 41,-13 + Actor290: lobrdg_b_d + Location: 99,-71 Owner: Neutral - Actor273: trock04 + Actor291: trock04 Location: 33,-4 Owner: Neutral - Actor274: trock03 - Location: 120,-89 - Owner: Neutral - Actor275: trock04 - Location: 115,-85 + Actor292: trock01 + Location: 68,-39 Owner: Neutral - Actor276: trock01 - Location: 110,-79 + Actor293: lobrdg_b + Location: 100,-71 Owner: Neutral - Actor277: lobrdg_b - Location: 102,-71 + Health: 25 + Actor294: trock02 + Location: 121,-92 Owner: Neutral - Actor278: lobrdg_b + Actor295: lobrdg_b Location: 101,-71 Owner: Neutral - Actor283: trock03 - Location: 96,-65 + Actor296: trock04 + Location: 115,-85 Owner: Neutral - Actor284: trock03 + Actor297: trock03 Location: 33,-2 Owner: Neutral - Actor285: trock03 - Location: 127,-94 + Actor298: trock03 + Location: 96,-65 Owner: Neutral - Actor286: trock04 - Location: 107,-75 + Actor299: lobrdg_b + Location: 102,-71 Owner: Neutral - Actor287: trock02 - Location: 106,-74 + Actor300: trock01 + Location: 110,-79 Owner: Neutral - Actor288: lobrdg_r_se - Location: 104,-71 + Actor301: trock03 + Location: 120,-89 Owner: Neutral - Actor289: lobrdg_b + Actor302: lobrdg_b Location: 103,-71 Owner: Neutral - Actor294: trock02 + Actor303: trock02 + Location: 106,-74 + Owner: Neutral + Actor304: trock04 + Location: 107,-75 + Owner: Neutral + Actor305: trock02 Location: 93,-60 Owner: Neutral - Actor298: trock05 - Location: 95,-58 + Actor306: lobrdg_r_se + Location: 104,-71 Owner: Neutral - Actor299: trock03 - Location: 115,-76 + Actor307: trock03 + Location: 127,-94 Owner: Neutral - Actor300: trock05 + Actor308: trock05 + Location: 95,-58 + Owner: Neutral + Actor309: trock05 Location: 23,15 Owner: Neutral - Actor301: trock05 - Location: 138,-97 + Actor310: trock03 + Location: 115,-76 + Owner: Neutral + Actor311: trock03 + Location: 26,14 Owner: Neutral - Actor302: trock03 + Actor312: trock03 Location: 49,-9 Owner: Neutral - Actor303: trock03 - Location: 26,14 + Actor313: trock05 + Location: 138,-97 Owner: Neutral - Actor304: trock03 - Location: 141,-99 + Actor314: trock03 + Location: 121,-79 Owner: Neutral - Actor305: trock04 + Actor315: trock04 Location: 127,-85 Owner: Neutral - Actor306: trock03 - Location: 121,-79 + Actor316: trock03 + Location: 141,-99 Owner: Neutral - Actor307: trock04 + Actor317: trock04 Location: 56,-11 Owner: Neutral - Actor308: trock05 + Actor318: trock05 Location: 60,-14 Owner: Neutral - Actor309: trock03 + Actor319: trock02 + Location: 50,-3 + Owner: Neutral + Actor320: trock03 Location: 58,-11 Owner: Neutral - Actor310: trock02 - Location: 50,-3 + Actor321: trock02 + Location: 33,15 Owner: Neutral - Actor311: trock04 + Actor322: trock04 Location: 142,-94 Owner: Neutral - Actor312: trock05 + Actor323: trock05 Location: 130,-81 Owner: Neutral - Actor313: trock02 - Location: 33,15 + Actor324: trock03 + Location: 119,-67 Owner: Neutral - Actor314: trock02 + Actor325: trock02 Location: 124,-72 Owner: Neutral - Actor315: trock03 - Location: 119,-67 - Owner: Neutral - Actor316: trock05 + Actor326: trock05 Location: 131,-77 Owner: Neutral - Actor317: trock04 + Actor327: trock04 Location: 32,23 Owner: Neutral - Actor318: trock03 + Actor328: trock03 Location: 137,-78 Owner: Neutral - Actor319: trock03 + Actor329: trock03 Location: 60,1 Owner: Neutral - Actor320: trock03 + Actor330: trock02 + Location: 43,21 + Owner: Neutral + Actor331: trock03 Location: 154,-90 Owner: Neutral - Actor321: trock02 + Actor332: trock02 Location: 142,-77 Owner: Neutral - Actor322: trock02 - Location: 43,21 - Owner: Neutral - Actor323: trock02 - Location: 155,-86 - Owner: Neutral - Actor324: trock02 + Actor333: trock02 Location: 126,-58 Owner: Neutral - Actor325: trock03 + Actor334: trock03 Location: 48,21 Owner: Neutral - Actor326: trock04 - Location: 128,-55 + Actor335: trock02 + Location: 155,-86 Owner: Neutral - Actor327: trock05 + Actor336: trock05 Location: 127,-54 Owner: Neutral - Actor328: trock02 - Location: 145,-68 + Actor337: trock04 + Location: 128,-55 Owner: Neutral - Actor329: trock04 + Actor338: trock04 Location: 72,4 Owner: Neutral - Actor330: trock05 + Actor339: trock03 + Location: 48,29 + Owner: Neutral + Actor340: trock05 Location: 72,5 Owner: Neutral - Actor331: trock03 - Location: 48,29 + Actor341: trock02 + Location: 145,-68 Owner: Neutral - Actor332: trock04 + Actor342: trock04 Location: 44,35 Owner: Neutral - Actor333: trock02 + Actor343: trock02 Location: 154,-74 Owner: Neutral - Actor334: trock02 - Location: 171,-84 - Owner: Neutral - Actor335: trock01 + Actor344: trock01 Location: 68,19 Owner: Neutral - Actor336: lobrdg_r_ne - Location: 146,-57 + Actor345: trock02 + Location: 171,-84 Owner: Neutral - Actor337: trock03 + Actor346: trock03 Location: 75,13 Owner: Neutral - Actor338: trock01 - Location: 168,-77 + Actor347: lobrdg_r_ne + Location: 146,-57 Owner: Neutral - Actor342: lobrdg_a + Actor348: lobrdg_a Location: 146,-56 Owner: Neutral - Actor343: lobrdg_a + Actor349: trock02 + Location: 70,21 + Owner: Neutral + Actor350: lobrdg_a Location: 146,-55 Owner: Neutral Health: 25 - Actor344: trock02 - Location: 70,21 + Actor351: trock01 + Location: 168,-77 Owner: Neutral - Actor349: lobrdg_a_d + Actor352: lobrdg_a_d Location: 146,-54 Owner: Neutral - Actor350: lobrdg_a + Actor353: trock02 + Location: 84,9 + Owner: Neutral + Actor354: lobrdg_a Location: 146,-53 Owner: Neutral Health: 25 - Actor351: trock02 - Location: 84,9 + Actor355: trock03 + Location: 56,38 Owner: Neutral Actor356: lobrdg_a Location: 146,-52 @@ -1053,547 +1183,569 @@ Actor357: lobrdg_a Location: 146,-51 Owner: Neutral - Actor358: trock03 - Location: 56,38 - Owner: Neutral - Actor363: lobrdg_r_sw - Location: 146,-50 + Actor358: trock05 + Location: 55,41 Owner: Neutral - Actor364: trock04 + Actor359: trock04 Location: 68,28 Owner: Neutral - Actor365: trock05 - Location: 55,41 + Actor360: lobrdg_r_sw + Location: 146,-50 Owner: Neutral - Actor367: trock05 + Actor361: trock05 Location: 70,30 Owner: Neutral - Actor368: trock03 + Actor362: trock03 Location: 115,-12 Owner: Neutral - Actor369: trock02 + Actor363: trock02 Location: 60,44 Owner: Neutral - Actor370: trock04 - Location: 166,-58 - Owner: Neutral - Actor371: trock05 + Actor364: trock05 Location: 120,-12 Owner: Neutral - Actor372: trock03 + Actor365: trock04 + Location: 166,-58 + Owner: Neutral + Actor366: trock03 Location: 63,46 Owner: Neutral - Actor373: trock02 + Actor367: trock02 + Location: 153,-42 + Owner: Neutral + Actor368: trock02 Location: 173,-62 Owner: Neutral - Actor374: trock02 - Location: 153,-42 + Actor369: lobrdg_r_nw + Location: 87,25 Owner: Neutral - Actor375: trock03 - Location: 170,-57 + Actor370: lobrdg_b + Location: 88,25 Owner: Neutral - Actor376: trock01 + Actor371: trock01 Location: 156,-43 Owner: Neutral - Actor377: lobrdg_b - Location: 88,25 + Actor372: trock03 + Location: 170,-57 Owner: Neutral - Actor378: lobrdg_r_nw - Location: 87,25 + Actor373: lobrdg_b + Location: 89,25 Owner: Neutral - Actor380: trock01 + Actor374: trock01 Location: 173,-59 Owner: Neutral - Actor381: lobrdg_b + Actor375: lobrdg_b Location: 90,25 Owner: Neutral Health: 25 - Actor382: lobrdg_b - Location: 89,25 + Actor376: lobrdg_b_d + Location: 91,25 Owner: Neutral - Actor387: lobrdg_b + Actor377: lobrdg_b Location: 92,25 Owner: Neutral Health: 25 - Actor388: lobrdg_b_d - Location: 91,25 + Actor378: lobrdg_b + Location: 93,25 Owner: Neutral - Actor393: lobrdg_b + Actor379: lobrdg_b Location: 94,25 Owner: Neutral - Actor394: lobrdg_b - Location: 93,25 + Actor380: trock02 + Location: 74,46 Owner: Neutral - Actor399: lobrdg_r_se + Actor381: lobrdg_r_se Location: 95,25 Owner: Neutral - Actor404: trock02 - Location: 74,46 - Owner: Neutral - Actor405: trock03 + Actor382: trock03 Location: 184,-62 Owner: Neutral - Actor407: trock04 + Actor383: trock04 Location: 75,48 Owner: Neutral - Actor408: veinhole + Actor384: veinhole Location: 138,-13 Owner: Neutral - Actor409: trock03 - Location: 145,-16 - Owner: Neutral - Actor410: trock01 + Actor385: trock01 Location: 144,-16 Owner: Neutral - Actor411: trock05 - Location: 192,-62 + Actor386: trock03 + Location: 145,-16 Owner: Neutral - Actor412: trock04 + Actor387: trock04 Location: 191,-61 Owner: Neutral - Actor413: trock01 - Location: 68,63 + Actor388: trock05 + Location: 192,-62 Owner: Neutral - Actor414: trock02 - Location: 73,60 + Actor389: trock01 + Location: 68,63 Owner: Neutral - Actor415: trock02 + Actor390: trock02 Location: 69,63 Owner: Neutral - Actor416: lobrdg_r_nw + Actor391: trock02 + Location: 73,60 + Owner: Neutral + Actor392: lobrdg_r_nw Location: 172,-29 Owner: Neutral - Actor417: trock03 - Location: 193,-48 + Actor393: lobrdg_b + Location: 173,-29 Owner: Neutral - Actor418: lobrdg_b + Actor394: lobrdg_b Location: 174,-29 Owner: Neutral Health: 25 - Actor419: lobrdg_b - Location: 173,-29 + Actor395: trock03 + Location: 193,-48 + Owner: Neutral + Actor396: lobrdg_b_d + Location: 175,-29 Owner: Neutral - Actor423: lobrdg_b + Actor397: lobrdg_b Location: 176,-29 Owner: Neutral Health: 25 - Actor424: lobrdg_b_d - Location: 175,-29 - Owner: Neutral - Actor429: lobrdg_b - Location: 178,-29 + Actor398: trock03 + Location: 85,63 Owner: Neutral - Actor430: lobrdg_b + Actor399: lobrdg_b Location: 177,-29 Owner: Neutral - Actor435: lobrdg_r_ne - Location: 157,-8 - Owner: Neutral - Actor436: trock04 + Actor400: trock04 Location: 88,61 Owner: Neutral - Actor437: trock03 - Location: 85,63 + Actor401: lobrdg_r_ne + Location: 157,-8 Owner: Neutral - Actor444: lobrdg_a_d + Actor402: lobrdg_b + Location: 178,-29 + Owner: Neutral + Actor403: lobrdg_a_d Location: 157,-7 Owner: Neutral - Actor445: lobrdg_a_d + Actor404: lobrdg_r_se + Location: 179,-29 + Owner: Neutral + Actor405: lobrdg_a_d Location: 157,-6 Owner: Neutral - Actor451: lobrdg_a_d + Actor406: lobrdg_a_d Location: 157,-5 Owner: Neutral - Actor452: lobrdg_a_d + Actor407: lobrdg_a_d Location: 157,-4 Owner: Neutral - Actor457: lobrdg_a_d + Actor408: lobrdg_a_d Location: 157,-3 Owner: Neutral - Actor458: lobrdg_a_d + Actor409: lobrdg_a_d Location: 157,-2 Owner: Neutral - Actor463: lobrdg_a_d + Actor410: lobrdg_a_d Location: 157,-1 Owner: Neutral - Actor464: lobrdg_r_sw + Actor411: lobrdg_r_sw Location: 157,0 Owner: Neutral - Actor465: trock05 - Location: 204,-46 - Owner: Neutral - Actor467: trock05 + Actor412: trock05 Location: 81,77 Owner: Neutral - Actor468: lobrdg_r_ne + Actor413: trock05 + Location: 204,-46 + Owner: Neutral + Actor414: lobrdg_r_ne Location: 117,44 Owner: Neutral - Actor472: lobrdg_a + Actor415: lobrdg_a Location: 117,45 Owner: Neutral - Actor473: lobrdg_a + Actor416: lobrdg_a Location: 117,46 Owner: Neutral - Actor478: lobrdg_a + Actor417: lobrdg_a Location: 117,47 Owner: Neutral - Actor479: lobrdg_a + Actor418: lobrdg_a Location: 117,48 Owner: Neutral Health: 25 - Actor480: trock02 - Location: 206,-40 - Owner: Neutral - Actor485: lobrdg_a_d + Actor419: lobrdg_a_d Location: 117,49 Owner: Neutral - Actor486: lobrdg_a_d - Location: 117,50 - Owner: Neutral - Actor487: trock03 - Location: 208,-40 + Actor420: trock02 + Location: 206,-40 Owner: Neutral - Actor491: lobrdg_r_se + Actor421: lobrdg_a_d + Location: 117,50 Owner: Neutral - Location: 179,-29 - Actor492: lobrdg_a_d + Actor422: lobrdg_a_d Location: 117,51 Owner: Neutral - Actor493: lobrdg_a + Actor423: trock03 + Location: 208,-40 + Owner: Neutral + Actor424: lobrdg_a Location: 117,52 Owner: Neutral Health: 25 - Actor498: lobrdg_a + Actor425: lobrdg_a Location: 117,53 Owner: Neutral - Actor499: lobrdg_a + Actor426: lobrdg_a Location: 117,54 Owner: Neutral - Actor504: lobrdg_r_sw + Actor427: lobrdg_r_sw Location: 117,55 Owner: Neutral - Actor506: trock03 + Actor428: trock03 Location: 94,80 Owner: Neutral - Actor507: trock01 + Actor429: bridge1 + Location: 177,4 + Owner: Neutral + Actor430: bridge1 + Location: 178,4 + Owner: Neutral + Actor431: bridge1 + Location: 179,4 + Owner: Neutral + Actor432: bridge1 + Location: 180,4 + Owner: Neutral + Actor433: trock01 Location: 183,1 Owner: Neutral - Actor508: trock05 + Actor434: trock05 Location: 97,91 Owner: Neutral - Actor509: trock02 + Actor435: trock03 + Location: 183,7 + Owner: Neutral + Actor436: trock02 Location: 191,0 Owner: Neutral - Actor510: trock03 - Location: 183,7 + Actor437: trock01 + Location: 107,85 Owner: Neutral - Actor511: trock03 + Actor438: trock03 Location: 193,-1 Owner: Neutral - Actor512: trock05 + Actor439: trock05 Location: 138,55 Owner: Neutral - Actor513: trock01 - Location: 107,85 + Actor440: trock02 + Location: 140,55 Owner: Neutral - Actor514: trock02 + Actor441: trock02 Location: 225,-30 Owner: Neutral - Actor515: trock02 - Location: 140,55 - Owner: Neutral - Actor516: trock03 + Actor442: trock03 Location: 217,-21 Owner: Neutral - Actor517: trock04 - Location: 212,-15 - Owner: Neutral - Actor518: trock04 + Actor443: trock04 Location: 141,56 Owner: Neutral - Actor519: trock03 - Location: 202,-3 + Actor444: trock04 + Location: 212,-15 Owner: Neutral - Actor520: trock02 - Location: 191,8 + Actor445: trock01 + Location: 126,72 Owner: Neutral - Actor521: trock03 + Actor446: trock03 Location: 143,55 Owner: Neutral - Actor522: trock01 - Location: 126,72 + Actor447: trock02 + Location: 191,8 Owner: Neutral - Actor523: trock05 - Location: 213,-12 + Actor448: trock03 + Location: 202,-3 Owner: Neutral - Actor524: trock04 + Actor449: trock04 Location: 106,95 Owner: Neutral - Actor525: trock05 + Actor450: trock05 + Location: 213,-12 + Owner: Neutral + Actor451: trock05 Location: 205,-3 Owner: Neutral - Actor526: trock01 - Location: 198,6 + Actor452: trock02 + Location: 111,93 Owner: Neutral - Actor527: trock03 + Actor453: trock03 Location: 150,54 Owner: Neutral - Actor528: trock02 - Location: 111,93 + Actor454: trock01 + Location: 198,6 Owner: Neutral - Actor529: trock03 + Actor455: trock03 Location: 110,96 Owner: Neutral - Actor530: trock01 - Location: 235,-26 + Actor456: trock02 + Location: 200,8 Owner: Neutral - Actor531: trock03 + Actor457: trock03 Location: 201,8 Owner: Neutral - Actor532: trock02 - Location: 200,8 + Actor458: trock01 + Location: 235,-26 Owner: Neutral - Actor533: trock04 + Actor459: trock04 Location: 214,-4 Owner: Neutral - Actor534: trock02 + Actor460: trock02 Location: 216,-4 Owner: Neutral - Actor535: trock03 + Actor461: trock03 Location: 212,2 Owner: Neutral - Actor536: trock01 - Location: 188,28 - Owner: Neutral - Actor537: trock04 - Location: 165,52 + Actor462: trock03 + Location: 140,76 Owner: Neutral - Actor538: trock03 + Actor463: trock03 Location: 156,60 Owner: Neutral - Actor539: trock03 - Location: 140,76 + Actor464: trock01 + Location: 188,28 Owner: Neutral - Actor540: trock05 + Actor465: trock05 Location: 124,93 Owner: Neutral - Actor541: trock04 + Actor466: trock04 + Location: 165,52 + Owner: Neutral + Actor467: trock04 Location: 236,-18 Owner: Neutral - Actor542: trock05 - Location: 237,-17 + Actor468: trock04 + Location: 143,77 + Owner: Neutral + Actor469: trock03 + Location: 211,9 Owner: Neutral - Actor543: trock01 + Actor470: trock01 Location: 226,-6 Owner: Neutral - Actor544: trock02 - Location: 216,5 + Actor471: trock05 + Location: 237,-17 Owner: Neutral - Actor545: trock03 - Location: 211,9 + Actor472: trock02 + Location: 130,91 + Owner: Neutral + Actor473: trock05 + Location: 143,78 Owner: Neutral - Actor546: trock04 + Actor474: trock04 Location: 204,17 Owner: Neutral - Actor547: trock04 - Location: 143,77 + Actor475: trock02 + Location: 216,5 Owner: Neutral - Actor548: trock05 - Location: 143,78 + Actor476: trock03 + Location: 206,17 Owner: Neutral - Actor549: trock02 - Location: 130,91 + Actor477: trock04 + Location: 215,8 Owner: Neutral - Actor550: trock01 + Actor478: trock01 Location: 241,-18 Owner: Neutral - Actor551: trock04 - Location: 215,8 - Owner: Neutral - Actor552: trock03 - Location: 206,17 + Actor479: lobrdg_r_nw + Location: 159,65 Owner: Neutral - Actor553: trock05 + Actor480: trock05 Location: 218,6 Owner: Neutral - Actor554: trock02 - Location: 179,46 - Owner: Neutral - Actor555: trock02 - Location: 176,49 + Actor481: trock03 + Location: 116,109 Owner: Neutral - Actor556: lobrdg_b + Actor482: lobrdg_b Location: 160,65 Owner: Neutral - Actor557: lobrdg_r_nw - Location: 159,65 - Owner: Neutral - Actor559: trock03 - Location: 116,109 + Actor483: trock02 + Location: 176,49 Owner: Neutral - Actor560: trock03 - Location: 236,-10 + Actor484: trock02 + Location: 179,46 Owner: Neutral - Actor561: trock03 - Location: 202,25 + Actor485: lobrdg_b + Location: 161,65 Owner: Neutral - Actor562: trock01 - Location: 182,45 + Health: 25 + Actor486: trock03 + Location: 236,-10 Owner: Neutral - Actor563: lobrdg_b_d + Actor487: lobrdg_b_d Location: 162,65 Owner: Neutral - Actor564: lobrdg_b - Location: 161,65 + Actor488: trock01 + Location: 182,45 Owner: Neutral - Health: 25 - Actor569: trock02 - Location: 243,-15 + Actor489: trock03 + Location: 202,25 Owner: Neutral - Actor570: trock04 - Location: 179,49 + Actor490: lobrdg_b_d + Location: 163,65 Owner: Neutral - Actor571: trock05 + Actor491: trock05 Location: 176,52 Owner: Neutral - Actor572: lobrdg_b_d - Location: 164,65 + Actor492: trock04 + Location: 179,49 Owner: Neutral - Actor573: lobrdg_b_d - Location: 163,65 + Actor493: trock02 + Location: 243,-15 Owner: Neutral - Actor578: trock02 + Actor494: trock02 Location: 160,69 Owner: Neutral - Actor579: trock03 - Location: 228,3 - Owner: Neutral - Actor580: trock03 - Location: 172,58 + Actor495: lobrdg_b_d + Location: 164,65 Owner: Neutral - Actor581: lobrdg_b - Location: 166,65 + Actor496: trock04 + Location: 138,92 Owner: Neutral - Actor582: lobrdg_b + Actor497: lobrdg_b Location: 165,65 Owner: Neutral Health: 25 - Actor587: trock04 - Location: 138,92 + Actor498: trock03 + Location: 172,58 Owner: Neutral - Actor588: trock05 + Actor499: trock05 Location: 138,93 Owner: Neutral - Actor589: trock03 - Location: 247,-14 + Actor500: lobrdg_b + Location: 166,65 Owner: Neutral - Actor590: trock02 - Location: 206,27 + Actor501: trock03 + Location: 228,3 Owner: Neutral - Actor591: lobrdg_b - Location: 168,65 + Actor502: trock04 + Location: 120,112 Owner: Neutral - Actor592: lobrdg_b + Actor503: lobrdg_b Location: 167,65 Owner: Neutral - Actor597: trock04 - Location: 120,112 + Actor504: bridge1 + Location: 232,0 Owner: Neutral - Actor598: trock05 + Actor505: trock05 Location: 120,113 Owner: Neutral - Actor599: trock02 - Location: 216,18 + Actor506: lobrdg_b + Location: 168,65 Owner: Neutral - Actor600: trock02 - Location: 195,40 + Actor507: trock02 + Location: 206,27 + Owner: Neutral + Actor508: bridge1 + Location: 233,0 Owner: Neutral - Actor601: lobrdg_r_se + Actor509: trock03 + Location: 247,-14 + Owner: Neutral + Actor510: lobrdg_r_se Location: 169,65 Owner: Neutral - Actor606: trock03 + Actor511: trock02 + Location: 216,18 + Owner: Neutral + Actor512: bridge1 + Location: 234,0 + Owner: Neutral + Actor513: trock03 Location: 158,77 Owner: Neutral - Actor607: trock03 - Location: 239,-2 + Actor514: trock02 + Location: 195,40 Owner: Neutral - Actor608: trock03 - Location: 201,36 + Actor515: bridge1 + Location: 235,0 + Owner: Neutral + Actor516: bridge1 + Location: 236,0 Owner: Neutral - Actor609: trock04 + Actor517: trock04 Location: 194,43 Owner: Neutral - Actor611: trock05 + Actor518: trock03 + Location: 201,36 + Owner: Neutral + Actor519: trock03 + Location: 239,-2 + Owner: Neutral + Actor520: trock05 Location: 222,16 Owner: Neutral - Actor612: trock02 + Actor521: trock02 Location: 130,110 Owner: Neutral - Actor613: trock04 + Actor522: trock04 Location: 236,8 Owner: Neutral - Actor614: trock05 - Location: 196,51 - Owner: Neutral - Actor615: trock03 + Actor523: trock03 Location: 193,53 Owner: Neutral - Actor616: trock03 + Actor524: trock03 Location: 147,100 Owner: Neutral - Actor617: trock02 + Actor525: trock05 + Location: 196,51 + Owner: Neutral + Actor526: trock02 Location: 246,3 Owner: Neutral - Actor618: trock03 + Actor527: trock03 Location: 138,112 Owner: Neutral - Actor619: trock02 + Actor528: trock02 Location: 147,106 Owner: Neutral - Actor620: tuntop04 + Actor529: tuntop04 Owner: Neutral Location: 146,5 - Actor621: tuntop04 + Actor530: tuntop04 Owner: Neutral Location: 117,9 - Actor622: tuntop02 + Actor531: tuntop02 Owner: Neutral Location: 146,-19 - Actor623: tuntop02 + Actor532: tuntop02 Owner: Neutral Location: 117,-15 - Actor494: bridge1 + Actor533: bridge1 Owner: Neutral Location: 232,0 - Actor495: bridge1 + Actor534: bridge1 Owner: Neutral Location: 233,0 - Actor496: bridge1 + Actor535: bridge1 Owner: Neutral Location: 234,0 - Actor497: bridge1 + Actor536: bridge1 Owner: Neutral Location: 235,0 - Actor500: bridge1 + Actor537: bridge1 Owner: Neutral Location: 236,0 - Actor501: bridge1 + Actor538: bridge1 Owner: Neutral Location: 177,4 - Actor502: bridge1 + Actor539: bridge1 Owner: Neutral Location: 178,4 - Actor503: bridge1 + Actor540: bridge1 Owner: Neutral Location: 179,4 - Actor505: bridge1 + Actor541: bridge1 Owner: Neutral Location: 180,4 Rules: World: - GlobalLightingPaletteEffect: - Ambient: 0.72 ElevatedBridgeLayer: TerrainTunnelLayer: ElevatedBridgePlaceholder@a: @@ -1618,3 +1770,14 @@ Footprint: ooo ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ooo Height: 2 TerrainType: Clear + ^BaseWorld: + TerrainLighting: + Intensity: 0.695 + HeightStep: 0.05 + INGRNLMP: + TerrainLightSource: + Range: 7c832 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 1 + BlueTint: 0.01 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/cliffsin/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/cliffsin/map.png differ diff -Nru openra-20200503/mods/ts/maps/cliffsin/map.yaml openra-20210321/mods/ts/maps/cliffsin/map.yaml --- openra-20200503/mods/ts/maps/cliffsin/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/cliffsin/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -62,1444 +62,1478 @@ Actor0: bboard01 Location: 94,84 Owner: Neutral - Health: 100 - Facing: 96 - Actor1: visc_lrg + Facing: 896 + Actor1: ingrnlmp + Location: 219,1 + Owner: Neutral + Facing: 896 + Actor2: ingrnlmp + Location: 157,28 + Owner: Neutral + Facing: 896 + Actor3: ingrnlmp + Location: 155,65 + Owner: Neutral + Facing: 896 + Actor4: ingrnlmp + Location: 93,10 + Owner: Neutral + Facing: 896 + Actor5: ingrnlmp + Location: 96,-35 + Owner: Neutral + Facing: 896 + Actor6: ingrnlmp + Location: 153,-27 + Owner: Neutral + Facing: 896 + Actor7: ingrnlmp + Location: 131,-99 + Owner: Neutral + Facing: 896 + Actor8: ingrnlmp + Location: 22,3 + Owner: Neutral + Facing: 896 + Actor9: ingrnlmp + Location: 109,-3 + Owner: Neutral + Facing: 896 + Actor10: visc_lrg Location: 26,3 Owner: Creeps - Health: 100 - Facing: 96 - Actor2: visc_lrg + Facing: 896 + Actor11: visc_lrg Location: 58,39 Owner: Creeps - Health: 100 - Facing: 96 - Actor3: visc_lrg + Facing: 896 + Actor12: visc_lrg Location: 159,65 Owner: Creeps - Health: 100 - Facing: 96 - Actor4: visc_lrg + Facing: 896 + Actor13: visc_lrg Location: 98,10 Owner: Creeps - Health: 100 - Facing: 96 - Actor5: visc_lrg + Facing: 896 + Actor14: visc_lrg Location: 135,-99 Owner: Creeps - Health: 100 - Facing: 96 - Actor6: visc_lrg + Facing: 896 + Actor15: visc_lrg Location: 224,2 Owner: Creeps - Health: 100 - Facing: 96 - Actor7: visc_lrg + Facing: 896 + Actor16: visc_lrg Location: 160,29 Owner: Creeps - Health: 100 - Facing: 96 - Actor8: visc_lrg + Facing: 896 + Actor17: visc_lrg Location: 97,-39 Owner: Creeps - Health: 100 - Facing: 96 - Actor9: visc_lrg + Facing: 896 + Actor18: visc_lrg Location: 151,-28 Owner: Creeps - Health: 100 - Facing: 96 - Actor10: tibtre01 + Facing: 896 + Actor19: tibtre01 Location: 21,2 Owner: Neutral - Actor11: tibtre03 + Actor20: tibtre03 Location: 154,65 Owner: Neutral - Actor12: tibtre01 + Actor21: tibtre01 Location: 156,28 Owner: Neutral - Actor13: tibtre01 + Actor22: tibtre01 Location: 218,0 Owner: Neutral - Actor14: tibtre02 + Actor23: tibtre02 Location: 154,-27 Owner: Neutral - Actor15: tibtre03 + Actor24: tibtre03 Location: 96,-36 Owner: Neutral - Actor16: tibtre01 + Actor25: tibtre01 Location: 130,-100 Owner: Neutral - Actor17: tibtre02 + Actor26: tibtre02 Location: 92,10 Owner: Neutral - Actor18: tree01 + Actor27: tree01 Location: 15,5 Owner: Neutral - Actor19: tree02 + Actor28: tree02 Location: 27,-6 Owner: Neutral - Actor20: tree04 + Actor29: tree04 Location: 27,-7 Owner: Neutral - Actor21: tree03 + Actor30: tree03 Location: 30,-6 Owner: Neutral - Actor22: tree04 + Actor31: tree04 Location: 46,6 Owner: Neutral - Actor23: tree05 + Actor32: tree05 Location: 47,6 Owner: Neutral - Actor24: tree06 + Actor33: tree06 Location: 41,-3 Owner: Neutral - Actor25: tree06 + Actor34: tree06 Location: 55,-29 Owner: Neutral - Actor26: tree07 + Actor35: tree07 Location: 60,-26 Owner: Neutral - Actor27: tree08 + Actor36: tree08 Location: 61,-26 Owner: Neutral - Actor28: tree09 + Actor37: tree09 Location: 61,-28 Owner: Neutral - Actor29: tree11 + Actor38: tree11 Location: 68,-30 Owner: Neutral - Actor30: tree12 + Actor39: tree12 Location: 69,-30 Owner: Neutral - Actor31: tree13 + Actor40: tree13 Location: 69,-28 Owner: Neutral - Actor32: tree13 + Actor41: tree13 Location: 81,-14 Owner: Neutral - Actor33: tree14 + Actor42: tree14 Location: 80,-14 Owner: Neutral - Actor34: tree16 + Actor43: tree16 Location: 82,-15 Owner: Neutral - Actor35: tree17 + Actor44: tree17 Location: 81,-25 Owner: Neutral - Actor36: tree17 + Actor45: tree17 Location: 52,-22 Owner: Neutral - Actor37: tree18 + Actor46: tree18 Location: 53,-22 Owner: Neutral - Actor38: tree20 + Actor47: tree20 Location: 52,-23 Owner: Neutral - Actor39: tree21 + Actor48: tree21 Location: 54,-23 Owner: Neutral - Actor40: tree22 + Actor49: tree22 Location: 61,-24 Owner: Neutral - Actor41: tree24 + Actor50: tree24 Location: 60,-24 Owner: Neutral - Actor42: tree25 + Actor51: tree25 Location: 64,-38 Owner: Neutral - Actor43: tree01 + Actor52: tree01 Location: 38,27 Owner: Neutral - Actor44: tree02 + Actor53: tree02 Location: 39,30 Owner: Neutral - Actor45: tree03 + Actor54: tree03 Location: 43,28 Owner: Neutral - Actor46: tree04 + Actor55: tree04 Location: 47,37 Owner: Neutral - Actor47: tree05 + Actor56: tree05 Location: 47,36 Owner: Neutral - Actor48: tree06 + Actor57: tree06 Location: 55,28 Owner: Neutral - Actor49: tree07 + Actor58: tree07 Location: 55,29 Owner: Neutral - Actor50: tree08 + Actor59: tree08 Location: 56,29 Owner: Neutral - Actor51: tree09 + Actor60: tree09 Location: 58,30 Owner: Neutral - Actor52: tree10 + Actor61: tree10 Location: 74,37 Owner: Neutral - Actor53: tree11 + Actor62: tree11 Location: 75,36 Owner: Neutral - Actor54: tree12 + Actor63: tree12 Location: 76,36 Owner: Neutral - Actor55: tree13 + Actor64: tree13 Location: 75,41 Owner: Neutral - Actor56: tree15 + Actor65: tree15 Location: 78,22 Owner: Neutral - Actor57: tree16 + Actor66: tree16 Location: 78,23 Owner: Neutral - Actor58: tree16 + Actor67: tree16 Location: 71,64 Owner: Neutral - Actor59: tree17 + Actor68: tree17 Location: 71,63 Owner: Neutral - Actor60: tree18 + Actor69: tree18 Location: 71,66 Owner: Neutral - Actor61: tree01 + Actor70: tree01 Location: 93,71 Owner: Neutral - Actor62: tree03 + Actor71: tree03 Location: 93,70 Owner: Neutral - Actor63: tree04 + Actor72: tree04 Location: 94,71 Owner: Neutral - Actor64: tree05 + Actor73: tree05 Location: 96,71 Owner: Neutral - Actor65: tree05 + Actor74: tree05 Location: 99,60 Owner: Neutral - Actor66: tree06 + Actor75: tree06 Location: 100,61 Owner: Neutral - Actor67: tree06 + Actor76: tree06 Location: 97,53 Owner: Neutral - Actor68: tree07 + Actor77: tree07 Location: 96,53 Owner: Neutral - Actor69: tree08 + Actor78: tree08 Location: 96,55 Owner: Neutral - Actor70: tree09 + Actor79: tree09 Location: 97,56 Owner: Neutral - Actor71: tree10 + Actor80: tree10 Location: 108,57 Owner: Neutral - Actor72: tree11 + Actor81: tree11 Location: 108,56 Owner: Neutral - Actor73: tree12 + Actor82: tree12 Location: 109,57 Owner: Neutral - Actor74: tree13 + Actor83: tree13 Location: 112,58 Owner: Neutral - Actor75: tree14 + Actor84: tree14 Location: 107,43 Owner: Neutral - Actor76: tree15 + Actor85: tree15 Location: 110,46 Owner: Neutral - Actor77: tree16 + Actor86: tree16 Location: 110,45 Owner: Neutral - Actor78: tree17 + Actor87: tree17 Location: 111,44 Owner: Neutral - Actor79: tree18 + Actor88: tree18 Location: 110,42 Owner: Neutral - Actor80: tree19 + Actor89: tree19 Location: 110,49 Owner: Neutral - Actor81: tree20 + Actor90: tree20 Location: 113,53 Owner: Neutral - Actor82: tree21 + Actor91: tree21 Location: 121,60 Owner: Neutral - Actor83: tree22 + Actor92: tree22 Location: 120,58 Owner: Neutral - Actor84: tree23 + Actor93: tree23 Location: 122,59 Owner: Neutral - Actor85: tree24 + Actor94: tree24 Location: 122,58 Owner: Neutral - Actor86: tree25 + Actor95: tree25 Location: 122,56 Owner: Neutral - Actor87: tree01 + Actor96: tree01 Location: 116,101 Owner: Neutral - Actor88: tree02 + Actor97: tree02 Location: 117,102 Owner: Neutral - Actor89: tree03 + Actor98: tree03 Location: 116,103 Owner: Neutral - Actor90: tree05 + Actor99: tree05 Location: 133,106 Owner: Neutral - Actor91: tree06 + Actor100: tree06 Location: 142,95 Owner: Neutral - Actor92: tree08 + Actor101: tree08 Location: 148,90 Owner: Neutral - Actor93: tree09 + Actor102: tree09 Location: 147,90 Owner: Neutral - Actor94: tree10 + Actor103: tree10 Location: 146,90 Owner: Neutral - Actor95: tree11 + Actor104: tree11 Location: 150,94 Owner: Neutral - Actor96: tree11 + Actor105: tree11 Location: 120,111 Owner: Neutral - Actor97: tree01 + Actor106: tree01 Location: 145,67 Owner: Neutral - Actor98: tree02 + Actor107: tree02 Location: 146,66 Owner: Neutral - Actor99: tree03 + Actor108: tree03 Location: 147,67 Owner: Neutral - Actor100: tree03 + Actor109: tree03 Location: 152,58 Owner: Neutral - Actor101: tree04 + Actor110: tree04 Location: 151,59 Owner: Neutral - Actor102: tree05 + Actor111: tree05 Location: 149,59 Owner: Neutral - Actor103: tree06 + Actor112: tree06 Location: 148,57 Owner: Neutral - Actor104: tree07 + Actor113: tree07 Location: 150,57 Owner: Neutral - Actor105: tree08 + Actor114: tree08 Location: 156,59 Owner: Neutral - Actor106: tree09 + Actor115: tree09 Location: 150,63 Owner: Neutral - Actor107: tree10 + Actor116: tree10 Location: 163,75 Owner: Neutral - Actor108: tree11 + Actor117: tree11 Location: 166,76 Owner: Neutral - Actor109: tree13 + Actor118: tree13 Location: 165,72 Owner: Neutral - Actor110: tree14 + Actor119: tree14 Location: 164,72 Owner: Neutral - Actor111: tree14 + Actor120: tree14 Location: 182,57 Owner: Neutral - Actor112: tree15 + Actor121: tree15 Location: 183,56 Owner: Neutral - Actor113: tree16 + Actor122: tree16 Location: 184,58 Owner: Neutral - Actor114: tree17 + Actor123: tree17 Location: 187,55 Owner: Neutral - Actor115: tree18 + Actor124: tree18 Location: 187,54 Owner: Neutral - Actor116: tree19 + Actor125: tree19 Location: 186,54 Owner: Neutral - Actor117: tree20 + Actor126: tree20 Location: 195,46 Owner: Neutral - Actor118: tree21 + Actor127: tree21 Location: 197,47 Owner: Neutral - Actor119: tree22 + Actor128: tree22 Location: 143,45 Owner: Neutral - Actor120: tree23 + Actor129: tree23 Location: 142,45 Owner: Neutral - Actor121: tree24 + Actor130: tree24 Location: 144,47 Owner: Neutral - Actor122: tree25 + Actor131: tree25 Location: 175,63 Owner: Neutral - Actor123: tree02 + Actor132: tree02 Location: 174,63 Owner: Neutral - Actor124: tree03 + Actor133: tree03 Location: 176,62 Owner: Neutral - Actor125: tree03 + Actor134: tree03 Location: 184,53 Owner: Neutral - Actor126: tree01 + Actor135: tree01 Location: 120,26 Owner: Neutral - Actor127: tree02 + Actor136: tree02 Location: 124,28 Owner: Neutral - Actor128: tree03 + Actor137: tree03 Location: 124,27 Owner: Neutral - Actor129: tree04 + Actor138: tree04 Location: 126,29 Owner: Neutral - Actor130: tree04 + Actor139: tree04 Location: 127,21 Owner: Neutral - Actor131: tree05 + Actor140: tree05 Location: 129,22 Owner: Neutral - Actor132: tree06 + Actor141: tree06 Location: 128,23 Owner: Neutral - Actor133: tree07 + Actor142: tree07 Location: 131,21 Owner: Neutral - Actor134: tree08 + Actor143: tree08 Location: 136,27 Owner: Neutral - Actor135: tree09 + Actor144: tree09 Location: 140,27 Owner: Neutral - Actor136: tree10 + Actor145: tree10 Location: 138,24 Owner: Neutral - Actor137: tree11 + Actor146: tree11 Location: 139,23 Owner: Neutral - Actor138: tree11 + Actor147: tree11 Location: 159,36 Owner: Neutral - Actor139: tree11 + Actor148: tree11 Location: 158,36 Owner: Neutral - Actor140: tree12 + Actor149: tree12 Location: 157,36 Owner: Neutral - Actor141: tree13 + Actor150: tree13 Location: 168,29 Owner: Neutral - Actor142: tree14 + Actor151: tree14 Location: 168,27 Owner: Neutral - Actor143: tree15 + Actor152: tree15 Location: 170,28 Owner: Neutral - Actor144: tree16 + Actor153: tree16 Location: 171,27 Owner: Neutral - Actor145: tree17 + Actor154: tree17 Location: 164,21 Owner: Neutral - Actor146: tree18 + Actor155: tree18 Location: 165,23 Owner: Neutral - Actor147: tree19 + Actor156: tree19 Location: 164,23 Owner: Neutral - Actor148: tree21 + Actor157: tree21 Location: 156,20 Owner: Neutral - Actor149: tree21 + Actor158: tree21 Location: 157,20 Owner: Neutral - Actor150: tree23 + Actor159: tree23 Location: 157,21 Owner: Neutral - Actor151: tree08 + Actor160: tree08 Location: 158,21 Owner: Neutral - Actor152: tree01 + Actor161: tree01 Location: 97,23 Owner: Neutral - Actor153: tree02 + Actor162: tree02 Location: 97,21 Owner: Neutral - Actor154: tree03 + Actor163: tree03 Location: 102,23 Owner: Neutral - Actor155: tree04 + Actor164: tree04 Location: 101,22 Owner: Neutral - Actor156: tree05 + Actor165: tree05 Location: 101,21 Owner: Neutral - Actor157: tree06 + Actor166: tree06 Location: 85,6 Owner: Neutral - Actor158: tree07 + Actor167: tree07 Location: 86,7 Owner: Neutral - Actor159: tree08 + Actor168: tree08 Location: 85,7 Owner: Neutral - Actor160: tree09 + Actor169: tree09 Location: 86,5 Owner: Neutral - Actor161: tree09 + Actor170: tree09 Location: 87,16 Owner: Neutral - Actor162: tree10 + Actor171: tree10 Location: 85,15 Owner: Neutral - Actor163: tree11 + Actor172: tree11 Location: 88,15 Owner: Neutral - Actor164: tree12 + Actor173: tree12 Location: 88,13 Owner: Neutral - Actor165: tree13 + Actor174: tree13 Location: 90,18 Owner: Neutral - Actor166: tree13 + Actor175: tree13 Location: 98,2 Owner: Neutral - Actor167: tree14 + Actor176: tree14 Location: 99,1 Owner: Neutral - Actor168: tree15 + Actor177: tree15 Location: 100,3 Owner: Neutral - Actor169: tree16 + Actor178: tree16 Location: 99,4 Owner: Neutral - Actor170: tree17 + Actor179: tree17 Location: 101,5 Owner: Neutral - Actor171: tree19 + Actor180: tree19 Location: 101,4 Owner: Neutral - Actor172: tree20 + Actor181: tree20 Location: 93,-6 Owner: Neutral - Actor173: tree21 + Actor182: tree21 Location: 93,-7 Owner: Neutral - Actor174: tree22 + Actor183: tree22 Location: 96,-6 Owner: Neutral - Actor175: tree23 + Actor184: tree23 Location: 104,-9 Owner: Neutral - Actor176: tree24 + Actor185: tree24 Location: 104,-12 Owner: Neutral - Actor177: tree01 + Actor186: tree01 Location: 100,-17 Owner: Neutral - Actor178: tree03 + Actor187: tree03 Location: 101,-16 Owner: Neutral - Actor179: tree04 + Actor188: tree04 Location: 102,-17 Owner: Neutral - Actor180: tree05 + Actor189: tree05 Location: 101,-11 Owner: Neutral - Actor181: tree06 + Actor190: tree06 Location: 101,-13 Owner: Neutral - Actor182: tree06 + Actor191: tree06 Location: 109,3 Owner: Neutral - Actor183: tree07 + Actor192: tree07 Location: 110,4 Owner: Neutral - Actor184: tree08 + Actor193: tree08 Location: 107,3 Owner: Neutral - Actor185: tree01 + Actor194: tree01 Location: 101,-30 Owner: Neutral - Actor186: tree02 + Actor195: tree02 Location: 101,-32 Owner: Neutral - Actor187: tree03 + Actor196: tree03 Location: 103,-31 Owner: Neutral - Actor188: tree04 + Actor197: tree04 Location: 102,-32 Owner: Neutral - Actor189: tree05 + Actor198: tree05 Location: 112,-32 Owner: Neutral - Actor190: tree06 + Actor199: tree06 Location: 112,-34 Owner: Neutral - Actor191: tree07 + Actor200: tree07 Location: 114,-33 Owner: Neutral - Actor192: tree08 + Actor201: tree08 Location: 111,-46 Owner: Neutral - Actor193: tree09 + Actor202: tree09 Location: 110,-44 Owner: Neutral - Actor194: tree10 + Actor203: tree10 Location: 110,-46 Owner: Neutral - Actor195: tree11 + Actor204: tree11 Location: 120,-27 Owner: Neutral - Actor196: tree12 + Actor205: tree12 Location: 119,-29 Owner: Neutral - Actor197: tree13 + Actor206: tree13 Location: 121,-29 Owner: Neutral - Actor198: tree15 + Actor207: tree15 Location: 119,-30 Owner: Neutral - Actor199: tree16 + Actor208: tree16 Location: 120,-46 Owner: Neutral - Actor200: tree17 + Actor209: tree17 Location: 122,-46 Owner: Neutral - Actor201: tree18 + Actor210: tree18 Location: 122,-44 Owner: Neutral - Actor202: tree19 + Actor211: tree19 Location: 119,-46 Owner: Neutral - Actor203: tree20 + Actor212: tree20 Location: 121,-44 Owner: Neutral - Actor204: tree21 + Actor213: tree21 Location: 148,6 Owner: Neutral - Actor205: tree22 + Actor214: tree22 Location: 145,8 Owner: Neutral - Actor206: tree23 + Actor215: tree23 Location: 150,8 Owner: Neutral - Actor207: tree01 + Actor216: tree01 Location: 93,-76 Owner: Neutral - Actor208: tree02 + Actor217: tree02 Location: 95,-75 Owner: Neutral - Actor209: tree03 + Actor218: tree03 Location: 96,-75 Owner: Neutral - Actor210: tree04 + Actor219: tree04 Location: 108,-82 Owner: Neutral - Actor211: tree05 + Actor220: tree05 Location: 111,-81 Owner: Neutral - Actor212: tree06 + Actor221: tree06 Location: 109,-80 Owner: Neutral - Actor213: tree07 + Actor222: tree07 Location: 112,-93 Owner: Neutral - Actor214: tree08 + Actor223: tree08 Location: 113,-95 Owner: Neutral - Actor215: tree09 + Actor224: tree09 Location: 116,-96 Owner: Neutral - Actor216: tree11 + Actor225: tree11 Location: 119,-97 Owner: Neutral - Actor217: tree13 + Actor226: tree13 Location: 112,-90 Owner: Neutral - Actor218: tree14 + Actor227: tree14 Location: 113,-87 Owner: Neutral - Actor219: tree15 + Actor228: tree15 Location: 113,-86 Owner: Neutral - Actor220: tree16 + Actor229: tree16 Location: 114,-86 Owner: Neutral - Actor221: tree17 + Actor230: tree17 Location: 120,-88 Owner: Neutral - Actor222: tree18 + Actor231: tree18 Location: 122,-88 Owner: Neutral - Actor223: tree19 + Actor232: tree19 Location: 124,-89 Owner: Neutral - Actor224: tree20 + Actor233: tree20 Location: 127,-89 Owner: Neutral - Actor225: tree21 + Actor234: tree21 Location: 129,-89 Owner: Neutral - Actor226: tree03 + Actor235: tree03 Location: 129,-85 Owner: Neutral - Actor227: tree02 + Actor236: tree02 Location: 127,-84 Owner: Neutral - Actor228: tree02 + Actor237: tree02 Location: 131,-107 Owner: Neutral - Actor229: tree06 + Actor238: tree06 Location: 132,-107 Owner: Neutral - Actor230: tree07 + Actor239: tree07 Location: 134,-106 Owner: Neutral - Actor231: tree08 + Actor240: tree08 Location: 129,-107 Owner: Neutral - Actor232: tree09 + Actor241: tree09 Location: 127,-106 Owner: Neutral - Actor233: tree11 + Actor242: tree11 Location: 148,-88 Owner: Neutral - Actor234: tree12 + Actor243: tree12 Location: 148,-91 Owner: Neutral - Actor235: tree13 + Actor244: tree13 Location: 146,-94 Owner: Neutral - Actor236: tree14 + Actor245: tree14 Location: 142,-89 Owner: Neutral - Actor237: tree16 + Actor246: tree16 Location: 142,-69 Owner: Neutral - Actor238: tree17 + Actor247: tree17 Location: 138,-68 Owner: Neutral - Actor239: tree18 + Actor248: tree18 Location: 139,-67 Owner: Neutral - Actor240: tree20 + Actor249: tree20 Location: 130,-57 Owner: Neutral - Actor241: tree21 + Actor250: tree21 Location: 124,-70 Owner: Neutral - Actor242: tree22 + Actor251: tree22 Location: 132,-71 Owner: Neutral - Actor243: tree01 + Actor252: tree01 Location: 135,-43 Owner: Neutral - Actor244: tree03 + Actor253: tree03 Location: 139,-47 Owner: Neutral - Actor245: tree04 + Actor254: tree04 Location: 148,-52 Owner: Neutral - Actor246: tree18 + Actor255: tree18 Location: 147,-54 Owner: Neutral - Actor247: tree01 + Actor256: tree01 Location: 144,-13 Owner: Neutral - Actor248: tree02 + Actor257: tree02 Location: 146,-11 Owner: Neutral - Actor249: tree03 + Actor258: tree03 Location: 148,-4 Owner: Neutral - Actor250: tree04 + Actor259: tree04 Location: 150,-4 Owner: Neutral - Actor251: tree05 + Actor260: tree05 Location: 150,-7 Owner: Neutral - Actor252: tree06 + Actor261: tree06 Location: 151,-9 Owner: Neutral - Actor253: tree07 + Actor262: tree07 Location: 149,-12 Owner: Neutral - Actor254: tree08 + Actor263: tree08 Location: 149,-9 Owner: Neutral - Actor255: tree09 + Actor264: tree09 Location: 150,-15 Owner: Neutral - Actor256: tree11 + Actor265: tree11 Location: 153,-4 Owner: Neutral - Actor257: tree12 + Actor266: tree12 Location: 153,-3 Owner: Neutral - Actor258: tree13 + Actor267: tree13 Location: 155,-3 Owner: Neutral - Actor259: tree14 + Actor268: tree14 Location: 154,-7 Owner: Neutral - Actor260: tree16 + Actor269: tree16 Location: 168,-4 Owner: Neutral - Actor261: tree17 + Actor270: tree17 Location: 172,-3 Owner: Neutral - Actor262: tree18 + Actor271: tree18 Location: 169,-8 Owner: Neutral - Actor263: tree19 + Actor272: tree19 Location: 167,-1 Owner: Neutral - Actor264: tree20 + Actor273: tree20 Location: 169,-10 Owner: Neutral - Actor265: tree22 + Actor274: tree22 Location: 159,-13 Owner: Neutral - Actor266: tree23 + Actor275: tree23 Location: 162,-13 Owner: Neutral - Actor267: tree24 + Actor276: tree24 Location: 168,-21 Owner: Neutral - Actor268: tree25 + Actor277: tree25 Location: 168,-18 Owner: Neutral - Actor269: tree01 + Actor278: tree01 Location: 152,-39 Owner: Neutral - Actor270: tree01 + Actor279: tree01 Location: 184,-27 Owner: Neutral - Actor271: tree02 + Actor280: tree02 Location: 188,-26 Owner: Neutral - Actor272: tree05 + Actor281: tree05 Location: 191,-24 Owner: Neutral - Actor273: tree06 + Actor282: tree06 Location: 194,-23 Owner: Neutral - Actor274: tree07 + Actor283: tree07 Location: 196,-25 Owner: Neutral - Actor275: tree08 + Actor284: tree08 Location: 194,-26 Owner: Neutral - Actor276: tree09 + Actor285: tree09 Location: 198,-25 Owner: Neutral - Actor277: tree10 + Actor286: tree10 Location: 201,-24 Owner: Neutral - Actor278: tree11 + Actor287: tree11 Location: 201,-22 Owner: Neutral - Actor279: tree12 + Actor288: tree12 Location: 196,-23 Owner: Neutral - Actor280: tree13 + Actor289: tree13 Location: 198,-24 Owner: Neutral - Actor281: tree16 + Actor290: tree16 Location: 216,24 Owner: Neutral - Actor282: tree17 + Actor291: tree17 Location: 215,20 Owner: Neutral - Actor283: tree19 + Actor292: tree19 Location: 205,25 Owner: Neutral - Actor284: tree20 + Actor293: tree20 Location: 201,27 Owner: Neutral - Actor285: tree21 + Actor294: tree21 Location: 199,6 Owner: Neutral - Actor286: tree23 + Actor295: tree23 Location: 189,-7 Owner: Neutral - Actor287: tree24 + Actor296: tree24 Location: 190,-9 Owner: Neutral - Actor288: tree22 + Actor297: tree22 Location: 188,-5 Owner: Neutral - Actor289: tree21 + Actor298: tree21 Location: 188,-10 Owner: Neutral - Actor290: tree13 + Actor299: tree13 Location: 191,-7 Owner: Neutral - Actor291: tree12 + Actor300: tree12 Location: 187,-8 Owner: Neutral - Actor292: tree10 + Actor301: tree10 Location: 191,-12 Owner: Neutral - Actor293: tree09 + Actor302: tree09 Location: 191,-11 Owner: Neutral - Actor294: tree10 + Actor303: tree10 Location: 200,-10 Owner: Neutral - Actor295: tree18 + Actor304: tree18 Location: 197,-15 Owner: Neutral - Actor296: tree19 + Actor305: tree19 Location: 231,8 Owner: Neutral - Actor297: tree22 + Actor306: tree22 Location: 234,10 Owner: Neutral - Actor298: tree24 + Actor307: tree24 Location: 232,9 Owner: Neutral - Actor299: tree01 + Actor308: tree01 Location: 197,-46 Owner: Neutral - Actor300: tree03 + Actor309: tree03 Location: 202,-39 Owner: Neutral - Actor301: tree04 + Actor310: tree04 Location: 202,-40 Owner: Neutral - Actor302: tree05 + Actor311: tree05 Location: 211,-30 Owner: Neutral - Actor303: tree06 + Actor312: tree06 Location: 210,-32 Owner: Neutral - Actor304: tree07 + Actor313: tree07 Location: 215,-28 Owner: Neutral - Actor305: tree08 + Actor314: tree08 Location: 215,-26 Owner: Neutral - Actor306: tree09 + Actor315: tree09 Location: 213,-25 Owner: Neutral - Actor307: tree10 + Actor316: tree10 Location: 211,-24 Owner: Neutral - Actor308: tree11 + Actor317: tree11 Location: 216,-23 Owner: Neutral - Actor309: tree13 + Actor318: tree13 Location: 220,-21 Owner: Neutral - Actor310: tree14 + Actor319: tree14 Location: 222,-17 Owner: Neutral - Actor311: tree15 + Actor320: tree15 Location: 223,-16 Owner: Neutral - Actor312: tree16 + Actor321: tree16 Location: 225,-15 Owner: Neutral - Actor313: tree18 + Actor322: tree18 Location: 221,-10 Owner: Neutral - Actor314: tree19 + Actor323: tree19 Location: 224,-10 Owner: Neutral - Actor315: tree20 + Actor324: tree20 Location: 226,-8 Owner: Neutral - Actor316: tree21 + Actor325: tree21 Location: 225,-13 Owner: Neutral - Actor317: tree23 + Actor326: tree23 Location: 236,-2 Owner: Neutral - Actor318: tree24 + Actor327: tree24 Location: 234,2 Owner: Neutral - Actor319: tree25 + Actor328: tree25 Location: 239,0 Owner: Neutral - Actor320: tree04 + Actor329: tree04 Location: 211,9 Owner: Neutral - Actor321: tree05 + Actor330: tree05 Location: 210,0 Owner: Neutral - Actor322: tree02 + Actor331: tree02 Location: 150,1 Owner: Neutral - Actor323: tree03 + Actor332: tree03 Location: 153,2 Owner: Neutral - Actor324: tree04 + Actor333: tree04 Location: 152,4 Owner: Neutral - Actor325: tree05 + Actor334: tree05 Location: 150,2 Owner: Neutral - Actor326: tree06 + Actor335: tree06 Location: 152,0 Owner: Neutral - Actor327: tree09 + Actor336: tree09 Location: 154,3 Owner: Neutral - Actor328: tree10 + Actor337: tree10 Location: 154,1 Owner: Neutral - Actor329: tree11 + Actor338: tree11 Location: 153,8 Owner: Neutral - Actor330: tree14 + Actor339: tree14 Location: 154,8 Owner: Neutral - Actor331: tree15 + Actor340: tree15 Location: 153,5 Owner: Neutral - Actor332: tree17 + Actor341: tree17 Location: 153,3 Owner: Neutral - Actor333: tree18 + Actor342: tree18 Location: 151,1 Owner: Neutral - Actor334: tree20 + Actor343: tree20 Location: 155,10 Owner: Neutral - Actor335: tree21 + Actor344: tree21 Location: 153,11 Owner: Neutral - Actor336: tree22 + Actor345: tree22 Location: 153,9 Owner: Neutral - Actor337: tree23 + Actor346: tree23 Location: 156,9 Owner: Neutral - Actor338: tree24 + Actor347: tree24 Location: 155,7 Owner: Neutral - Actor339: tree02 + Actor348: tree02 Location: 70,17 Owner: Neutral - Actor340: tree01 + Actor349: tree01 Location: 73,17 Owner: Neutral - Actor341: tree02 + Actor350: tree02 Location: 74,18 Owner: Neutral - Actor342: tree03 + Actor351: tree03 Location: 75,18 Owner: Neutral - Actor343: tree06 + Actor352: tree06 Location: 79,14 Owner: Neutral - Actor344: tree07 + Actor353: tree07 Location: 80,16 Owner: Neutral - Actor345: tree08 + Actor354: tree08 Location: 82,18 Owner: Neutral - Actor346: tree09 + Actor355: tree09 Location: 83,19 Owner: Neutral - Actor347: tree10 + Actor356: tree10 Location: 78,7 Owner: Neutral - Actor348: tree11 + Actor357: tree11 Location: 81,8 Owner: Neutral - Actor349: tree13 + Actor358: tree13 Location: 70,10 Owner: Neutral - Actor350: tree14 + Actor359: tree14 Location: 71,12 Owner: Neutral - Actor351: tree15 + Actor360: tree15 Location: 74,10 Owner: Neutral - Actor352: tree16 + Actor361: tree16 Location: 73,7 Owner: Neutral - Actor353: tree18 + Actor362: tree18 Location: 73,9 Owner: Neutral - Actor354: tree19 + Actor363: tree19 Location: 74,8 Owner: Neutral - Actor355: tree20 + Actor364: tree20 Location: 79,11 Owner: Neutral - Actor356: tree21 + Actor365: tree21 Location: 81,11 Owner: Neutral - Actor357: tree01 + Actor366: tree01 Location: 180,-23 Owner: Neutral - Actor358: tree02 + Actor367: tree02 Location: 182,-23 Owner: Neutral - Actor359: tree03 + Actor368: tree03 Location: 182,-21 Owner: Neutral - Actor360: tree04 + Actor369: tree04 Location: 185,-21 Owner: Neutral - Actor361: tree06 + Actor370: tree06 Location: 189,-20 Owner: Neutral - Actor362: tree07 + Actor371: tree07 Location: 189,-21 Owner: Neutral - Actor363: tree08 + Actor372: tree08 Location: 186,-21 Owner: Neutral - Actor364: tree09 + Actor373: tree09 Location: 187,-21 Owner: Neutral - Actor365: tree11 + Actor374: tree11 Location: 188,-18 Owner: Neutral - Actor366: tree12 + Actor375: tree12 Location: 189,-18 Owner: Neutral - Actor367: tree13 + Actor376: tree13 Location: 186,-15 Owner: Neutral - Actor368: tree14 + Actor377: tree14 Location: 185,-15 Owner: Neutral - Actor369: tree15 + Actor378: tree15 Location: 183,-15 Owner: Neutral - Actor370: tree16 + Actor379: tree16 Location: 186,-18 Owner: Neutral - Actor371: tree17 + Actor380: tree17 Location: 185,-18 Owner: Neutral - Actor372: tree01 + Actor381: tree01 Location: 72,-43 Owner: Neutral - Actor373: tree02 + Actor382: tree02 Location: 76,-42 Owner: Neutral - Actor374: tree03 + Actor383: tree03 Location: 79,-39 Owner: Neutral - Actor375: tree04 + Actor384: tree04 Location: 80,-42 Owner: Neutral - Actor376: tree05 + Actor385: tree05 Location: 78,-36 Owner: Neutral - Actor377: tree06 + Actor386: tree06 Location: 75,-39 Owner: Neutral - Actor378: tree07 + Actor387: tree07 Location: 74,-40 Owner: Neutral - Actor379: tree08 + Actor388: tree08 Location: 78,-37 Owner: Neutral - Actor380: tree10 + Actor389: tree10 Location: 81,-36 Owner: Neutral - Actor381: tree14 + Actor390: tree14 Location: 68,-41 Owner: Neutral - Actor382: tree15 + Actor391: tree15 Location: 68,-39 Owner: Neutral - Actor383: tree16 + Actor392: tree16 Location: 76,-47 Owner: Neutral - Actor384: tree17 + Actor393: tree17 Location: 81,-31 Owner: Neutral - Actor385: tree18 + Actor394: tree18 Location: 78,-31 Owner: Neutral - Actor386: tree19 + Actor395: tree19 Location: 79,-47 Owner: Neutral - Actor387: tree20 + Actor396: tree20 Location: 81,-45 Owner: Neutral - Actor388: tree20 + Actor397: tree20 Location: 76,-38 Owner: Neutral - Actor389: tree21 + Actor398: tree21 Location: 82,-35 Owner: Neutral - Actor390: tree22 + Actor399: tree22 Location: 82,-38 Owner: Neutral - Actor391: tree02 + Actor400: tree02 Location: 151,10 Owner: Neutral - Actor392: tree03 + Actor401: tree03 Location: 154,10 Owner: Neutral - Actor393: tree04 + Actor402: tree04 Location: 153,10 Owner: Neutral - Actor394: tree05 + Actor403: tree05 Location: 156,10 Owner: Neutral - Actor395: tree06 + Actor404: tree06 Location: 157,10 Owner: Neutral - Actor396: tree08 + Actor405: tree08 Location: 154,7 Owner: Neutral - Actor397: tree09 + Actor406: tree09 Location: 155,8 Owner: Neutral - Actor398: tree12 + Actor407: tree12 Location: 154,4 Owner: Neutral - Actor399: tree14 + Actor408: tree14 Location: 151,2 Owner: Neutral - Actor400: tree14 + Actor409: tree14 Location: 153,12 Owner: Neutral - Actor401: tree15 + Actor410: tree15 Location: 153,13 Owner: Neutral - Actor402: tree16 + Actor411: tree16 Location: 153,14 Owner: Neutral - Actor403: tree17 + Actor412: tree17 Location: 153,15 Owner: Neutral - Actor404: tree18 + Actor413: tree18 Location: 153,16 Owner: Neutral - Actor405: tree20 + Actor414: tree20 Location: 154,15 Owner: Neutral - Actor406: tree21 + Actor415: tree21 Location: 154,14 Owner: Neutral - Actor407: tree22 + Actor416: tree22 Location: 152,16 Owner: Neutral - Actor408: tree23 + Actor417: tree23 Location: 155,12 Owner: Neutral - Actor409: tree24 + Actor418: tree24 Location: 154,11 Owner: Neutral - Actor410: tree25 + Actor419: tree25 Location: 148,13 Owner: Neutral - Actor411: tibtre03 + Actor420: tibtre03 Location: 109,-4 Owner: Neutral - Actor412: tree03 + Actor421: tree03 Location: 81,-56 Owner: Neutral - Actor413: tree04 + Actor422: tree04 Location: 82,-56 Owner: Neutral - Actor414: tree01 + Actor423: tree01 Location: 113,68 Owner: Neutral - Actor415: tree02 + Actor424: tree02 Location: 114,67 Owner: Neutral - Actor416: tree03 + Actor425: tree03 Location: 114,68 Owner: Neutral - Actor417: tree04 + Actor426: tree04 Location: 116,69 Owner: Neutral - Actor418: tree05 + Actor427: tree05 Location: 116,67 Owner: Neutral - Actor419: tree06 + Actor428: tree06 Location: 118,69 Owner: Neutral - Actor420: tree07 + Actor429: tree07 Location: 117,67 Owner: Neutral - Actor421: tree08 + Actor430: tree08 Location: 115,66 Owner: Neutral - Actor422: tree10 + Actor431: tree10 Location: 126,74 Owner: Neutral - Actor423: tree12 + Actor432: tree12 Location: 125,72 Owner: Neutral - Actor424: tree14 + Actor433: tree14 Location: 127,73 Owner: Neutral - Actor425: tree15 + Actor434: tree15 Location: 126,73 Owner: Neutral - Actor426: tree17 + Actor435: tree17 Location: 124,71 Owner: Neutral - Actor427: tree18 + Actor436: tree18 Location: 126,72 Owner: Neutral - Actor428: tree19 + Actor437: tree19 Location: 125,73 Owner: Neutral - Actor429: tree20 + Actor438: tree20 Location: 120,70 Owner: Neutral - Actor430: tree21 + Actor439: tree21 Location: 119,67 Owner: Neutral - Actor431: tree22 + Actor440: tree22 Location: 121,69 Owner: Neutral - Actor432: tree23 + Actor441: tree23 Location: 119,73 Owner: Neutral - Actor433: tree24 + Actor442: tree24 Location: 122,73 Owner: Neutral - Actor434: tree08 + Actor443: tree08 Location: 176,-7 Owner: Neutral - Actor435: tree09 + Actor444: tree09 Location: 177,-8 Owner: Neutral - Actor436: tree10 + Actor445: tree10 Location: 177,-7 Owner: Neutral - Actor437: tree11 + Actor446: tree11 Location: 177,-5 Owner: Neutral - Actor438: tree12 + Actor447: tree12 Location: 178,-5 Owner: Neutral - Actor439: tree13 + Actor448: tree13 Location: 179,-3 Owner: Neutral - Actor440: tree14 + Actor449: tree14 Location: 179,-4 Owner: Neutral - Actor441: tree17 + Actor450: tree17 Location: 178,-2 Owner: Neutral - Actor442: tree02 + Actor451: tree02 Location: 172,-62 Owner: Neutral - Actor443: tree03 + Actor452: tree03 Location: 173,-62 Owner: Neutral - Actor444: tree04 + Actor453: tree04 Location: 174,-61 Owner: Neutral - Actor445: tree05 + Actor454: tree05 Location: 176,-61 Owner: Neutral - Actor446: tree06 + Actor455: tree06 Location: 176,-62 Owner: Neutral - Actor447: tree07 + Actor456: tree07 Location: 173,-63 Owner: Neutral - Actor448: tree11 + Actor457: tree11 Location: 137,-2 Owner: Neutral - Actor449: tree12 + Actor458: tree12 Location: 136,-3 Owner: Neutral - Actor450: tree13 + Actor459: tree13 Location: 136,-1 Owner: Neutral - Actor451: tree14 + Actor460: tree14 Location: 138,0 Owner: Neutral - Actor452: tree15 + Actor461: tree15 Location: 140,-4 Owner: Neutral - Actor453: tree16 + Actor462: tree16 Location: 139,7 Owner: Neutral - Actor454: tree03 + Actor463: tree03 Location: 116,8 Owner: Neutral - Actor455: tree04 + Actor464: tree04 Location: 117,9 Owner: Neutral - Actor456: tree06 + Actor465: tree06 Location: 118,8 Owner: Neutral - Actor457: tree07 + Actor466: tree07 Location: 120,4 Owner: Neutral - Actor458: tree08 + Actor467: tree08 Location: 121,4 Owner: Neutral - Actor459: tree09 + Actor468: tree09 Location: 121,6 Owner: Neutral - Actor460: tree12 + Actor469: tree12 Location: 120,8 Owner: Neutral - Actor461: tree14 + Actor470: tree14 Location: 116,4 Owner: Neutral - Actor462: tree15 + Actor471: tree15 Location: 117,4 Owner: Neutral - Actor463: tree16 + Actor472: tree16 Location: 117,5 Owner: Neutral - Actor464: mpspawn + Actor473: mpspawn Location: 64,-3 Owner: Neutral - Actor465: mpspawn + Actor474: mpspawn Location: 114,78 Owner: Neutral - Actor466: mpspawn + Actor475: mpspawn Location: 181,11 Owner: Neutral - Actor467: mpspawn + Actor476: mpspawn Location: 163,-64 Owner: Neutral - Actor468: mpspawn + Actor477: mpspawn Location: 83,-60 Owner: Neutral - Actor469: mpspawn + Actor478: mpspawn Location: 126,-7 Owner: Neutral - Actor470: waypoint + Actor479: waypoint Location: 124,-1 Owner: Neutral - Actor471: waypoint + Actor480: waypoint Location: 124,-1 Owner: Neutral - Actor472: trock02 + Actor481: trock02 Location: 123,87 Owner: Neutral Rules: - World: - GlobalLightingPaletteEffect: - Ambient: 0.68 + ^BaseWorld: + TerrainLighting: + Intensity: 0.68 + HeightStep: 0.039 + INGRNLMP: + TerrainLightSource: + Range: 7c832 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.8 + BlueTint: 0.01 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/drawbrid/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/drawbrid/map.png differ diff -Nru openra-20200503/mods/ts/maps/drawbrid/map.yaml openra-20210321/mods/ts/maps/drawbrid/map.yaml --- openra-20200503/mods/ts/maps/drawbrid/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/drawbrid/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -69,947 +69,1077 @@ Enemies: Creeps Actors: + Actor0: cabhut + Location: 126,-52 + Owner: Neutral + Facing: 896 + Actor1: cabhut + Location: 109,-56 + Owner: Neutral + Facing: 896 + Actor2: cabhut + Location: 155,-83 + Owner: Neutral + Facing: 896 + Actor3: cabhut + Location: 159,-106 + Owner: Neutral + Facing: 896 + Actor4: cabhut + Location: 101,75 + Owner: Neutral + Facing: 896 + Actor5: cabhut + Location: 115,79 + Owner: Neutral + Facing: 896 + Actor6: cabhut + Location: 154,32 + Owner: Neutral + Facing: 896 + Actor7: cabhut + Location: 158,18 + Owner: Neutral + Facing: 896 + Actor8: cabhut + Location: 221,-41 + Owner: Neutral + Facing: 896 + Actor9: cabhut + Location: 225,-55 + Owner: Neutral + Facing: 896 Actor10: city15 Location: 58,43 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor11: bboard02 Location: 55,49 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor12: ca0009 Location: 64,41 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor13: ca0010 Location: 68,48 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor14: ca0011 Location: 63,49 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor15: ca0011 Location: 65,49 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor16: ca0014 Location: 69,42 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor17: ca0015 Location: 68,44 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor18: city19 Location: 93,40 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor19: city20 Location: 93,43 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor20: city20 Location: 94,43 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor21: city20 Location: 93,44 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor22: city20 Location: 94,44 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor23: city21 Location: 95,42 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor24: ca0014 Location: 189,-75 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor25: ca0015 Location: 190,-72 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor26: ca0016 Location: 193,-75 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor27: caaray Location: 193,-72 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor28: bboard07 Location: 187,-76 Owner: Neutral Health: 50 - Facing: 96 - Actor31: car + Facing: 896 + Actor29: cabhut + Location: 53,29 + Owner: Neutral + Facing: 896 + Actor30: cabhut + Location: 49,5 + Owner: Neutral + Facing: 896 + Actor31: ingrnlmp + Location: 234,-44 + Owner: Neutral + Facing: 896 + Actor32: ingrnlmp + Location: 214,-12 + Owner: Neutral + Facing: 896 + Actor33: ingrnlmp + Location: 194,10 + Owner: Neutral + Facing: 896 + Actor34: ingrnlmp + Location: 141,65 + Owner: Neutral + Facing: 896 + Actor35: ingrnlmp + Location: 71,59 + Owner: Neutral + Facing: 896 + Actor36: ingrnlmp + Location: 81,26 + Owner: Neutral + Facing: 896 + Actor37: ingrnlmp + Location: 180,-64 + Owner: Neutral + Facing: 896 + Actor38: ingrnlmp + Location: 179,-95 + Owner: Neutral + Facing: 896 + Actor39: ingrnlmp + Location: 149,-113 + Owner: Neutral + Facing: 896 + Actor40: ingrnlmp + Location: 72,-29 + Owner: Neutral + Facing: 896 + Actor41: ingrnlmp + Location: 58,-11 + Owner: Neutral + Facing: 896 + Actor42: ingrnlmp + Location: 123,-31 + Owner: Neutral + Facing: 896 + Actor43: ingrnlmp + Location: 122,-41 + Owner: Neutral + Facing: 896 + Actor44: ingrnlmp + Location: 172,6 + Owner: Neutral + Facing: 896 + Actor45: inblulmp + Location: 217,-31 + Owner: Neutral + Facing: 896 + Actor46: inblulmp + Location: 61,25 + Owner: Neutral + Facing: 896 + Actor47: ingrnlmp + Location: 116,-22 + Owner: Neutral + Facing: 896 + Actor48: inblulmp + Location: 174,-29 + Owner: Neutral + Facing: 896 + Actor49: inblulmp + Location: 169,-42 + Owner: Neutral + Facing: 896 + Actor50: ingrnlmp + Location: 117,46 + Owner: Neutral + Facing: 896 + Actor51: inblulmp + Location: 166,52 + Owner: Neutral + Facing: 896 + Actor52: inblulmp + Location: 130,44 + Owner: Neutral + Facing: 896 + Actor53: inblulmp + Location: 151,-73 + Owner: Neutral + Facing: 896 + Actor54: car Location: 94,42 Owner: Neutral - Health: 100 - Facing: 64 - Actor32: pick + Facing: 0 + Actor55: pick Location: 193,-70 Owner: Neutral - Health: 100 - Facing: 160 - Actor33: tibtre01 + Facing: 640 + Actor56: tibtre01 Location: 58,-11 Owner: Neutral - Actor34: tibtre02 + Actor57: tibtre02 Location: 72,-29 Owner: Neutral - Actor35: tibtre03 + Actor58: tibtre03 Location: 149,-113 Owner: Neutral - Actor36: tibtre01 + Actor59: tibtre01 Location: 179,-95 Owner: Neutral - Actor37: tibtre02 + Actor60: tibtre02 Location: 71,59 Owner: Neutral - Actor38: tibtre01 + Actor61: tibtre01 Location: 81,26 Owner: Neutral - Actor39: tibtre03 + Actor62: tibtre03 Location: 180,-64 Owner: Neutral - Actor40: tibtre03 + Actor63: tibtre03 Location: 234,-44 Owner: Neutral - Actor41: tibtre02 + Actor64: tibtre02 Location: 214,-12 Owner: Neutral - Actor42: tibtre01 + Actor65: tibtre01 Location: 194,10 Owner: Neutral - Actor43: tibtre03 + Actor66: tibtre03 Location: 141,65 Owner: Neutral - Actor44: tibtre02 + Actor67: tibtre02 Location: 123,-31 Owner: Neutral - Actor45: tibtre03 + Actor68: tibtre03 Location: 122,-41 Owner: Neutral - Actor46: tibtre01 + Actor69: tibtre01 Location: 172,6 Owner: Neutral - Actor47: tibtre02 + Actor70: tibtre02 Location: 116,-22 Owner: Neutral - Actor48: tibtre03 + Actor71: tibtre03 Location: 117,46 Owner: Neutral - Actor49: fona06 + Actor72: fona06 Location: 177,-11 Owner: Neutral - Actor50: fona07 + Actor73: fona07 Location: 181,-10 Owner: Neutral - Actor51: fona08 + Actor74: fona08 Location: 182,-10 Owner: Neutral - Actor52: fona09 + Actor75: fona09 Location: 183,-9 Owner: Neutral - Actor53: fona08 + Actor76: fona08 Location: 185,-21 Owner: Neutral - Actor54: fona10 + Actor77: fona10 Location: 183,-19 Owner: Neutral - Actor55: fona06 + Actor78: fona06 Location: 181,-18 Owner: Neutral - Actor56: fona07 + Actor79: fona07 Location: 182,-18 Owner: Neutral - Actor57: fona08 + Actor80: fona08 Location: 185,-16 Owner: Neutral - Actor58: fona09 + Actor81: fona09 Location: 178,-17 Owner: Neutral - Actor59: fona06 + Actor82: fona06 Location: 93,-37 Owner: Neutral - Actor60: fona07 + Actor83: fona07 Location: 99,-31 Owner: Neutral - Actor61: fona08 + Actor84: fona08 Location: 97,-38 Owner: Neutral - Actor62: fona09 + Actor85: fona09 Location: 97,-37 Owner: Neutral - Actor63: fona10 + Actor86: fona10 Location: 102,-28 Owner: Neutral - Actor64: fona07 + Actor87: fona07 Location: 102,-24 Owner: Neutral - Actor65: fona07 + Actor88: fona07 Location: 94,-37 Owner: Neutral - Actor66: fona10 + Actor89: fona10 Location: 96,-40 Owner: Neutral - Actor67: fona06 + Actor90: fona06 Location: 100,-32 Owner: Neutral - Actor68: fona08 + Actor91: fona08 Location: 106,-25 Owner: Neutral - Actor69: fona02 + Actor92: fona02 Location: 144,-70 Owner: Neutral - Actor70: fona03 + Actor93: fona03 Location: 153,-71 Owner: Neutral - Actor71: fona04 + Actor94: fona04 Location: 150,-79 Owner: Neutral - Actor72: fona05 + Actor95: fona05 Location: 149,-72 Owner: Neutral - Actor73: fona11 + Actor96: fona11 Location: 146,-69 Owner: Neutral - Actor74: fona12 + Actor97: fona12 Location: 151,-71 Owner: Neutral - Actor75: fona13 + Actor98: fona13 Location: 148,-69 Owner: Neutral - Actor76: fona14 + Actor99: fona14 Location: 149,-76 Owner: Neutral - Actor77: fona15 + Actor100: fona15 Location: 153,-73 Owner: Neutral - Actor78: fona01 + Actor101: fona01 Location: 126,44 Owner: Neutral - Actor79: fona02 + Actor102: fona02 Location: 130,43 Owner: Neutral - Actor80: fona03 + Actor103: fona03 Location: 129,51 Owner: Neutral - Actor81: fona04 + Actor104: fona04 Location: 136,41 Owner: Neutral - Actor82: fona05 + Actor105: fona05 Location: 135,45 Owner: Neutral - Actor83: fona11 + Actor106: fona11 Location: 131,47 Owner: Neutral - Actor84: fona12 + Actor107: fona12 Location: 134,43 Owner: Neutral - Actor85: fona13 + Actor108: fona13 Location: 127,41 Owner: Neutral - Actor86: fona15 + Actor109: fona15 Location: 129,54 Owner: Neutral - Actor87: tree01 + Actor110: tree01 Location: 117,105 Owner: Neutral - Actor88: tree02 + Actor111: tree02 Location: 119,108 Owner: Neutral - Actor89: tree03 + Actor112: tree03 Location: 120,107 Owner: Neutral - Actor90: tree03 + Actor113: tree03 Location: 122,87 Owner: Neutral - Actor91: tree04 + Actor114: tree04 Location: 122,85 Owner: Neutral - Actor92: tree05 + Actor115: tree05 Location: 125,87 Owner: Neutral - Actor93: tree06 + Actor116: tree06 Location: 125,86 Owner: Neutral - Actor94: tree07 + Actor117: tree07 Location: 126,90 Owner: Neutral - Actor95: tree08 + Actor118: tree08 Location: 150,53 Owner: Neutral - Actor96: tree09 + Actor119: tree09 Location: 149,53 Owner: Neutral - Actor97: tree10 + Actor120: tree10 Location: 150,55 Owner: Neutral - Actor98: tree11 + Actor121: tree11 Location: 157,54 Owner: Neutral - Actor99: tree12 + Actor122: tree12 Location: 159,55 Owner: Neutral - Actor100: tree13 + Actor123: tree13 Location: 158,57 Owner: Neutral - Actor101: tree15 + Actor124: tree15 Location: 160,57 Owner: Neutral - Actor102: tree16 + Actor125: tree16 Location: 158,52 Owner: Neutral - Actor103: tree17 + Actor126: tree17 Location: 155,55 Owner: Neutral - Actor104: tree18 + Actor127: tree18 Location: 178,48 Owner: Neutral - Actor105: tree19 + Actor128: tree19 Location: 180,47 Owner: Neutral - Actor106: tree20 + Actor129: tree20 Location: 185,47 Owner: Neutral - Actor107: tree21 + Actor130: tree21 Location: 186,45 Owner: Neutral - Actor108: tree22 + Actor131: tree22 Location: 180,28 Owner: Neutral - Actor109: tree23 + Actor132: tree23 Location: 178,23 Owner: Neutral - Actor110: tree24 + Actor133: tree24 Location: 182,20 Owner: Neutral - Actor111: tree25 + Actor134: tree25 Location: 185,22 Owner: Neutral - Actor112: tree01 + Actor135: tree01 Location: 184,21 Owner: Neutral - Actor113: tree02 + Actor136: tree02 Location: 187,21 Owner: Neutral - Actor114: tree03 + Actor137: tree03 Location: 191,24 Owner: Neutral - Actor115: tree04 + Actor138: tree04 Location: 177,29 Owner: Neutral - Actor116: tree05 + Actor139: tree05 Location: 177,28 Owner: Neutral - Actor117: tree05 + Actor140: tree05 Location: 236,-26 Owner: Neutral - Actor118: tree06 + Actor141: tree06 Location: 238,-28 Owner: Neutral - Actor119: tree07 + Actor142: tree07 Location: 236,-31 Owner: Neutral - Actor120: tree08 + Actor143: tree08 Location: 237,-27 Owner: Neutral - Actor121: tree09 + Actor144: tree09 Location: 240,-29 Owner: Neutral - Actor122: tree10 + Actor145: tree10 Location: 229,-36 Owner: Neutral - Actor123: tree11 + Actor146: tree11 Location: 227,-37 Owner: Neutral - Actor124: tree12 + Actor147: tree12 Location: 226,-39 Owner: Neutral - Actor125: tree13 + Actor148: tree13 Location: 232,-35 Owner: Neutral - Actor126: tree14 + Actor149: tree14 Location: 225,-2 Owner: Neutral - Actor127: tree15 + Actor150: tree15 Location: 228,-3 Owner: Neutral - Actor128: tree16 + Actor151: tree16 Location: 226,-3 Owner: Neutral - Actor129: tree17 + Actor152: tree17 Location: 224,-4 Owner: Neutral - Actor130: tree18 + Actor153: tree18 Location: 190,-33 Owner: Neutral - Actor131: tree19 + Actor154: tree19 Location: 189,-33 Owner: Neutral - Actor132: tree20 + Actor155: tree20 Location: 191,-31 Owner: Neutral - Actor133: tree21 + Actor156: tree21 Location: 191,-30 Owner: Neutral - Actor134: tree22 + Actor157: tree22 Location: 163,31 Owner: Neutral - Actor135: tree23 + Actor158: tree23 Location: 164,31 Owner: Neutral - Actor136: tree24 + Actor159: tree24 Location: 165,33 Owner: Neutral - Actor137: tree25 + Actor160: tree25 Location: 166,30 Owner: Neutral - Actor138: tree01 + Actor161: tree01 Location: 166,28 Owner: Neutral - Actor139: tree02 + Actor162: tree02 Location: 167,29 Owner: Neutral - Actor140: tree04 + Actor163: tree04 Location: 167,28 Owner: Neutral - Actor141: tree05 + Actor164: tree05 Location: 108,65 Owner: Neutral - Actor142: tree06 + Actor165: tree06 Location: 103,67 Owner: Neutral - Actor143: tree07 + Actor166: tree07 Location: 105,67 Owner: Neutral - Actor144: tree08 + Actor167: tree08 Location: 104,65 Owner: Neutral - Actor145: tree09 + Actor168: tree09 Location: 106,67 Owner: Neutral - Actor146: tree10 + Actor169: tree10 Location: 103,69 Owner: Neutral - Actor147: tree10 + Actor170: tree10 Location: 110,40 Owner: Neutral - Actor148: tree11 + Actor171: tree11 Location: 110,38 Owner: Neutral - Actor149: tree12 + Actor172: tree12 Location: 111,11 Owner: Neutral - Actor150: tree13 + Actor173: tree13 Location: 112,12 Owner: Neutral - Actor151: tree14 + Actor174: tree14 Location: 107,11 Owner: Neutral - Actor152: tree15 + Actor175: tree15 Location: 132,16 Owner: Neutral - Actor153: tree16 + Actor176: tree16 Location: 134,16 Owner: Neutral - Actor154: tree17 + Actor177: tree17 Location: 135,18 Owner: Neutral - Actor155: tree18 + Actor178: tree18 Location: 118,-16 Owner: Neutral - Actor156: tree19 + Actor179: tree19 Location: 118,-12 Owner: Neutral - Actor157: tree20 + Actor180: tree20 Location: 120,-11 Owner: Neutral - Actor158: tree22 + Actor181: tree22 Location: 116,-13 Owner: Neutral - Actor159: tree01 + Actor182: tree01 Location: 147,0 Owner: Neutral - Actor160: tree02 + Actor183: tree02 Location: 150,4 Owner: Neutral - Actor161: tree03 + Actor184: tree03 Location: 151,5 Owner: Neutral - Actor162: tree04 + Actor185: tree04 Location: 151,8 Owner: Neutral - Actor163: tree04 + Actor186: tree04 Location: 131,-48 Owner: Neutral - Actor164: tree05 + Actor187: tree05 Location: 131,-50 Owner: Neutral - Actor165: tree06 + Actor188: tree06 Location: 132,-50 Owner: Neutral - Actor166: tree06 + Actor189: tree06 Location: 166,-37 Owner: Neutral - Actor167: tree06 + Actor190: tree06 Location: 181,-54 Owner: Neutral - Actor168: tree07 + Actor191: tree07 Location: 180,-51 Owner: Neutral - Actor169: tree08 + Actor192: tree08 Location: 178,-53 Owner: Neutral - Actor170: tree09 + Actor193: tree09 Location: 176,-54 Owner: Neutral - Actor171: tree09 + Actor194: tree09 Location: 174,-77 Owner: Neutral - Actor172: tree10 + Actor195: tree10 Location: 176,-78 Owner: Neutral - Actor173: tree11 + Actor196: tree11 Location: 177,-80 Owner: Neutral - Actor174: tree11 + Actor197: tree11 Location: 162,-83 Owner: Neutral - Actor175: tree12 + Actor198: tree12 Location: 163,-84 Owner: Neutral - Actor176: tree13 + Actor199: tree13 Location: 188,-81 Owner: Neutral - Actor177: tree14 + Actor200: tree14 Location: 188,-84 Owner: Neutral - Actor178: tree14 + Actor201: tree14 Location: 33,24 Owner: Neutral - Actor179: tree15 + Actor202: tree15 Location: 35,28 Owner: Neutral - Actor180: tree15 + Actor203: tree15 Location: 42,6 Owner: Neutral - Actor181: tree16 + Actor204: tree16 Location: 47,4 Owner: Neutral - Actor182: tree17 + Actor205: tree17 Location: 49,2 Owner: Neutral - Actor183: tree18 + Actor206: tree18 Location: 43,5 Owner: Neutral - Actor184: tree01 + Actor207: tree01 Location: 31,-8 Owner: Neutral - Actor185: tree02 + Actor208: tree02 Location: 35,-11 Owner: Neutral - Actor186: tree03 + Actor209: tree03 Location: 35,-8 Owner: Neutral - Actor187: tree04 + Actor210: tree04 Location: 39,-18 Owner: Neutral - Actor188: tree05 + Actor211: tree05 Location: 56,-26 Owner: Neutral - Actor189: tree06 + Actor212: tree06 Location: 56,-28 Owner: Neutral - Actor190: tree06 + Actor213: tree06 Location: 78,-5 Owner: Neutral - Actor191: tree07 + Actor214: tree07 Location: 80,-5 Owner: Neutral - Actor192: tree08 + Actor215: tree08 Location: 81,-15 Owner: Neutral - Actor193: tree09 + Actor216: tree09 Location: 82,-16 Owner: Neutral - Actor194: tree10 + Actor217: tree10 Location: 83,-14 Owner: Neutral - Actor195: tree11 + Actor218: tree11 Location: 71,-45 Owner: Neutral - Actor196: tree12 + Actor219: tree12 Location: 71,-46 Owner: Neutral - Actor197: tree13 + Actor220: tree13 Location: 73,-44 Owner: Neutral - Actor198: tree14 + Actor221: tree14 Location: 70,-49 Owner: Neutral - Actor199: tree14 + Actor222: tree14 Location: 89,-40 Owner: Neutral - Actor200: tree15 + Actor223: tree15 Location: 90,-67 Owner: Neutral - Actor201: tree16 + Actor224: tree16 Location: 100,-65 Owner: Neutral - Actor202: tree17 + Actor225: tree17 Location: 105,-64 Owner: Neutral - Actor203: tree18 + Actor226: tree18 Location: 107,-51 Owner: Neutral - Actor204: tree19 + Actor227: tree19 Location: 120,-89 Owner: Neutral - Actor205: tree20 + Actor228: tree20 Location: 120,-90 Owner: Neutral - Actor206: tree21 + Actor229: tree21 Location: 117,-94 Owner: Neutral - Actor207: tree22 + Actor230: tree22 Location: 119,-93 Owner: Neutral - Actor208: tree01 + Actor231: tree01 Location: 140,-89 Owner: Neutral - Actor209: tree03 + Actor232: tree03 Location: 142,-89 Owner: Neutral - Actor210: tree04 + Actor233: tree04 Location: 141,-92 Owner: Neutral - Actor211: tree05 + Actor234: tree05 Location: 141,-93 Owner: Neutral - Actor212: tree05 + Actor235: tree05 Location: 159,-113 Owner: Neutral - Actor213: tree06 + Actor236: tree06 Location: 161,-112 Owner: Neutral - Actor214: tree07 + Actor237: tree07 Location: 162,-112 Owner: Neutral - Actor215: tree08 + Actor238: tree08 Location: 163,-107 Owner: Neutral - Actor216: tree09 + Actor239: tree09 Location: 166,-109 Owner: Neutral - Actor217: tree10 + Actor240: tree10 Location: 164,-118 Owner: Neutral - Actor218: tree11 + Actor241: tree11 Location: 163,-118 Owner: Neutral - Actor219: bigblue3 + Actor242: bigblue3 Location: 61,25 Owner: Neutral - Actor220: bigblue3 + Actor243: bigblue3 Location: 166,52 Owner: Neutral - Actor221: bigblue3 + Actor244: bigblue3 Location: 174,-29 Owner: Neutral - Actor222: bigblue3 + Actor245: bigblue3 Location: 169,-42 Owner: Neutral - Actor223: bigblue3 + Actor246: bigblue3 Location: 217,-31 Owner: Neutral - Actor224: mpspawn + Actor247: mpspawn Location: 233,-19 Owner: Neutral - Actor225: mpspawn + Actor248: mpspawn Location: 188,25 Owner: Neutral - Actor226: mpspawn + Actor249: mpspawn Location: 131,86 Owner: Neutral - Actor227: mpspawn + Actor250: mpspawn Location: 94,27 Owner: Neutral - Actor228: mpspawn + Actor251: mpspawn Location: 189,-57 Owner: Neutral - Actor229: mpspawn + Actor252: mpspawn Location: 47,-4 Owner: Neutral - Actor230: mpspawn + Actor253: mpspawn Location: 89,-43 Owner: Neutral - Actor231: mpspawn + Actor254: mpspawn Location: 139,-101 Owner: Neutral - Actor232: waypoint + Actor255: waypoint Location: 105,21 Owner: Neutral - Actor233: waypoint + Actor256: waypoint Location: 105,21 Owner: Neutral - Actor234: bridge2 - Owner: Neutral - Location: 51,8 - Actor235: bridge2 - Owner: Neutral - Location: 51,9 - Actor236: bridge2 - Owner: Neutral - Location: 51,10 - Actor237: bridge2 - Owner: Neutral - Location: 51,11 - Actor238: bridge2 - Owner: Neutral - Location: 51,12 - Actor240: bridge2 - Owner: Neutral - Location: 51,13 - Actor239: bridge2 - Owner: Neutral - Location: 51,26 - Actor241: bridge2 - Owner: Neutral - Location: 51,25 - Actor242: bridge2 - Owner: Neutral - Location: 51,24 - Actor243: bridge2 - Owner: Neutral - Location: 51,23 - Actor244: bridge2 - Owner: Neutral - Location: 51,22 - Actor245: bridge2 - Owner: Neutral - Location: 51,21 - Actor246: bridge2 - Owner: Neutral - Location: 51,20 - Actor247: bridge2 - Owner: Neutral - Location: 51,19 - Actor248: bridge2 - Owner: Neutral - Location: 51,18 - Actor249: bridge2 - Owner: Neutral - Location: 51,17 - Actor250: bridge2 - Owner: Neutral - Location: 51,16 - Actor252: bridge2 - Owner: Neutral - Location: 51,15 - Actor253: bridge2 - Owner: Neutral - Location: 51,14 - Actor251: bridge1 - Owner: Neutral - Location: 104,77 - Actor254: bridge1 - Owner: Neutral - Location: 105,77 - Actor255: bridge1 - Owner: Neutral - Location: 106,77 - Actor256: bridge1 + Actor257: bridge2 + Location: 157,-103 Owner: Neutral - Location: 107,77 - Actor257: bridge1 + Actor258: bridge2 + Location: 157,-102 Owner: Neutral - Location: 108,77 - Actor258: bridge1 + Actor259: bridge2 + Location: 157,-101 Owner: Neutral - Location: 109,77 - Actor259: bridge1 + Actor260: bridge2 + Location: 157,-100 Owner: Neutral - Location: 110,77 Actor261: bridge1 + Location: 112,-54 Owner: Neutral - Location: 111,77 - Actor262: bridge1 + Actor262: bridge2 + Location: 157,-99 Owner: Neutral - Location: 112,77 Actor263: bridge2 + Location: 51,8 Owner: Neutral - Location: 156,21 - Actor264: bridge2 + Actor264: bridge1 + Location: 113,-54 Owner: Neutral - Location: 156,22 Actor265: bridge2 + Location: 157,-98 Owner: Neutral - Location: 156,23 Actor266: bridge2 + Location: 51,9 Owner: Neutral - Location: 156,24 - Actor267: bridge2 + Actor267: bridge1 + Location: 114,-54 Owner: Neutral - Location: 156,25 Actor268: bridge2 + Location: 157,-97 Owner: Neutral - Location: 156,26 Actor269: bridge2 + Location: 51,10 Owner: Neutral - Location: 156,27 - Actor270: bridge2 + Actor270: bridge1 + Location: 115,-54 Owner: Neutral - Location: 156,28 Actor271: bridge2 + Location: 157,-96 Owner: Neutral - Location: 156,29 - Actor272: bridge1 + Actor272: bridge2 + Location: 51,11 Owner: Neutral - Location: 112,-54 Actor273: bridge1 + Location: 116,-54 Owner: Neutral - Location: 113,-54 - Actor274: bridge1 + Actor274: bridge2 + Location: 157,-95 Owner: Neutral - Location: 114,-54 - Actor275: bridge1 + Actor275: bridge2 + Location: 51,12 Owner: Neutral - Location: 115,-54 Actor276: bridge1 + Location: 117,-54 Owner: Neutral - Location: 116,-54 - Actor277: bridge1 + Actor277: bridge2 + Location: 157,-94 Owner: Neutral - Location: 117,-54 - Actor279: bridge1 + Actor278: bridge2 + Location: 51,13 Owner: Neutral - Location: 123,-54 - Actor280: bridge1 + Actor279: bridge1 + Location: 118,-54 Owner: Neutral - Location: 122,-54 - Actor281: bridge1 + Actor280: bridge2 + Location: 157,-93 Owner: Neutral - Location: 121,-54 - Actor283: bridge1 + Actor281: bridge2 + Location: 51,14 Owner: Neutral - Location: 120,-54 Actor282: bridge1 - Owner: Neutral Location: 119,-54 - Actor284: bridge1 Owner: Neutral - Location: 118,-54 - Actor278: bridge2 + Actor283: bridge2 + Location: 157,-92 Owner: Neutral - Location: 157,-103 - Actor285: bridge2 + Actor284: bridge2 + Location: 51,15 Owner: Neutral - Location: 157,-102 - Actor287: bridge2 + Actor285: bridge1 + Location: 120,-54 Owner: Neutral - Location: 157,-101 Actor286: bridge2 + Location: 157,-91 Owner: Neutral - Location: 157,-100 - Actor289: bridge2 + Actor287: bridge2 + Location: 51,16 Owner: Neutral - Location: 157,-99 - Actor288: bridge2 + Actor288: bridge1 + Location: 121,-54 + Owner: Neutral + Actor289: bridge2 + Location: 157,-90 Owner: Neutral - Location: 157,-98 Actor290: bridge2 + Location: 51,17 Owner: Neutral - Location: 157,-97 - Actor291: bridge2 + Actor291: bridge1 + Location: 122,-54 Owner: Neutral - Location: 157,-96 Actor292: bridge2 + Location: 157,-89 Owner: Neutral - Location: 157,-95 Actor293: bridge2 + Location: 51,18 Owner: Neutral - Location: 157,-94 - Actor294: bridge2 + Actor294: bridge1 + Location: 123,-54 Owner: Neutral - Location: 157,-93 Actor295: bridge2 + Location: 157,-88 Owner: Neutral - Location: 157,-92 Actor296: bridge2 + Location: 51,19 Owner: Neutral - Location: 157,-91 Actor297: bridge2 + Location: 157,-87 Owner: Neutral - Location: 157,-90 Actor298: bridge2 + Location: 51,20 Owner: Neutral - Location: 157,-89 Actor299: bridge2 + Location: 157,-86 Owner: Neutral - Location: 157,-88 Actor300: bridge2 + Location: 51,21 Owner: Neutral - Location: 157,-87 Actor301: bridge2 + Location: 51,22 Owner: Neutral - Location: 157,-86 Actor302: bridge2 + Location: 51,23 Owner: Neutral - Location: 223,-52 Actor303: bridge2 + Location: 51,24 Owner: Neutral - Location: 223,-51 Actor304: bridge2 + Location: 51,25 Owner: Neutral - Location: 223,-50 Actor305: bridge2 + Location: 51,26 Owner: Neutral - Location: 223,-49 Actor306: bridge2 + Location: 223,-52 Owner: Neutral - Location: 223,-48 Actor307: bridge2 + Location: 223,-51 + Owner: Neutral + Actor308: bridge2 + Location: 223,-50 Owner: Neutral - Location: 223,-47 Actor309: bridge2 + Location: 223,-49 Owner: Neutral + Actor310: bridge2 + Location: 223,-48 + Owner: Neutral + Actor311: bridge2 + Location: 223,-47 + Owner: Neutral + Actor312: bridge2 + Location: 156,21 + Owner: Neutral + Actor313: bridge2 Location: 223,-46 - Actor308: bridge2 Owner: Neutral + Actor314: bridge2 + Location: 156,22 + Owner: Neutral + Actor315: bridge2 Location: 223,-45 - Actor310: bridge2 Owner: Neutral + Actor316: bridge2 + Location: 156,23 + Owner: Neutral + Actor317: bridge2 Location: 223,-44 + Owner: Neutral + Actor318: bridge2 + Location: 156,24 + Owner: Neutral + Actor319: bridge1 + Location: 104,77 + Owner: Neutral + Actor320: bridge2 + Location: 156,25 + Owner: Neutral + Actor321: bridge1 + Location: 105,77 + Owner: Neutral + Actor322: bridge2 + Location: 156,26 + Owner: Neutral + Actor323: bridge1 + Location: 106,77 + Owner: Neutral + Actor324: bridge2 + Location: 156,27 + Owner: Neutral + Actor325: bridge1 + Location: 107,77 + Owner: Neutral + Actor326: bridge2 + Location: 156,28 + Owner: Neutral + Actor327: bridge1 + Location: 108,77 + Owner: Neutral + Actor328: bridge2 + Location: 156,29 + Owner: Neutral + Actor329: bridge1 + Location: 109,77 + Owner: Neutral + Actor330: bridge1 + Location: 110,77 + Owner: Neutral + Actor331: bridge1 + Location: 111,77 + Owner: Neutral + Actor332: bridge1 + Location: 112,77 + Owner: Neutral Rules: World: - GlobalLightingPaletteEffect: - Ambient: 0.93 TerrainTunnelLayer: ElevatedBridgeLayer: ElevatedBridgePlaceholder@a: @@ -1042,3 +1172,20 @@ Height: 6 Orientation: Y Length: 10 + ^BaseWorld: + TerrainLighting: + Intensity: 0.93 + INGRNLMP: + TerrainLightSource: + Range: 7c832 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.7 + BlueTint: 0.01 + INBLULMP: + TerrainLightSource: + Range: 9c784 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.01 + BlueTint: 0.7 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/fields-of-green/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/fields-of-green/map.png differ diff -Nru openra-20200503/mods/ts/maps/fields-of-green/map.yaml openra-20210321/mods/ts/maps/fields-of-green/map.yaml --- openra-20200503/mods/ts/maps/fields-of-green/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/fields-of-green/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -28,17 +28,17 @@ Enemies: Creeps, Nod, GDI PlayerReference@Nod: Name: Nod + LockFaction: True Faction: nod - LockFaction: true + LockColor: True Color: FE1100 - LockColor: true Enemies: GDI, Creeps PlayerReference@GDI: Name: GDI + LockFaction: True Faction: gdi - LockFaction: true + LockColor: True Color: EEEE66 - LockColor: true Enemies: Nod, Creeps Actors: @@ -120,15 +120,15 @@ Actor27: nalasr Owner: Nod Location: 43,5 - Facing: 170 + Facing: 680 Actor28: nalasr Owner: Nod Location: 43,9 - Facing: 170 + Facing: 680 nodhand1: nahand Owner: Nod Location: 38,4 - Actor30: galite + Actor30: tstlamp Owner: Nod Location: 40,2 Actor31: gaoldcc2 @@ -206,16 +206,14 @@ Actor55: gactwr Owner: GDI Location: 84,-1 - TurretFacing: 92 - Facing: 60 - Plugs: - 0,0: tower.vulcan + TurretFacing: 128 + Facing: 240 + Plug: tower.vulcan Actor56: gactwr Owner: GDI Location: 80,-3 - Facing: 60 - Plugs: - 0,0: tower.vulcan + Facing: 240 + Plug: tower.vulcan Actor57: gawall Owner: GDI Location: 79,-3 @@ -246,9 +244,8 @@ Actor66: gactwr Owner: GDI Location: 84,-4 - Facing: 60 - Plugs: - 0,0: tower.rocket + Facing: 240 + Plug: tower.rocket Actor67: gawall Owner: GDI Location: 88,-1 @@ -285,7 +282,7 @@ Actor78: proc Owner: GDI Location: 79,-7 - Actor79: galite + Actor79: tstlamp Owner: GDI Location: 78,-4 gdibar1: gapile @@ -294,22 +291,19 @@ Actor81: gapowr Owner: GDI Location: 86,-3 - Facing: 60 - Plugs: - 0,1: powrup - 1,1: powrup + Facing: 240 + Plug@pluga: powrup + Plug@plugb: powrup Actor82: gapowr Owner: GDI Location: 86,-5 - Plugs: - 0,1: powrup - 1,1: powrup + Plug@pluga: powrup + Plug@plugb: powrup Actor91: gactwr Owner: GDI Location: 85,-11 - Facing: -40 - Plugs: - 0,0: tower.vulcan + Facing: 864 + Plug: tower.vulcan Actor90: gasilo Owner: GDI Location: 79,-10 @@ -325,9 +319,8 @@ Actor88: gactwr Owner: GDI Location: 81,-11 - Facing: -40 - Plugs: - 0,0: tower.vulcan + Facing: 864 + Plug: tower.vulcan Actor89: gagate_a Owner: GDI Location: 82,-11 @@ -415,15 +408,15 @@ Actor119: pick Owner: Neutral Location: 73,1 - Facing: 92 + Facing: 368 Actor120: car Owner: Neutral Location: 49,-11 - Facing: 92 + Facing: 368 Actor121: wini Owner: Neutral Location: 48,-11 - Facing: 92 + Facing: 368 Actor122: srock01 Owner: Neutral Location: 52,6 @@ -439,7 +432,7 @@ Actor126: trucka Owner: Neutral Location: 51,1 - Facing: 92 + Facing: 368 Actor127: ca0014 Owner: Neutral Location: 53,22 @@ -1350,62 +1343,52 @@ Owner: GDI Location: 85,-5 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor440: e1 Owner: GDI Location: 86,-10 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor431: e1 Owner: GDI Location: 85,-7 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor432: e2 Owner: GDI Location: 83,-8 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor433: e2 Owner: GDI Location: 83,-9 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor434: e1 Owner: Nod Location: 39,6 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor439: e1 Owner: Nod Location: 39,11 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor436: e1 Owner: Nod Location: 40,6 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor437: e3 Owner: Nod Location: 37,3 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 Actor438: e3 Owner: Nod Location: 37,4 SubCell: 2 - Facing: 92 - TurretFacing: 92 + Facing: 368 North: waypoint Owner: Neutral Location: 41,-33 @@ -1418,5 +1401,17 @@ NodBase: waypoint Owner: Neutral Location: 45,6 + Actor441: ingrnlmp + Owner: Neutral + Location: 60,-6 + Actor442: ingrnlmp + Owner: Neutral + Location: 66,-1 + Actor443: ingrnlmp + Owner: Neutral + Location: 60,11 + Actor444: ingrnlmp + Owner: Neutral + Location: 58,16 Rules: rules.yaml diff -Nru openra-20200503/mods/ts/maps/fields-of-green/rules.yaml openra-20210321/mods/ts/maps/fields-of-green/rules.yaml --- openra-20200503/mods/ts/maps/fields-of-green/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/fields-of-green/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -14,9 +14,19 @@ BackgroundMusic: intro DisableWorldSounds: true AllowMuteBackgroundMusic: true - GlobalLightingPaletteEffect: - Blue: 0.7 - Ambient: 0.7 + +^BaseWorld: + TerrainLighting: + BlueTint: 0.7 + Intensity: 0.6 + +INGRNLMP: + TerrainLightSource: + RedTint: 0.01 + GreenTint: 0.7 + BlueTint: 0.01 + Intensity: 0.1 + Range: 5c0 ^ExistsInWorld: GivesExperience: Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/float/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/float/map.png differ diff -Nru openra-20200503/mods/ts/maps/float/map.yaml openra-20210321/mods/ts/maps/float/map.yaml --- openra-20200503/mods/ts/maps/float/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/float/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -39,598 +39,694 @@ Enemies: Creeps Actors: - Actor0: jfish + Actor0: ingrnlmp + Location: 56,24 + Owner: Neutral + Facing: 896 + Actor1: ingrnlmp + Location: 41,-14 + Owner: Neutral + Facing: 896 + Actor2: ingrnlmp + Location: 91,-12 + Owner: Neutral + Facing: 896 + Actor3: ingrnlmp + Location: 90,-60 + Owner: Neutral + Facing: 896 + Actor4: inblulmp + Location: 120,-43 + Owner: Neutral + Facing: 896 + Actor5: inblulmp + Location: 19,8 + Owner: Neutral + Facing: 896 + Actor6: inblulmp + Location: 41,5 + Owner: Neutral + Facing: 896 + Actor7: inblulmp + Location: 73,-27 + Owner: Neutral + Facing: 896 + Actor8: inblulmp + Location: 106,-38 + Owner: Neutral + Facing: 896 + Actor9: inblulmp + Location: 80,4 + Owner: Neutral + Facing: 896 + Actor10: ingrnlmp + Location: 69,17 + Owner: Neutral + Facing: 896 + Actor11: ingrnlmp + Location: 70,10 + Owner: Neutral + Facing: 896 + Actor12: ingrnlmp + Location: 78,-43 + Owner: Neutral + Facing: 896 + Actor13: neglamp + Location: 107,-70 + Owner: Neutral + Facing: 896 + Actor14: neglamp + Location: 101,-76 + Owner: Neutral + Facing: 896 + Actor15: neglamp + Location: 134,-41 + Owner: Neutral + Facing: 896 + Actor16: inblulmp + Location: 83,-78 + Owner: Neutral + Facing: 896 + Actor17: ingrnlmp + Location: 39,37 + Owner: Neutral + Facing: 896 + Actor18: inblulmp + Location: 59,-44 + Owner: Neutral + Facing: 896 + Actor19: ingrnlmp + Location: 79,-32 + Owner: Neutral + Facing: 896 + Actor20: ingrnlmp + Location: 103,-29 + Owner: Neutral + Facing: 896 + Actor21: inblulmp + Location: 30,-28 + Owner: Neutral + Facing: 896 + Actor22: jfish Location: 39,5 Owner: Creeps - Health: 100 - Facing: 96 - Actor1: jfish + Facing: 896 + Actor23: jfish Location: 73,4 Owner: Creeps - Health: 100 - Facing: 96 - Actor2: jfish + Facing: 896 + Actor24: jfish Location: 68,-38 Owner: Creeps - Health: 100 - Facing: 96 - Actor3: jfish + Facing: 896 + Actor25: jfish Location: 79,-43 Owner: Creeps - Health: 100 - Facing: 96 - Actor4: tibtre01 + Facing: 896 + Actor26: tibtre01 Location: 56,24 Owner: Neutral - Actor5: tibtre02 + Actor27: tibtre02 Location: 69,17 Owner: Neutral - Actor6: tibtre03 + Actor28: tibtre03 Location: 70,10 Owner: Neutral - Actor7: tibtre01 + Actor29: tibtre01 Location: 41,-14 Owner: Neutral - Actor8: tibtre02 + Actor30: tibtre02 Location: 91,-12 Owner: Neutral - Actor9: tibtre03 + Actor31: tibtre03 Location: 78,-43 Owner: Neutral - Actor10: tibtre01 + Actor32: tibtre01 Location: 90,-60 Owner: Neutral - Actor11: fona06 + Actor33: fona06 Location: 37,32 Owner: Neutral - Actor12: fona07 + Actor34: fona07 Location: 38,31 Owner: Neutral - Actor13: fona08 + Actor35: fona08 Location: 43,37 Owner: Neutral - Actor14: fona09 + Actor36: fona09 Location: 41,37 Owner: Neutral - Actor15: fona10 + Actor37: fona10 Location: 38,28 Owner: Neutral - Actor16: fona08 + Actor38: fona08 Location: 45,-3 Owner: Neutral - Actor17: fona09 + Actor39: fona09 Location: 51,-7 Owner: Neutral - Actor18: fona10 + Actor40: fona10 Location: 53,-6 Owner: Neutral - Actor19: fona06 + Actor41: fona06 Location: 55,-5 Owner: Neutral - Actor20: fona07 + Actor42: fona07 Location: 53,-7 Owner: Neutral - Actor21: fona06 + Actor43: fona06 Location: 80,-27 Owner: Neutral - Actor22: fona07 + Actor44: fona07 Location: 80,-29 Owner: Neutral - Actor23: fona08 + Actor45: fona08 Location: 81,-32 Owner: Neutral - Actor24: fona09 + Actor46: fona09 Location: 82,-32 Owner: Neutral - Actor25: fona10 + Actor47: fona10 Location: 85,-31 Owner: Neutral - Actor26: fona06 + Actor48: fona06 Location: 104,-28 Owner: Neutral - Actor27: fona07 + Actor49: fona07 Location: 104,-25 Owner: Neutral - Actor28: fona08 + Actor50: fona08 Location: 102,-28 Owner: Neutral - Actor29: fona09 + Actor51: fona09 Location: 102,-30 Owner: Neutral - Actor30: fona10 + Actor52: fona10 Location: 104,-29 Owner: Neutral - Actor31: fona09 + Actor53: fona09 Location: 105,-22 Owner: Neutral - Actor32: fona01 + Actor54: fona01 Location: 19,11 Owner: Neutral - Actor33: fona02 + Actor55: fona02 Location: 22,10 Owner: Neutral - Actor34: fona14 + Actor56: fona14 Location: 16,3 Owner: Neutral - Actor35: fona01 + Actor57: fona01 Location: 80,11 Owner: Neutral - Actor36: fona02 + Actor58: fona02 Location: 78,8 Owner: Neutral - Actor37: fona04 + Actor59: fona04 Location: 84,11 Owner: Neutral - Actor38: fona05 + Actor60: fona05 Location: 67,2 Owner: Neutral - Actor39: fona11 + Actor61: fona11 Location: 70,2 Owner: Neutral - Actor40: fona12 + Actor62: fona12 Location: 77,14 Owner: Neutral - Actor41: fona13 + Actor63: fona13 Location: 78,14 Owner: Neutral - Actor42: fona14 + Actor64: fona14 Location: 68,3 Owner: Neutral - Actor43: fona15 + Actor65: fona15 Location: 83,11 Owner: Neutral - Actor44: fona04 + Actor66: fona04 Location: 72,-16 Owner: Neutral - Actor45: fona11 + Actor67: fona11 Location: 72,-15 Owner: Neutral - Actor46: fona12 + Actor68: fona12 Location: 81,-15 Owner: Neutral - Actor47: fona14 + Actor69: fona14 Location: 66,-35 Owner: Neutral - Actor48: fona15 + Actor70: fona15 Location: 64,-40 Owner: Neutral - Actor49: fona01 + Actor71: fona01 Location: 76,-28 Owner: Neutral - Actor50: fona02 + Actor72: fona02 Location: 67,-35 Owner: Neutral - Actor51: fona03 + Actor73: fona03 Location: 65,-39 Owner: Neutral - Actor52: fona05 + Actor74: fona05 Location: 79,-18 Owner: Neutral - Actor53: fona01 + Actor75: fona01 Location: 86,-71 Owner: Neutral - Actor54: fona02 + Actor76: fona02 Location: 88,-72 Owner: Neutral - Actor55: fona03 + Actor77: fona03 Location: 88,-73 Owner: Neutral - Actor56: fona04 + Actor78: fona04 Location: 90,-75 Owner: Neutral - Actor57: fona05 + Actor79: fona05 Location: 87,-77 Owner: Neutral - Actor58: fona11 + Actor80: fona11 Location: 91,-74 Owner: Neutral - Actor59: fona12 + Actor81: fona12 Location: 87,-73 Owner: Neutral - Actor60: fona13 + Actor82: fona13 Location: 88,-74 Owner: Neutral - Actor61: fona14 + Actor83: fona14 Location: 90,-78 Owner: Neutral - Actor62: fona01 + Actor84: fona01 Location: 129,-41 Owner: Neutral - Actor63: fona02 + Actor85: fona02 Location: 130,-41 Owner: Neutral - Actor64: fona03 + Actor86: fona03 Location: 129,-42 Owner: Neutral - Actor65: fona04 + Actor87: fona04 Location: 126,-47 Owner: Neutral - Actor66: fona05 + Actor88: fona05 Location: 122,-49 Owner: Neutral - Actor67: fona11 + Actor89: fona11 Location: 129,-39 Owner: Neutral - Actor68: fona12 + Actor90: fona12 Location: 127,-45 Owner: Neutral - Actor69: fona13 + Actor91: fona13 Location: 129,-43 Owner: Neutral - Actor70: fona14 + Actor92: fona14 Location: 123,-50 Owner: Neutral - Actor71: fona15 + Actor93: fona15 Location: 122,-47 Owner: Neutral - Actor72: tree01 + Actor94: tree01 Location: 90,-52 Owner: Neutral - Actor73: tree04 + Actor95: tree04 Location: 90,-51 Owner: Neutral - Actor74: tree05 + Actor96: tree05 Location: 92,-50 Owner: Neutral - Actor75: tree06 + Actor97: tree06 Location: 83,-50 Owner: Neutral - Actor76: tree07 + Actor98: tree07 Location: 86,-51 Owner: Neutral - Actor77: tree08 + Actor99: tree08 Location: 87,-48 Owner: Neutral - Actor78: tree09 + Actor100: tree09 Location: 87,-47 Owner: Neutral - Actor79: tree09 + Actor101: tree09 Location: 110,-52 Owner: Neutral - Actor80: tree10 + Actor102: tree10 Location: 110,-48 Owner: Neutral - Actor81: tree11 + Actor103: tree11 Location: 110,-50 Owner: Neutral - Actor82: tree12 + Actor104: tree12 Location: 112,-48 Owner: Neutral - Actor83: tree13 + Actor105: tree13 Location: 113,-55 Owner: Neutral - Actor84: tree13 + Actor106: tree13 Location: 113,-56 Owner: Neutral - Actor85: tree15 + Actor107: tree15 Location: 115,-56 Owner: Neutral - Actor86: tree15 + Actor108: tree15 Location: 112,-30 Owner: Neutral - Actor87: tree16 + Actor109: tree16 Location: 115,-30 Owner: Neutral - Actor88: tree17 + Actor110: tree17 Location: 115,-27 Owner: Neutral - Actor89: tree19 + Actor111: tree19 Location: 119,-27 Owner: Neutral - Actor90: tree21 + Actor112: tree21 Location: 114,-29 Owner: Neutral - Actor91: tree03 + Actor113: tree03 Location: 116,-27 Owner: Neutral - Actor92: tree04 + Actor114: tree04 Location: 79,-37 Owner: Neutral - Actor93: tree05 + Actor115: tree05 Location: 82,-37 Owner: Neutral - Actor94: tree06 + Actor116: tree06 Location: 84,-37 Owner: Neutral - Actor95: tree07 + Actor117: tree07 Location: 87,-36 Owner: Neutral - Actor96: tree08 + Actor118: tree08 Location: 85,-39 Owner: Neutral - Actor97: tree09 + Actor119: tree09 Location: 82,-39 Owner: Neutral - Actor98: tree09 + Actor120: tree09 Location: 86,-26 Owner: Neutral - Actor99: tree22 + Actor121: tree22 Location: 87,-27 Owner: Neutral - Actor100: tree23 + Actor122: tree23 Location: 84,-27 Owner: Neutral - Actor101: tree24 + Actor123: tree24 Location: 82,-11 Owner: Neutral - Actor102: tree21 + Actor124: tree21 Location: 84,-15 Owner: Neutral - Actor103: tree20 + Actor125: tree20 Location: 83,-12 Owner: Neutral - Actor104: tree01 + Actor126: tree01 Location: 87,7 Owner: Neutral - Actor105: tree03 + Actor127: tree03 Location: 86,5 Owner: Neutral - Actor106: tree02 + Actor128: tree02 Location: 86,2 Owner: Neutral - Actor107: tree04 + Actor129: tree04 Location: 90,5 Owner: Neutral - Actor108: tree07 + Actor130: tree07 Location: 88,5 Owner: Neutral - Actor109: tree01 + Actor131: tree01 Location: 48,-36 Owner: Neutral - Actor110: tree02 + Actor132: tree02 Location: 49,-35 Owner: Neutral - Actor111: tree03 + Actor133: tree03 Location: 51,-36 Owner: Neutral - Actor112: tree04 + Actor134: tree04 Location: 56,-33 Owner: Neutral - Actor113: tree05 + Actor135: tree05 Location: 61,-30 Owner: Neutral - Actor114: tree06 + Actor136: tree06 Location: 57,-27 Owner: Neutral - Actor115: tree07 + Actor137: tree07 Location: 55,-31 Owner: Neutral - Actor116: tree08 + Actor138: tree08 Location: 56,-30 Owner: Neutral - Actor117: tree09 + Actor139: tree09 Location: 58,-30 Owner: Neutral - Actor118: tree15 + Actor140: tree15 Location: 52,-34 Owner: Neutral - Actor119: tree15 + Actor141: tree15 Location: 36,-7 Owner: Neutral - Actor120: tree16 + Actor142: tree16 Location: 34,-11 Owner: Neutral - Actor121: tree17 + Actor143: tree17 Location: 36,-10 Owner: Neutral - Actor122: tree18 + Actor144: tree18 Location: 36,-13 Owner: Neutral - Actor123: tree19 + Actor145: tree19 Location: 35,-13 Owner: Neutral - Actor124: tree21 + Actor146: tree21 Location: 33,-17 Owner: Neutral - Actor125: tree22 + Actor147: tree22 Location: 31,-15 Owner: Neutral - Actor126: tree23 + Actor148: tree23 Location: 32,-13 Owner: Neutral - Actor127: tree22 + Actor149: tree22 Location: 56,8 Owner: Neutral - Actor128: tree23 + Actor150: tree23 Location: 60,8 Owner: Neutral - Actor129: tree24 + Actor151: tree24 Location: 60,9 Owner: Neutral - Actor130: tree01 + Actor152: tree01 Location: 58,14 Owner: Neutral - Actor131: tree02 + Actor153: tree02 Location: 64,24 Owner: Neutral - Actor132: tree03 + Actor154: tree03 Location: 60,16 Owner: Neutral - Actor133: tree04 + Actor155: tree04 Location: 60,20 Owner: Neutral - Actor134: tree05 + Actor156: tree05 Location: 60,18 Owner: Neutral - Actor135: tree06 + Actor157: tree06 Location: 64,26 Owner: Neutral - Actor136: tree07 + Actor158: tree07 Location: 65,26 Owner: Neutral - Actor137: tree08 + Actor159: tree08 Location: 65,28 Owner: Neutral - Actor138: tree09 + Actor160: tree09 Location: 64,29 Owner: Neutral - Actor139: tree04 + Actor161: tree04 Location: 25,-4 Owner: Neutral - Actor140: tree05 + Actor162: tree05 Location: 24,-3 Owner: Neutral - Actor141: tree06 + Actor163: tree06 Location: 26,-2 Owner: Neutral - Actor142: tree07 + Actor164: tree07 Location: 26,-10 Owner: Neutral - Actor143: tree08 + Actor165: tree08 Location: 28,-10 Owner: Neutral - Actor144: tree09 + Actor166: tree09 Location: 29,-9 Owner: Neutral - Actor145: tree10 + Actor167: tree10 Location: 26,-8 Owner: Neutral - Actor146: tree11 + Actor168: tree11 Location: 25,-7 Owner: Neutral - Actor147: tree12 + Actor169: tree12 Location: 24,-10 Owner: Neutral - Actor148: tree13 + Actor170: tree13 Location: 26,-11 Owner: Neutral - Actor149: tree10 + Actor171: tree10 Location: 34,30 Owner: Neutral - Actor150: tree11 + Actor172: tree11 Location: 34,28 Owner: Neutral - Actor151: tree12 + Actor173: tree12 Location: 32,25 Owner: Neutral - Actor152: tree13 + Actor174: tree13 Location: 32,24 Owner: Neutral - Actor153: tree14 + Actor175: tree14 Location: 33,26 Owner: Neutral - Actor154: tree15 + Actor176: tree15 Location: 30,23 Owner: Neutral - Actor155: tree16 + Actor177: tree16 Location: 29,22 Owner: Neutral - Actor156: tree18 + Actor178: tree18 Location: 30,22 Owner: Neutral - Actor157: bigblue3 + Actor179: bigblue3 Location: 19,8 Owner: Neutral - Actor158: bigblue3 + Actor180: bigblue3 Location: 41,5 Owner: Neutral - Actor159: bigblue3 + Actor181: bigblue3 Location: 80,4 Owner: Neutral - Actor160: bigblue3 + Actor182: bigblue3 Location: 73,-27 Owner: Neutral - Actor161: bigblue3 + Actor183: bigblue3 Location: 106,-38 Owner: Neutral - Actor162: bigblue3 + Actor184: bigblue3 Location: 120,-43 Owner: Neutral - Actor163: fona10 + Actor185: fona10 Location: 44,32 Owner: Neutral - Actor164: fona10 + Actor186: fona10 Location: 40,32 Owner: Neutral - Actor165: fona10 + Actor187: fona10 Location: 38,25 Owner: Neutral - Actor166: tree02 + Actor188: tree02 Location: 98,-33 Owner: Neutral - Actor167: fona06 + Actor189: fona06 Location: 98,-35 Owner: Neutral - Actor168: fona08 + Actor190: fona08 Location: 101,-33 Owner: Neutral - Actor169: mpspawn + Actor191: mpspawn Location: 46,25 Owner: Neutral - Actor170: mpspawn + Actor192: mpspawn Location: 98,-62 Owner: Neutral - Actor171: waypoint + Actor193: waypoint Location: 70,-20 Owner: Neutral - Actor172: waypoint + Actor194: waypoint Location: 70,-20 Owner: Neutral - Actor173: veinhole + Actor195: veinhole Location: 31,11 Owner: Neutral - Actor174: srock05 + Actor196: srock05 Location: 34,14 Owner: Neutral - Actor175: srock04 + Actor197: srock04 Location: 34,15 Owner: Neutral - Actor176: trock03 + Actor198: trock03 Location: 38,15 Owner: Neutral - Actor177: trock02 + Actor199: trock02 Location: 98,-44 Owner: Neutral - Actor178: veinhole + Actor200: veinhole Location: 97,-39 Owner: Neutral - Actor179: trock03 + Actor201: trock03 Location: 102,-44 Owner: Neutral - Actor180: veinhole + Actor202: veinhole Location: 71,-8 Owner: Neutral - Actor181: trock01 + Actor203: trock01 Location: 96,-33 Owner: Neutral - Actor182: trock02 + Actor204: trock02 Location: 97,-33 Owner: Neutral - Actor183: tuntop01 + Actor205: tuntop01 Owner: Neutral Location: 26,15 - Actor184: tuntop03 + Actor206: tuntop03 Owner: Neutral Location: 35,15 - Actor185: tuntop02 + Actor207: tuntop02 Owner: Neutral Location: 39,-6 - Actor186: tuntop04 + Actor208: tuntop04 Owner: Neutral Location: 39,12 - Actor187: tuntop01 + Actor209: tuntop01 Owner: Neutral Location: 64,-24 - Actor188: tuntop03 + Actor210: tuntop03 Owner: Neutral Location: 82,-24 - Actor189: tuntop04 + Actor211: tuntop04 Owner: Neutral Location: 97,-32 - Actor190: tuntop02 + Actor212: tuntop02 Owner: Neutral Location: 97,-48 - Actor191: tuntop01 + Actor213: tuntop01 Owner: Neutral Location: 105,-51 - Actor192: tuntop03 + Actor214: tuntop03 Owner: Neutral Location: 114,-51 Rules: + INGRNLMP: + TerrainLightSource: + Range: 5c880 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.7 + BlueTint: 0.01 + INBLULMP: + TerrainLightSource: + Range: 7c832 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.01 + BlueTint: 0.7 World: - GlobalLightingPaletteEffect: - Ambient: 0.81 TerrainTunnelLayer: TerrainTunnel@a: Location: 26, 15 @@ -662,3 +758,6 @@ Footprint: o________o o________o o________o Height: 2 TerrainType: Clear + ^BaseWorld: + TerrainLighting: + Intensity: 0.81 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/forestfr/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/forestfr/map.png differ diff -Nru openra-20200503/mods/ts/maps/forestfr/map.yaml openra-20210321/mods/ts/maps/forestfr/map.yaml --- openra-20200503/mods/ts/maps/forestfr/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/forestfr/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -72,1529 +72,1566 @@ Actor0: cabhut Location: 139,9 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor1: cabhut Location: 143,-11 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor2: bboard06 Location: 28,2 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor3: city22 Location: 146,-43 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor4: ca0003 Location: 144,-35 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor5: ca0005 Location: 149,-37 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor6: ca0014 Location: 145,-38 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor7: ca0016 Location: 148,-39 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor8: city15 Location: 144,39 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor9: city09 Location: 144,33 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor10: bboard11 Location: 145,25 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor11: bboard13 Location: 144,-14 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor12: city08 Location: 147,32 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor13: ca0001 Location: 147,102 Owner: Neutral Health: 50 - Facing: 96 - Actor14: cabhut + Facing: 896 + Actor14: ingrnlmp + Location: 215,-31 + Owner: Neutral + Facing: 896 + Actor15: ingrnlmp + Location: 205,-23 + Owner: Neutral + Facing: 896 + Actor16: ingrnlmp + Location: 172,-18 + Owner: Neutral + Facing: 896 + Actor17: ingrnlmp + Location: 133,-66 + Owner: Neutral + Facing: 896 + Actor18: ingrnlmp + Location: 60,-37 + Owner: Neutral + Facing: 896 + Actor19: ingrnlmp + Location: 41,28 + Owner: Neutral + Facing: 896 + Actor20: ingrnlmp + Location: 63,28 + Owner: Neutral + Facing: 896 + Actor21: ingrnlmp + Location: 97,59 + Owner: Neutral + Facing: 896 + Actor22: ingrnlmp + Location: 130,116 + Owner: Neutral + Facing: 896 + Actor23: ingrnlmp + Location: 190,54 + Owner: Neutral + Facing: 896 + Actor24: ingrnlmp + Location: 199,18 + Owner: Neutral + Facing: 896 + Actor25: ingrnlmp + Location: 174,-73 + Owner: Neutral + Facing: 896 + Actor26: ingrnlmp + Location: 152,-82 + Owner: Neutral + Facing: 896 + Actor27: cabhut Location: 102,-4 Owner: Neutral - Health: 100 - Facing: 96 - Actor15: cabhut + Facing: 896 + Actor28: cabhut Location: 98,-18 Owner: Neutral - Health: 100 - Facing: 96 - Actor16: car + Facing: 896 + Actor29: car Location: 145,42 Owner: Neutral - Health: 100 - Facing: 96 - Actor17: pick + Facing: 896 + Actor30: pick Location: 144,-40 Owner: Neutral - Health: 100 - Facing: 96 - Actor18: civ1 + Facing: 896 + Actor31: civ1 Location: 144,38 Owner: Neutral - Health: 100 - Facing: 100 - Actor19: civ2 + Facing: 880 + Actor32: civ2 Location: 144,31 Owner: Neutral - Health: 100 - Facing: 99 - Actor20: civ3 + Facing: 884 + Actor33: civ3 Location: 144,35 Owner: Neutral - Health: 100 - Facing: 99 - Actor21: civ3 + Facing: 884 + Actor34: civ3 Location: 146,-36 Owner: Neutral - Health: 100 - Facing: 100 - Actor22: civ2 + Facing: 880 + Actor35: civ2 Location: 148,-37 Owner: Neutral - Health: 100 - Facing: 98 - Actor23: civ1 + Facing: 888 + Actor36: civ1 Location: 145,-41 Owner: Neutral - Health: 100 - Facing: 100 - Actor24: tree01 + Facing: 880 + Actor37: tree01 Location: 178,-29 Owner: Neutral - Actor25: tree02 + Actor38: tree02 Location: 178,-30 Owner: Neutral - Actor26: tree03 + Actor39: tree03 Location: 178,-31 Owner: Neutral - Actor27: tree06 + Actor40: tree06 Location: 178,-34 Owner: Neutral - Actor28: tree07 + Actor41: tree07 Location: 178,-35 Owner: Neutral - Actor29: tree09 + Actor42: tree09 Location: 179,-36 Owner: Neutral - Actor30: tree10 + Actor43: tree10 Location: 179,-37 Owner: Neutral - Actor31: tree11 + Actor44: tree11 Location: 170,-32 Owner: Neutral - Actor32: tree14 + Actor45: tree14 Location: 170,-35 Owner: Neutral - Actor33: tree15 + Actor46: tree15 Location: 170,-36 Owner: Neutral - Actor34: tree02 + Actor47: tree02 Location: 148,-53 Owner: Neutral - Actor35: tree03 + Actor48: tree03 Location: 148,-52 Owner: Neutral - Actor36: tree07 + Actor49: tree07 Location: 144,-52 Owner: Neutral - Actor37: tree09 + Actor50: tree09 Location: 143,-52 Owner: Neutral - Actor38: tree13 + Actor51: tree13 Location: 151,-61 Owner: Neutral - Actor39: tree14 + Actor52: tree14 Location: 150,-61 Owner: Neutral - Actor40: tree15 + Actor53: tree15 Location: 149,-61 Owner: Neutral - Actor41: tree18 + Actor54: tree18 Location: 146,-61 Owner: Neutral - Actor42: tree19 + Actor55: tree19 Location: 145,-61 Owner: Neutral - Actor43: tree20 + Actor56: tree20 Location: 144,-61 Owner: Neutral - Actor44: tree21 + Actor57: tree21 Location: 144,-60 Owner: Neutral - Actor45: tree22 + Actor58: tree22 Location: 144,-59 Owner: Neutral - Actor46: tree23 + Actor59: tree23 Location: 143,-59 Owner: Neutral - Actor47: tree24 + Actor60: tree24 Location: 143,-58 Owner: Neutral - Actor48: tree02 + Actor61: tree02 Location: 112,-34 Owner: Neutral - Actor49: tree03 + Actor62: tree03 Location: 112,-33 Owner: Neutral - Actor50: tree06 + Actor63: tree06 Location: 112,-30 Owner: Neutral - Actor51: tree07 + Actor64: tree07 Location: 111,-30 Owner: Neutral - Actor52: tree08 + Actor65: tree08 Location: 103,-38 Owner: Neutral - Actor53: tree09 + Actor66: tree09 Location: 103,-37 Owner: Neutral - Actor54: tree10 + Actor67: tree10 Location: 104,-37 Owner: Neutral - Actor55: tree11 + Actor68: tree11 Location: 104,-36 Owner: Neutral - Actor56: tree12 + Actor69: tree12 Location: 104,-35 Owner: Neutral - Actor57: tree14 + Actor70: tree14 Location: 104,-33 Owner: Neutral - Actor58: tree16 + Actor71: tree16 Location: 104,-31 Owner: Neutral - Actor59: tree17 + Actor72: tree17 Location: 103,-31 Owner: Neutral - Actor60: tree18 + Actor73: tree18 Location: 103,-30 Owner: Neutral - Actor61: tree25 + Actor74: tree25 Location: 190,-18 Owner: Neutral - Actor62: tree24 + Actor75: tree24 Location: 190,-17 Owner: Neutral - Actor63: tree23 + Actor76: tree23 Location: 189,-17 Owner: Neutral - Actor64: tree22 + Actor77: tree22 Location: 189,-16 Owner: Neutral - Actor65: tree20 + Actor78: tree20 Location: 189,-14 Owner: Neutral - Actor66: tree19 + Actor79: tree19 Location: 190,-16 Owner: Neutral - Actor67: tree18 + Actor80: tree18 Location: 189,-13 Owner: Neutral - Actor68: tree17 + Actor81: tree17 Location: 189,-11 Owner: Neutral - Actor69: tree14 + Actor82: tree14 Location: 188,-9 Owner: Neutral - Actor70: tree14 + Actor83: tree14 Location: 180,-19 Owner: Neutral - Actor71: tree13 + Actor84: tree13 Location: 180,-18 Owner: Neutral - Actor72: tree12 + Actor85: tree12 Location: 182,-17 Owner: Neutral - Actor73: tree10 + Actor86: tree10 Location: 181,-15 Owner: Neutral - Actor74: tree09 + Actor87: tree09 Location: 181,-16 Owner: Neutral - Actor75: tree06 + Actor88: tree06 Location: 181,-11 Owner: Neutral - Actor76: tree05 + Actor89: tree05 Location: 181,-10 Owner: Neutral - Actor77: tree04 + Actor90: tree04 Location: 181,-9 Owner: Neutral - Actor78: tree03 + Actor91: tree03 Location: 182,-9 Owner: Neutral - Actor79: tree02 + Actor92: tree02 Location: 183,-9 Owner: Neutral - Actor80: tree01 + Actor93: tree01 Location: 184,-9 Owner: Neutral - Actor81: tree01 + Actor94: tree01 Location: 184,-8 Owner: Neutral - Actor82: tree02 + Actor95: tree02 Location: 185,-9 Owner: Neutral - Actor83: tree04 + Actor96: tree04 Location: 65,20 Owner: Neutral - Actor84: tree05 + Actor97: tree05 Location: 65,19 Owner: Neutral - Actor85: tree05 + Actor98: tree05 Location: 65,18 Owner: Neutral - Actor86: tree08 + Actor99: tree08 Location: 64,16 Owner: Neutral - Actor87: tree10 + Actor100: tree10 Location: 63,16 Owner: Neutral - Actor88: tree11 + Actor101: tree11 Location: 63,15 Owner: Neutral - Actor89: tree12 + Actor102: tree12 Location: 63,14 Owner: Neutral - Actor90: tree13 + Actor103: tree13 Location: 62,14 Owner: Neutral - Actor91: tree14 + Actor104: tree14 Location: 61,14 Owner: Neutral - Actor92: tree15 + Actor105: tree15 Location: 61,13 Owner: Neutral - Actor93: tree17 + Actor106: tree17 Location: 61,11 Owner: Neutral - Actor94: tree18 + Actor107: tree18 Location: 61,10 Owner: Neutral - Actor95: tree19 + Actor108: tree19 Location: 60,10 Owner: Neutral - Actor96: tree20 + Actor109: tree20 Location: 59,10 Owner: Neutral - Actor97: tree21 + Actor110: tree21 Location: 59,9 Owner: Neutral - Actor98: tree01 + Actor111: tree01 Location: 101,29 Owner: Neutral - Actor99: tree02 + Actor112: tree02 Location: 100,29 Owner: Neutral - Actor100: tree03 + Actor113: tree03 Location: 100,28 Owner: Neutral - Actor101: tree04 + Actor114: tree04 Location: 100,27 Owner: Neutral - Actor102: tree05 + Actor115: tree05 Location: 99,27 Owner: Neutral - Actor103: tree06 + Actor116: tree06 Location: 98,27 Owner: Neutral - Actor104: tree10 + Actor117: tree10 Location: 97,24 Owner: Neutral - Actor105: tree11 + Actor118: tree11 Location: 96,24 Owner: Neutral - Actor106: tree12 + Actor119: tree12 Location: 96,23 Owner: Neutral - Actor107: tree01 + Actor120: tree01 Location: 182,39 Owner: Neutral - Actor108: tree02 + Actor121: tree02 Location: 181,38 Owner: Neutral - Actor109: tree03 + Actor122: tree03 Location: 184,36 Owner: Neutral - Actor110: tree05 + Actor123: tree05 Location: 181,36 Owner: Neutral - Actor111: tree09 + Actor124: tree09 Location: 180,33 Owner: Neutral - Actor112: tree25 + Actor125: tree25 Location: 154,84 Owner: Neutral - Actor113: tree24 + Actor126: tree24 Location: 154,83 Owner: Neutral - Actor114: tree23 + Actor127: tree23 Location: 153,82 Owner: Neutral - Actor115: tree22 + Actor128: tree22 Location: 152,83 Owner: Neutral - Actor116: tree21 + Actor129: tree21 Location: 152,82 Owner: Neutral - Actor117: tree20 + Actor130: tree20 Location: 151,83 Owner: Neutral - Actor118: tree18 + Actor131: tree18 Location: 150,82 Owner: Neutral - Actor119: tree16 + Actor132: tree16 Location: 148,83 Owner: Neutral - Actor120: tree15 + Actor133: tree15 Location: 148,82 Owner: Neutral - Actor121: tree12 + Actor134: tree12 Location: 145,82 Owner: Neutral - Actor122: tree11 + Actor135: tree11 Location: 144,82 Owner: Neutral - Actor123: tree10 + Actor136: tree10 Location: 144,81 Owner: Neutral - Actor124: tree09 + Actor137: tree09 Location: 144,80 Owner: Neutral - Actor125: tree08 + Actor138: tree08 Location: 145,80 Owner: Neutral - Actor126: tree07 + Actor139: tree07 Location: 145,81 Owner: Neutral - Actor127: tibtre01 + Actor140: tibtre01 Location: 59,-38 Owner: Neutral - Actor128: tibtre01 + Actor141: tibtre01 Location: 40,29 Owner: Neutral - Actor129: tibtre02 + Actor142: tibtre02 Location: 153,-83 Owner: Neutral - Actor130: tibtre03 + Actor143: tibtre03 Location: 214,-31 Owner: Neutral - Actor131: tibtre02 + Actor144: tibtre02 Location: 198,17 Owner: Neutral - Actor132: tibtre03 + Actor145: tibtre03 Location: 129,116 Owner: Neutral - Actor133: tibtre02 + Actor146: tibtre02 Location: 63,27 Owner: Neutral - Actor134: tibtre01 + Actor147: tibtre01 Location: 98,60 Owner: Neutral - Actor135: tibtre03 + Actor148: tibtre03 Location: 190,55 Owner: Neutral - Actor136: tibtre02 + Actor149: tibtre02 Location: 205,-24 Owner: Neutral - Actor137: tibtre01 + Actor150: tibtre01 Location: 173,-73 Owner: Neutral - Actor138: tibtre03 + Actor151: tibtre03 Location: 132,-67 Owner: Neutral - Actor139: tree01 + Actor152: tree01 Location: 57,10 Owner: Neutral - Actor140: tree02 + Actor153: tree02 Location: 54,15 Owner: Neutral - Actor141: tree03 + Actor154: tree03 Location: 62,16 Owner: Neutral - Actor142: tree04 + Actor155: tree04 Location: 60,17 Owner: Neutral - Actor143: tree05 + Actor156: tree05 Location: 57,14 Owner: Neutral - Actor144: tree05 + Actor157: tree05 Location: 57,12 Owner: Neutral - Actor145: tree06 + Actor158: tree06 Location: 58,11 Owner: Neutral - Actor146: tree07 + Actor159: tree07 Location: 58,16 Owner: Neutral - Actor147: tree07 + Actor160: tree07 Location: 57,17 Owner: Neutral - Actor148: tree08 + Actor161: tree08 Location: 53,13 Owner: Neutral - Actor149: tree09 + Actor162: tree09 Location: 59,14 Owner: Neutral - Actor150: tree12 + Actor163: tree12 Location: 68,20 Owner: Neutral - Actor151: tree16 + Actor164: tree16 Location: 55,16 Owner: Neutral - Actor152: tree18 + Actor165: tree18 Location: 60,14 Owner: Neutral - Actor153: tree22 + Actor166: tree22 Location: 66,20 Owner: Neutral - Actor154: tree23 + Actor167: tree23 Location: 56,14 Owner: Neutral - Actor155: tree25 + Actor168: tree25 Location: 58,13 Owner: Neutral - Actor156: tree07 + Actor169: tree07 Location: 55,11 Owner: Neutral - Actor157: tree09 + Actor170: tree09 Location: 55,12 Owner: Neutral - Actor158: tree11 + Actor171: tree11 Location: 57,16 Owner: Neutral - Actor159: tree15 + Actor172: tree15 Location: 55,10 Owner: Neutral - Actor160: tree20 + Actor173: tree20 Location: 59,13 Owner: Neutral - Actor161: tree21 + Actor174: tree21 Location: 55,19 Owner: Neutral - Actor162: tree22 + Actor175: tree22 Location: 50,12 Owner: Neutral - Actor163: tree01 + Actor176: tree01 Location: 85,22 Owner: Neutral - Actor164: tree02 + Actor177: tree02 Location: 89,23 Owner: Neutral - Actor165: tree03 + Actor178: tree03 Location: 90,24 Owner: Neutral - Actor166: tree04 + Actor179: tree04 Location: 90,23 Owner: Neutral - Actor167: tree07 + Actor180: tree07 Location: 93,24 Owner: Neutral - Actor168: tree09 + Actor181: tree09 Location: 94,27 Owner: Neutral - Actor169: tree10 + Actor182: tree10 Location: 96,27 Owner: Neutral - Actor170: tree11 + Actor183: tree11 Location: 94,24 Owner: Neutral - Actor171: tree12 + Actor184: tree12 Location: 94,26 Owner: Neutral - Actor172: tree13 + Actor185: tree13 Location: 96,25 Owner: Neutral - Actor173: tree15 + Actor186: tree15 Location: 92,27 Owner: Neutral - Actor174: tree16 + Actor187: tree16 Location: 94,22 Owner: Neutral - Actor175: tree17 + Actor188: tree17 Location: 92,22 Owner: Neutral - Actor176: tree18 + Actor189: tree18 Location: 90,22 Owner: Neutral - Actor177: tree18 + Actor190: tree18 Location: 102,20 Owner: Neutral - Actor178: tree19 + Actor191: tree19 Location: 104,14 Owner: Neutral - Actor179: tree20 + Actor192: tree20 Location: 105,17 Owner: Neutral - Actor180: tree21 + Actor193: tree21 Location: 106,33 Owner: Neutral - Actor181: tree22 + Actor194: tree22 Location: 108,35 Owner: Neutral - Actor182: tree23 + Actor195: tree23 Location: 107,33 Owner: Neutral - Actor183: tree24 + Actor196: tree24 Location: 99,31 Owner: Neutral - Actor184: tree01 + Actor197: tree01 Location: 146,77 Owner: Neutral - Actor185: tree02 + Actor198: tree02 Location: 147,79 Owner: Neutral - Actor186: tree08 + Actor199: tree08 Location: 148,77 Owner: Neutral - Actor187: tree09 + Actor200: tree09 Location: 149,73 Owner: Neutral - Actor188: tree10 + Actor201: tree10 Location: 152,76 Owner: Neutral - Actor189: tree11 + Actor202: tree11 Location: 151,79 Owner: Neutral - Actor190: tree12 + Actor203: tree12 Location: 150,74 Owner: Neutral - Actor191: tree14 + Actor204: tree14 Location: 147,76 Owner: Neutral - Actor192: tree15 + Actor205: tree15 Location: 150,81 Owner: Neutral - Actor193: tree16 + Actor206: tree16 Location: 148,80 Owner: Neutral - Actor194: tree17 + Actor207: tree17 Location: 149,84 Owner: Neutral - Actor195: tree18 + Actor208: tree18 Location: 148,87 Owner: Neutral - Actor196: tree19 + Actor209: tree19 Location: 146,83 Owner: Neutral - Actor197: tree20 + Actor210: tree20 Location: 153,84 Owner: Neutral - Actor198: tree22 + Actor211: tree22 Location: 153,83 Owner: Neutral - Actor199: tree02 + Actor212: tree02 Location: 151,85 Owner: Neutral - Actor200: tree03 + Actor213: tree03 Location: 145,83 Owner: Neutral - Actor201: tree05 + Actor214: tree05 Location: 149,80 Owner: Neutral - Actor202: tree06 + Actor215: tree06 Location: 150,72 Owner: Neutral - Actor203: tree09 + Actor216: tree09 Location: 177,36 Owner: Neutral - Actor204: tree10 + Actor217: tree10 Location: 177,34 Owner: Neutral - Actor205: tree12 + Actor218: tree12 Location: 184,32 Owner: Neutral - Actor206: tree14 + Actor219: tree14 Location: 183,40 Owner: Neutral - Actor207: tree15 + Actor220: tree15 Location: 181,39 Owner: Neutral - Actor208: tree16 + Actor221: tree16 Location: 176,36 Owner: Neutral - Actor209: tree17 + Actor222: tree17 Location: 174,33 Owner: Neutral - Actor210: tree18 + Actor223: tree18 Location: 178,35 Owner: Neutral - Actor211: tree19 + Actor224: tree19 Location: 172,34 Owner: Neutral - Actor212: tree20 + Actor225: tree20 Location: 170,30 Owner: Neutral - Actor213: tree21 + Actor226: tree21 Location: 170,29 Owner: Neutral - Actor214: tree22 + Actor227: tree22 Location: 172,30 Owner: Neutral - Actor215: tree24 + Actor228: tree24 Location: 175,36 Owner: Neutral - Actor216: tree25 + Actor229: tree25 Location: 176,35 Owner: Neutral - Actor217: tree01 + Actor230: tree01 Location: 168,35 Owner: Neutral - Actor218: tree02 + Actor231: tree02 Location: 170,36 Owner: Neutral - Actor219: tree03 + Actor232: tree03 Location: 174,36 Owner: Neutral - Actor220: tree05 + Actor233: tree05 Location: 177,33 Owner: Neutral - Actor221: tree06 + Actor234: tree06 Location: 180,34 Owner: Neutral - Actor222: tree08 + Actor235: tree08 Location: 178,33 Owner: Neutral - Actor223: tree09 + Actor236: tree09 Location: 180,43 Owner: Neutral - Actor224: tree10 + Actor237: tree10 Location: 170,41 Owner: Neutral - Actor225: tree11 + Actor238: tree11 Location: 172,44 Owner: Neutral - Actor226: tree12 + Actor239: tree12 Location: 168,45 Owner: Neutral - Actor227: tree13 + Actor240: tree13 Location: 173,33 Owner: Neutral - Actor228: tree14 + Actor241: tree14 Location: 171,31 Owner: Neutral - Actor229: tree15 + Actor242: tree15 Location: 179,36 Owner: Neutral - Actor230: tree16 + Actor243: tree16 Location: 180,32 Owner: Neutral - Actor231: tree17 + Actor244: tree17 Location: 182,34 Owner: Neutral - Actor232: tree03 + Actor245: tree03 Location: 185,-15 Owner: Neutral - Actor233: tree05 + Actor246: tree05 Location: 184,-14 Owner: Neutral - Actor234: tree07 + Actor247: tree07 Location: 187,-13 Owner: Neutral - Actor235: tree10 + Actor248: tree10 Location: 184,-11 Owner: Neutral - Actor236: tree12 + Actor249: tree12 Location: 186,-11 Owner: Neutral - Actor237: tree14 + Actor250: tree14 Location: 187,-15 Owner: Neutral - Actor238: tree15 + Actor251: tree15 Location: 187,-11 Owner: Neutral - Actor239: tree17 + Actor252: tree17 Location: 183,-16 Owner: Neutral - Actor240: tree20 + Actor253: tree20 Location: 185,-14 Owner: Neutral - Actor241: tree21 + Actor254: tree21 Location: 188,-14 Owner: Neutral - Actor242: tree22 + Actor255: tree22 Location: 190,-13 Owner: Neutral - Actor243: tibtre01 + Actor256: tibtre01 Location: 171,-19 Owner: Neutral - Actor244: tree03 + Actor257: tree03 Location: 197,-22 Owner: Neutral - Actor245: tree05 + Actor258: tree05 Location: 193,-16 Owner: Neutral - Actor246: tree06 + Actor259: tree06 Location: 193,-17 Owner: Neutral - Actor247: tree07 + Actor260: tree07 Location: 200,-4 Owner: Neutral - Actor248: tree08 + Actor261: tree08 Location: 193,-13 Owner: Neutral - Actor249: tree09 + Actor262: tree09 Location: 196,-11 Owner: Neutral - Actor250: tree10 + Actor263: tree10 Location: 189,-9 Owner: Neutral - Actor251: tree11 + Actor264: tree11 Location: 181,-30 Owner: Neutral - Actor252: tree12 + Actor265: tree12 Location: 180,-34 Owner: Neutral - Actor253: tree13 + Actor266: tree13 Location: 179,-33 Owner: Neutral - Actor254: tree14 + Actor267: tree14 Location: 176,-32 Owner: Neutral - Actor255: tree16 + Actor268: tree16 Location: 171,-33 Owner: Neutral - Actor256: tree17 + Actor269: tree17 Location: 174,-31 Owner: Neutral - Actor257: tree18 + Actor270: tree18 Location: 175,-31 Owner: Neutral - Actor258: tree19 + Actor271: tree19 Location: 175,-34 Owner: Neutral - Actor259: tree20 + Actor272: tree20 Location: 173,-33 Owner: Neutral - Actor260: tree21 + Actor273: tree21 Location: 172,-32 Owner: Neutral - Actor261: tree22 + Actor274: tree22 Location: 175,-32 Owner: Neutral - Actor262: tree23 + Actor275: tree23 Location: 173,-35 Owner: Neutral - Actor263: tree24 + Actor276: tree24 Location: 172,-34 Owner: Neutral - Actor264: tree01 + Actor277: tree01 Location: 185,-20 Owner: Neutral - Actor265: tree02 + Actor278: tree02 Location: 185,-21 Owner: Neutral - Actor266: tree03 + Actor279: tree03 Location: 184,-21 Owner: Neutral - Actor267: tree04 + Actor280: tree04 Location: 184,-25 Owner: Neutral - Actor268: tree05 + Actor281: tree05 Location: 181,-28 Owner: Neutral - Actor269: tree06 + Actor282: tree06 Location: 179,-29 Owner: Neutral - Actor270: tree07 + Actor283: tree07 Location: 143,-54 Owner: Neutral - Actor271: tree08 + Actor284: tree08 Location: 143,-57 Owner: Neutral - Actor272: tree09 + Actor285: tree09 Location: 145,-56 Owner: Neutral - Actor273: tree10 + Actor286: tree10 Location: 146,-55 Owner: Neutral - Actor274: tree11 + Actor287: tree11 Location: 143,-55 Owner: Neutral - Actor275: tree12 + Actor288: tree12 Location: 147,-58 Owner: Neutral - Actor276: tree13 + Actor289: tree13 Location: 145,-60 Owner: Neutral - Actor277: tree14 + Actor290: tree14 Location: 145,-58 Owner: Neutral - Actor278: tree15 + Actor291: tree15 Location: 147,-59 Owner: Neutral - Actor279: tree16 + Actor292: tree16 Location: 146,-57 Owner: Neutral - Actor280: tree17 + Actor293: tree17 Location: 147,-56 Owner: Neutral - Actor281: tree18 + Actor294: tree18 Location: 144,-56 Owner: Neutral - Actor282: tree19 + Actor295: tree19 Location: 146,-54 Owner: Neutral - Actor283: tree20 + Actor296: tree20 Location: 145,-57 Owner: Neutral - Actor284: tree21 + Actor297: tree21 Location: 143,-56 Owner: Neutral - Actor285: tree22 + Actor298: tree22 Location: 147,-51 Owner: Neutral - Actor286: tree23 + Actor299: tree23 Location: 148,-49 Owner: Neutral - Actor287: tree24 + Actor300: tree24 Location: 146,-50 Owner: Neutral - Actor288: tree25 + Actor301: tree25 Location: 150,-49 Owner: Neutral - Actor289: tree01 + Actor302: tree01 Location: 145,-50 Owner: Neutral - Actor290: tree03 + Actor303: tree03 Location: 143,-70 Owner: Neutral - Actor291: tree04 + Actor304: tree04 Location: 144,-70 Owner: Neutral - Actor292: tree05 + Actor305: tree05 Location: 144,-68 Owner: Neutral - Actor293: tree06 + Actor306: tree06 Location: 147,-64 Owner: Neutral - Actor294: tree01 + Actor307: tree01 Location: 105,-36 Owner: Neutral - Actor295: tree02 + Actor308: tree02 Location: 106,-34 Owner: Neutral - Actor296: tree03 + Actor309: tree03 Location: 109,-34 Owner: Neutral - Actor297: tree05 + Actor310: tree05 Location: 106,-32 Owner: Neutral - Actor298: tree06 + Actor311: tree06 Location: 110,-32 Owner: Neutral - Actor299: tree07 + Actor312: tree07 Location: 106,-35 Owner: Neutral - Actor300: tree09 + Actor313: tree09 Location: 114,-33 Owner: Neutral - Actor301: tree10 + Actor314: tree10 Location: 113,-31 Owner: Neutral - Actor302: tree11 + Actor315: tree11 Location: 115,-31 Owner: Neutral - Actor303: tree12 + Actor316: tree12 Location: 114,-34 Owner: Neutral - Actor304: tree13 + Actor317: tree13 Location: 108,-33 Owner: Neutral - Actor305: tree15 + Actor318: tree15 Location: 109,-31 Owner: Neutral - Actor306: tree16 + Actor319: tree16 Location: 114,-30 Owner: Neutral - Actor307: tree17 + Actor320: tree17 Location: 116,-33 Owner: Neutral - Actor308: tree18 + Actor321: tree18 Location: 116,-36 Owner: Neutral - Actor309: tree19 + Actor322: tree19 Location: 114,-27 Owner: Neutral - Actor310: tree20 + Actor323: tree20 Location: 115,-25 Owner: Neutral - Actor311: tree21 + Actor324: tree21 Location: 116,-26 Owner: Neutral - Actor312: tree22 + Actor325: tree22 Location: 114,-26 Owner: Neutral - Actor313: tree23 + Actor326: tree23 Location: 116,-38 Owner: Neutral - Actor314: tree24 + Actor327: tree24 Location: 114,-36 Owner: Neutral - Actor315: tree25 + Actor328: tree25 Location: 100,-33 Owner: Neutral - Actor316: tree03 + Actor329: tree03 Location: 100,-42 Owner: Neutral - Actor317: tree04 + Actor330: tree04 Location: 99,-40 Owner: Neutral - Actor318: tree05 + Actor331: tree05 Location: 101,-35 Owner: Neutral - Actor319: tree06 + Actor332: tree06 Location: 102,-34 Owner: Neutral - Actor320: tree05 + Actor333: tree05 Location: 68,23 Owner: Neutral - Actor321: tree06 + Actor334: tree06 Location: 68,22 Owner: Neutral - Actor322: tree09 + Actor335: tree09 Location: 68,21 Owner: Neutral - Actor323: tree10 + Actor336: tree10 Location: 62,18 Owner: Neutral - Actor324: tree11 + Actor337: tree11 Location: 58,18 Owner: Neutral - Actor325: tree10 + Actor338: tree10 Location: 151,80 Owner: Neutral - Actor326: tree11 + Actor339: tree11 Location: 152,77 Owner: Neutral - Actor327: tree06 + Actor340: tree06 Location: 149,82 Owner: Neutral - Actor328: tree07 + Actor341: tree07 Location: 146,86 Owner: Neutral - Actor329: tree08 + Actor342: tree08 Location: 147,88 Owner: Neutral - Actor330: tree10 + Actor343: tree10 Location: 148,90 Owner: Neutral - Actor331: tree11 + Actor344: tree11 Location: 155,86 Owner: Neutral - Actor332: tree24 + Actor345: tree24 Location: 189,-7 Owner: Neutral - Actor333: tree12 + Actor346: tree12 Location: 193,-11 Owner: Neutral - Actor334: tree13 + Actor347: tree13 Location: 191,-13 Owner: Neutral - Actor335: tree14 + Actor348: tree14 Location: 197,-7 Owner: Neutral - Actor336: tree16 + Actor349: tree16 Location: 201,-5 Owner: Neutral - Actor337: tree17 + Actor350: tree17 Location: 200,-5 Owner: Neutral - Actor338: tree18 + Actor351: tree18 Location: 195,-15 Owner: Neutral - Actor339: tree19 + Actor352: tree19 Location: 194,-23 Owner: Neutral - Actor340: tree20 + Actor353: tree20 Location: 193,-21 Owner: Neutral - Actor341: tree02 + Actor354: tree02 Location: 90,85 Owner: Neutral - Actor342: tree03 + Actor355: tree03 Location: 91,85 Owner: Neutral - Actor343: tree04 + Actor356: tree04 Location: 90,84 Owner: Neutral - Actor344: tree05 + Actor357: tree05 Location: 56,30 Owner: Neutral - Actor345: tree06 + Actor358: tree06 Location: 58,31 Owner: Neutral - Actor346: tree07 + Actor359: tree07 Location: 58,29 Owner: Neutral - Actor347: tree08 + Actor360: tree08 Location: 71,52 Owner: Neutral - Actor348: tree08 + Actor361: tree08 Location: 24,-11 Owner: Neutral - Actor349: tree10 + Actor362: tree10 Location: 27,-11 Owner: Neutral - Actor350: tree11 + Actor363: tree11 Location: 16,10 Owner: Neutral - Actor351: tree13 + Actor364: tree13 Location: 44,-2 Owner: Neutral - Actor352: tree14 + Actor365: tree14 Location: 48,-3 Owner: Neutral - Actor353: tree15 + Actor366: tree15 Location: 54,3 Owner: Neutral - Actor354: tree16 + Actor367: tree16 Location: 58,3 Owner: Neutral - Actor355: tree17 + Actor368: tree17 Location: 74,6 Owner: Neutral - Actor356: tree18 + Actor369: tree18 Location: 74,2 Owner: Neutral - Actor357: tree01 + Actor370: tree01 Location: 50,-16 Owner: Neutral - Actor358: tree03 + Actor371: tree03 Location: 52,-14 Owner: Neutral - Actor359: tree04 + Actor372: tree04 Location: 54,-12 Owner: Neutral - Actor360: tree05 + Actor373: tree05 Location: 59,-11 Owner: Neutral - Actor361: tree07 + Actor374: tree07 Location: 72,-50 Owner: Neutral - Actor362: tree08 + Actor375: tree08 Location: 72,-52 Owner: Neutral - Actor363: tree10 + Actor376: tree10 Location: 93,-66 Owner: Neutral - Actor364: tree11 + Actor377: tree11 Location: 99,-60 Owner: Neutral - Actor365: tree12 + Actor378: tree12 Location: 98,-58 Owner: Neutral - Actor366: tree13 + Actor379: tree13 Location: 101,-60 Owner: Neutral - Actor367: tree15 + Actor380: tree15 Location: 111,-40 Owner: Neutral - Actor368: tree16 + Actor381: tree16 Location: 121,-47 Owner: Neutral - Actor369: tree17 + Actor382: tree17 Location: 125,-46 Owner: Neutral - Actor370: tree18 + Actor383: tree18 Location: 131,-50 Owner: Neutral - Actor371: tree01 + Actor384: tree01 Location: 147,-36 Owner: Neutral - Actor372: tree01 + Actor385: tree01 Location: 108,-70 Owner: Neutral - Actor373: tree02 + Actor386: tree02 Location: 112,-69 Owner: Neutral - Actor374: tree03 + Actor387: tree03 Location: 112,-67 Owner: Neutral - Actor375: tree04 + Actor388: tree04 Location: 112,-72 Owner: Neutral - Actor376: tree06 + Actor389: tree06 Location: 116,-66 Owner: Neutral - Actor377: tree08 + Actor390: tree08 Location: 110,-71 Owner: Neutral - Actor378: tree09 + Actor391: tree09 Location: 111,-70 Owner: Neutral - Actor379: tree10 + Actor392: tree10 Location: 130,-84 Owner: Neutral - Actor380: tree11 + Actor393: tree11 Location: 129,-88 Owner: Neutral - Actor381: tree12 + Actor394: tree12 Location: 132,-85 Owner: Neutral - Actor382: tree13 + Actor395: tree13 Location: 130,-91 Owner: Neutral - Actor383: tree14 + Actor396: tree14 Location: 129,-93 Owner: Neutral - Actor384: tree15 + Actor397: tree15 Location: 131,-93 Owner: Neutral - Actor385: tree17 + Actor398: tree17 Location: 158,-87 Owner: Neutral - Actor386: tree18 + Actor399: tree18 Location: 157,-88 Owner: Neutral - Actor387: tree19 + Actor400: tree19 Location: 159,-88 Owner: Neutral - Actor388: tree21 + Actor401: tree21 Location: 164,-91 Owner: Neutral - Actor389: tree22 + Actor402: tree22 Location: 165,-91 Owner: Neutral - Actor390: tree23 + Actor403: tree23 Location: 139,-114 Owner: Neutral - Actor391: tree24 + Actor404: tree24 Location: 138,-114 Owner: Neutral - Actor392: tree02 + Actor405: tree02 Location: 187,-67 Owner: Neutral - Actor393: tree04 + Actor406: tree04 Location: 187,-65 Owner: Neutral - Actor394: tree05 + Actor407: tree05 Location: 188,-66 Owner: Neutral - Actor395: tree07 + Actor408: tree07 Location: 200,-61 Owner: Neutral - Actor396: tree08 + Actor409: tree08 Location: 199,-30 Owner: Neutral - Actor397: tree09 + Actor410: tree09 Location: 197,-30 Owner: Neutral - Actor398: tree10 + Actor411: tree10 Location: 198,-29 Owner: Neutral - Actor399: tree11 + Actor412: tree11 Location: 238,-19 Owner: Neutral - Actor400: tree12 + Actor413: tree12 Location: 241,-18 Owner: Neutral - Actor401: tree13 + Actor414: tree13 Location: 240,-17 Owner: Neutral - Actor402: tree14 + Actor415: tree14 Location: 239,-16 Owner: Neutral - Actor403: tree14 + Actor416: tree14 Location: 224,-20 Owner: Neutral - Actor404: tree15 + Actor417: tree15 Location: 240,-15 Owner: Neutral - Actor405: tree15 + Actor418: tree15 Location: 248,-10 Owner: Neutral - Actor406: tree06 + Actor419: tree06 Location: 244,6 Owner: Neutral - Actor407: tree12 + Actor420: tree12 Location: 229,2 Owner: Neutral - Actor408: tree13 + Actor421: tree13 Location: 224,3 Owner: Neutral - Actor409: tree14 + Actor422: tree14 Location: 217,0 Owner: Neutral - Actor410: tree15 + Actor423: tree15 Location: 215,2 Owner: Neutral - Actor411: tree16 + Actor424: tree16 Location: 215,1 Owner: Neutral - Actor412: tree17 + Actor425: tree17 Location: 212,21 Owner: Neutral - Actor413: tree18 + Actor426: tree18 Location: 214,22 Owner: Neutral - Actor414: tree19 + Actor427: tree19 Location: 213,22 Owner: Neutral - Actor415: tree20 + Actor428: tree20 Location: 213,21 Owner: Neutral - Actor416: tree21 + Actor429: tree21 Location: 215,24 Owner: Neutral - Actor417: tree05 + Actor430: tree05 Location: 67,20 Owner: Neutral - Actor418: tree09 + Actor431: tree09 Location: 66,19 Owner: Neutral - Actor419: tree16 + Actor432: tree16 Location: 69,21 Owner: Neutral - Actor420: tree02 + Actor433: tree02 Location: 232,17 Owner: Neutral - Actor421: tree03 + Actor434: tree03 Location: 230,19 Owner: Neutral - Actor422: tree04 + Actor435: tree04 Location: 228,21 Owner: Neutral - Actor423: tree05 + Actor436: tree05 Location: 230,22 Owner: Neutral - Actor424: tree06 + Actor437: tree06 Location: 229,24 Owner: Neutral - Actor425: tree07 + Actor438: tree07 Location: 231,24 Owner: Neutral - Actor426: tree08 + Actor439: tree08 Location: 241,18 Owner: Neutral - Actor427: mpspawn + Actor440: mpspawn Location: 34,14 Owner: Neutral - Actor428: mpspawn + Actor441: mpspawn Location: 69,41 Owner: Neutral - Actor429: mpspawn + Actor442: mpspawn Location: 137,106 Owner: Neutral - Actor430: mpspawn + Actor443: mpspawn Location: 202,31 Owner: Neutral - Actor431: mpspawn + Actor444: mpspawn Location: 230,-10 Owner: Neutral - Actor432: mpspawn + Actor445: mpspawn Location: 80,-45 Owner: Neutral - Actor433: mpspawn + Actor446: mpspawn Location: 142,-98 Owner: Neutral - Actor434: mpspawn + Actor447: mpspawn Location: 191,-48 Owner: Neutral - Actor435: waypoint + Actor448: waypoint Location: 137,-3 Owner: Neutral - Actor436: waypoint + Actor449: waypoint Location: 137,-3 Owner: Neutral - Actor437: trock01 + Actor450: trock01 Location: 76,-59 Owner: Neutral - Actor438: trock03 + Actor451: trock03 Location: 29,1 Owner: Neutral - Actor439: trock04 + Actor452: trock04 Location: 135,-105 Owner: Neutral - Actor440: trock03 + Actor453: trock03 Location: 122,-75 Owner: Neutral - Actor441: trock02 + Actor454: trock02 Location: 106,-44 Owner: Neutral - Actor442: trock05 + Actor455: trock05 Location: 161,-98 Owner: Neutral - Actor443: trock04 + Actor456: trock04 Location: 79,-8 Owner: Neutral - Actor444: lobrdg_r_ne + Actor457: lobrdg_r_ne Location: 99,-18 Owner: Neutral - Actor445: lobrdg_a + Actor458: lobrdg_a Location: 99,-17 Owner: Neutral - Actor446: lobrdg_a + Actor459: lobrdg_a Location: 99,-16 Owner: Neutral - Actor447: lobrdg_a + Actor460: lobrdg_a Location: 99,-15 Owner: Neutral - Actor448: lobrdg_a + Actor461: lobrdg_a Location: 99,-14 Owner: Neutral - Actor449: lobrdg_a + Actor462: lobrdg_a Location: 99,-13 Owner: Neutral - Actor450: lobrdg_a + Actor463: lobrdg_a Location: 99,-12 Owner: Neutral - Actor451: lobrdg_a + Actor464: lobrdg_a Location: 99,-11 Owner: Neutral - Actor452: lobrdg_a + Actor465: lobrdg_a Location: 99,-10 Owner: Neutral - Actor453: lobrdg_a + Actor466: lobrdg_a Location: 99,-9 Owner: Neutral - Actor454: lobrdg_a + Actor467: lobrdg_a Location: 99,-8 Owner: Neutral - Actor455: lobrdg_a + Actor468: lobrdg_a Location: 99,-7 Owner: Neutral - Actor456: lobrdg_a + Actor469: lobrdg_a Location: 99,-6 Owner: Neutral - Actor457: lobrdg_a + Actor470: lobrdg_a Location: 99,-5 Owner: Neutral - Actor458: lobrdg_r_sw + Actor471: lobrdg_r_sw Location: 99,-4 Owner: Neutral - Actor459: crat03 + Actor472: crat03 Location: 146,-43 Owner: Neutral - Actor460: trock05 + Actor473: trock05 Location: 117,0 Owner: Neutral - Actor461: trock02 + Actor474: trock02 Location: 66,57 Owner: Neutral - Actor462: lobrdg_r_ne + Actor475: lobrdg_r_ne Location: 140,-11 Owner: Neutral - Actor463: lobrdg_a + Actor476: lobrdg_a Location: 140,-10 Owner: Neutral Health: 50 - Actor464: lobrdg_a + Actor477: lobrdg_a Location: 140,-9 Owner: Neutral Health: 50 - Actor465: lobrdg_a + Actor478: lobrdg_a Location: 140,-8 Owner: Neutral Health: 25 - Actor466: lobrdg_a_d + Actor479: lobrdg_a_d Location: 140,-7 Owner: Neutral - Actor467: lobrdg_a_d + Actor480: lobrdg_a_d Location: 140,-6 Owner: Neutral - Actor468: lobrdg_a_d + Actor481: lobrdg_a_d Location: 140,-5 Owner: Neutral - Actor469: lobrdg_a_d + Actor482: lobrdg_a_d Location: 140,-4 Owner: Neutral - Actor470: lobrdg_a_d + Actor483: lobrdg_a_d Location: 140,-3 Owner: Neutral - Actor471: lobrdg_a_d + Actor484: lobrdg_a_d Location: 140,-2 Owner: Neutral - Actor472: lobrdg_a_d + Actor485: lobrdg_a_d Location: 140,-1 Owner: Neutral - Actor473: lobrdg_a_d + Actor486: lobrdg_a_d Location: 140,0 Owner: Neutral - Actor474: lobrdg_a_d + Actor487: lobrdg_a_d Location: 140,1 Owner: Neutral - Actor475: lobrdg_a_d + Actor488: lobrdg_a_d Location: 140,2 Owner: Neutral - Actor476: lobrdg_a_d + Actor489: lobrdg_a_d Location: 140,3 Owner: Neutral - Actor477: lobrdg_a + Actor490: lobrdg_a Location: 140,4 Owner: Neutral Health: 25 - Actor478: lobrdg_a + Actor491: lobrdg_a Location: 140,5 Owner: Neutral Health: 50 - Actor479: trock01 + Actor492: trock01 Location: 87,59 Owner: Neutral - Actor480: lobrdg_a + Actor493: lobrdg_a Location: 140,6 Owner: Neutral Health: 50 - Actor481: lobrdg_a + Actor494: lobrdg_a Location: 140,7 Owner: Neutral - Actor482: lobrdg_a + Actor495: lobrdg_a Location: 140,8 Owner: Neutral - Actor483: lobrdg_r_sw + Actor496: lobrdg_r_sw Location: 140,9 Owner: Neutral - Actor484: trock02 + Actor497: trock02 Location: 144,8 Owner: Neutral - Actor485: trock01 + Actor498: trock01 Location: 189,-8 Owner: Neutral - Actor486: crat03 + Actor499: crat03 Location: 144,39 Owner: Neutral - Actor487: trock03 + Actor500: trock03 Location: 154,30 Owner: Neutral - Actor488: trock05 + Actor501: trock05 Location: 191,21 Owner: Neutral - Actor489: trock04 + Actor502: trock04 Location: 170,62 Owner: Neutral Rules: - World: - GlobalLightingPaletteEffect: - Ambient: 0.81 + ^BaseWorld: + TerrainLighting: + Intensity: 0.81 + HeightStep: 0.025 + INGRNLMP: + TerrainLightSource: + Range: 9c184 + Intensity: 0.03 + RedTint: 0.01 + GreenTint: 0.6 + BlueTint: 0.01 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/karasjok/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/karasjok/map.png differ diff -Nru openra-20200503/mods/ts/maps/karasjok/map.yaml openra-20210321/mods/ts/maps/karasjok/map.yaml --- openra-20200503/mods/ts/maps/karasjok/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/karasjok/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -54,1510 +54,1697 @@ Enemies: Creeps Actors: - Actor0: aban18 + Actor0: ingrnlmp + Location: 108,86 + Owner: Neutral + Facing: 640 + Actor1: ingrnlmp + Location: 80,68 + Owner: Neutral + Facing: 640 + Actor2: ingrnlmp + Location: 85,75 + Owner: Neutral + Facing: 640 + Actor3: inblulmp + Location: 95,90 + Owner: Neutral + Facing: 640 + Actor4: inblulmp + Location: 109,95 + Owner: Neutral + Facing: 640 + Actor5: inblulmp + Location: 115,96 + Owner: Neutral + Facing: 640 + Actor6: inblulmp + Location: 122,98 + Owner: Neutral + Facing: 640 + Actor7: inblulmp + Location: 89,88 + Owner: Neutral + Facing: 640 + Actor8: inblulmp + Location: 129,100 + Owner: Neutral + Facing: 640 + Actor9: aban18 Location: 68,53 Owner: Neutral - Health: 100 - Facing: 160 - Actor1: aban16 + Facing: 640 + Actor10: aban16 Location: 65,53 Owner: Neutral - Health: 100 - Facing: 160 - Actor2: aban17 + Facing: 640 + Actor11: aban17 Location: 65,55 Owner: Neutral - Health: 100 - Facing: 160 - Actor3: aban17 + Facing: 640 + Actor12: aban17 Location: 67,55 Owner: Neutral - Health: 100 - Facing: 160 - Actor4: aban11 + Facing: 640 + Actor13: aban11 Location: 69,51 Owner: Neutral - Health: 100 - Facing: 160 - Actor5: aban10 + Facing: 640 + Actor14: aban10 Location: 62,52 Owner: Neutral - Health: 100 - Facing: 160 - Actor6: aban07 + Facing: 640 + Actor15: aban07 Location: 70,58 Owner: Neutral - Health: 100 - Facing: 160 - Actor7: aban05 + Facing: 640 + Actor16: aban05 Location: 64,59 Owner: Neutral - Health: 100 - Facing: 160 - Actor8: aban01 + Facing: 640 + Actor17: ingrnlmp + Location: 66,-57 + Owner: Neutral + Facing: 640 + Actor18: aban01 Location: 79,41 Owner: Neutral - Health: 100 - Facing: 160 - Actor9: aban13 + Facing: 640 + Actor19: aban13 Location: 84,47 Owner: Neutral - Health: 100 - Facing: 160 - Actor10: aban14 + Facing: 640 + Actor20: aban14 Location: 86,48 Owner: Neutral - Health: 100 - Facing: 160 - Actor11: aban12 + Facing: 640 + Actor21: inblulmp + Location: 76,-17 + Owner: Neutral + Facing: 640 + Actor22: aban12 Location: 82,51 Owner: Neutral - Health: 100 - Facing: 160 - Actor12: tstlamp + Facing: 640 + Actor23: tstlamp Location: 70,53 Owner: Neutral - Health: 100 - Facing: 160 - Actor13: tstlamp + Facing: 640 + Actor24: inblulmp + Location: 86,-15 + Owner: Neutral + Facing: 640 + Actor25: tstlamp Location: 85,49 Owner: Neutral - Health: 100 - Facing: 160 - Actor14: aban05 + Facing: 640 + Actor26: ingrnlmp + Location: 172,26 + Owner: Neutral + Facing: 640 + Actor27: ingrnlmp + Location: 171,44 + Owner: Neutral + Facing: 640 + Actor28: inblulmp + Location: 47,42 + Owner: Neutral + Facing: 640 + Actor29: inblulmp + Location: 53,45 + Owner: Neutral + Facing: 640 + Actor30: inblulmp + Location: 50,36 + Owner: Neutral + Facing: 640 + Actor31: inblulmp + Location: 68,34 + Owner: Neutral + Facing: 640 + Actor32: ingrnlmp + Location: 118,-46 + Owner: Neutral + Facing: 640 + Actor33: inblulmp + Location: 68,26 + Owner: Neutral + Facing: 640 + Actor34: inblulmp + Location: 92,-91 + Owner: Neutral + Facing: 640 + Actor35: inblulmp + Location: 104,-86 + Owner: Neutral + Facing: 640 + Actor36: ingrnlmp + Location: 124,47 + Owner: Neutral + Facing: 640 + Actor37: aban05 Location: 156,-63 Owner: Neutral - Health: 100 - Facing: 160 - Actor15: aban06 + Facing: 640 + Actor38: aban06 Location: 152,-60 Owner: Neutral - Health: 100 - Facing: 160 - Actor16: aban07 + Facing: 640 + Actor39: ingrnlmp + Location: 39,-22 + Owner: Neutral + Facing: 640 + Actor40: ingrnlmp + Location: 29,13 + Owner: Neutral + Facing: 640 + Actor41: ingrnlmp + Location: 29,20 + Owner: Neutral + Facing: 640 + Actor42: inblulmp + Location: 54,-42 + Owner: Neutral + Facing: 640 + Actor43: inblulmp + Location: 56,-34 + Owner: Neutral + Facing: 640 + Actor44: inblulmp + Location: 57,-28 + Owner: Neutral + Facing: 640 + Actor45: inblulmp + Location: 59,-19 + Owner: Neutral + Facing: 640 + Actor46: inblulmp + Location: 67,-17 + Owner: Neutral + Facing: 640 + Actor47: inblulmp + Location: 65,-9 + Owner: Neutral + Facing: 640 + Actor48: inblulmp + Location: 67,0 + Owner: Neutral + Facing: 640 + Actor49: aban07 Location: 147,-71 Owner: Neutral - Health: 100 - Facing: 160 - Actor17: aban12 + Facing: 640 + Actor50: inblulmp + Location: 68,18 + Owner: Neutral + Facing: 640 + Actor51: ingrnlmp + Location: 72,-49 + Owner: Neutral + Facing: 640 + Actor52: ingrnlmp + Location: 91,-71 + Owner: Neutral + Facing: 640 + Actor53: ingrnlmp + Location: 59,15 + Owner: Neutral + Facing: 640 + Actor54: aban12 Location: 147,-68 Owner: Neutral - Health: 100 - Facing: 160 - Actor18: aban15 + Facing: 640 + Actor55: aban15 Location: 160,-62 Owner: Neutral - Health: 100 - Facing: 160 - Actor19: aban13 + Facing: 640 + Actor56: aban13 Location: 162,-62 Owner: Neutral - Health: 100 - Facing: 160 - Actor20: aban09 + Facing: 640 + Actor57: aban09 Location: 151,-68 Owner: Neutral - Health: 100 - Facing: 160 - Actor21: aban10 + Facing: 640 + Actor58: aban10 Location: 151,-64 Owner: Neutral - Health: 100 - Facing: 160 - Actor22: aban11 + Facing: 640 + Actor59: aban11 Location: 147,-74 Owner: Neutral - Health: 100 - Facing: 160 - Actor23: aban01 + Facing: 640 + Actor60: inblulmp + Location: 136,-98 + Owner: Neutral + Facing: 640 + Actor61: inblulmp + Location: 138,-90 + Owner: Neutral + Facing: 640 + Actor62: inblulmp + Location: 138,-80 + Owner: Neutral + Facing: 640 + Actor63: ingrnlmp + Location: 146,-47 + Owner: Neutral + Facing: 640 + Actor64: ingrnlmp + Location: 189,-41 + Owner: Neutral + Facing: 640 + Actor65: ingrnlmp + Location: 173,51 + Owner: Neutral + Facing: 640 + Actor66: inblulmp + Location: 115,-84 + Owner: Neutral + Facing: 640 + Actor67: aban01 Location: 116,-5 Owner: Neutral - Health: 100 - Facing: 160 - Actor24: aban02 + Facing: 640 + Actor68: aban02 Location: 123,-2 Owner: Neutral - Health: 100 - Facing: 160 - Actor25: aban05 + Facing: 640 + Actor69: aban05 Location: 114,2 Owner: Neutral - Health: 100 - Facing: 160 - Actor26: aban06 + Facing: 640 + Actor70: aban06 Location: 121,-13 Owner: Neutral - Health: 100 - Facing: 160 - Actor27: aban07 + Facing: 640 + Actor71: aban07 Location: 120,2 Owner: Neutral - Health: 100 - Facing: 160 - Actor28: aban09 + Facing: 640 + Actor72: aban09 Location: 115,-10 Owner: Neutral - Health: 100 - Facing: 160 - Actor29: aban11 + Facing: 640 + Actor73: aban11 Location: 124,3 Owner: Neutral - Health: 100 - Facing: 160 - Actor30: aban12 + Facing: 640 + Actor74: aban12 Location: 120,-5 Owner: Neutral - Health: 100 - Facing: 160 - Actor31: aban10 + Facing: 640 + Actor75: aban10 Location: 120,-9 Owner: Neutral - Health: 100 - Facing: 160 - Actor32: tstlamp + Facing: 640 + Actor76: tstlamp Location: 118,-2 Owner: Neutral - Health: 100 - Facing: 160 - Actor33: tstlamp + Facing: 640 + Actor77: tstlamp Location: 123,-9 Owner: Neutral - Health: 100 - Facing: 160 - Actor34: tstlamp + Facing: 640 + Actor78: tstlamp Location: 113,-9 Owner: Neutral - Health: 100 - Facing: 160 - Actor35: tstlamp + Facing: 640 + Actor79: tstlamp Location: 126,1 Owner: Neutral - Health: 100 - Facing: 160 - Actor36: tstlamp + Facing: 640 + Actor80: tstlamp Location: 116,6 Owner: Neutral - Health: 100 - Facing: 160 - Actor37: tstlamp + Facing: 640 + Actor81: inblulmp + Location: 223,-7 + Owner: Neutral + Facing: 640 + Actor82: inblulmp + Location: 214,-4 + Owner: Neutral + Facing: 640 + Actor83: inblulmp + Location: 219,8 + Owner: Neutral + Facing: 640 + Actor84: inblulmp + Location: 215,12 + Owner: Neutral + Facing: 640 + Actor85: inblulmp + Location: 204,13 + Owner: Neutral + Facing: 640 + Actor86: inblulmp + Location: 198,14 + Owner: Neutral + Facing: 640 + Actor87: inblulmp + Location: 191,14 + Owner: Neutral + Facing: 640 + Actor88: ingrnlmp + Location: 153,2 + Owner: Neutral + Facing: 640 + Actor89: ingrnlmp + Location: 176,-16 + Owner: Neutral + Facing: 640 + Actor90: tstlamp Location: 148,-64 Owner: Neutral - Health: 100 - Facing: 160 - Actor38: tstlamp + Facing: 640 + Actor91: tstlamp Location: 150,-73 Owner: Neutral - Health: 100 - Facing: 160 - Actor39: tstlamp + Facing: 640 + Actor92: tstlamp Location: 158,-59 Owner: Neutral - Health: 100 - Facing: 160 - Actor40: tree05 + Facing: 640 + Actor93: tree05 Location: 124,-105 Owner: Neutral - Actor41: tree15 + Actor94: tree15 Location: 121,-104 Owner: Neutral - Actor42: tree06 + Actor95: tree06 Location: 126,-104 Owner: Neutral - Actor43: tree08 + Actor96: tree08 Location: 124,-103 Owner: Neutral - Actor44: tree12 + Actor97: tree12 Location: 125,-103 Owner: Neutral - Actor45: tree18 + Actor98: tree18 Location: 117,-102 Owner: Neutral - Actor46: tree09 + Actor99: tree09 Location: 120,-102 Owner: Neutral - Actor47: tree08 + Actor100: tree08 Location: 123,-102 Owner: Neutral - Actor48: tree05 + Actor101: tree05 Location: 118,-101 Owner: Neutral - Actor49: tree02 + Actor102: tree02 Location: 117,-100 Owner: Neutral - Actor50: tree01 + Actor103: tree01 Location: 119,-99 Owner: Neutral - Actor51: tree16 + Actor104: tree16 Location: 122,-99 Owner: Neutral - Actor52: tree06 + Actor105: tree06 Location: 119,-94 Owner: Neutral - Actor53: tree04 + Actor106: tree04 Location: 126,-94 Owner: Neutral - Actor54: tree06 + Actor107: tree06 Location: 104,-93 Owner: Neutral - Actor55: tree19 + Actor108: tree19 Location: 107,-93 Owner: Neutral - Actor56: tree05 + Actor109: tree05 Location: 121,-93 Owner: Neutral - Actor57: tree05 + Actor110: tree05 Location: 111,-91 Owner: Neutral - Actor58: tree05 + Actor111: tree05 Location: 107,-90 Owner: Neutral - Actor59: tree16 + Actor112: tree16 Location: 109,-90 Owner: Neutral - Actor60: tree12 + Actor113: tree12 Location: 113,-88 Owner: Neutral - Actor61: tree14 + Actor114: tree14 Location: 128,-88 Owner: Neutral - Actor62: tree05 + Actor115: tree05 Location: 111,-87 Owner: Neutral - Actor63: tree05 + Actor116: tree05 Location: 118,-85 Owner: Neutral - Actor64: tree02 + Actor117: tree02 Location: 101,-84 Owner: Neutral - Actor65: tree04 + Actor118: tree04 Location: 99,-83 Owner: Neutral - Actor66: tree16 + Actor119: tree16 Location: 100,-83 Owner: Neutral - Actor67: tree16 + Actor120: tree16 Location: 116,-83 Owner: Neutral - Actor68: tree02 + Actor121: tree02 Location: 117,-83 Owner: Neutral - Actor69: tree01 + Actor122: tree01 Location: 101,-82 Owner: Neutral - Actor70: tree03 + Actor123: tree03 Location: 105,-81 Owner: Neutral - Actor71: tree01 + Actor124: tree01 Location: 117,-81 Owner: Neutral - Actor72: tree05 + Actor125: tree05 Location: 111,-80 Owner: Neutral - Actor73: tree02 + Actor126: tree02 Location: 112,-80 Owner: Neutral - Actor74: tree05 + Actor127: tree05 Location: 104,-79 Owner: Neutral - Actor75: tree08 + Actor128: tree08 Location: 113,-77 Owner: Neutral - Actor76: tree03 + Actor129: tree03 Location: 114,-77 Owner: Neutral - Actor77: tree12 + Actor130: tree12 Location: 116,-77 Owner: Neutral - Actor78: tree02 + Actor131: tree02 Location: 125,-77 Owner: Neutral - Actor79: tree05 + Actor132: tree05 Location: 146,-76 Owner: Neutral - Actor80: tree01 + Actor133: tree01 Location: 123,-75 Owner: Neutral - Actor81: tree16 + Actor134: tree16 Location: 111,-73 Owner: Neutral - Actor82: tree04 + Actor135: tree04 Location: 146,-73 Owner: Neutral - Actor83: tree11 + Actor136: tree11 Location: 160,-73 Owner: Neutral - Actor84: tree02 + Actor137: tree02 Location: 160,-72 Owner: Neutral - Actor85: tree03 + Actor138: tree03 Location: 142,-71 Owner: Neutral - Actor86: tree09 + Actor139: tree09 Location: 159,-71 Owner: Neutral - Actor87: tree12 + Actor140: tree12 Location: 160,-71 Owner: Neutral - Actor88: tibtre02 + Actor141: tibtre02 Location: 90,-70 Owner: Neutral - Actor89: tree02 + Actor142: tree02 Location: 138,-70 Owner: Neutral - Actor90: tree13 + Actor143: tree13 Location: 139,-70 Owner: Neutral - Actor91: tree02 + Actor144: tree02 Location: 151,-70 Owner: Neutral - Actor92: tree04 + Actor145: tree04 Location: 143,-69 Owner: Neutral - Actor93: tree03 + Actor146: tree03 Location: 153,-69 Owner: Neutral - Actor94: tree03 + Actor147: tree03 Location: 163,-69 Owner: Neutral - Actor95: tree06 + Actor148: tree06 Location: 82,-68 Owner: Neutral - Actor96: tree11 + Actor149: tree11 Location: 162,-68 Owner: Neutral - Actor97: tree02 + Actor150: tree02 Location: 164,-68 Owner: Neutral - Actor98: tree12 + Actor151: tree12 Location: 81,-66 Owner: Neutral - Actor99: tree12 + Actor152: tree12 Location: 159,-66 Owner: Neutral - Actor100: tree01 + Actor153: tree01 Location: 160,-66 Owner: Neutral - Actor101: tree01 + Actor154: tree01 Location: 153,-65 Owner: Neutral - Actor102: tree01 + Actor155: tree01 Location: 170,-63 Owner: Neutral - Actor103: tree02 + Actor156: tree02 Location: 81,-62 Owner: Neutral - Actor104: tree06 + Actor157: tree06 Location: 151,-62 Owner: Neutral - Actor105: tree11 + Actor158: tree11 Location: 154,-62 Owner: Neutral - Actor106: tree06 + Actor159: tree06 Location: 171,-62 Owner: Neutral - Actor107: tree03 + Actor160: tree03 Location: 78,-61 Owner: Neutral - Actor108: tree04 + Actor161: tree04 Location: 79,-61 Owner: Neutral - Actor109: tree02 + Actor162: tree02 Location: 171,-61 Owner: Neutral - Actor110: tibtre03 + Actor163: tibtre03 Location: 69,-56 Owner: Neutral - Actor111: tree13 + Actor164: tree13 Location: 147,-56 Owner: Neutral - Actor112: tree09 + Actor165: tree09 Location: 143,-55 Owner: Neutral - Actor113: tree03 + Actor166: tree03 Location: 144,-55 Owner: Neutral - Actor114: tree06 + Actor167: tree06 Location: 136,-54 Owner: Neutral - Actor115: tree05 + Actor168: tree05 Location: 139,-54 Owner: Neutral - Actor116: tree06 + Actor169: tree06 Location: 145,-54 Owner: Neutral - Actor117: tree02 + Actor170: tree02 Location: 156,-54 Owner: Neutral - Actor118: tree11 + Actor171: tree11 Location: 144,-53 Owner: Neutral - Actor119: tree04 + Actor172: tree04 Location: 150,-53 Owner: Neutral - Actor120: tree15 + Actor173: tree15 Location: 158,-53 Owner: Neutral - Actor121: tree02 + Actor174: tree02 Location: 139,-52 Owner: Neutral - Actor122: tibtre02 + Actor175: tibtre02 Location: 71,-48 Owner: Neutral - Actor123: tibtre03 + Actor176: tibtre03 Location: 117,-47 Owner: Neutral - Actor124: tibtre01 + Actor177: tibtre01 Location: 145,-47 Owner: Neutral - Actor125: tree06 + Actor178: tree06 Location: 133,-46 Owner: Neutral - Actor126: tree06 + Actor179: tree06 Location: 59,-45 Owner: Neutral - Actor127: tree04 + Actor180: tree04 Location: 136,-45 Owner: Neutral - Actor128: tree05 + Actor181: tree05 Location: 92,-44 Owner: Neutral - Actor129: tree12 + Actor182: tree12 Location: 134,-44 Owner: Neutral - Actor130: tree02 + Actor183: tree02 Location: 129,-43 Owner: Neutral - Actor131: tree05 + Actor184: tree05 Location: 133,-43 Owner: Neutral - Actor132: tree06 + Actor185: tree06 Location: 91,-42 Owner: Neutral - Actor133: tree04 + Actor186: tree04 Location: 94,-42 Owner: Neutral - Actor134: tree01 + Actor187: tree01 Location: 63,-41 Owner: Neutral - Actor135: tree13 + Actor188: tree13 Location: 130,-41 Owner: Neutral - Actor136: tibtre03 + Actor189: tibtre03 Location: 188,-41 Owner: Neutral - Actor137: tree09 + Actor190: tree09 Location: 143,-39 Owner: Neutral - Actor138: tree05 + Actor191: tree05 Location: 127,-38 Owner: Neutral - Actor139: tree10 + Actor192: tree10 Location: 129,-38 Owner: Neutral - Actor140: tree16 + Actor193: tree16 Location: 144,-37 Owner: Neutral - Actor141: tree05 + Actor194: tree05 Location: 154,-37 Owner: Neutral - Actor142: tree08 + Actor195: tree08 Location: 156,-37 Owner: Neutral - Actor143: tree02 + Actor196: tree02 Location: 143,-36 Owner: Neutral - Actor144: tree04 + Actor197: tree04 Location: 145,-36 Owner: Neutral - Actor145: tree08 + Actor198: tree08 Location: 64,-35 Owner: Neutral - Actor146: tree06 + Actor199: tree06 Location: 65,-35 Owner: Neutral - Actor147: tree12 + Actor200: tree12 Location: 65,-34 Owner: Neutral - Actor148: tree01 + Actor201: tree01 Location: 72,-34 Owner: Neutral - Actor149: tree02 + Actor202: tree02 Location: 74,-34 Owner: Neutral - Actor150: tree14 + Actor203: tree14 Location: 141,-34 Owner: Neutral - Actor151: tree05 + Actor204: tree05 Location: 144,-34 Owner: Neutral - Actor152: tree10 + Actor205: tree10 Location: 145,-34 Owner: Neutral - Actor153: tree09 + Actor206: tree09 Location: 62,-32 Owner: Neutral - Actor154: tree19 + Actor207: tree19 Location: 72,-32 Owner: Neutral - Actor155: tree16 + Actor208: tree16 Location: 73,-32 Owner: Neutral - Actor156: tree02 + Actor209: tree02 Location: 119,-32 Owner: Neutral - Actor157: tree02 + Actor210: tree02 Location: 64,-31 Owner: Neutral - Actor158: tree03 + Actor211: tree03 Location: 63,-30 Owner: Neutral - Actor159: tree04 + Actor212: tree04 Location: 73,-30 Owner: Neutral - Actor160: tree06 + Actor213: tree06 Location: 113,-30 Owner: Neutral - Actor161: tree05 + Actor214: tree05 Location: 64,-29 Owner: Neutral - Actor162: tree12 + Actor215: tree12 Location: 72,-29 Owner: Neutral - Actor163: tree24 + Actor216: tree24 Location: 65,-27 Owner: Neutral - Actor164: tree16 + Actor217: tree16 Location: 71,-26 Owner: Neutral - Actor165: tree22 + Actor218: tree22 Location: 73,-26 Owner: Neutral - Actor166: tree04 + Actor219: tree04 Location: 75,-25 Owner: Neutral - Actor167: tree02 + Actor220: tree02 Location: 65,-24 Owner: Neutral - Actor168: tree02 + Actor221: tree02 Location: 73,-24 Owner: Neutral - Actor169: tree06 + Actor222: tree06 Location: 74,-24 Owner: Neutral - Actor170: tree08 + Actor223: tree08 Location: 63,-23 Owner: Neutral - Actor171: tree17 + Actor224: tree17 Location: 78,-23 Owner: Neutral - Actor172: tree03 + Actor225: tree03 Location: 101,-23 Owner: Neutral - Actor173: tibtre02 + Actor226: tibtre02 Location: 39,-22 Owner: Neutral - Actor174: tree04 + Actor227: tree04 Location: 65,-22 Owner: Neutral - Actor175: tree03 + Actor228: tree03 Location: 67,-22 Owner: Neutral - Actor176: tree11 + Actor229: tree11 Location: 94,-22 Owner: Neutral - Actor177: tree02 + Actor230: tree02 Location: 209,-22 Owner: Neutral - Actor178: tree09 + Actor231: tree09 Location: 81,-21 Owner: Neutral - Actor179: tree04 + Actor232: tree04 Location: 101,-21 Owner: Neutral - Actor180: tree09 + Actor233: tree09 Location: 81,-20 Owner: Neutral - Actor181: tree02 + Actor234: tree02 Location: 82,-20 Owner: Neutral - Actor182: tree05 + Actor235: tree05 Location: 104,-20 Owner: Neutral - Actor183: tree17 + Actor236: tree17 Location: 95,-19 Owner: Neutral - Actor184: tree06 + Actor237: tree06 Location: 97,-19 Owner: Neutral - Actor185: tree16 + Actor238: tree16 Location: 168,-19 Owner: Neutral - Actor186: tree05 + Actor239: tree05 Location: 137,-18 Owner: Neutral - Actor187: tree13 + Actor240: tree13 Location: 116,-17 Owner: Neutral - Actor188: tree09 + Actor241: tree09 Location: 204,-17 Owner: Neutral - Actor189: tree20 + Actor242: tree20 Location: 207,-17 Owner: Neutral - Actor190: tree20 + Actor243: tree20 Location: 137,-16 Owner: Neutral - Actor191: tibtre02 + Actor244: tibtre02 Location: 176,-16 Owner: Neutral - Actor192: tree02 + Actor245: tree02 Location: 115,-15 Owner: Neutral - Actor193: tree08 + Actor246: tree08 Location: 117,-15 Owner: Neutral - Actor194: tree11 + Actor247: tree11 Location: 206,-15 Owner: Neutral - Actor195: tree03 + Actor248: tree03 Location: 208,-15 Owner: Neutral - Actor196: tree10 + Actor249: tree10 Location: 210,-15 Owner: Neutral - Actor197: tree12 + Actor250: tree12 Location: 207,-14 Owner: Neutral - Actor198: tree11 + Actor251: tree11 Location: 67,-13 Owner: Neutral - Actor199: tree05 + Actor252: tree05 Location: 92,-13 Owner: Neutral - Actor200: tree01 + Actor253: tree01 Location: 115,-13 Owner: Neutral - Actor201: tree02 + Actor254: tree02 Location: 58,-12 Owner: Neutral - Actor202: tree06 + Actor255: tree06 Location: 59,-12 Owner: Neutral - Actor203: tree02 + Actor256: tree02 Location: 128,-12 Owner: Neutral - Actor204: tree15 + Actor257: tree15 Location: 201,-12 Owner: Neutral - Actor205: tree03 + Actor258: tree03 Location: 128,-11 Owner: Neutral - Actor206: tree05 + Actor259: tree05 Location: 206,-11 Owner: Neutral - Actor207: tree01 + Actor260: tree01 Location: 61,-10 Owner: Neutral - Actor208: tree11 + Actor261: tree11 Location: 92,-10 Owner: Neutral - Actor209: tree02 + Actor262: tree02 Location: 95,-10 Owner: Neutral - Actor210: tree11 + Actor263: tree11 Location: 199,-10 Owner: Neutral - Actor211: tree06 + Actor264: tree06 Location: 201,-10 Owner: Neutral - Actor212: tree08 + Actor265: tree08 Location: 41,-9 Owner: Neutral - Actor213: tree05 + Actor266: tree05 Location: 60,-9 Owner: Neutral - Actor214: tree04 + Actor267: tree04 Location: 75,-9 Owner: Neutral - Actor215: tree06 + Actor268: tree06 Location: 207,-9 Owner: Neutral - Actor216: tree02 + Actor269: tree02 Location: 208,-9 Owner: Neutral - Actor217: tree17 + Actor270: tree17 Location: 210,-9 Owner: Neutral - Actor218: tree02 + Actor271: tree02 Location: 40,-8 Owner: Neutral - Actor219: tree04 + Actor272: tree04 Location: 43,-8 Owner: Neutral - Actor220: tree15 + Actor273: tree15 Location: 78,-8 Owner: Neutral - Actor221: tree06 + Actor274: tree06 Location: 80,-8 Owner: Neutral - Actor222: tree08 + Actor275: tree08 Location: 206,-8 Owner: Neutral - Actor223: tree10 + Actor276: tree10 Location: 70,-7 Owner: Neutral - Actor224: tree15 + Actor277: tree15 Location: 126,-7 Owner: Neutral - Actor225: tree22 + Actor278: tree22 Location: 207,-7 Owner: Neutral - Actor226: tree05 + Actor279: tree05 Location: 43,-6 Owner: Neutral - Actor227: tree04 + Actor280: tree04 Location: 27,-5 Owner: Neutral - Actor228: tree08 + Actor281: tree08 Location: 70,-5 Owner: Neutral - Actor229: tree04 + Actor282: tree04 Location: 79,-5 Owner: Neutral - Actor230: tree01 + Actor283: tree01 Location: 127,-5 Owner: Neutral - Actor231: tree20 + Actor284: tree20 Location: 22,-4 Owner: Neutral - Actor232: tree02 + Actor285: tree02 Location: 30,-4 Owner: Neutral - Actor233: tree02 + Actor286: tree02 Location: 69,-4 Owner: Neutral - Actor234: tree05 + Actor287: tree05 Location: 71,-2 Owner: Neutral - Actor235: nawall + Actor288: nawall Location: 37,-1 Owner: Neutral - Actor236: tree16 + Actor289: tree16 Location: 170,-1 Owner: Neutral - Actor237: tree02 + Actor290: tree02 Location: 172,-1 Owner: Neutral - Actor238: tree05 + Actor291: tree05 Location: 15,0 Owner: Neutral - Actor239: tree06 + Actor292: tree06 Location: 169,0 Owner: Neutral - Actor240: tree04 + Actor293: tree04 Location: 13,1 Owner: Neutral - Actor241: tree18 + Actor294: tree18 Location: 25,1 Owner: Neutral - Actor242: tree21 + Actor295: tree21 Location: 63,1 Owner: Neutral - Actor243: tibtre02 + Actor296: tibtre02 Location: 152,1 Owner: Neutral - Actor244: tree08 + Actor297: tree08 Location: 15,2 Owner: Neutral - Actor245: tree23 + Actor298: tree23 Location: 62,2 Owner: Neutral - Actor246: tree02 + Actor299: tree02 Location: 18,3 Owner: Neutral - Actor247: tree04 + Actor300: tree04 Location: 58,3 Owner: Neutral - Actor248: tree14 + Actor301: tree14 Location: 177,3 Owner: Neutral - Actor249: tree12 + Actor302: tree12 Location: 185,3 Owner: Neutral - Actor250: tree11 + Actor303: tree11 Location: 10,4 Owner: Neutral - Actor251: tree25 + Actor304: tree25 Location: 64,4 Owner: Neutral - Actor252: tree05 + Actor305: tree05 Location: 179,4 Owner: Neutral - Actor253: tree03 + Actor306: tree03 Location: 15,5 Owner: Neutral - Actor254: tree19 + Actor307: tree19 Location: 53,5 Owner: Neutral - Actor255: tree05 + Actor308: tree05 Location: 59,5 Owner: Neutral - Actor256: tree05 + Actor309: tree05 Location: 16,6 Owner: Neutral - Actor257: tree02 + Actor310: tree02 Location: 109,6 Owner: Neutral - Actor258: tree05 + Actor311: tree05 Location: 53,7 Owner: Neutral - Actor259: tree11 + Actor312: tree11 Location: 112,7 Owner: Neutral - Actor260: tree08 + Actor313: tree08 Location: 123,7 Owner: Neutral - Actor261: tree10 + Actor314: tree10 Location: 15,8 Owner: Neutral - Actor262: tree24 + Actor315: tree24 Location: 27,8 Owner: Neutral - Actor263: tree16 + Actor316: tree16 Location: 110,8 Owner: Neutral - Actor264: tree08 + Actor317: tree08 Location: 112,8 Owner: Neutral - Actor265: tree12 + Actor318: tree12 Location: 16,9 Owner: Neutral - Actor266: tree13 + Actor319: tree13 Location: 124,9 Owner: Neutral - Actor267: tree06 + Actor320: tree06 Location: 55,10 Owner: Neutral - Actor268: tree05 + Actor321: tree05 Location: 112,10 Owner: Neutral - Actor269: tree14 + Actor322: tree14 Location: 134,10 Owner: Neutral - Actor270: tibtre02 + Actor323: tibtre02 Location: 28,11 Owner: Neutral - Actor271: tree11 + Actor324: tree11 Location: 124,11 Owner: Neutral - Actor272: tree16 + Actor325: tree16 Location: 126,11 Owner: Neutral - Actor273: tree03 + Actor326: tree03 Location: 128,11 Owner: Neutral - Actor274: tree02 + Actor327: tree02 Location: 19,12 Owner: Neutral - Actor275: tree08 + Actor328: tree08 Location: 124,12 Owner: Neutral - Actor276: tree02 + Actor329: tree02 Location: 126,12 Owner: Neutral - Actor277: tree06 + Actor330: tree06 Location: 133,12 Owner: Neutral - Actor278: tree17 + Actor331: tree17 Location: 51,13 Owner: Neutral - Actor279: tree18 + Actor332: tree18 Location: 139,13 Owner: Neutral - Actor280: tree10 + Actor333: tree10 Location: 23,14 Owner: Neutral - Actor281: tree05 + Actor334: tree05 Location: 141,14 Owner: Neutral - Actor282: tibtre02 + Actor335: tibtre02 Location: 59,15 Owner: Neutral - Actor283: tree12 + Actor336: tree12 Location: 24,16 Owner: Neutral - Actor284: tree05 + Actor337: tree05 Location: 53,16 Owner: Neutral - Actor285: tree04 + Actor338: tree04 Location: 52,17 Owner: Neutral - Actor286: tree06 + Actor339: tree06 Location: 49,19 Owner: Neutral - Actor287: tree08 + Actor340: tree08 Location: 52,19 Owner: Neutral - Actor288: tree17 + Actor341: tree17 Location: 212,19 Owner: Neutral - Actor289: tree06 + Actor342: tree06 Location: 37,20 Owner: Neutral - Actor290: tree03 + Actor343: tree03 Location: 49,20 Owner: Neutral - Actor291: tree05 + Actor344: tree05 Location: 51,20 Owner: Neutral - Actor292: tree04 + Actor345: tree04 Location: 53,20 Owner: Neutral - Actor293: tree18 + Actor346: tree18 Location: 152,20 Owner: Neutral - Actor294: tibtre03 + Actor347: tibtre03 Location: 29,21 Owner: Neutral - Actor295: tree09 + Actor348: tree09 Location: 36,21 Owner: Neutral - Actor296: tree05 + Actor349: tree05 Location: 51,21 Owner: Neutral - Actor297: tree12 + Actor350: tree12 Location: 85,21 Owner: Neutral - Actor298: tree03 + Actor351: tree03 Location: 154,21 Owner: Neutral - Actor299: tree11 + Actor352: tree11 Location: 200,21 Owner: Neutral - Actor300: tree03 + Actor353: tree03 Location: 35,22 Owner: Neutral - Actor301: tree12 + Actor354: tree12 Location: 36,22 Owner: Neutral - Actor302: tree05 + Actor355: tree05 Location: 38,22 Owner: Neutral - Actor303: tree06 + Actor356: tree06 Location: 88,22 Owner: Neutral - Actor304: tree04 + Actor357: tree04 Location: 151,22 Owner: Neutral - Actor305: tree06 + Actor358: tree06 Location: 94,23 Owner: Neutral - Actor306: tree10 + Actor359: tree10 Location: 128,23 Owner: Neutral - Actor307: tree16 + Actor360: tree16 Location: 130,23 Owner: Neutral - Actor308: tree05 + Actor361: tree05 Location: 202,23 Owner: Neutral - Actor309: tree16 + Actor362: tree16 Location: 91,24 Owner: Neutral - Actor310: tree02 + Actor363: tree02 Location: 133,24 Owner: Neutral - Actor311: tree02 + Actor364: tree02 Location: 90,25 Owner: Neutral - Actor312: tree03 + Actor365: tree03 Location: 132,25 Owner: Neutral - Actor313: tree14 + Actor366: tree14 Location: 134,25 Owner: Neutral - Actor314: tree14 + Actor367: tree14 Location: 38,26 Owner: Neutral - Actor315: tree04 + Actor368: tree04 Location: 130,26 Owner: Neutral - Actor316: tree10 + Actor369: tree10 Location: 133,26 Owner: Neutral - Actor317: tibtre02 + Actor370: tibtre02 Location: 172,27 Owner: Neutral - Actor318: tree05 + Actor371: tree05 Location: 33,28 Owner: Neutral - Actor319: tree15 + Actor372: tree15 Location: 39,28 Owner: Neutral - Actor320: tree08 + Actor373: tree08 Location: 43,32 Owner: Neutral - Actor321: tree11 + Actor374: tree11 Location: 44,32 Owner: Neutral - Actor322: tree04 + Actor375: tree04 Location: 43,33 Owner: Neutral - Actor323: tree16 + Actor376: tree16 Location: 133,36 Owner: Neutral - Actor324: tree05 + Actor377: tree05 Location: 131,37 Owner: Neutral - Actor325: tree02 + Actor378: tree02 Location: 133,37 Owner: Neutral - Actor326: tree06 + Actor379: tree06 Location: 135,37 Owner: Neutral - Actor327: tree01 + Actor380: tree01 Location: 144,38 Owner: Neutral - Actor328: tree05 + Actor381: tree05 Location: 74,39 Owner: Neutral - Actor329: tree01 + Actor382: tree01 Location: 76,39 Owner: Neutral - Actor330: tree02 + Actor383: tree02 Location: 79,39 Owner: Neutral - Actor331: tree06 + Actor384: tree06 Location: 132,39 Owner: Neutral - Actor332: tree04 + Actor385: tree04 Location: 145,39 Owner: Neutral - Actor333: tree14 + Actor386: tree14 Location: 74,41 Owner: Neutral - Actor334: tree10 + Actor387: tree10 Location: 81,41 Owner: Neutral - Actor335: tree02 + Actor388: tree02 Location: 145,41 Owner: Neutral - Actor336: tree06 + Actor389: tree06 Location: 73,42 Owner: Neutral - Actor337: tree14 + Actor390: tree14 Location: 147,42 Owner: Neutral - Actor338: tree05 + Actor391: tree05 Location: 58,43 Owner: Neutral - Actor339: tree11 + Actor392: tree11 Location: 75,43 Owner: Neutral - Actor340: tree04 + Actor393: tree04 Location: 57,44 Owner: Neutral - Actor341: tree15 + Actor394: tree15 Location: 74,44 Owner: Neutral - Actor342: tree05 + Actor395: tree05 Location: 88,44 Owner: Neutral - Actor343: tree10 + Actor396: tree10 Location: 75,45 Owner: Neutral - Actor344: tree16 + Actor397: tree16 Location: 85,45 Owner: Neutral - Actor345: tree05 + Actor398: tree05 Location: 150,45 Owner: Neutral - Actor346: tree03 + Actor399: tree03 Location: 151,45 Owner: Neutral - Actor347: tibtre02 + Actor400: tibtre02 Location: 170,45 Owner: Neutral - Actor348: tree04 + Actor401: tree04 Location: 90,46 Owner: Neutral - Actor349: tibtre03 + Actor402: tibtre03 Location: 123,46 Owner: Neutral - Actor350: tree06 + Actor403: tree06 Location: 76,47 Owner: Neutral - Actor351: tree21 + Actor404: tree21 Location: 87,47 Owner: Neutral - Actor352: tree09 + Actor405: tree09 Location: 88,48 Owner: Neutral - Actor353: tree06 + Actor406: tree06 Location: 60,49 Owner: Neutral - Actor354: tree13 + Actor407: tree13 Location: 67,49 Owner: Neutral - Actor355: tree03 + Actor408: tree03 Location: 70,49 Owner: Neutral - Actor356: tree02 + Actor409: tree02 Location: 59,50 Owner: Neutral - Actor357: tree09 + Actor410: tree09 Location: 63,50 Owner: Neutral - Actor358: tree09 + Actor411: tree09 Location: 71,50 Owner: Neutral - Actor359: tree11 + Actor412: tree11 Location: 90,50 Owner: Neutral - Actor360: tree04 + Actor413: tree04 Location: 99,50 Owner: Neutral - Actor361: tibtre01 + Actor414: tibtre01 Location: 171,50 Owner: Neutral - Actor362: tree09 + Actor415: tree09 Location: 57,51 Owner: Neutral - Actor363: tree04 + Actor416: tree04 Location: 65,51 Owner: Neutral - Actor364: tree01 + Actor417: tree01 Location: 67,51 Owner: Neutral - Actor365: tree10 + Actor418: tree10 Location: 80,51 Owner: Neutral - Actor366: tree08 + Actor419: tree08 Location: 98,51 Owner: Neutral - Actor367: tree16 + Actor420: tree16 Location: 136,51 Owner: Neutral - Actor368: tree02 + Actor421: tree02 Location: 80,53 Owner: Neutral - Actor369: tree16 + Actor422: tree16 Location: 108,53 Owner: Neutral - Actor370: tree02 + Actor423: tree02 Location: 136,53 Owner: Neutral - Actor371: tree02 + Actor424: tree02 Location: 137,53 Owner: Neutral - Actor372: tree10 + Actor425: tree10 Location: 138,53 Owner: Neutral - Actor373: tree06 + Actor426: tree06 Location: 83,54 Owner: Neutral - Actor374: tree08 + Actor427: tree08 Location: 138,54 Owner: Neutral - Actor375: tree11 + Actor428: tree11 Location: 85,55 Owner: Neutral - Actor376: tree04 + Actor429: tree04 Location: 137,55 Owner: Neutral - Actor377: tree14 + Actor430: tree14 Location: 138,55 Owner: Neutral - Actor378: tree05 + Actor431: tree05 Location: 72,56 Owner: Neutral - Actor379: tree12 + Actor432: tree12 Location: 74,56 Owner: Neutral - Actor380: tree04 + Actor433: tree04 Location: 84,56 Owner: Neutral - Actor381: tree14 + Actor434: tree14 Location: 60,57 Owner: Neutral - Actor382: tree16 + Actor435: tree16 Location: 62,58 Owner: Neutral - Actor383: tree06 + Actor436: tree06 Location: 74,58 Owner: Neutral - Actor384: tree09 + Actor437: tree09 Location: 74,59 Owner: Neutral - Actor385: tree04 + Actor438: tree04 Location: 114,59 Owner: Neutral - Actor386: tree02 + Actor439: tree02 Location: 115,61 Owner: Neutral - Actor387: tree19 + Actor440: tree19 Location: 66,62 Owner: Neutral - Actor388: tree12 + Actor441: tree12 Location: 68,62 Owner: Neutral - Actor389: tree03 + Actor442: tree03 Location: 114,62 Owner: Neutral - Actor390: tree12 + Actor443: tree12 Location: 116,63 Owner: Neutral - Actor391: tibtre03 + Actor444: tibtre03 Location: 81,68 Owner: Neutral - Actor392: tree06 + Actor445: tree06 Location: 132,68 Owner: Neutral - Actor393: tree04 + Actor446: tree04 Location: 130,69 Owner: Neutral - Actor394: tree02 + Actor447: tree02 Location: 133,70 Owner: Neutral - Actor395: tree12 + Actor448: tree12 Location: 118,73 Owner: Neutral - Actor396: tibtre01 + Actor449: tibtre01 Location: 85,74 Owner: Neutral - Actor397: tree09 + Actor450: tree09 Location: 96,74 Owner: Neutral - Actor398: tree07 + Actor451: tree07 Location: 97,74 Owner: Neutral - Actor399: tree04 + Actor452: tree04 Location: 95,75 Owner: Neutral - Actor400: tree13 + Actor453: tree13 Location: 98,75 Owner: Neutral - Actor401: tree12 + Actor454: tree12 Location: 99,75 Owner: Neutral - Actor402: tree09 + Actor455: tree09 Location: 124,75 Owner: Neutral - Actor403: tree08 + Actor456: tree08 Location: 95,76 Owner: Neutral - Actor404: tree03 + Actor457: tree03 Location: 109,76 Owner: Neutral - Actor405: tree06 + Actor458: tree06 Location: 111,76 Owner: Neutral - Actor406: tree02 + Actor459: tree02 Location: 98,77 Owner: Neutral - Actor407: tree04 + Actor460: tree04 Location: 110,77 Owner: Neutral - Actor408: tree08 + Actor461: tree08 Location: 97,78 Owner: Neutral - Actor409: tree05 + Actor462: tree05 Location: 102,78 Owner: Neutral - Actor410: tree10 + Actor463: tree10 Location: 93,81 Owner: Neutral - Actor411: tree01 + Actor464: tree01 Location: 95,81 Owner: Neutral - Actor412: tree14 + Actor465: tree14 Location: 131,81 Owner: Neutral - Actor413: tree11 + Actor466: tree11 Location: 133,81 Owner: Neutral - Actor414: tree21 + Actor467: tree21 Location: 92,82 Owner: Neutral - Actor415: tree22 + Actor468: tree22 Location: 95,82 Owner: Neutral - Actor416: tree04 + Actor469: tree04 Location: 97,82 Owner: Neutral - Actor417: tree12 + Actor470: tree12 Location: 93,83 Owner: Neutral - Actor418: tree23 + Actor471: tree23 Location: 95,83 Owner: Neutral - Actor419: tree09 + Actor472: tree09 Location: 98,83 Owner: Neutral - Actor420: tree06 + Actor473: tree06 Location: 99,83 Owner: Neutral - Actor421: tree17 + Actor474: tree17 Location: 131,83 Owner: Neutral - Actor422: tree25 + Actor475: tree25 Location: 133,83 Owner: Neutral - Actor423: tree09 + Actor476: tree09 Location: 136,83 Owner: Neutral - Actor424: tree12 + Actor477: tree12 Location: 95,84 Owner: Neutral - Actor425: tree03 + Actor478: tree03 Location: 97,84 Owner: Neutral - Actor426: tree02 + Actor479: tree02 Location: 137,84 Owner: Neutral - Actor427: tree18 + Actor480: tree18 Location: 97,85 Owner: Neutral - Actor428: tree06 + Actor481: tree06 Location: 99,85 Owner: Neutral - Actor429: tree18 + Actor482: tree18 Location: 136,85 Owner: Neutral - Actor430: tree03 + Actor483: tree03 Location: 138,85 Owner: Neutral - Actor431: tibtre02 + Actor484: tibtre02 Location: 108,86 Owner: Neutral - Actor432: tree22 + Actor485: tree22 Location: 139,86 Owner: Neutral - Actor433: tree04 + Actor486: tree04 Location: 125,87 Owner: Neutral - Actor434: tree02 + Actor487: tree02 Location: 129,87 Owner: Neutral - Actor435: tree05 + Actor488: tree05 Location: 137,87 Owner: Neutral - Actor436: tree18 + Actor489: tree18 Location: 124,91 Owner: Neutral - Actor437: tree09 + Actor490: tree09 Location: 125,91 Owner: Neutral - Actor438: tree01 + Actor491: tree01 Location: 127,91 Owner: Neutral - Actor439: tree09 + Actor492: tree09 Location: 129,91 Owner: Neutral - Actor440: tree16 + Actor493: tree16 Location: 126,92 Owner: Neutral - Actor441: tree12 + Actor494: tree12 Location: 128,92 Owner: Neutral - Actor442: tree10 + Actor495: tree10 Location: 113,95 Owner: Neutral - Actor443: tree12 + Actor496: tree12 Location: 112,96 Owner: Neutral - Actor444: tree05 + Actor497: tree05 Location: 105,98 Owner: Neutral - Actor445: tree08 + Actor498: tree08 Location: 105,99 Owner: Neutral - Actor446: tree11 + Actor499: tree11 Location: 111,104 Owner: Neutral - Actor447: tree01 + Actor500: tree01 Location: 115,104 Owner: Neutral - Actor448: tree08 + Actor501: tree08 Location: 116,104 Owner: Neutral - Actor449: tree04 + Actor502: tree04 Location: 117,104 Owner: Neutral - Actor450: tree17 + Actor503: tree17 Location: 116,105 Owner: Neutral - Actor451: tree12 + Actor504: tree12 Location: 119,105 Owner: Neutral - Actor452: tree09 + Actor505: tree09 Location: 120,106 Owner: Neutral - Actor453: tree14 + Actor506: tree14 Location: 115,108 Owner: Neutral - Actor454: tree04 + Actor507: tree04 Location: 114,109 Owner: Neutral - Actor455: tree12 + Actor508: tree12 Location: 116,109 Owner: Neutral - Actor456: mpspawn + Actor509: mpspawn Location: 35,1 Owner: Neutral - Actor457: mpspawn + Actor510: mpspawn Location: 100,63 Owner: Neutral - Actor458: mpspawn + Actor511: mpspawn Location: 96,-53 Owner: Neutral - Actor459: mpspawn + Actor512: mpspawn Location: 170,-41 Owner: Neutral - Actor460: mpspawn + Actor513: mpspawn Location: 158,31 Owner: Neutral - Actor461: srock02 + Actor514: srock02 Location: 60,-52 Owner: Neutral - Actor462: srock04 + Actor515: srock04 Location: 72,-41 Owner: Neutral - Actor463: srock01 + Actor516: srock01 Location: 117,-71 Owner: Neutral - Actor464: srock03 - Location: 159,-48 - Owner: Neutral - Actor465: srock03 + Actor517: srock03 Location: 158,-48 Owner: Neutral - Actor466: trock05 + Actor518: srock03 + Location: 159,-48 + Owner: Neutral + Actor519: trock05 Location: 71,47 Owner: Neutral - Actor467: srock02 + Actor520: srock02 Location: 85,43 Owner: Neutral - Actor468: trock01 + Actor521: trock01 Location: 158,-20 Owner: Neutral - Actor469: trock04 + Actor522: trock04 Location: 209,-21 Owner: Neutral - Actor470: trock02 + Actor523: trock02 Location: 104,97 Owner: Neutral - Actor471: srock01 + Actor524: srock01 Location: 138,68 Owner: Neutral - Actor472: srock03 + Actor525: srock03 Location: 134,73 Owner: Neutral Rules: - World: - GlobalLightingPaletteEffect: - Red: 0.5 - Green: 0.7 - Blue: 0.7 - Ambient: 0.78 + ^BaseWorld: + TerrainLighting: + RedTint: 0.5 + GreenTint: 0.7 + BlueTint: 0.7 + Intensity: 0.78 + HeightStep: 0.018 + INGRNLMP: + TerrainLightSource: + RedTint: 0.01 + BlueTint: 0.01 + GreenTint: 0.3 + Intensity: 0.001 + Range: 6c856 + INBLULMP: + TerrainLightSource: + RedTint: 0.01 + BlueTint: 0.25 + GreenTint: 0.01 + Intensity: 0.003 + Range: 10c960 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/ot11/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/ot11/map.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/rivrrad4/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/rivrrad4/map.png differ diff -Nru openra-20200503/mods/ts/maps/rivrrad4/map.yaml openra-20210321/mods/ts/maps/rivrrad4/map.yaml --- openra-20200503/mods/ts/maps/rivrrad4/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/rivrrad4/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -72,1005 +72,1375 @@ Actor0: cabhut Location: 145,-51 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor1: cabhut Location: 149,-39 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor2: cabhut Location: 110,-64 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor3: cabhut Location: 121,-60 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor4: cabhut Location: 80,-24 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor5: cabhut Location: 84,-10 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor6: cabhut Location: 90,3 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor7: cabhut Location: 107,7 Owner: Neutral - Health: 100 - Facing: 96 - Actor8: tibtre01 + Facing: 896 + Actor8: inblulmp + Location: 193,-4 + Owner: Neutral + Facing: 896 + Actor9: inblulmp + Location: 134,-85 + Owner: Neutral + Facing: 896 + Actor10: inblulmp + Location: 76,-47 + Owner: Neutral + Facing: 896 + Actor11: inblulmp + Location: 29,1 + Owner: Neutral + Facing: 896 + Actor12: inblulmp + Location: 82,59 + Owner: Neutral + Facing: 896 + Actor13: inblulmp + Location: 155,131 + Owner: Neutral + Facing: 896 + Actor14: inblulmp + Location: 213,76 + Owner: Neutral + Facing: 896 + Actor15: inblulmp + Location: 159,26 + Owner: Neutral + Facing: 896 + Actor16: ingrnlmp + Location: 128,-47 + Owner: Neutral + Facing: 896 + Actor17: ingrnlmp + Location: 154,-64 + Owner: Neutral + Facing: 896 + Actor18: ingrnlmp + Location: 105,-76 + Owner: Neutral + Facing: 896 + Actor19: ingrnlmp + Location: 102,-28 + Owner: Neutral + Facing: 896 + Actor20: ingrnlmp + Location: 136,-19 + Owner: Neutral + Facing: 896 + Actor21: ingrnlmp + Location: 163,-11 + Owner: Neutral + Facing: 896 + Actor22: ingrnlmp + Location: 72,-12 + Owner: Neutral + Facing: 896 + Actor23: ingrnlmp + Location: 72,10 + Owner: Neutral + Facing: 896 + Actor24: ingrnlmp Location: 96,23 Owner: Neutral - Actor9: tibtre02 + Facing: 896 + Actor25: ingrnlmp Location: 118,67 Owner: Neutral - Actor10: tibtre02 + Facing: 896 + Actor26: ingrnlmp + Location: 163,99 + Owner: Neutral + Facing: 896 + Actor27: ingrnlmp + Location: 189,93 + Owner: Neutral + Facing: 896 + Actor28: ingrnlmp + Location: 198,53 + Owner: Neutral + Facing: 896 + Actor29: ingrnlmp + Location: 227,47 + Owner: Neutral + Facing: 896 + Actor30: ingrnlmp + Location: 242,26 + Owner: Neutral + Facing: 896 + Actor31: ingrnlmp + Location: 183,-33 + Owner: Neutral + Facing: 896 + Actor32: jfish + Location: 139,90 + Owner: Creeps + Facing: 896 + Actor33: jfish + Location: 154,61 + Owner: Creeps + Facing: 896 + Actor34: jfish + Location: 184,34 + Owner: Creeps + Facing: 896 + Actor35: jfish + Location: 204,25 + Owner: Creeps + Facing: 896 + Actor36: bigblue3 + Location: 82,59 + Owner: Neutral + Actor37: bigblue3 + Location: 155,131 + Owner: Neutral + Actor38: bigblue3 + Location: 213,76 + Owner: Neutral + Actor39: bigblue3 + Location: 193,-4 + Owner: Neutral + Actor40: bigblue3 + Location: 159,26 + Owner: Neutral + Actor41: bigblue3 + Location: 134,-85 + Owner: Neutral + Actor42: bigblue3 + Location: 29,1 + Owner: Neutral + Actor43: bigblue3 + Location: 76,-47 + Owner: Neutral + Actor44: tibtre01 + Location: 96,23 + Owner: Neutral + Actor45: tibtre02 + Location: 118,67 + Owner: Neutral + Actor46: tibtre02 Location: 136,-19 Owner: Neutral - Actor11: tibtre02 + Actor47: tibtre02 Location: 163,-11 Owner: Neutral - Actor12: tibtre02 + Actor48: tibtre02 Location: 242,26 Owner: Neutral - Actor13: tibtre02 + Actor49: tibtre02 Location: 128,-47 Owner: Neutral - Actor14: tibtre02 + Actor50: tibtre02 Location: 105,-76 Owner: Neutral - Actor15: tibtre02 + Actor51: tibtre02 Location: 102,-28 Owner: Neutral - Actor16: tibtre02 + Actor52: tibtre02 Location: 72,-12 Owner: Neutral - Actor17: tibtre02 + Actor53: tibtre02 Location: 163,99 Owner: Neutral - Actor18: tibtre02 + Actor54: tibtre02 Location: 198,53 Owner: Neutral - Actor19: tibtre03 + Actor55: tibtre03 Location: 183,-33 Owner: Neutral - Actor20: tibtre01 + Actor56: tibtre01 Location: 154,-64 Owner: Neutral - Actor21: tibtre01 + Actor57: tibtre01 Location: 72,10 Owner: Neutral - Actor22: tibtre03 + Actor58: tibtre03 Location: 189,93 Owner: Neutral - Actor23: tibtre03 + Actor59: tibtre03 Location: 227,47 Owner: Neutral - Actor24: tree01 + Actor60: fona01 + Location: 90,65 + Owner: Neutral + Actor61: fona02 + Location: 74,56 + Owner: Neutral + Actor62: fona03 + Location: 85,57 + Owner: Neutral + Actor63: fona04 + Location: 31,5 + Owner: Neutral + Actor64: fona05 + Location: 32,-1 + Owner: Neutral + Actor65: fona04 + Location: 80,-47 + Owner: Neutral + Actor66: fona02 + Location: 72,-47 + Owner: Neutral + Actor67: fona01 + Location: 77,-43 + Owner: Neutral + Actor68: fona01 + Location: 136,-86 + Owner: Neutral + Actor69: fona03 + Location: 132,-79 + Owner: Neutral + Actor70: fona03 + Location: 189,-4 + Owner: Neutral + Actor71: fona04 + Location: 193,-8 + Owner: Neutral + Actor72: fona04 + Location: 209,70 + Owner: Neutral + Actor73: fona05 + Location: 213,79 + Owner: Neutral + Actor74: fona02 + Location: 217,73 + Owner: Neutral + Actor75: fona02 + Location: 160,135 + Owner: Neutral + Actor76: fona04 + Location: 150,130 + Owner: Neutral + Actor77: fona04 + Location: 159,21 + Owner: Neutral + Actor78: fona05 + Location: 159,33 + Owner: Neutral + Actor79: fona06 + Location: 103,-76 + Owner: Neutral + Actor80: fona07 + Location: 103,-33 + Owner: Neutral + Actor81: fona08 + Location: 70,-14 + Owner: Neutral + Actor82: fona09 + Location: 74,7 + Owner: Neutral + Actor83: fona10 + Location: 67,10 + Owner: Neutral + Actor84: fona11 + Location: 93,19 + Owner: Neutral + Actor85: fona12 + Location: 96,27 + Owner: Neutral + Actor86: fona12 + Location: 99,-26 + Owner: Neutral + Actor87: fona13 + Location: 118,69 + Owner: Neutral + Actor88: fona09 + Location: 119,63 + Owner: Neutral + Actor89: fona08 + Location: 138,-20 + Owner: Neutral + Actor90: fona15 + Location: 134,-20 + Owner: Neutral + Actor91: fona14 + Location: 123,-51 + Owner: Neutral + Actor92: fona07 + Location: 131,-45 + Owner: Neutral + Actor93: fona11 + Location: 110,-75 + Owner: Neutral + Actor94: fona11 + Location: 158,-58 + Owner: Neutral + Actor95: fona12 + Location: 150,-66 + Owner: Neutral + Actor96: fona07 + Location: 154,-68 + Owner: Neutral + Actor97: fona08 + Location: 183,-27 + Owner: Neutral + Actor98: fona09 + Location: 186,-27 + Owner: Neutral + Actor99: fona13 + Location: 178,-34 + Owner: Neutral + Actor100: fona15 + Location: 187,-33 + Owner: Neutral + Actor101: fona15 + Location: 245,29 + Owner: Neutral + Actor102: fona14 + Location: 238,22 + Owner: Neutral + Actor103: fona10 + Location: 241,28 + Owner: Neutral + Actor104: fona09 + Location: 239,19 + Owner: Neutral + Actor105: fona09 + Location: 229,48 + Owner: Neutral + Actor106: fona08 + Location: 222,46 + Owner: Neutral + Actor107: fona07 + Location: 224,39 + Owner: Neutral + Actor108: fona11 + Location: 228,45 + Owner: Neutral + Actor109: fona11 + Location: 192,54 + Owner: Neutral + Actor110: fona12 + Location: 204,51 + Owner: Neutral + Actor111: fona08 + Location: 199,51 + Owner: Neutral + Actor112: fona06 + Location: 198,56 + Owner: Neutral + Actor113: fona06 + Location: 186,94 + Owner: Neutral + Actor114: fona07 + Location: 196,96 + Owner: Neutral + Actor115: fona13 + Location: 190,88 + Owner: Neutral + Actor116: fona14 + Location: 191,100 + Owner: Neutral + Actor117: fona14 + Location: 159,102 + Owner: Neutral + Actor118: fona15 + Location: 168,97 + Owner: Neutral + Actor119: fona10 + Location: 161,95 + Owner: Neutral + Actor120: fona09 + Location: 166,103 + Owner: Neutral + Actor121: fona08 + Location: 163,107 + Owner: Neutral + Actor122: fona07 + Location: 115,64 + Owner: Neutral + Actor123: fona09 + Location: 98,20 + Owner: Neutral + Actor124: fona11 + Location: 75,-13 + Owner: Neutral + Actor125: fona12 + Location: 77,14 + Owner: Neutral + Actor126: fona09 + Location: 105,-27 + Owner: Neutral + Actor127: fona09 + Location: 161,-14 + Owner: Neutral + Actor128: fona10 + Location: 164,-6 + Owner: Neutral + Actor129: fona12 + Location: 165,-13 + Owner: Neutral + Actor130: fona13 + Location: 160,-8 + Owner: Neutral + Actor131: fona10 + Location: 123,-47 + Owner: Neutral + Actor132: fona09 + Location: 129,-52 + Owner: Neutral + Actor133: fona09 + Location: 107,-72 + Owner: Neutral + Actor134: fona09 + Location: 100,-32 + Owner: Neutral + Actor135: fona09 + Location: 73,-8 + Owner: Neutral + Actor136: tree01 Location: 142,121 Owner: Neutral - Actor25: tree02 + Actor137: tree02 Location: 152,115 Owner: Neutral - Actor26: tree03 + Actor138: tree03 Location: 160,123 Owner: Neutral - Actor27: tree04 + Actor139: tree04 Location: 159,107 Owner: Neutral - Actor28: tree05 + Actor140: tree05 Location: 171,125 Owner: Neutral - Actor29: tree06 + Actor141: tree06 Location: 170,108 Owner: Neutral - Actor30: tree07 + Actor142: tree07 Location: 176,94 Owner: Neutral - Actor31: tree08 + Actor143: tree08 Location: 192,104 Owner: Neutral - Actor32: tree09 + Actor144: tree09 Location: 177,80 Owner: Neutral - Actor33: tree10 + Actor145: tree10 Location: 161,80 Owner: Neutral - Actor34: tree11 + Actor146: tree11 Location: 151,104 Owner: Neutral - Actor35: tree12 + Actor147: tree12 Location: 141,109 Owner: Neutral - Actor36: tree13 + Actor148: tree13 Location: 114,94 Owner: Neutral - Actor37: tree14 + Actor149: tree14 Location: 117,84 Owner: Neutral - Actor38: tree15 + Actor150: tree15 Location: 125,73 Owner: Neutral - Actor39: tree16 + Actor151: tree16 Location: 131,71 Owner: Neutral - Actor40: tree17 + Actor152: tree17 Location: 119,58 Owner: Neutral - Actor41: tree18 + Actor153: tree18 Location: 107,71 Owner: Neutral - Actor42: tree18 + Actor154: tree18 Location: 173,90 Owner: Neutral - Actor43: tree19 + Actor155: tree19 Location: 174,94 Owner: Neutral - Actor44: tree19 + Actor156: tree19 Location: 184,111 Owner: Neutral - Actor45: tree20 + Actor157: tree20 Location: 182,87 Owner: Neutral - Actor46: tree20 + Actor158: tree20 Location: 165,68 Owner: Neutral - Actor47: tree21 + Actor159: tree21 Location: 173,71 Owner: Neutral - Actor48: tree22 + Actor160: tree22 Location: 186,60 Owner: Neutral - Actor49: tree23 + Actor161: tree23 Location: 181,64 Owner: Neutral - Actor50: tree24 + Actor162: tree24 Location: 202,76 Owner: Neutral - Actor51: tree25 + Actor163: tree25 Location: 195,51 Owner: Neutral - Actor52: tree01 + Actor164: tree01 Location: 176,60 Owner: Neutral - Actor53: tree02 + Actor165: tree02 Location: 197,68 Owner: Neutral - Actor54: tree03 + Actor166: tree03 Location: 203,84 Owner: Neutral - Actor55: tree04 + Actor167: tree04 Location: 210,59 Owner: Neutral - Actor56: tree05 + Actor168: tree05 Location: 228,56 Owner: Neutral - Actor57: tree06 + Actor169: tree06 Location: 201,41 Owner: Neutral - Actor58: tree07 + Actor170: tree07 Location: 217,44 Owner: Neutral - Actor59: tree08 + Actor171: tree08 Location: 210,46 Owner: Neutral - Actor60: tree08 + Actor172: tree08 Location: 217,55 Owner: Neutral - Actor61: tree07 + Actor173: tree07 Location: 175,101 Owner: Neutral - Actor62: tree09 + Actor174: tree09 Location: 221,70 Owner: Neutral - Actor63: tree10 + Actor175: tree10 Location: 242,46 Owner: Neutral - Actor64: tree11 + Actor176: tree11 Location: 219,24 Owner: Neutral - Actor65: tree12 + Actor177: tree12 Location: 215,36 Owner: Neutral - Actor66: tree12 + Actor178: tree12 Location: 256,38 Owner: Neutral - Actor67: tree13 + Actor179: tree13 Location: 234,21 Owner: Neutral - Actor68: tree14 + Actor180: tree14 Location: 222,14 Owner: Neutral - Actor69: tree14 + Actor181: tree14 Location: 204,4 Owner: Neutral - Actor70: tree15 + Actor182: tree15 Location: 181,-23 Owner: Neutral - Actor71: tree15 + Actor183: tree15 Location: 195,-23 Owner: Neutral - Actor72: tree16 + Actor184: tree16 Location: 183,4 Owner: Neutral - Actor73: tree17 + Actor185: tree17 Location: 187,16 Owner: Neutral - Actor74: tree17 + Actor186: tree17 Location: 173,0 Owner: Neutral - Actor75: tree18 + Actor187: tree18 Location: 172,18 Owner: Neutral - Actor76: tree19 + Actor188: tree19 Location: 169,23 Owner: Neutral - Actor77: tree20 + Actor189: tree20 Location: 163,27 Owner: Neutral - Actor78: tree21 + Actor190: tree21 Location: 151,44 Owner: Neutral - Actor79: tree22 + Actor191: tree22 Location: 141,56 Owner: Neutral - Actor80: tree22 + Actor192: tree22 Location: 136,42 Owner: Neutral - Actor81: tree23 + Actor193: tree23 Location: 137,42 Owner: Neutral - Actor82: tree24 + Actor194: tree24 Location: 140,25 Owner: Neutral - Actor83: tree25 + Actor195: tree25 Location: 132,7 Owner: Neutral - Actor84: tree25 + Actor196: tree25 Location: 115,31 Owner: Neutral - Actor85: tree24 + Actor197: tree24 Location: 151,-33 Owner: Neutral - Actor86: tree24 + Actor198: tree24 Location: 146,-6 Owner: Neutral - Actor87: tree23 + Actor199: tree23 Location: 154,-2 Owner: Neutral - Actor88: tree23 + Actor200: tree23 Location: 141,-28 Owner: Neutral - Actor89: tree22 + Actor201: tree22 Location: 130,-10 Owner: Neutral - Actor90: tree21 + Actor202: tree21 Location: 142,8 Owner: Neutral - Actor91: tree20 + Actor203: tree20 Location: 148,18 Owner: Neutral - Actor92: tree19 + Actor204: tree19 Location: 167,5 Owner: Neutral - Actor93: tree18 + Actor205: tree18 Location: 118,-4 Owner: Neutral - Actor94: tree17 + Actor206: tree17 Location: 120,-24 Owner: Neutral - Actor95: tree16 + Actor207: tree16 Location: 122,-37 Owner: Neutral - Actor96: tree16 + Actor208: tree16 Location: 144,-51 Owner: Neutral - Actor97: tree15 + Actor209: tree15 Location: 129,-75 Owner: Neutral - Actor98: tree14 + Actor210: tree14 Location: 122,-65 Owner: Neutral - Actor99: tree13 + Actor211: tree13 Location: 138,-60 Owner: Neutral - Actor100: tree12 + Actor212: tree12 Location: 134,-59 Owner: Neutral - Actor101: tree12 + Actor213: tree12 Location: 116,-92 Owner: Neutral - Actor102: tree11 + Actor214: tree11 Location: 108,-53 Owner: Neutral - Actor103: tree10 + Actor215: tree10 Location: 96,-65 Owner: Neutral - Actor104: tree09 + Actor216: tree09 Location: 95,-35 Owner: Neutral - Actor105: tree10 + Actor217: tree10 Location: 95,-37 Owner: Neutral - Actor106: tree11 + Actor218: tree11 Location: 84,-61 Owner: Neutral - Actor107: tree11 + Actor219: tree11 Location: 64,-40 Owner: Neutral - Actor108: tree12 + Actor220: tree12 Location: 80,-30 Owner: Neutral - Actor109: tree13 + Actor221: tree13 Location: 89,-19 Owner: Neutral - Actor110: tree07 + Actor222: tree07 Location: 98,-12 Owner: Neutral - Actor111: tree06 + Actor223: tree06 Location: 103,-19 Owner: Neutral - Actor112: tree06 + Actor224: tree06 Location: 86,-36 Owner: Neutral - Actor113: tree06 + Actor225: tree06 Location: 54,-26 Owner: Neutral - Actor114: tree05 + Actor226: tree05 Location: 75,0 Owner: Neutral - Actor115: tree04 + Actor227: tree04 Location: 60,-14 Owner: Neutral - Actor116: tree03 + Actor228: tree03 Location: 44,4 Owner: Neutral - Actor117: tree02 + Actor229: tree02 Location: 38,-9 Owner: Neutral - Actor118: tree01 + Actor230: tree01 Location: 58,4 Owner: Neutral - Actor119: tree05 + Actor231: tree05 Location: 54,15 Owner: Neutral - Actor120: tree06 + Actor232: tree06 Location: 39,18 Owner: Neutral - Actor121: tree07 + Actor233: tree07 Location: 58,36 Owner: Neutral - Actor122: tree08 + Actor234: tree08 Location: 73,27 Owner: Neutral - Actor123: tree09 + Actor235: tree09 Location: 83,32 Owner: Neutral - Actor124: tree10 + Actor236: tree10 Location: 90,35 Owner: Neutral - Actor125: tree11 + Actor237: tree11 Location: 101,22 Owner: Neutral - Actor126: tree12 + Actor238: tree12 Location: 105,12 Owner: Neutral - Actor127: tree13 + Actor239: tree13 Location: 118,26 Owner: Neutral - Actor128: tree14 + Actor240: tree14 Location: 110,1 Owner: Neutral - Actor129: tree14 + Actor241: tree14 Location: 108,28 Owner: Neutral - Actor130: tree14 + Actor242: tree14 Location: 106,68 Owner: Neutral - Actor131: tree14 + Actor243: tree14 Location: 124,48 Owner: Neutral - Actor132: tree11 + Actor244: tree11 Location: 118,50 Owner: Neutral - Actor133: tree11 + Actor245: tree11 Location: 144,34 Owner: Neutral - Actor134: tree01 + Actor246: tree01 Location: 97,38 Owner: Neutral - Actor135: tree02 + Actor247: tree02 Location: 109,50 Owner: Neutral - Actor136: tree11 + Actor248: tree11 Location: 79,52 Owner: Neutral - Actor137: tree12 + Actor249: tree12 Location: 93,57 Owner: Neutral - Actor138: tree12 + Actor250: tree12 Location: 50,-15 Owner: Neutral - Actor139: tree12 + Actor251: tree12 Location: 204,-9 Owner: Neutral - Actor140: tree13 + Actor252: tree13 Location: 218,0 Owner: Neutral - Actor141: tree01 + Actor253: tree01 Location: 128,84 Owner: Neutral - Actor142: tree02 + Actor254: tree02 Location: 145,98 Owner: Neutral - Actor143: tree03 + Actor255: tree03 Location: 143,79 Owner: Neutral - Actor144: tree04 + Actor256: tree04 Location: 156,73 Owner: Neutral - Actor145: tree05 + Actor257: tree05 Location: 149,58 Owner: Neutral - Actor146: tree06 + Actor258: tree06 Location: 162,52 Owner: Neutral - Actor147: tree07 + Actor259: tree07 Location: 178,49 Owner: Neutral - Actor148: tree08 + Actor260: tree08 Location: 172,31 Owner: Neutral - Actor149: tree09 + Actor261: tree09 Location: 182,23 Owner: Neutral - Actor150: tree10 + Actor262: tree10 Location: 193,37 Owner: Neutral - Actor151: tree11 + Actor263: tree11 Location: 146,88 Owner: Neutral - Actor152: tree12 + Actor264: tree12 Location: 141,64 Owner: Neutral - Actor153: tree13 + Actor265: tree13 Location: 149,71 Owner: Neutral - Actor154: tree14 + Actor266: tree14 Location: 164,57 Owner: Neutral - Actor155: tree15 + Actor267: tree15 Location: 169,40 Owner: Neutral - Actor156: tree16 + Actor268: tree16 Location: 184,36 Owner: Neutral - Actor157: tree16 + Actor269: tree16 Location: 181,42 Owner: Neutral - Actor158: tree17 + Actor270: tree17 Location: 181,43 Owner: Neutral - Actor159: tree17 + Actor271: tree17 Location: 198,22 Owner: Neutral - Actor160: tree18 + Actor272: tree18 Location: 210,25 Owner: Neutral - Actor161: tree19 + Actor273: tree19 Location: 206,30 Owner: Neutral - Actor162: tree20 + Actor274: tree20 Location: 203,23 Owner: Neutral - Actor163: tree20 + Actor275: tree20 Location: 186,29 Owner: Neutral - Actor164: tree21 + Actor276: tree21 Location: 164,45 Owner: Neutral - Actor165: tree22 + Actor277: tree22 Location: 154,67 Owner: Neutral - Actor166: tree23 + Actor278: tree23 Location: 134,79 Owner: Neutral - Actor167: tree24 + Actor279: tree24 Location: 154,94 Owner: Neutral - Actor168: tree25 + Actor280: tree25 Location: 147,88 Owner: Neutral - Actor169: tree25 + Actor281: tree25 Location: 134,89 Owner: Neutral - Actor170: tree22 + Actor282: tree22 Location: 131,96 Owner: Neutral - Actor171: tree11 + Actor283: tree11 Location: 202,11 Owner: Neutral - Actor172: tree12 + Actor284: tree12 Location: 206,19 Owner: Neutral - Actor173: tree03 + Actor285: tree03 Location: 169,-41 Owner: Neutral - Actor174: tree04 + Actor286: tree04 Location: 172,-39 Owner: Neutral - Actor175: tree05 + Actor287: tree05 Location: 165,-54 Owner: Neutral - Actor176: tree06 + Actor288: tree06 Location: 169,-49 Owner: Neutral - Actor177: tree07 + Actor289: tree07 Location: 166,-48 Owner: Neutral - Actor178: tree08 + Actor290: tree08 Location: 167,-48 Owner: Neutral - Actor179: mpspawn + Actor291: mpspawn Location: 42,-3 Owner: Neutral - Actor180: mpspawn + Actor292: mpspawn Location: 218,59 Owner: Neutral - Actor181: mpspawn + Actor293: mpspawn Location: 134,-63 Owner: Neutral - Actor182: mpspawn + Actor294: mpspawn Location: 102,44 Owner: Neutral - Actor183: mpspawn + Actor295: mpspawn Location: 203,-4 Owner: Neutral - Actor184: mpspawn + Actor296: mpspawn Location: 92,-40 Owner: Neutral - Actor185: mpspawn + Actor297: mpspawn Location: 178,103 Owner: Neutral - Actor186: mpspawn + Actor298: mpspawn Location: 150,-3 Owner: Neutral - Actor187: waypoint + Actor299: waypoint Location: 135,15 Owner: Neutral - Actor188: waypoint + Actor300: waypoint Location: 135,15 Owner: Neutral - Actor189: trock02 + Actor301: trock02 Location: 104,-80 Owner: Neutral - Actor190: srock02 + Actor302: srock02 Location: 65,-38 Owner: Neutral - Actor191: trock03 + Actor303: trock03 Location: 114,-84 Owner: Neutral - Actor192: srock05 - Location: 60,-25 - Owner: Neutral - Actor193: trock01 + Actor304: trock01 Location: 55,-21 Owner: Neutral - Actor194: srock03 - Location: 77,-39 + Actor305: srock05 + Location: 60,-25 Owner: Neutral - Actor195: trock05 - Location: 131,-88 + Actor306: srock03 + Location: 77,-39 Owner: Neutral - Actor196: trock01 + Actor307: trock01 Location: 107,-65 Owner: Neutral - Actor197: lobrdg_r_nw - Location: 110,-63 + Actor308: trock05 + Location: 131,-88 Owner: Neutral - Actor198: srock03 + Actor309: srock03 Location: 35,11 Owner: Neutral - Actor199: srock05 - Location: 125,-76 - Owner: Neutral - Actor200: lobrdg_b - Location: 112,-63 + Actor310: lobrdg_r_nw + Location: 110,-63 Owner: Neutral - Actor201: lobrdg_b + Actor311: lobrdg_b Location: 111,-63 Owner: Neutral - Actor205: lobrdg_b - Location: 114,-63 + Actor312: lobrdg_b + Location: 112,-63 + Owner: Neutral + Actor313: srock05 + Location: 125,-76 Owner: Neutral - Actor206: lobrdg_b + Actor314: lobrdg_b Location: 113,-63 Owner: Neutral - Actor211: lobrdg_b - Location: 116,-63 + Actor315: lobrdg_b + Location: 114,-63 Owner: Neutral - Actor212: lobrdg_b + Actor316: lobrdg_b Location: 115,-63 Owner: Neutral - Actor217: lobrdg_b - Location: 118,-63 + Actor317: lobrdg_b + Location: 116,-63 Owner: Neutral - Actor218: lobrdg_b + Actor318: lobrdg_b Location: 117,-63 Owner: Neutral - Actor223: srock04 - Location: 124,-67 + Actor319: lobrdg_b + Location: 118,-63 + Owner: Neutral + Actor320: lobrdg_b + Location: 119,-63 Owner: Neutral - Actor224: lobrdg_r_se + Actor321: lobrdg_r_se Location: 120,-63 Owner: Neutral - Actor225: lobrdg_b - Location: 119,-63 + Actor322: srock04 + Location: 124,-67 + Owner: Neutral + Actor323: trock02 + Location: 62,-4 Owner: Neutral - Actor234: lobrdg_r_ne + Actor324: lobrdg_r_ne Location: 81,-23 Owner: Neutral - Actor235: lobrdg_a + Actor325: lobrdg_a Location: 81,-22 Owner: Neutral - Actor236: trock02 - Location: 62,-4 - Owner: Neutral - Actor241: lobrdg_a + Actor326: lobrdg_a Location: 81,-21 Owner: Neutral - Actor242: lobrdg_a + Actor327: lobrdg_a Location: 81,-20 Owner: Neutral - Actor243: srock04 - Location: 86,-23 - Owner: Neutral - Actor248: lobrdg_a + Actor328: lobrdg_a Location: 81,-19 Owner: Neutral - Actor249: lobrdg_a + Actor329: lobrdg_a Location: 81,-18 Owner: Neutral - Actor254: lobrdg_a + Actor330: srock04 + Location: 86,-23 + Owner: Neutral + Actor331: lobrdg_a Location: 81,-17 Owner: Neutral - Actor255: lobrdg_a + Actor332: lobrdg_a Location: 81,-16 Owner: Neutral - Actor260: lobrdg_a - Location: 81,-15 - Owner: Neutral - Actor261: lobrdg_a - Location: 81,-14 - Owner: Neutral - Actor262: srock04 + Actor333: srock04 Location: 54,12 Owner: Neutral - Actor263: srock02 + Actor334: lobrdg_a + Location: 81,-15 + Owner: Neutral + Actor335: srock02 Location: 48,19 Owner: Neutral - Actor268: lobrdg_a + Actor336: lobrdg_a + Location: 81,-14 + Owner: Neutral + Actor337: lobrdg_a Location: 81,-13 Owner: Neutral - Actor269: lobrdg_a + Actor338: lobrdg_a Location: 81,-12 Owner: Neutral - Actor274: lobrdg_a + Actor339: lobrdg_a Location: 81,-11 Owner: Neutral - Actor275: lobrdg_r_sw + Actor340: lobrdg_r_sw Location: 81,-10 Owner: Neutral - Actor279: srock03 - Location: 125,-47 - Owner: Neutral - Actor280: trock01 + Actor341: trock01 Location: 78,0 Owner: Neutral - Actor281: srock01 - Location: 85,-4 + Actor342: srock03 + Location: 125,-47 Owner: Neutral - Actor282: srock05 + Actor343: srock05 Location: 70,11 Owner: Neutral - Actor283: srock01 + Actor344: srock01 + Location: 85,-4 + Owner: Neutral + Actor345: srock01 Location: 57,29 Owner: Neutral - Actor284: srock01 + Actor346: srock01 Location: 119,-31 Owner: Neutral - Actor285: trock04 - Location: 155,-61 + Actor347: trock03 + Location: 124,-30 Owner: Neutral - Actor286: lobrdg_r_ne - Location: 146,-51 + Actor348: trock04 + Location: 155,-61 Owner: Neutral - Actor287: trock03 - Location: 124,-30 + Actor349: lobrdg_r_nw + Location: 91,4 Owner: Neutral - Actor288: srock02 + Actor350: srock02 Location: 115,-20 Owner: Neutral - Actor289: lobrdg_r_nw - Location: 91,4 + Actor351: lobrdg_r_ne + Location: 146,-51 Owner: Neutral - Actor293: lobrdg_a - Location: 146,-50 + Actor352: lobrdg_b + Location: 92,4 Owner: Neutral - Actor294: lobrdg_a - Location: 146,-49 + Actor353: lobrdg_a + Location: 146,-50 Owner: Neutral - Actor295: lobrdg_b + Actor354: lobrdg_b Location: 93,4 Owner: Neutral - Actor296: lobrdg_b - Location: 92,4 + Actor355: lobrdg_a + Location: 146,-49 Owner: Neutral - Actor304: lobrdg_a - Location: 146,-48 + Actor356: lobrdg_b + Location: 94,4 Owner: Neutral - Actor305: lobrdg_a - Location: 146,-47 + Actor357: lobrdg_a + Location: 146,-48 Owner: Neutral - Actor306: lobrdg_b + Actor358: lobrdg_b Location: 95,4 Owner: Neutral - Actor307: lobrdg_b - Location: 94,4 + Actor359: lobrdg_a + Location: 146,-47 Owner: Neutral - Actor316: lobrdg_a - Location: 146,-46 + Actor360: lobrdg_b + Location: 96,4 Owner: Neutral - Actor317: lobrdg_a - Location: 146,-45 + Actor361: lobrdg_a + Location: 146,-46 Owner: Neutral - Actor318: lobrdg_b + Actor362: lobrdg_b Location: 97,4 Owner: Neutral - Actor319: lobrdg_b - Location: 96,4 + Actor363: lobrdg_a + Location: 146,-45 Owner: Neutral - Actor328: lobrdg_a - Location: 146,-44 + Actor364: lobrdg_b + Location: 98,4 Owner: Neutral - Actor329: lobrdg_a - Location: 146,-43 + Actor365: lobrdg_a + Location: 146,-44 Owner: Neutral - Actor330: lobrdg_b + Actor366: lobrdg_b Location: 99,4 Owner: Neutral - Actor331: lobrdg_b - Location: 98,4 + Actor367: lobrdg_a + Location: 146,-43 Owner: Neutral - Actor340: lobrdg_a - Location: 146,-42 + Actor368: lobrdg_b + Location: 100,4 Owner: Neutral - Actor341: lobrdg_a - Location: 146,-41 + Actor369: lobrdg_a + Location: 146,-42 Owner: Neutral - Actor342: lobrdg_b + Actor370: lobrdg_b Location: 101,4 Owner: Neutral - Actor343: lobrdg_b - Location: 100,4 + Actor371: lobrdg_a + Location: 146,-41 Owner: Neutral - Actor352: lobrdg_a - Location: 146,-40 + Actor372: lobrdg_b + Location: 102,4 Owner: Neutral - Actor353: lobrdg_r_sw - Location: 146,-39 + Actor373: lobrdg_a + Location: 146,-40 Owner: Neutral - Actor354: lobrdg_b + Actor374: lobrdg_b Location: 103,4 Owner: Neutral - Actor355: lobrdg_b - Location: 102,4 - Owner: Neutral - Actor363: lobrdg_b - Location: 105,4 + Actor375: lobrdg_r_sw + Location: 146,-39 Owner: Neutral - Actor364: lobrdg_b + Actor376: lobrdg_b Location: 104,4 Owner: Neutral - Actor369: lobrdg_r_se + Actor377: lobrdg_b + Location: 105,4 + Owner: Neutral + Actor378: lobrdg_r_se Location: 106,4 Owner: Neutral - Actor374: srock02 + Actor379: srock02 Location: 76,35 Owner: Neutral - Actor376: srock04 + Actor380: srock04 Location: 152,-37 Owner: Neutral - Actor377: srock03 - Location: 131,-14 - Owner: Neutral - Actor378: srock03 + Actor381: srock03 Location: 93,24 Owner: Neutral - Actor379: srock04 + Actor382: srock03 + Location: 131,-14 + Owner: Neutral + Actor383: srock04 Location: 106,17 Owner: Neutral - Actor380: trock04 + Actor384: trock04 Location: 129,-5 Owner: Neutral - Actor381: srock05 + Actor385: srock05 Location: 115,10 Owner: Neutral - Actor382: trock03 + Actor386: trock03 Location: 158,-29 Owner: Neutral - Actor383: trock01 + Actor387: trock01 Location: 154,-17 Owner: Neutral - Actor384: srock01 + Actor388: srock01 Location: 131,10 Owner: Neutral - Actor385: trock01 + Actor389: trock01 Location: 109,34 Owner: Neutral - Actor386: trock02 + Actor390: trock02 Location: 181,-30 Owner: Neutral - Actor387: trock01 + Actor391: trock01 Location: 177,-21 Owner: Neutral - Actor388: srock04 + Actor392: srock04 Location: 166,-9 Owner: Neutral - Actor389: trock02 + Actor393: trock02 Location: 117,41 Owner: Neutral - Actor390: srock02 + Actor394: srock02 Location: 142,25 Owner: Neutral - Actor391: trock03 + Actor395: trock03 Location: 121,53 Owner: Neutral - Actor392: srock05 - Location: 187,-11 - Owner: Neutral - Actor393: srock03 + Actor396: srock03 Location: 170,6 Owner: Neutral - Actor394: srock01 - Location: 103,79 + Actor397: srock05 + Location: 187,-11 Owner: Neutral - Actor395: srock02 - Location: 165,19 + Actor398: srock01 + Location: 103,79 Owner: Neutral - Actor396: trock05 + Actor399: trock05 Location: 152,32 Owner: Neutral - Actor397: srock02 + Actor400: srock02 + Location: 165,19 + Owner: Neutral + Actor401: srock02 Location: 125,62 Owner: Neutral - Actor398: trock04 + Actor402: trock04 Location: 135,53 Owner: Neutral - Actor399: trock02 + Actor403: trock02 Location: 189,10 Owner: Neutral - Actor400: srock05 + Actor404: srock05 Location: 182,19 Owner: Neutral - Actor401: srock01 + Actor405: srock01 Location: 160,43 Owner: Neutral - Actor402: srock03 + Actor406: srock03 Location: 172,34 Owner: Neutral - Actor403: srock04 + Actor407: srock04 Location: 146,62 Owner: Neutral - Actor404: trock02 + Actor408: trock02 Location: 140,73 Owner: Neutral - Actor405: srock01 + Actor409: srock01 Location: 209,5 Owner: Neutral - Actor406: trock04 + Actor410: trock04 Location: 179,36 Owner: Neutral - Actor407: trock02 - Location: 185,32 - Owner: Neutral - Actor408: trock05 + Actor411: trock05 Location: 166,51 Owner: Neutral - Actor409: trock01 - Location: 198,27 - Owner: Neutral - Actor410: trock03 - Location: 184,40 + Actor412: trock02 + Location: 185,32 Owner: Neutral - Actor411: srock03 + Actor413: srock03 Location: 163,61 Owner: Neutral - Actor412: srock02 - Location: 171,56 + Actor414: trock03 + Location: 184,40 + Owner: Neutral + Actor415: trock01 + Location: 198,27 Owner: Neutral - Actor413: trock04 + Actor416: trock04 Location: 141,86 Owner: Neutral - Actor414: srock05 + Actor417: srock02 + Location: 171,56 + Owner: Neutral + Actor418: srock05 Location: 155,77 Owner: Neutral - Actor415: srock04 - Location: 190,46 + Actor419: trock01 + Location: 138,98 Owner: Neutral - Actor416: trock02 + Actor420: trock02 Location: 167,69 Owner: Neutral - Actor417: trock05 - Location: 151,86 + Actor421: srock04 + Location: 190,46 Owner: Neutral - Actor418: trock01 - Location: 138,98 + Actor422: trock05 + Location: 151,86 Owner: Neutral - Actor419: trock03 + Actor423: trock03 Location: 155,83 Owner: Neutral - Actor420: trock04 - Location: 220,23 - Owner: Neutral - Actor421: trock01 + Actor424: trock01 Location: 206,37 Owner: Neutral - Actor422: trock04 - Location: 183,62 + Actor425: trock04 + Location: 220,23 Owner: Neutral - Actor423: trock01 + Actor426: trock01 Location: 162,83 Owner: Neutral - Actor424: srock04 - Location: 193,55 + Actor427: trock04 + Location: 183,62 Owner: Neutral - Actor425: srock03 + Actor428: srock03 Location: 136,112 Owner: Neutral - Actor426: srock05 - Location: 201,50 + Actor429: srock04 + Location: 193,55 Owner: Neutral - Actor427: srock02 - Location: 222,31 + Actor430: srock05 + Location: 201,50 Owner: Neutral - Actor428: trock03 + Actor431: trock03 Location: 217,35 Owner: Neutral - Actor429: srock05 + Actor432: srock02 + Location: 222,31 + Owner: Neutral + Actor433: srock05 Location: 169,88 Owner: Neutral - Actor430: trock03 + Actor434: trock03 Location: 178,84 Owner: Neutral - Actor431: srock04 + Actor435: srock04 Location: 156,108 Owner: Neutral - Actor432: srock03 + Actor436: srock03 Location: 201,69 Owner: Neutral - Actor433: trock05 + Actor437: trock05 Location: 205,77 Owner: Neutral - Actor434: trock02 + Actor438: trock02 Location: 236,54 Owner: Neutral - Actor435: trock05 + Actor439: trock05 Location: 254,39 Owner: Neutral Rules: - World: - GlobalLightingPaletteEffect: - Ambient: 0.85 + ^BaseWorld: + TerrainLighting: + Intensity: 0.85 + INGRNLMP: + TerrainLightSource: + Range: 13c688 + Intensity: 0.002 + RedTint: 0.01 + GreenTint: 1 + BlueTint: 0.01 + INBLULMP: + TerrainLightSource: + Range: 15c640 + Intensity: 0.09 + RedTint: 0.01 + GreenTint: 0.01 + BlueTint: 0.5 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/springs/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/springs/map.png differ diff -Nru openra-20200503/mods/ts/maps/springs/map.yaml openra-20210321/mods/ts/maps/springs/map.yaml --- openra-20200503/mods/ts/maps/springs/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/springs/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -10,11 +10,11 @@ MapSize: 81,146 -Bounds: 2,8,77,126 +Bounds: 2,4,77,134 Visibility: Lobby -Categories: Conquest, Original FS Map, Playable +Categories: Conquest Players: PlayerReference@Neutral: @@ -39,845 +39,889 @@ Enemies: Creeps Actors: - Actor0: aban06 + Actor0: ingrnlmp + Location: 34,16 + Owner: Neutral + Facing: 896 + Actor1: ingrnlmp + Location: 120,-27 + Owner: Neutral + Facing: 896 + Actor2: ingrnlmp + Location: 78,-2 + Owner: Neutral + Facing: 896 + Actor3: ingrnlmp + Location: 87,4 + Owner: Neutral + Facing: 896 + Actor4: ingrnlmp + Location: 88,-6 + Owner: Neutral + Facing: 896 + Actor5: ingrnlmp + Location: 72,57 + Owner: Neutral + Facing: 896 + Actor6: ingrnlmp + Location: 135,-9 + Owner: Neutral + Facing: 896 + Actor7: ingrnlmp + Location: 86,-33 + Owner: Neutral + Facing: 896 + Actor8: ingrnlmp + Location: 33,2 + Owner: Neutral + Facing: 896 + Actor9: inblulmp + Location: 42,-9 + Owner: Neutral + Facing: 896 + Actor10: inblulmp + Location: 82,33 + Owner: Neutral + Facing: 896 + Actor11: inblulmp + Location: 117,1 + Owner: Neutral + Facing: 896 + Actor12: inblulmp + Location: 69,-40 + Owner: Neutral + Facing: 896 + Actor13: inblulmp + Location: 61,2 + Owner: Neutral + Facing: 896 + Actor14: inblulmp + Location: 98,-14 + Owner: Neutral + Facing: 896 + Actor15: inblulmp + Location: 95,22 + Owner: Neutral + Facing: 896 + Actor16: aban06 Location: 54,-15 Owner: Neutral - Health: 100 - Facing: 96 - Actor1: aban07 + Facing: 896 + Actor17: aban07 Location: 62,-7 Owner: Neutral - Health: 100 - Facing: 96 - Actor2: aban09 + Facing: 896 + Actor18: aban09 Location: 60,-12 Owner: Neutral - Health: 100 - Facing: 96 - Actor3: aban11 + Facing: 896 + Actor19: aban11 Location: 55,-9 Owner: Neutral - Health: 100 - Facing: 96 - Actor4: aban12 + Facing: 896 + Actor20: aban12 Location: 63,-14 Owner: Neutral - Health: 100 - Facing: 96 - Actor5: aban13 + Facing: 896 + Actor21: aban13 Location: 58,-16 Owner: Neutral - Health: 100 - Facing: 96 - Actor6: aban15 + Facing: 896 + Actor22: aban15 Location: 52,-13 Owner: Neutral - Health: 100 - Facing: 96 - Actor7: aban03 + Facing: 896 + Actor23: aban03 Location: 74,18 Owner: Neutral - Health: 100 - Facing: 96 - Actor8: aban05 + Facing: 896 + Actor24: aban05 Location: 81,21 Owner: Neutral - Health: 100 - Facing: 96 - Actor9: aban10 + Facing: 896 + Actor25: aban10 Location: 76,14 Owner: Neutral - Health: 100 - Facing: 96 - Actor10: aban16 + Facing: 896 + Actor26: aban16 Location: 81,15 Owner: Neutral - Health: 100 - Facing: 96 - Actor11: aban17 + Facing: 896 + Actor27: aban17 Location: 82,17 Owner: Neutral - Health: 100 - Facing: 96 - Actor12: aban18 + Facing: 896 + Actor28: aban18 Location: 81,17 Owner: Neutral - Health: 100 - Facing: 96 - Actor13: aban17 + Facing: 896 + Actor29: aban17 Location: 83,17 Owner: Neutral - Health: 100 - Facing: 96 - Actor14: ca0012 + Facing: 896 + Actor30: ca0012 Location: 85,20 Owner: Neutral - Health: 100 - Facing: 96 - Actor15: ca0012 + Facing: 896 + Actor31: ca0012 Location: 86,20 Owner: Neutral - Health: 100 - Facing: 96 - Actor16: ca0013 + Facing: 896 + Actor32: ca0013 Location: 65,29 Owner: Neutral - Health: 100 - Facing: 96 - Actor17: ca0014 + Facing: 896 + Actor33: ca0014 Location: 62,24 Owner: Neutral - Health: 100 - Facing: 96 - Actor18: ca0016 + Facing: 896 + Actor34: ca0016 Location: 70,26 Owner: Neutral - Health: 100 - Facing: 96 - Actor19: aban02 + Facing: 896 + Actor35: aban02 Location: 51,12 Owner: Neutral - Health: 100 - Facing: 96 - Actor20: ca0004 + Facing: 896 + Actor36: ca0004 Location: 85,-59 Owner: Neutral - Health: 100 - Facing: 96 - Actor21: ca0005 + Facing: 896 + Actor37: ca0005 Location: 87,-59 Owner: Neutral - Health: 100 - Facing: 96 - Actor22: ca0006 + Facing: 896 + Actor38: ca0006 Location: 88,-59 Owner: Neutral - Health: 100 - Facing: 96 - Actor23: ca0007 + Facing: 896 + Actor39: ca0007 Location: 83,-56 Owner: Neutral - Health: 100 - Facing: 96 - Actor24: ca0017 + Facing: 896 + Actor40: ca0017 Location: 82,-56 Owner: Neutral - Health: 100 - Facing: 96 - Actor25: ca0018 + Facing: 896 + Actor41: ca0018 Location: 82,-58 Owner: Neutral - Health: 100 - Facing: 96 - Actor26: ca0020 + Facing: 896 + Actor42: ca0020 Location: 82,-55 Owner: Neutral - Health: 100 - Facing: 96 - Actor27: ca0010 + Facing: 896 + Actor43: ca0010 Location: 91,-52 Owner: Neutral - Health: 100 - Facing: 96 - Actor28: ca0011 + Facing: 896 + Actor44: ca0011 Location: 90,-57 Owner: Neutral - Health: 100 - Facing: 96 - Actor29: ca0011 + Facing: 896 + Actor45: ca0011 Location: 91,-57 Owner: Neutral - Health: 100 - Facing: 96 - Actor30: car + Facing: 896 + Actor46: tstlamp + Location: 78,20 + Owner: Neutral + Facing: 896 + Actor47: tstlamp + Location: 86,18 + Owner: Neutral + Facing: 896 + Actor48: tstlamp + Location: 65,26 + Owner: Neutral + Facing: 896 + Actor49: tstlamp + Location: 56,11 + Owner: Neutral + Facing: 896 + Actor50: tstlamp + Location: 56,-16 + Owner: Neutral + Facing: 896 + Actor51: tstlamp + Location: 60,-9 + Owner: Neutral + Facing: 896 + Actor52: tstlamp + Location: 53,-11 + Owner: Neutral + Facing: 896 + Actor53: tstlamp + Location: 90,-59 + Owner: Neutral + Facing: 896 + Actor54: tstlamp + Location: 84,-57 + Owner: Neutral + Facing: 896 + Actor55: car Location: 76,19 Owner: Neutral - Health: 100 - Facing: 96 - Actor31: car + Facing: 896 + Actor56: car Location: 83,15 Owner: Neutral - Health: 100 - Facing: 96 - Actor32: car + Facing: 896 + Actor57: car Location: 57,-8 Owner: Neutral - Health: 100 - Facing: 96 - Actor33: car + Facing: 896 + Actor58: car Location: 64,-12 Owner: Neutral - Health: 100 - Facing: 160 - Actor34: car + Facing: 640 + Actor59: car Location: 56,14 Owner: Neutral - Health: 100 - Facing: 128 - Actor35: car + Facing: 768 + Actor60: car Location: 84,-56 Owner: Neutral - Health: 100 - Facing: 128 - Actor36: pick + Facing: 768 + Actor61: pick Location: 88,-56 Owner: Neutral - Health: 100 - Facing: 224 - Actor37: pick + Facing: 384 + Actor62: pick Location: 82,18 Owner: Neutral - Health: 100 - Facing: 32 - Actor38: pick + Facing: 128 + Actor63: pick Location: 84,22 Owner: Neutral - Health: 100 - Facing: 64 - Actor39: pick + Facing: 0 + Actor64: pick Location: 52,15 Owner: Neutral - Health: 100 - Facing: 224 - Actor40: pick + Facing: 384 + Actor65: pick Location: 53,-13 Owner: Neutral - Health: 100 - Facing: 0 - Actor41: bus + Facing: 256 + Actor66: bus Location: 64,-7 Owner: Neutral - Health: 100 - Facing: 224 - Actor42: wini + Facing: 384 + Actor67: wini Location: 59,-10 Owner: Neutral - Health: 100 - Facing: 160 - Actor43: civ1 + Facing: 640 + Actor68: civ1 Location: 64,24 Owner: Neutral - Health: 100 - Facing: 98 - Actor44: civ2 + Facing: 888 + Actor69: civ2 Location: 74,23 Owner: Neutral - Health: 100 - Facing: 100 - Actor45: civ3 + Facing: 880 + Actor70: civ3 Location: 88,18 Owner: Neutral - Health: 100 - Facing: 99 - Actor46: civ1 + Facing: 884 + Actor71: civ1 Location: 78,13 Owner: Neutral - Health: 100 - Facing: 98 - Actor47: civ2 + Facing: 888 + Actor72: civ2 Location: 86,23 Owner: Neutral - Health: 100 - Facing: 99 - Actor48: civ3 + Facing: 884 + Actor73: civ3 Location: 78,18 Owner: Neutral - Health: 100 - Facing: 99 - Actor49: civ1 + Facing: 884 + Actor74: civ1 Location: 55,-12 Owner: Neutral - Health: 100 - Facing: 100 - Actor50: civ2 + Facing: 880 + Actor75: civ2 Location: 59,-8 Owner: Neutral - Health: 100 - Facing: 98 - Actor51: civ3 + Facing: 888 + Actor76: civ3 Location: 64,-11 Owner: Neutral - Health: 100 - Facing: 98 - Actor52: civ2 + Facing: 888 + Actor77: civ2 Location: 84,-58 Owner: Neutral - Health: 100 - Facing: 100 - Actor53: civ3 + Facing: 880 + Actor78: civ3 Location: 91,-54 Owner: Neutral - Health: 100 - Facing: 99 - Actor54: tibtre01 + Facing: 884 + Actor79: tibtre01 Location: 78,-2 Owner: Neutral - Actor55: tibtre02 + Actor80: tibtre02 Location: 88,-6 Owner: Neutral - Actor56: tibtre03 + Actor81: tibtre03 Location: 87,4 Owner: Neutral - Actor57: tibtre01 + Actor82: tibtre01 Location: 34,16 Owner: Neutral - Actor58: tibtre02 + Actor83: tibtre02 Location: 33,2 Owner: Neutral - Actor59: tibtre03 + Actor84: tibtre03 Location: 72,57 Owner: Neutral - Actor60: tibtre01 + Actor85: tibtre01 Location: 86,-33 Owner: Neutral - Actor61: tibtre02 + Actor86: tibtre02 Location: 135,-9 Owner: Neutral - Actor62: tibtre03 + Actor87: tibtre03 Location: 120,-27 Owner: Neutral - Actor63: tree01 + Actor88: tree01 Location: 51,22 Owner: Neutral - Actor64: tree02 + Actor89: tree02 Location: 52,25 Owner: Neutral - Actor65: tree14 + Actor90: tree14 Location: 57,28 Owner: Neutral - Actor66: tree01 + Actor91: tree01 Location: 28,9 Owner: Neutral - Actor67: tree02 + Actor92: tree02 Location: 27,7 Owner: Neutral - Actor68: tree03 + Actor93: tree03 Location: 29,8 Owner: Neutral - Actor69: tree05 + Actor94: tree05 Location: 42,4 Owner: Neutral - Actor70: tree06 + Actor95: tree06 Location: 44,5 Owner: Neutral - Actor71: tree07 + Actor96: tree07 Location: 58,17 Owner: Neutral - Actor72: tree08 + Actor97: tree08 Location: 64,22 Owner: Neutral - Actor73: tree09 + Actor98: tree09 Location: 62,45 Owner: Neutral - Actor74: tree10 + Actor99: tree10 Location: 64,46 Owner: Neutral - Actor75: tree11 + Actor100: tree11 Location: 63,43 Owner: Neutral - Actor76: tree12 + Actor101: tree12 Location: 82,53 Owner: Neutral - Actor77: tree01 + Actor102: tree01 Location: 81,55 Owner: Neutral - Actor78: tree01 + Actor103: tree01 Location: 79,18 Owner: Neutral - Actor79: tree02 + Actor104: tree02 Location: 72,11 Owner: Neutral - Actor80: tree03 + Actor105: tree03 Location: 58,-13 Owner: Neutral - Actor81: tree04 + Actor106: tree04 Location: 63,-11 Owner: Neutral - Actor82: tree05 + Actor107: tree05 Location: 48,-22 Owner: Neutral - Actor83: tree06 + Actor108: tree06 Location: 51,-24 Owner: Neutral - Actor84: tree07 + Actor109: tree07 Location: 56,-28 Owner: Neutral - Actor85: tree08 + Actor110: tree08 Location: 82,-25 Owner: Neutral - Actor86: tree09 + Actor111: tree09 Location: 83,-23 Owner: Neutral - Actor87: tree10 + Actor112: tree10 Location: 83,-25 Owner: Neutral - Actor88: tree11 + Actor113: tree11 Location: 81,-24 Owner: Neutral - Actor89: tree01 + Actor114: tree01 Location: 90,-46 Owner: Neutral - Actor90: tree02 + Actor115: tree02 Location: 94,-46 Owner: Neutral - Actor91: tree03 + Actor116: tree03 Location: 97,-50 Owner: Neutral - Actor92: tree04 + Actor117: tree04 Location: 97,-53 Owner: Neutral - Actor93: tree05 + Actor118: tree05 Location: 102,-52 Owner: Neutral - Actor94: tree06 + Actor119: tree06 Location: 102,-50 Owner: Neutral - Actor95: tree07 + Actor120: tree07 Location: 99,-27 Owner: Neutral - Actor96: tree08 + Actor121: tree08 Location: 101,-26 Owner: Neutral - Actor97: tree09 + Actor122: tree09 Location: 103,-24 Owner: Neutral - Actor98: tree10 + Actor123: tree10 Location: 101,-46 Owner: Neutral - Actor99: tree11 + Actor124: tree11 Location: 96,-43 Owner: Neutral - Actor100: tree12 + Actor125: tree12 Location: 102,-42 Owner: Neutral - Actor101: tree13 + Actor126: tree13 Location: 119,-15 Owner: Neutral - Actor102: tree01 + Actor127: tree01 Location: 120,-17 Owner: Neutral - Actor103: tree02 + Actor128: tree02 Location: 122,-14 Owner: Neutral - Actor104: tree02 + Actor129: tree02 Location: 113,18 Owner: Neutral - Actor105: tree03 + Actor130: tree03 Location: 110,20 Owner: Neutral - Actor106: tree04 + Actor131: tree04 Location: 103,13 Owner: Neutral - Actor107: tree05 + Actor132: tree05 Location: 109,24 Owner: Neutral - Actor108: tree06 + Actor133: tree06 Location: 105,29 Owner: Neutral - Actor109: tree07 + Actor134: tree07 Location: 100,-4 Owner: Neutral - Actor110: tree08 + Actor135: tree08 Location: 101,-2 Owner: Neutral - Actor111: tree15 + Actor136: tree15 Location: 51,23 Owner: Neutral - Actor112: tree16 + Actor137: tree16 Location: 55,27 Owner: Neutral - Actor113: tree17 + Actor138: tree17 Location: 53,27 Owner: Neutral - Actor114: tree17 + Actor139: tree17 Location: 27,16 Owner: Neutral - Actor115: tree18 + Actor140: tree18 Location: 27,15 Owner: Neutral - Actor116: tree19 + Actor141: tree19 Location: 27,5 Owner: Neutral - Actor117: tree20 + Actor142: tree20 Location: 25,1 Owner: Neutral - Actor118: tree21 + Actor143: tree21 Location: 26,3 Owner: Neutral - Actor119: tree22 + Actor144: tree22 Location: 20,1 Owner: Neutral - Actor120: tree23 + Actor145: tree23 Location: 21,1 Owner: Neutral - Actor121: tree24 + Actor146: tree24 Location: 51,-22 Owner: Neutral - Actor122: tree25 + Actor147: tree25 Location: 53,-19 Owner: Neutral - Actor123: tree13 + Actor148: tree13 Location: 57,-11 Owner: Neutral - Actor124: tree14 + Actor149: tree14 Location: 65,-8 Owner: Neutral - Actor125: tree15 + Actor150: tree15 Location: 65,-15 Owner: Neutral - Actor126: tree16 + Actor151: tree16 Location: 63,-16 Owner: Neutral - Actor127: tree17 + Actor152: tree17 Location: 60,-17 Owner: Neutral - Actor128: tree18 + Actor153: tree18 Location: 64,-22 Owner: Neutral - Actor129: tree19 + Actor154: tree19 Location: 55,-28 Owner: Neutral - Actor130: tree20 + Actor155: tree20 Location: 82,-24 Owner: Neutral - Actor131: tree21 + Actor156: tree21 Location: 82,-26 Owner: Neutral - Actor132: tree22 + Actor157: tree22 Location: 91,-46 Owner: Neutral - Actor133: tree13 + Actor158: tree13 Location: 96,-52 Owner: Neutral - Actor134: tree14 + Actor159: tree14 Location: 97,-54 Owner: Neutral - Actor135: tree15 + Actor160: tree15 Location: 100,-52 Owner: Neutral - Actor136: tree16 + Actor161: tree16 Location: 105,-50 Owner: Neutral - Actor137: tree17 + Actor162: tree17 Location: 98,-50 Owner: Neutral - Actor138: tree18 + Actor163: tree18 Location: 96,-48 Owner: Neutral - Actor139: tree19 + Actor164: tree19 Location: 97,-43 Owner: Neutral - Actor140: tree20 + Actor165: tree20 Location: 102,-46 Owner: Neutral - Actor141: tree21 + Actor166: tree21 Location: 102,-43 Owner: Neutral - Actor142: tree22 + Actor167: tree22 Location: 100,-27 Owner: Neutral - Actor143: tree23 + Actor168: tree23 Location: 100,-26 Owner: Neutral - Actor144: tree24 + Actor169: tree24 Location: 102,-25 Owner: Neutral - Actor145: tree25 + Actor170: tree25 Location: 121,-15 Owner: Neutral - Actor146: tree13 + Actor171: tree13 Location: 93,-25 Owner: Neutral - Actor147: tree14 + Actor172: tree14 Location: 95,-24 Owner: Neutral - Actor148: tree15 + Actor173: tree15 Location: 94,-23 Owner: Neutral - Actor149: tree16 + Actor174: tree16 Location: 100,4 Owner: Neutral - Actor150: tree17 + Actor175: tree17 Location: 101,5 Owner: Neutral - Actor151: tree18 + Actor176: tree18 Location: 101,-3 Owner: Neutral - Actor152: tree19 + Actor177: tree19 Location: 109,21 Owner: Neutral - Actor153: tree20 + Actor178: tree20 Location: 109,22 Owner: Neutral - Actor154: tree21 + Actor179: tree21 Location: 109,28 Owner: Neutral - Actor155: tree22 + Actor180: tree22 Location: 108,26 Owner: Neutral - Actor156: tree23 + Actor181: tree23 Location: 113,17 Owner: Neutral - Actor157: tree24 + Actor182: tree24 Location: 101,26 Owner: Neutral - Actor158: tree25 + Actor183: tree25 Location: 102,28 Owner: Neutral - Actor159: tree13 + Actor184: tree13 Location: 77,16 Owner: Neutral - Actor160: tree14 + Actor185: tree14 Location: 84,23 Owner: Neutral - Actor161: tree15 + Actor186: tree15 Location: 88,17 Owner: Neutral - Actor162: tree15 + Actor187: tree15 Location: 69,16 Owner: Neutral - Actor163: tree16 + Actor188: tree16 Location: 69,18 Owner: Neutral - Actor164: tree17 + Actor189: tree17 Location: 72,23 Owner: Neutral - Actor165: tree18 + Actor190: tree18 Location: 70,23 Owner: Neutral - Actor166: tree19 + Actor191: tree19 Location: 71,21 Owner: Neutral - Actor167: tree20 + Actor192: tree20 Location: 56,-5 Owner: Neutral - Actor168: tree21 + Actor193: tree21 Location: 59,18 Owner: Neutral - Actor169: tree22 + Actor194: tree22 Location: 61,20 Owner: Neutral - Actor170: tree13 + Actor195: tree13 Location: 57,10 Owner: Neutral - Actor171: tree14 + Actor196: tree14 Location: 52,17 Owner: Neutral - Actor172: tree14 + Actor197: tree14 Location: 72,44 Owner: Neutral - Actor173: tree15 + Actor198: tree15 Location: 74,44 Owner: Neutral - Actor174: tree16 + Actor199: tree16 Location: 81,53 Owner: Neutral - Actor175: tree17 + Actor200: tree17 Location: 82,55 Owner: Neutral - Actor176: tree18 + Actor201: tree18 Location: 84,55 Owner: Neutral - Actor177: tree19 + Actor202: tree19 Location: 62,46 Owner: Neutral - Actor178: tree20 + Actor203: tree20 Location: 64,45 Owner: Neutral - Actor179: tree21 + Actor204: tree21 Location: 62,43 Owner: Neutral - Actor180: tree14 + Actor205: tree14 Location: 61,44 Owner: Neutral - Actor181: tree15 + Actor206: tree15 Location: 61,47 Owner: Neutral - Actor182: tree15 + Actor207: tree15 Location: 62,57 Owner: Neutral - Actor183: tree16 + Actor208: tree16 Location: 63,56 Owner: Neutral - Actor184: tree17 + Actor209: tree17 Location: 64,58 Owner: Neutral - Actor185: tree18 + Actor210: tree18 Location: 65,58 Owner: Neutral - Actor186: tree19 + Actor211: tree19 Location: 65,56 Owner: Neutral - Actor187: tree19 + Actor212: tree19 Location: 44,4 Owner: Neutral - Actor188: tree20 + Actor213: tree20 Location: 45,3 Owner: Neutral - Actor189: tree21 + Actor214: tree21 Location: 43,7 Owner: Neutral - Actor190: tree15 + Actor215: tree15 Location: 43,6 Owner: Neutral - Actor191: tree01 + Actor216: tree01 Location: 73,-45 Owner: Neutral - Actor192: tree03 + Actor217: tree03 Location: 75,-44 Owner: Neutral - Actor193: tree04 + Actor218: tree04 Location: 62,-38 Owner: Neutral - Actor194: tree04 + Actor219: tree04 Location: 38,-5 Owner: Neutral - Actor195: tree05 + Actor220: tree05 Location: 41,-16 Owner: Neutral - Actor196: tree06 + Actor221: tree06 Location: 36,-13 Owner: Neutral - Actor197: tree06 + Actor222: tree06 Location: 81,29 Owner: Neutral - Actor198: tree07 + Actor223: tree07 Location: 76,30 Owner: Neutral - Actor199: tree08 + Actor224: tree08 Location: 83,43 Owner: Neutral - Actor200: tree09 + Actor225: tree09 Location: 85,43 Owner: Neutral - Actor201: tree10 + Actor226: tree10 Location: 90,35 Owner: Neutral - Actor202: tree10 + Actor227: tree10 Location: 123,-3 Owner: Neutral - Actor203: tree11 + Actor228: tree11 Location: 124,-2 Owner: Neutral - Actor204: tree12 + Actor229: tree12 Location: 122,5 Owner: Neutral - Actor205: tree13 + Actor230: tree13 Location: 122,4 Owner: Neutral - Actor206: tree13 + Actor231: tree13 Location: 112,12 Owner: Neutral - Actor207: tree14 + Actor232: tree14 Location: 111,10 Owner: Neutral - Actor208: tree07 + Actor233: tree07 Location: 113,11 Owner: Neutral - Actor209: tree08 + Actor234: tree08 Location: 116,-5 Owner: Neutral - Actor210: mpspawn + Actor235: mpspawn Location: 44,27 Owner: Neutral - Actor211: mpspawn + Actor236: mpspawn Location: 106,-34 Owner: Neutral - Actor212: waypoint + Actor237: waypoint Location: 73,0 Owner: Neutral - Actor213: waypoint + Actor238: waypoint Location: 81,-3 Owner: Neutral - Actor214: waypoint + Actor239: waypoint Location: 83,3 Owner: Neutral - Actor215: waypoint + Actor240: waypoint Location: 85,-5 Owner: Neutral - Actor216: waypoint + Actor241: waypoint Location: 90,5 Owner: Neutral - Actor217: waypoint + Actor242: waypoint Location: 78,-2 Owner: Neutral - Actor218: waypoint + Actor243: waypoint Location: 78,-2 Owner: Neutral - Actor219: tuntop03 + Actor244: bigblue + Location: 69,-40 + Owner: Neutral + Actor245: bigblue + Location: 42,-9 + Owner: Neutral + Actor246: bigblue + Location: 61,2 + Owner: Neutral + Actor247: bigblue + Location: 98,-14 + Owner: Neutral + Actor248: bigblue + Location: 95,22 + Owner: Neutral + Actor249: bigblue + Location: 117,1 + Owner: Neutral + Actor250: bigblue + Location: 83,36 + Owner: Neutral + Actor251: tuntop03 Owner: Neutral Location: 68,-4 - Actor220: tuntop04 + Actor252: tuntop04 Owner: Neutral Location: 74,-12 - Actor221: tuntop04 + Actor253: tuntop04 Owner: Neutral Location: 108,-7 - Actor222: tuntop03 + Actor254: tuntop03 Owner: Neutral Location: 109,5 - Actor224: tuntop04 + Actor255: tuntop04 Owner: Neutral Location: 88,28 - Actor225: tuntop03 + Actor256: tuntop03 Owner: Neutral Location: 73,35 - Actor227: tuntop01 + Actor257: tuntop01 Owner: Neutral Location: 60,35 - Actor228: tuntop04 + Actor258: tuntop04 Owner: Neutral Location: 43,13 - Actor233: tuntop03 + Actor259: tuntop03 Owner: Neutral Location: 93,-36 - Actor237: tuntop02 + Actor260: tuntop02 Owner: Neutral Location: 108,-16 - Actor238: tuntop01 + Actor261: tuntop01 Owner: Neutral Location: 77,-36 - Actor239: tuntop01 + Actor262: tuntop01 Owner: Neutral Location: 95,5 - Actor240: tuntop02 + Actor263: tuntop02 Owner: Neutral Location: 73,-28 - Actor234: tuntop02 + Actor264: tuntop02 Owner: Neutral Location: 43,-2 - Actor236: tuntop01 + Actor265: tuntop01 Owner: Neutral Location: 51,-4 - Actor235: tuntop02 + Actor266: tuntop02 Owner: Neutral Location: 88,13 - Actor246: bigblue - Owner: Neutral - Location: 98,-14 - Actor248: bigblue - Owner: Neutral - Location: 83,36 - Actor243: bigblue - Owner: Neutral - Location: 95,22 - Actor242: bigblue - Owner: Neutral - Location: 61,2 - Actor241: bigblue - Owner: Neutral - Location: 41,-10 - Actor244: bigblue - Owner: Neutral - Location: 69,-40 - Actor245: bigblue - Owner: Neutral - Location: 117,1 Rules: World: - GlobalLightingPaletteEffect: - Ambient: 0.62 TerrainTunnelLayer: TerrainTunnel@a: Location: 60, 35 @@ -927,3 +971,27 @@ Footprint: o_______________o o_______________o o_______________o Height: 2 TerrainType: Clear + ^BaseWorld: + TerrainLighting: + Intensity: 0.62 + INGRNLMP: + TerrainLightSource: + Range: 7c832 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.7 + BlueTint: 0.01 + INREDLMP: + TerrainLightSource: + Range: 9c784 + Intensity: 0.01 + RedTint: 1.5 + GreenTint: 0.01 + BlueTint: 0.01 + INBLULMP: + TerrainLightSource: + Range: 9c784 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.01 + BlueTint: 0.7 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/sunstroke/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/sunstroke/map.png differ diff -Nru openra-20200503/mods/ts/maps/sunstroke/map.yaml openra-20210321/mods/ts/maps/sunstroke/map.yaml --- openra-20200503/mods/ts/maps/sunstroke/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/sunstroke/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -52,2527 +52,2576 @@ Actor0: city01 Location: 64,1 Owner: Neutral - Health: 100 - Facing: 160 + Facing: 640 Actor1: ca0001 Location: 63,6 Owner: Neutral - Health: 100 - Facing: 160 + Facing: 640 Actor2: city08 Location: 60,1 Owner: Neutral - Health: 100 - Facing: 160 + Facing: 640 Actor3: ca0011 Location: 68,6 Owner: Neutral - Health: 100 - Facing: 160 + Facing: 640 Actor4: ca0012 Location: 70,5 Owner: Neutral - Health: 100 - Facing: 160 + Facing: 640 Actor5: ca0014 Location: 54,5 Owner: Neutral - Health: 100 - Facing: 160 + Facing: 640 Actor6: ca0008 Location: 56,4 Owner: Neutral - Health: 100 - Facing: 160 + Facing: 640 Actor7: ca0009 Location: 58,4 Owner: Neutral Health: 23 - Facing: 160 + Facing: 640 Actor8: ca0015 Location: 59,3 Owner: Neutral - Health: 100 - Facing: 160 + Facing: 640 Actor9: ca0011 Location: 71,14 Owner: Neutral - Health: 100 - Facing: 160 + Facing: 640 Actor10: ca0011 Location: 73,14 Owner: Neutral Health: 28 - Facing: 160 + Facing: 640 Actor11: ca0013 Location: 74,16 Owner: Neutral Health: 31 - Facing: 160 + Facing: 640 Actor12: city09 Location: 143,17 Owner: Neutral Health: 38 - Facing: 160 - #Actor13: cabhut - # Location: 138,-12 - # Owner: Neutral - # Health: 100 - # Facing: 160 - #Actor14: cabhut - # Location: 63,-16 - # Owner: Neutral - # Health: 100 - # Facing: 160 - Actor15: ca0011 + Facing: 640 + Actor13: ingrnlmp + Location: 124,13 + Owner: Neutral + Facing: 640 + Actor14: inredlmp + Location: 136,19 + Owner: Neutral + Facing: 640 + Actor15: cabhut + Location: 138,-12 + Owner: Neutral + Facing: 640 + Actor16: cabhut + Location: 63,-16 + Owner: Neutral + Facing: 640 + Actor17: inredlmp + Location: 87,67 + Owner: Neutral + Facing: 640 + Actor18: inredlmp + Location: 67,52 + Owner: Neutral + Facing: 640 + Actor19: inblulmp + Location: 77,70 + Owner: Neutral + Facing: 640 + Actor20: inblulmp + Location: 86,51 + Owner: Neutral + Facing: 640 + Actor21: inblulmp + Location: 103,60 + Owner: Neutral + Facing: 640 + Actor22: grenlamp + Location: 75,58 + Owner: Neutral + Facing: 640 + Actor23: ca0011 Location: 110,26 Owner: Neutral Health: 21 - Facing: 160 - Actor16: ca0011 + Facing: 640 + Actor24: ca0011 Location: 110,23 Owner: Neutral Health: 92 - Facing: 160 - Actor17: ca0018 + Facing: 640 + Actor25: ca0018 Location: 106,26 Owner: Neutral Health: 25 - Facing: 160 - Actor18: ca0019 + Facing: 640 + Actor26: ca0019 Location: 108,26 Owner: Neutral - Health: 100 - Facing: 160 - Actor19: ca0017 + Facing: 640 + Actor27: ca0017 Location: 108,25 Owner: Neutral Health: 23 - Facing: 160 - Actor20: ca0013 + Facing: 640 + Actor28: ca0013 Location: 110,25 Owner: Neutral - Health: 100 - Facing: 160 - Actor21: bboard14 + Facing: 640 + Actor29: bboard14 Location: 59,-15 Owner: Neutral Health: 28 - Facing: 160 - Actor22: ca0016 + Facing: 640 + Actor30: ca0016 Location: 63,-14 Owner: Neutral Health: 30 - Facing: 160 - Actor23: ca0003 + Facing: 640 + Actor31: ca0003 Location: 64,-12 Owner: Neutral Health: 31 - Facing: 160 - Actor24: city09 + Facing: 640 + Actor32: city09 Location: 42,13 Owner: Neutral - Health: 100 - Facing: 160 - Actor25: ca0010 + Facing: 640 + Actor33: ca0010 Location: 45,11 Owner: Neutral Health: 28 - Facing: 160 - Actor26: ca0004 + Facing: 640 + Actor34: ca0004 Location: 44,15 Owner: Neutral - Health: 100 - Facing: 160 - Actor27: ca0005 + Facing: 640 + Actor35: ca0005 Location: 46,15 Owner: Neutral Health: 25 - Facing: 160 - Actor28: ca0002 + Facing: 640 + Actor36: ca0002 Location: 49,18 Owner: Neutral Health: 28 - Facing: 160 - Actor29: tstlamp + Facing: 640 + Actor37: tstlamp Location: 60,7 Owner: Neutral Health: 29 - Facing: 160 - Actor30: city19 + Facing: 640 + Actor38: city19 Location: 142,11 Owner: Neutral - Health: 100 - Facing: 160 - Actor31: city20 + Facing: 640 + Actor39: city20 Location: 142,13 Owner: Neutral Health: 28 - Facing: 160 - Actor32: city22 + Facing: 640 + Actor40: city22 Location: 111,10 Owner: Neutral - Health: 100 - Facing: 160 - Actor33: ca0001 + Facing: 640 + Actor41: ca0001 Location: 111,6 Owner: Neutral - Health: 100 - Facing: 160 - Actor34: city09 + Facing: 640 + Actor42: city09 Location: 136,-48 Owner: Neutral Health: 32 - Facing: 160 - Actor35: city05 + Facing: 640 + Actor43: city05 Location: 108,15 Owner: Neutral Health: 16 - Facing: 160 - Actor36: ca0011 + Facing: 640 + Actor44: ca0011 Location: 107,6 Owner: Neutral - Health: 100 - Facing: 160 - Actor37: ca0013 + Facing: 640 + Actor45: ca0013 Location: 107,8 Owner: Neutral - Health: 100 - Facing: 160 - Actor38: bboard12 + Facing: 640 + Actor46: inyelwlamp + Location: 120,-9 + Owner: Neutral + Facing: 640 + Actor47: inyelwlamp + Location: 86,-18 + Owner: Neutral + Facing: 640 + Actor48: inredlmp + Location: 56,17 + Owner: Neutral + Facing: 640 + Actor49: grenlamp + Location: 70,14 + Owner: Neutral + Facing: 640 + Actor50: bboard12 Location: 53,20 Owner: Neutral Health: 29 - Facing: 160 - Actor39: bboard16 + Facing: 640 + Actor51: inredlmp + Location: 55,-10 + Owner: Neutral + Facing: 640 + Actor52: bboard16 Location: 63,9 Owner: Neutral - Health: 100 - Facing: 160 - Actor40: city10 + Facing: 640 + Actor53: grenlamp + Location: 98,-86 + Owner: Neutral + Facing: 640 + Actor54: inredlmp + Location: 110,-84 + Owner: Neutral + Facing: 640 + Actor55: inredlmp + Location: 124,-94 + Owner: Neutral + Facing: 640 + Actor56: grenlamp + Location: 116,-99 + Owner: Neutral + Facing: 640 + Actor57: ingrnlmp + Location: 86,-35 + Owner: Neutral + Facing: 640 + Actor58: inredlmp + Location: 65,-43 + Owner: Neutral + Facing: 640 + Actor59: city10 Location: 51,-34 Owner: Neutral - Health: 100 - Facing: 160 - Actor41: city15 + Facing: 640 + Actor60: city15 Location: 50,-40 Owner: Neutral - Health: 100 - Facing: 160 - Actor42: city02 + Facing: 640 + Actor61: city02 Location: 58,-37 Owner: Neutral Health: 31 - Facing: 160 - Actor43: city08 + Facing: 640 + Actor62: city08 Location: 55,-33 Owner: Neutral - Health: 100 - Facing: 160 - Actor44: ca0003 + Facing: 640 + Actor63: ca0003 Location: 54,-37 Owner: Neutral - Health: 100 - Facing: 160 - Actor45: ca0017 + Facing: 640 + Actor64: ca0017 Location: 48,-35 Owner: Neutral - Health: 100 - Facing: 160 - Actor46: ca0018 + Facing: 640 + Actor65: ca0018 Location: 48,-34 Owner: Neutral - Health: 100 - Facing: 160 - Actor47: ca0021 + Facing: 640 + Actor66: ca0021 Location: 48,-37 Owner: Neutral - Health: 100 - Facing: 160 - Actor48: ca0015 + Facing: 640 + Actor67: ca0015 Location: 59,-30 Owner: Neutral Health: 39 - Facing: 160 - Actor49: ca0016 + Facing: 640 + Actor68: ca0016 Location: 58,-29 Owner: Neutral - Health: 100 - Facing: 160 - Actor50: ca0011 + Facing: 640 + Actor69: ca0011 Location: 51,-38 Owner: Neutral - Health: 100 - Facing: 160 - Actor51: ca0009 + Facing: 640 + Actor70: ca0009 Location: 52,-44 Owner: Neutral - Health: 100 - Facing: 160 - Actor52: ca0014 + Facing: 640 + Actor71: ca0014 Location: 57,-42 Owner: Neutral Health: 28 - Facing: 160 - Actor53: ca0005 + Facing: 640 + Actor72: ca0005 Location: 55,-44 Owner: Neutral Health: 32 - Facing: 160 - Actor54: city12 + Facing: 640 + Actor73: city12 Location: 63,-35 Owner: Neutral - Health: 100 - Facing: 160 - Actor55: city13 + Facing: 640 + Actor74: city13 Location: 66,-35 Owner: Neutral Health: 30 - Facing: 160 - Actor56: city14 + Facing: 640 + Actor75: city14 Location: 63,-39 Owner: Neutral Health: 28 - Facing: 160 - Actor57: tstlamp + Facing: 640 + Actor76: tstlamp Location: 61,-37 Owner: Neutral - Health: 100 - Facing: 160 - Actor58: bboard07 + Facing: 640 + Actor77: bboard07 Location: 53,-32 Owner: Neutral - Health: 100 - Facing: 160 - Actor59: ca0010 + Facing: 640 + Actor78: inblulmp + Location: 55,-38 + Owner: Neutral + Facing: 640 + Actor79: inredlmp + Location: 142,-18 + Owner: Neutral + Facing: 640 + Actor80: inblulmp + Location: 43,31 + Owner: Neutral + Facing: 640 + Actor81: inredlmp + Location: 140,-45 + Owner: Neutral + Facing: 640 + Actor82: grenlamp + Location: 144,-58 + Owner: Neutral + Facing: 640 + Actor83: inblulmp + Location: 154,-37 + Owner: Neutral + Facing: 640 + Actor84: ca0010 Location: 139,-41 Owner: Neutral Health: 30 - Facing: 160 - Actor60: ca0014 + Facing: 640 + Actor85: ca0014 Location: 136,-41 Owner: Neutral Health: 24 - Facing: 160 - Actor61: ca0005 + Facing: 640 + Actor86: ca0005 Location: 28,-6 Owner: Neutral - Health: 100 - Facing: 160 - Actor62: ca0006 + Facing: 640 + Actor87: ca0006 Location: 30,-6 Owner: Neutral Health: 25 - Facing: 160 - Actor63: ca0014 + Facing: 640 + Actor88: ca0014 Location: 31,1 Owner: Neutral Health: 23 - Facing: 160 - Actor64: ca0013 + Facing: 640 + Actor89: ca0013 Location: 30,3 Owner: Neutral Health: 22 - Facing: 160 - Actor65: gaoldcc3 + Facing: 640 + Actor90: gaoldcc3 Location: 74,-6 Owner: CreepsGDIBase Health: 21 - Facing: 160 - Actor66: gaoldcc1 + Facing: 640 + Actor91: gaoldcc1 Location: 72,-3 Owner: CreepsGDIBase Health: 39 - Facing: 160 - Actor67: tstlamp + Facing: 640 + Actor92: tstlamp Location: 76,-3 Owner: Neutral Health: 24 - Facing: 160 - Actor68: ca0012 + Facing: 640 + Actor93: ca0012 Location: 70,-40 Owner: Neutral Health: 22 - Facing: 160 - Actor69: ca0006 + Facing: 640 + Actor94: ca0006 Location: 71,-42 Owner: Neutral Health: 29 - Facing: 160 - Actor70: ca0012 + Facing: 640 + Actor95: ca0012 Location: 72,-40 Owner: Neutral - Health: 100 - Facing: 160 - Actor71: cacrsh04 + Facing: 640 + Actor96: cacrsh04 Location: 144,-2 Owner: Neutral - Health: 100 - Facing: 160 - Actor72: ca0009 + Facing: 640 + Actor97: ca0009 Location: 80,-56 Owner: Neutral Health: 28 - Facing: 160 - Actor73: ca0015 + Facing: 640 + Actor98: ca0015 Location: 82,-55 Owner: Neutral - Health: 100 - Facing: 160 - Actor74: ca0007 + Facing: 640 + Actor99: ca0007 Location: 138,-53 Owner: Neutral Health: 19 - Facing: 160 - Actor75: ca0015 + Facing: 640 + Actor100: ca0015 Location: 137,-54 Owner: Neutral - Health: 100 - Facing: 160 - Actor76: city03 + Facing: 640 + Actor101: city03 Location: 174,-14 Owner: Neutral Health: 30 - Facing: 160 - Actor77: city06 + Facing: 640 + Actor102: city06 Location: 173,-11 Owner: Neutral - Health: 100 - Facing: 160 - Actor78: tstlamp + Facing: 640 + Actor103: tstlamp Location: 122,43 Owner: Neutral Health: 31 - Facing: 160 - Actor79: ca0003 + Facing: 640 + Actor104: ca0003 Location: 124,42 Owner: Neutral Health: 21 - Facing: 160 - Actor80: ca0009 + Facing: 640 + Actor105: ca0009 Location: 121,45 Owner: Neutral Health: 26 - Facing: 160 - Actor81: gaoldcc2 + Facing: 640 + Actor106: gaoldcc2 Location: 122,-40 Owner: CreepsNodBase - Health: 100 - Facing: 160 - Actor82: tstlamp + Facing: 640 + Actor107: inblulmp + Location: 120,-39 + Owner: Neutral + Facing: 640 + Actor108: tstlamp Location: 104,53 Owner: Neutral Health: 31 - Facing: 160 - Actor83: city18 + Facing: 640 + Actor109: city18 Location: 114,53 Owner: Neutral Health: 24 - Facing: 160 - Actor84: city15 + Facing: 640 + Actor110: city15 Location: 113,45 Owner: Neutral Health: 74 - Facing: 160 - Actor85: city08 + Facing: 640 + Actor111: city08 Location: 111,50 Owner: Neutral - Health: 100 - Facing: 160 - Actor86: ca0011 + Facing: 640 + Actor112: ca0011 Location: 114,48 Owner: Neutral - Health: 100 - Facing: 160 - Actor87: ca0016 + Facing: 640 + Actor113: ca0016 Location: 109,52 Owner: Neutral Health: 25 - Facing: 160 - Actor88: ca0003 + Facing: 640 + Actor114: ca0003 Location: 112,20 Owner: Neutral Health: 21 - Facing: 160 - Actor89: city02 + Facing: 640 + Actor115: city02 Location: 179,-14 Owner: Neutral Health: 28 - Facing: 160 - Actor90: ca0001 + Facing: 640 + Actor116: ca0001 Location: 170,-10 Owner: Neutral - Health: 100 - Facing: 160 - Actor91: city22 + Facing: 640 + Actor117: city22 Location: 175,-24 Owner: Neutral Health: 26 - Facing: 160 - Actor92: ca0008 + Facing: 640 + Actor118: ca0008 Location: 173,-20 Owner: Neutral - Health: 100 - Facing: 160 - Actor93: ca0009 + Facing: 640 + Actor119: ca0009 Location: 175,-20 Owner: Neutral Health: 23 - Facing: 160 - Actor94: ca0016 + Facing: 640 + Actor120: ca0016 Location: 171,-23 Owner: Neutral Health: 22 - Facing: 160 - Actor95: bboard07 + Facing: 640 + Actor121: bboard07 Location: 179,-18 Owner: Neutral - Health: 100 - Facing: 160 - Actor96: tstlamp + Facing: 640 + Actor122: tstlamp Location: 176,-16 Owner: Neutral Health: 70 - Facing: 160 - Actor97: city09 + Facing: 640 + Actor123: city09 Location: 181,-19 Owner: Neutral Health: 25 - Facing: 160 - Actor98: city14 + Facing: 640 + Actor124: city14 Location: 185,-18 Owner: Neutral Health: 22 - Facing: 160 - Actor99: city11 + Facing: 640 + Actor125: city11 Location: 187,-20 Owner: Neutral Health: 24 - Facing: 160 - Actor100: city10 + Facing: 640 + Actor126: city10 Location: 150,-23 Owner: Neutral Health: 25 - Facing: 160 - Actor101: ca0013 + Facing: 640 + Actor127: ca0013 Location: 152,-19 Owner: Neutral - Health: 100 - Facing: 160 - Actor102: ca0012 + Facing: 640 + Actor128: ca0012 Location: 136,-15 Owner: Neutral Health: 28 - Facing: 160 - Actor103: ca0014 + Facing: 640 + Actor129: ca0014 Location: 152,-14 Owner: Neutral Health: 24 - Facing: 160 - Actor104: ca0014 + Facing: 640 + Actor130: ca0014 Location: 172,-18 Owner: Neutral - Health: 100 - Facing: 160 - Actor105: city08 + Facing: 640 + Actor131: city08 Location: 101,51 Owner: Neutral - Health: 100 - Facing: 160 - Actor106: ca0002 + Facing: 640 + Actor132: ca0002 Location: 105,54 Owner: Neutral - Health: 100 - Facing: 160 - Actor107: ca0001 + Facing: 640 + Actor133: inblulmp + Location: 75,-3 + Owner: Neutral + Facing: 640 + Actor134: ca0001 Location: 110,-75 Owner: Neutral Health: 24 - Facing: 160 - Actor108: city04 + Facing: 640 + Actor135: city04 Location: 180,-37 Owner: Neutral Health: 25 - Facing: 160 - Actor109: bboard11 + Facing: 640 + Actor136: bboard11 Location: 186,-36 Owner: Neutral - Health: 100 - Facing: 160 - Actor110: tstlamp + Facing: 640 + Actor137: tstlamp Location: 184,-36 Owner: Neutral Health: 24 - Facing: 160 - Actor111: cacrsh02 + Facing: 640 + Actor138: inblulmp + Location: 162,-17 + Owner: Neutral + Facing: 640 + Actor139: inblulmp + Location: 194,-31 + Owner: Neutral + Facing: 640 + Actor140: cacrsh02 Location: 178,-25 Owner: Neutral - Health: 100 - Facing: 160 - Actor112: cacrsh05 + Facing: 640 + Actor141: cacrsh05 Location: 174,-39 Owner: Neutral - Health: 100 - Facing: 160 - Actor113: tstlamp + Facing: 640 + Actor142: tstlamp Location: 83,-57 Owner: Neutral Health: 26 - Facing: 160 - Actor114: tstlamp + Facing: 640 + Actor143: tstlamp Location: 61,-39 Owner: Neutral - Health: 100 - Facing: 160 - Actor115: tstlamp + Facing: 640 + Actor144: tstlamp Location: 111,22 Owner: Neutral - Health: 100 - Facing: 160 - Actor116: bboard13 + Facing: 640 + Actor145: bboard13 Location: 142,21 Owner: Neutral Health: 61 - Facing: 160 - Actor117: cacrsh01 + Facing: 640 + Actor146: cacrsh01 Location: 94,35 Owner: Neutral - Health: 100 - Facing: 160 - Actor118: cacrsh03 + Facing: 640 + Actor147: cacrsh03 Location: 138,25 Owner: Neutral - Health: 100 - Facing: 160 - Actor119: cacrsh05 + Facing: 640 + Actor148: cacrsh05 Location: 101,29 Owner: Neutral - Health: 100 - Facing: 160 - Actor120: cacrsh02 + Facing: 640 + Actor149: cacrsh02 Location: 96,30 Owner: Neutral - Health: 100 - Facing: 160 - Actor121: cacrsh03 + Facing: 640 + Actor150: cacrsh03 Location: 32,5 Owner: Neutral - Health: 100 - Facing: 160 - Actor122: cacrsh05 + Facing: 640 + Actor151: cacrsh05 Location: 38,-2 Owner: Neutral - Health: 100 - Facing: 160 - Actor123: cacrsh04 + Facing: 640 + Actor152: cacrsh04 Location: 33,-13 Owner: Neutral - Health: 100 - Facing: 160 - Actor124: cacrsh03 + Facing: 640 + Actor153: cacrsh03 Location: 99,-74 Owner: Neutral - Health: 100 - Facing: 160 - Actor125: cacrsh02 + Facing: 640 + Actor154: cacrsh02 Location: 104,-68 Owner: Neutral - Health: 100 - Facing: 160 - Actor126: cacrsh01 + Facing: 640 + Actor155: inblulmp + Location: 151,0 + Owner: Neutral + Facing: 640 + Actor156: cacrsh01 Location: 160,-60 Owner: Neutral - Health: 100 - Facing: 160 - Actor127: pick + Facing: 640 + Actor157: inblulmp + Location: 110,11 + Owner: Neutral + Facing: 640 + Actor158: inblulmp + Location: 92,16 + Owner: Neutral + Facing: 640 + Actor159: inblulmp + Location: 66,28 + Owner: Neutral + Facing: 640 + Actor160: inblulmp + Location: 23,12 + Owner: Neutral + Facing: 640 + Actor161: inblulmp + Location: 25,-14 + Owner: Neutral + Facing: 640 + Actor162: ingrnlmp + Location: 118,-59 + Owner: Neutral + Facing: 640 + Actor163: ingrnlmp + Location: 86,36 + Owner: Neutral + Facing: 640 + Actor164: grenlamp + Location: 39,-21 + Owner: Neutral + Facing: 640 + Actor165: pick Location: 64,3 Owner: Neutral - Health: 100 - Facing: 32 - Actor128: truckb + Facing: 128 + Actor166: truckb Location: 64,5 Owner: Neutral - Health: 100 - Facing: 0 - Actor129: car + Facing: 256 + Actor167: car Location: 61,4 Owner: Neutral - Health: 100 - Facing: 64 - Actor130: trucka + Facing: 0 + Actor168: trucka Location: 44,12 Owner: Neutral - Health: 100 - Facing: 64 - Actor131: car + Facing: 0 + Actor169: car Location: 53,-34 Owner: Neutral - Health: 100 - Facing: 0 - Actor132: trucka + Facing: 256 + Actor170: trucka Location: 53,-41 Owner: Neutral - Health: 100 - Facing: 160 - Actor133: pick + Facing: 640 + Actor171: pick Location: 62,-30 Owner: Neutral Health: 19 - Facing: 128 - Actor134: pick + Facing: 768 + Actor172: pick Location: 138,-39 Owner: Neutral Health: 23 - Facing: 128 - Actor135: car + Facing: 768 + Actor173: car Location: 29,-3 Owner: Neutral - Health: 100 - Facing: 128 - Actor136: trucka + Facing: 768 + Actor174: trucka Location: 32,2 Owner: Neutral Health: 22 - Facing: 32 - Actor137: 4tnk + Facing: 128 + Actor175: 4tnk Location: 74,-4 - Owner: CreepsGDIBase + Owner: Neutral Health: 27 - Facing: 0 - Actor138: pick + Facing: 256 + Actor176: pick Location: 182,-35 Owner: Neutral - Health: 100 - Facing: 160 - Actor139: car + Facing: 640 + Actor177: car Location: 180,-17 Owner: Neutral - Health: 100 - Facing: 192 - Actor140: trucka + Facing: 512 + Actor178: trucka Location: 171,-12 Owner: Neutral - Health: 100 - Facing: 128 - Actor141: truckb + Facing: 768 + Actor179: truckb Location: 105,53 Owner: Neutral - Health: 100 - Facing: 160 - Actor142: pick + Facing: 640 + Actor180: pick Location: 115,49 Owner: Neutral - Health: 100 - Facing: 128 - Actor143: car + Facing: 768 + Actor181: car Location: 115,26 Owner: Neutral - Health: 100 - Facing: 224 - Actor144: tree23 + Facing: 384 + Actor182: tree23 Location: 119,-98 Owner: Neutral - Actor145: tibtre03 + Actor183: tibtre03 Location: 124,-94 Owner: Neutral - Actor146: tree24 + Actor184: tree24 Location: 131,-91 Owner: Neutral - Actor147: tree21 + Actor185: tree21 Location: 124,-86 Owner: Neutral - Actor148: tibtre02 + Actor186: tibtre02 Location: 110,-84 Owner: Neutral - Actor149: tree22 + Actor187: tree22 Location: 103,-83 Owner: Neutral - Actor150: tree25 + Actor188: tree25 Location: 130,-80 Owner: Neutral - Actor151: tree15 + Actor189: tree15 Location: 111,-78 Owner: Neutral - Actor152: tree14 + Actor190: tree14 Location: 97,-77 Owner: Neutral - Actor153: tree11 + Actor191: tree11 Location: 104,-76 Owner: Neutral - Actor154: tree12 + Actor192: tree12 Location: 109,-76 Owner: Neutral - Actor155: tree23 + Actor193: tree23 Location: 127,-76 Owner: Neutral - Actor156: tree17 + Actor194: tree17 Location: 113,-74 Owner: Neutral - Actor157: tree23 + Actor195: tree23 Location: 122,-74 Owner: Neutral - Actor158: tree24 + Actor196: tree24 Location: 94,-71 Owner: Neutral - Actor159: tree16 + Actor197: tree16 Location: 99,-71 Owner: Neutral - Actor160: tree24 + Actor198: tree24 Location: 133,-71 Owner: Neutral - Actor161: tree18 + Actor199: tree18 Location: 150,-71 Owner: Neutral - Actor162: tree20 + Actor200: tree20 Location: 102,-70 Owner: Neutral - Actor163: tree13 + Actor201: tree13 Location: 141,-70 Owner: Neutral - Actor164: tree16 + Actor202: tree16 Location: 146,-70 Owner: Neutral - Actor165: tree23 + Actor203: tree23 Location: 89,-68 Owner: Neutral - Actor166: tree23 + Actor204: tree23 Location: 107,-68 Owner: Neutral - Actor167: tree14 + Actor205: tree14 Location: 124,-68 Owner: Neutral - Actor168: tree22 + Actor206: tree22 Location: 129,-68 Owner: Neutral - Actor169: tree22 + Actor207: tree22 Location: 113,-67 Owner: Neutral - Actor170: tree25 + Actor208: tree25 Location: 94,-66 Owner: Neutral - Actor171: tree20 + Actor209: tree20 Location: 88,-65 Owner: Neutral - Actor172: tree11 + Actor210: tree11 Location: 133,-65 Owner: Neutral - Actor173: tree14 + Actor211: tree14 Location: 142,-65 Owner: Neutral - Actor174: tree17 + Actor212: tree17 Location: 145,-65 Owner: Neutral - Actor175: tree18 + Actor213: tree18 Location: 98,-64 Owner: Neutral - Actor176: tree14 + Actor214: tree14 Location: 104,-64 Owner: Neutral - Actor177: tree18 + Actor215: tree18 Location: 119,-64 Owner: Neutral - Actor178: tree21 + Actor216: tree21 Location: 127,-64 Owner: Neutral - Actor179: tree19 + Actor217: tree19 Location: 155,-64 Owner: Neutral - Actor180: tree19 + Actor218: tree19 Location: 82,-62 Owner: Neutral - Actor181: tree23 + Actor219: tree23 Location: 91,-62 Owner: Neutral - Actor182: tree11 + Actor220: tree11 Location: 96,-62 Owner: Neutral - Actor183: tree24 + Actor221: tree24 Location: 159,-62 Owner: Neutral - Actor184: tree13 + Actor222: tree13 Location: 102,-61 Owner: Neutral - Actor185: tree23 + Actor223: tree23 Location: 149,-61 Owner: Neutral - Actor186: tree24 + Actor224: tree24 Location: 90,-60 Owner: Neutral - Actor187: tree20 + Actor225: tree20 Location: 140,-60 Owner: Neutral - Actor188: tree21 + Actor226: tree21 Location: 80,-59 Owner: Neutral - Actor189: tree22 + Actor227: tree22 Location: 86,-59 Owner: Neutral - Actor190: tree21 + Actor228: tree21 Location: 108,-59 Owner: Neutral - Actor191: tree23 + Actor229: tree23 Location: 72,-58 Owner: Neutral - Actor192: tibtre01 + Actor230: tibtre01 Location: 120,-58 Owner: Neutral - Actor193: tree18 + Actor231: tree18 Location: 159,-58 Owner: Neutral - Actor194: tree16 + Actor232: tree16 Location: 133,-57 Owner: Neutral - Actor195: tree22 + Actor233: tree22 Location: 138,-57 Owner: Neutral - Actor196: tree16 + Actor234: tree16 Location: 163,-57 Owner: Neutral - Actor197: tree18 + Actor235: tree18 Location: 75,-56 Owner: Neutral - Actor198: tree14 + Actor236: tree14 Location: 166,-56 Owner: Neutral - Actor199: tree21 + Actor237: tree21 Location: 126,-55 Owner: Neutral - Actor200: tree18 + Actor238: tree18 Location: 129,-55 Owner: Neutral - Actor201: tree16 + Actor239: tree16 Location: 67,-53 Owner: Neutral - Actor202: tree22 + Actor240: tree22 Location: 106,-53 Owner: Neutral - Actor203: tree15 + Actor241: tree15 Location: 170,-53 Owner: Neutral - Actor204: tree20 + Actor242: tree20 Location: 112,-52 Owner: Neutral - Actor205: tree17 + Actor243: tree17 Location: 72,-51 Owner: Neutral - Actor206: tree21 + Actor244: tree21 Location: 127,-51 Owner: Neutral - Actor207: tree13 + Actor245: tree13 Location: 160,-51 Owner: Neutral - Actor208: tree21 + Actor246: tree21 Location: 62,-50 Owner: Neutral - Actor209: tree22 + Actor247: tree22 Location: 69,-50 Owner: Neutral - Actor210: tree11 + Actor248: tree11 Location: 157,-50 Owner: Neutral - Actor211: tree12 + Actor249: tree12 Location: 164,-50 Owner: Neutral - Actor212: tree17 + Actor250: tree17 Location: 105,-49 Owner: Neutral - Actor213: tree17 + Actor251: tree17 Location: 119,-49 Owner: Neutral - Actor214: tree25 + Actor252: tree25 Location: 142,-49 Owner: Neutral - Actor215: tree22 + Actor253: tree22 Location: 170,-49 Owner: Neutral - Actor216: tree19 + Actor254: tree19 Location: 70,-48 Owner: Neutral - Actor217: tree21 + Actor255: tree21 Location: 109,-48 Owner: Neutral - Actor218: tree19 + Actor256: tree19 Location: 127,-48 Owner: Neutral - Actor219: tree24 + Actor257: tree24 Location: 134,-48 Owner: Neutral - Actor220: tree19 + Actor258: tree19 Location: 171,-47 Owner: Neutral - Actor221: tree17 + Actor259: tree17 Location: 117,-46 Owner: Neutral - Actor222: tree07 + Actor260: tree07 Location: 165,-46 Owner: Neutral - Actor223: tree21 + Actor261: tree21 Location: 176,-46 Owner: Neutral - Actor224: tree24 + Actor262: tree24 Location: 57,-45 Owner: Neutral - Actor225: tree18 + Actor263: tree18 Location: 121,-45 Owner: Neutral - Actor226: tree13 + Actor264: tree13 Location: 124,-45 Owner: Neutral - Actor227: tree24 + Actor265: tree24 Location: 130,-45 Owner: Neutral - Actor228: tree18 + Actor266: tree18 Location: 169,-45 Owner: Neutral - Actor229: tibtre03 + Actor267: tibtre03 Location: 65,-43 Owner: Neutral - Actor230: tree20 + Actor268: tree20 Location: 79,-43 Owner: Neutral - Actor231: tree21 + Actor269: tree21 Location: 90,-43 Owner: Neutral - Actor232: tree15 + Actor270: tree15 Location: 109,-43 Owner: Neutral - Actor233: tree13 + Actor271: tree13 Location: 163,-43 Owner: Neutral - Actor234: tree16 + Actor272: tree16 Location: 170,-43 Owner: Neutral - Actor235: tree20 + Actor273: tree20 Location: 174,-43 Owner: Neutral - Actor236: tree16 + Actor274: tree16 Location: 59,-42 Owner: Neutral - Actor237: tree18 + Actor275: tree18 Location: 104,-42 Owner: Neutral - Actor238: tree04 + Actor276: tree04 Location: 107,-42 Owner: Neutral - Actor239: tree14 + Actor277: tree14 Location: 128,-42 Owner: Neutral - Actor240: tree04 + Actor278: tree04 Location: 166,-42 Owner: Neutral - Actor241: tree14 + Actor279: tree14 Location: 55,-41 Owner: Neutral - Actor242: tree16 + Actor280: tree16 Location: 98,-40 Owner: Neutral - Actor243: tree17 + Actor281: tree17 Location: 102,-40 Owner: Neutral - Actor244: tree12 + Actor282: tree12 Location: 109,-40 Owner: Neutral - Actor245: tree17 + Actor283: tree17 Location: 165,-40 Owner: Neutral - Actor246: tree25 + Actor284: tree25 Location: 65,-39 Owner: Neutral - Actor247: tree11 + Actor285: tree11 Location: 68,-39 Owner: Neutral - Actor248: tree23 + Actor286: tree23 Location: 78,-39 Owner: Neutral - Actor249: tree05 + Actor287: tree05 Location: 105,-39 Owner: Neutral - Actor250: tree12 + Actor288: tree12 Location: 125,-39 Owner: Neutral - Actor251: tree06 + Actor289: tree06 Location: 163,-39 Owner: Neutral - Actor252: tree13 + Actor290: tree13 Location: 74,-38 Owner: Neutral - Actor253: tree24 + Actor291: tree24 Location: 91,-38 Owner: Neutral - Actor254: tree08 + Actor292: tree08 Location: 124,-38 Owner: Neutral - Actor255: tree08 + Actor293: tree08 Location: 170,-38 Owner: Neutral - Actor256: tree13 + Actor294: tree13 Location: 102,-37 Owner: Neutral - Actor257: tree09 + Actor295: tree09 Location: 109,-37 Owner: Neutral - Actor258: tree25 + Actor296: tree25 Location: 134,-37 Owner: Neutral - Actor259: tree07 + Actor297: tree07 Location: 123,-36 Owner: Neutral - Actor260: tree15 + Actor298: tree15 Location: 126,-36 Owner: Neutral - Actor261: tree09 + Actor299: tree09 Location: 130,-36 Owner: Neutral - Actor262: tree10 + Actor300: tree10 Location: 163,-36 Owner: Neutral - Actor263: tree11 + Actor301: tree11 Location: 168,-36 Owner: Neutral - Actor264: tree19 + Actor302: tree19 Location: 173,-36 Owner: Neutral - Actor265: tree18 + Actor303: tree18 Location: 46,-35 Owner: Neutral - Actor266: tree19 + Actor304: tree19 Location: 73,-35 Owner: Neutral - Actor267: tibtre01 + Actor305: tibtre01 Location: 86,-35 Owner: Neutral - Actor268: tree22 + Actor306: tree22 Location: 95,-34 Owner: Neutral - Actor269: tree06 + Actor307: tree06 Location: 101,-34 Owner: Neutral - Actor270: tree10 + Actor308: tree10 Location: 112,-34 Owner: Neutral - Actor271: tree04 + Actor309: tree04 Location: 119,-34 Owner: Neutral - Actor272: tree10 + Actor310: tree10 Location: 127,-34 Owner: Neutral - Actor273: tree12 + Actor311: tree12 Location: 164,-34 Owner: Neutral - Actor274: tree20 + Actor312: tree20 Location: 176,-34 Owner: Neutral - Actor275: tree12 + Actor313: tree12 Location: 186,-34 Owner: Neutral - Actor276: tree22 + Actor314: tree22 Location: 46,-33 Owner: Neutral - Actor277: tree23 + Actor315: tree23 Location: 54,-33 Owner: Neutral - Actor278: tree08 + Actor316: tree08 Location: 106,-33 Owner: Neutral - Actor279: tree09 + Actor317: tree09 Location: 167,-33 Owner: Neutral - Actor280: tree17 + Actor318: tree17 Location: 66,-32 Owner: Neutral - Actor281: tree11 + Actor319: tree11 Location: 122,-32 Owner: Neutral - Actor282: tree05 + Actor320: tree05 Location: 125,-32 Owner: Neutral - Actor283: tree18 + Actor321: tree18 Location: 74,-31 Owner: Neutral - Actor284: tree25 + Actor322: tree25 Location: 80,-31 Owner: Neutral - Actor285: tree07 + Actor323: tree07 Location: 150,-31 Owner: Neutral - Actor286: tree05 + Actor324: tree05 Location: 188,-31 Owner: Neutral - Actor287: tree19 + Actor325: tree19 Location: 63,-30 Owner: Neutral - Actor288: tree14 + Actor326: tree14 Location: 100,-30 Owner: Neutral - Actor289: tree07 + Actor327: tree07 Location: 102,-30 Owner: Neutral - Actor290: tree11 + Actor328: tree11 Location: 104,-30 Owner: Neutral - Actor291: tree12 + Actor329: tree12 Location: 152,-30 Owner: Neutral - Actor292: tree15 + Actor330: tree15 Location: 166,-30 Owner: Neutral - Actor293: tree11 + Actor331: tree11 Location: 182,-30 Owner: Neutral - Actor294: tree20 + Actor332: tree20 Location: 56,-29 Owner: Neutral - Actor295: tree06 + Actor333: tree06 Location: 120,-29 Owner: Neutral - Actor296: tree14 + Actor334: tree14 Location: 141,-29 Owner: Neutral - Actor297: tree04 + Actor335: tree04 Location: 156,-29 Owner: Neutral - Actor298: tree09 + Actor336: tree09 Location: 186,-29 Owner: Neutral - Actor299: tree16 + Actor337: tree16 Location: 77,-28 Owner: Neutral - Actor300: tree13 + Actor338: tree13 Location: 136,-28 Owner: Neutral - Actor301: tree08 + Actor339: tree08 Location: 138,-28 Owner: Neutral - Actor302: tree06 + Actor340: tree06 Location: 149,-28 Owner: Neutral - Actor303: tree05 + Actor341: tree05 Location: 166,-28 Owner: Neutral - Actor304: tree17 + Actor342: tree17 Location: 172,-28 Owner: Neutral - Actor305: tree18 + Actor343: tree18 Location: 176,-28 Owner: Neutral - Actor306: tree13 + Actor344: tree13 Location: 180,-28 Owner: Neutral - Actor307: tree11 + Actor345: tree11 Location: 189,-28 Owner: Neutral - Actor308: tree10 + Actor346: tree10 Location: 144,-27 Owner: Neutral - Actor309: tree21 + Actor347: tree21 Location: 36,-26 Owner: Neutral - Actor310: tree14 + Actor348: tree14 Location: 74,-26 Owner: Neutral - Actor311: tree14 + Actor349: tree14 Location: 121,-26 Owner: Neutral - Actor312: tree04 + Actor350: tree04 Location: 128,-26 Owner: Neutral - Actor313: tree09 + Actor351: tree09 Location: 133,-26 Owner: Neutral - Actor314: tree15 + Actor352: tree15 Location: 147,-26 Owner: Neutral - Actor315: tree16 + Actor353: tree16 Location: 157,-26 Owner: Neutral - Actor316: tree14 + Actor354: tree14 Location: 163,-26 Owner: Neutral - Actor317: tree24 + Actor355: tree24 Location: 184,-26 Owner: Neutral - Actor318: tree04 + Actor356: tree04 Location: 188,-26 Owner: Neutral - Actor319: tree09 + Actor357: tree09 Location: 111,-25 Owner: Neutral - Actor320: tree08 + Actor358: tree08 Location: 117,-25 Owner: Neutral - Actor321: tree11 + Actor359: tree11 Location: 136,-25 Owner: Neutral - Actor322: tree16 + Actor360: tree16 Location: 170,-25 Owner: Neutral - Actor323: tree13 + Actor361: tree13 Location: 33,-24 Owner: Neutral - Actor324: tree21 + Actor362: tree21 Location: 64,-24 Owner: Neutral - Actor325: tree05 + Actor363: tree05 Location: 145,-24 Owner: Neutral - Actor326: tree17 + Actor364: tree17 Location: 153,-24 Owner: Neutral - Actor327: tree16 + Actor365: tree16 Location: 40,-23 Owner: Neutral - Actor328: tree22 + Actor366: tree22 Location: 81,-22 Owner: Neutral - Actor329: tree06 + Actor367: tree06 Location: 163,-22 Owner: Neutral - Actor330: tree07 + Actor368: tree07 Location: 168,-22 Owner: Neutral - Actor331: tree21 + Actor369: tree21 Location: 182,-22 Owner: Neutral - Actor332: tree23 + Actor370: tree23 Location: 39,-21 Owner: Neutral - Actor333: tree18 + Actor371: tree18 Location: 94,-21 Owner: Neutral - Actor334: tree05 + Actor372: tree05 Location: 157,-21 Owner: Neutral - Actor335: tree10 + Actor373: tree10 Location: 165,-21 Owner: Neutral - Actor336: tree05 + Actor374: tree05 Location: 36,-20 Owner: Neutral - Actor337: tree24 + Actor375: tree24 Location: 99,-20 Owner: Neutral - Actor338: tree14 + Actor376: tree14 Location: 111,-20 Owner: Neutral - Actor339: tree11 + Actor377: tree11 Location: 116,-20 Owner: Neutral - Actor340: tree04 + Actor378: tree04 Location: 30,-19 Owner: Neutral - Actor341: tree24 + Actor379: tree24 Location: 149,-19 Owner: Neutral - Actor342: tree14 + Actor380: tree14 Location: 168,-19 Owner: Neutral - Actor343: tree12 + Actor381: tree12 Location: 33,-18 Owner: Neutral - Actor344: tibtre03 + Actor382: tibtre03 Location: 144,-18 Owner: Neutral - Actor345: tree13 + Actor383: tree13 Location: 155,-18 Owner: Neutral - Actor346: tree18 + Actor384: tree18 Location: 109,-17 Owner: Neutral - Actor347: tree24 + Actor385: tree24 Location: 41,-16 Owner: Neutral - Actor348: tree13 + Actor386: tree13 Location: 111,-16 Owner: Neutral - Actor349: tree07 + Actor387: tree07 Location: 31,-15 Owner: Neutral - Actor350: tree24 + Actor388: tree24 Location: 72,-15 Owner: Neutral - Actor351: tree22 + Actor389: tree22 Location: 133,-14 Owner: Neutral - Actor352: tree24 + Actor390: tree24 Location: 165,-14 Owner: Neutral - Actor353: tree11 + Actor391: tree11 Location: 37,-13 Owner: Neutral - Actor354: tree25 + Actor392: tree25 Location: 69,-13 Owner: Neutral - Actor355: tree23 + Actor393: tree23 Location: 81,-13 Owner: Neutral - Actor356: tree25 + Actor394: tree25 Location: 113,-13 Owner: Neutral - Actor357: tree25 + Actor395: tree25 Location: 137,-13 Owner: Neutral - Actor358: tree06 + Actor396: tree06 Location: 31,-12 Owner: Neutral - Actor359: tree08 + Actor397: tree08 Location: 40,-12 Owner: Neutral - Actor360: tree21 + Actor398: tree21 Location: 143,-12 Owner: Neutral - Actor361: tree15 + Actor399: tree15 Location: 168,-12 Owner: Neutral - Actor362: tree04 + Actor400: tree04 Location: 160,-11 Owner: Neutral - Actor363: tree09 + Actor401: tree09 Location: 167,-11 Owner: Neutral - Actor364: tree06 + Actor402: tree06 Location: 23,-10 Owner: Neutral - Actor365: tree10 + Actor403: tree10 Location: 36,-10 Owner: Neutral - Actor366: tibtre03 + Actor404: tibtre03 Location: 55,-10 Owner: Neutral - Actor367: tree15 + Actor405: tree15 Location: 76,-10 Owner: Neutral - Actor368: tree09 + Actor406: tree09 Location: 40,-9 Owner: Neutral - Actor369: tree19 + Actor407: tree19 Location: 94,-9 Owner: Neutral - Actor370: tree23 + Actor408: tree23 Location: 136,-9 Owner: Neutral - Actor371: tree11 + Actor409: tree11 Location: 167,-9 Owner: Neutral - Actor372: tree19 + Actor410: tree19 Location: 173,-9 Owner: Neutral - Actor373: tree21 + Actor411: tree21 Location: 151,-8 Owner: Neutral - Actor374: tree12 + Actor412: tree12 Location: 159,-8 Owner: Neutral - Actor375: tree08 + Actor413: tree08 Location: 165,-8 Owner: Neutral - Actor376: tree12 + Actor414: tree12 Location: 20,-7 Owner: Neutral - Actor377: tree19 + Actor415: tree19 Location: 29,-7 Owner: Neutral - Actor378: tree18 + Actor416: tree18 Location: 46,-7 Owner: Neutral - Actor379: tree23 + Actor417: tree23 Location: 72,-7 Owner: Neutral - Actor380: tree09 + Actor418: tree09 Location: 91,-7 Owner: Neutral - Actor381: tree13 + Actor419: tree13 Location: 143,-7 Owner: Neutral - Actor382: tree16 + Actor420: tree16 Location: 147,-7 Owner: Neutral - Actor383: tree07 + Actor421: tree07 Location: 24,-6 Owner: Neutral - Actor384: tree17 + Actor422: tree17 Location: 78,-6 Owner: Neutral - Actor385: tree13 + Actor423: tree13 Location: 89,-6 Owner: Neutral - Actor386: tree25 + Actor424: tree25 Location: 81,-5 Owner: Neutral - Actor387: tree21 + Actor425: tree21 Location: 84,-5 Owner: Neutral - Actor388: tree20 + Actor426: tree20 Location: 96,-5 Owner: Neutral - Actor389: tree20 + Actor427: tree20 Location: 168,-5 Owner: Neutral - Actor390: tree17 + Actor428: tree17 Location: 27,-4 Owner: Neutral - Actor391: tree20 + Actor429: tree20 Location: 71,-4 Owner: Neutral - Actor392: tree16 + Actor430: tree16 Location: 17,-3 Owner: Neutral - Actor393: tree19 + Actor431: tree19 Location: 46,-3 Owner: Neutral - Actor394: tree05 + Actor432: tree05 Location: 87,-3 Owner: Neutral - Actor395: tree21 + Actor433: tree21 Location: 106,-3 Owner: Neutral - Actor396: tree09 + Actor434: tree09 Location: 157,-3 Owner: Neutral - Actor397: tree22 + Actor435: tree22 Location: 49,-2 Owner: Neutral - Actor398: tree22 + Actor436: tree22 Location: 79,-2 Owner: Neutral - Actor399: tree16 + Actor437: tree16 Location: 83,-2 Owner: Neutral - Actor400: tree18 + Actor438: tree18 Location: 26,-1 Owner: Neutral - Actor401: tree14 + Actor439: tree14 Location: 37,-1 Owner: Neutral - Actor402: tree11 + Actor440: tree11 Location: 86,-1 Owner: Neutral - Actor403: tree08 + Actor441: tree08 Location: 92,-1 Owner: Neutral - Actor404: tree11 + Actor442: tree11 Location: 17,0 Owner: Neutral - Actor405: tree10 + Actor443: tree10 Location: 19,0 Owner: Neutral - Actor406: tree15 + Actor444: tree15 Location: 22,0 Owner: Neutral - Actor407: tree11 + Actor445: tree11 Location: 33,0 Owner: Neutral - Actor408: tree20 + Actor446: tree20 Location: 43,0 Owner: Neutral - Actor409: tree18 + Actor447: tree18 Location: 71,0 Owner: Neutral - Actor410: tree20 + Actor448: tree20 Location: 103,0 Owner: Neutral - Actor411: tree04 + Actor449: tree04 Location: 84,1 Owner: Neutral - Actor412: tree06 + Actor450: tree06 Location: 90,1 Owner: Neutral - Actor413: tree22 + Actor451: tree22 Location: 108,1 Owner: Neutral - Actor414: tree24 + Actor452: tree24 Location: 122,1 Owner: Neutral - Actor415: tree05 + Actor453: tree05 Location: 16,2 Owner: Neutral - Actor416: tree13 + Actor454: tree13 Location: 46,2 Owner: Neutral - Actor417: tree14 + Actor455: tree14 Location: 76,2 Owner: Neutral - Actor418: tree07 + Actor456: tree07 Location: 95,2 Owner: Neutral - Actor419: tree10 + Actor457: tree10 Location: 80,3 Owner: Neutral - Actor420: tree07 + Actor458: tree07 Location: 103,3 Owner: Neutral - Actor421: tree14 + Actor459: tree14 Location: 113,3 Owner: Neutral - Actor422: tree18 + Actor460: tree18 Location: 135,3 Owner: Neutral - Actor423: tree25 + Actor461: tree25 Location: 136,3 Owner: Neutral - Actor424: tree09 + Actor462: tree09 Location: 11,4 Owner: Neutral - Actor425: tree13 + Actor463: tree13 Location: 14,4 Owner: Neutral - Actor426: tree24 + Actor464: tree24 Location: 33,4 Owner: Neutral - Actor427: tree15 + Actor465: tree15 Location: 40,4 Owner: Neutral - Actor428: tree14 + Actor466: tree14 Location: 69,4 Owner: Neutral - Actor429: tree19 + Actor467: tree19 Location: 132,4 Owner: Neutral - Actor430: tree09 + Actor468: tree09 Location: 37,5 Owner: Neutral - Actor431: tree18 + Actor469: tree18 Location: 108,5 Owner: Neutral - Actor432: tree16 + Actor470: tree16 Location: 117,5 Owner: Neutral - Actor433: tree11 + Actor471: tree11 Location: 120,5 Owner: Neutral - Actor434: tree20 + Actor472: tree20 Location: 127,5 Owner: Neutral - Actor435: tree08 + Actor473: tree08 Location: 23,6 Owner: Neutral - Actor436: tree21 + Actor474: tree21 Location: 44,6 Owner: Neutral - Actor437: tree20 + Actor475: tree20 Location: 74,6 Owner: Neutral - Actor438: tree13 + Actor476: tree13 Location: 115,6 Owner: Neutral - Actor439: tree24 + Actor477: tree24 Location: 143,6 Owner: Neutral - Actor440: tree12 + Actor478: tree12 Location: 11,7 Owner: Neutral - Actor441: tree14 + Actor479: tree14 Location: 20,7 Owner: Neutral - Actor442: tree23 + Actor480: tree23 Location: 29,7 Owner: Neutral - Actor443: tree25 + Actor481: tree25 Location: 34,7 Owner: Neutral - Actor444: tree12 + Actor482: tree12 Location: 78,7 Owner: Neutral - Actor445: tree17 + Actor483: tree17 Location: 151,7 Owner: Neutral - Actor446: tree14 + Actor484: tree14 Location: 40,8 Owner: Neutral - Actor447: tree17 + Actor485: tree17 Location: 105,8 Owner: Neutral - Actor448: tree04 + Actor486: tree04 Location: 17,9 Owner: Neutral - Actor449: tree06 + Actor487: tree06 Location: 22,9 Owner: Neutral - Actor450: tree16 + Actor488: tree16 Location: 34,9 Owner: Neutral - Actor451: tree16 + Actor489: tree16 Location: 56,9 Owner: Neutral - Actor452: tree09 + Actor490: tree09 Location: 89,9 Owner: Neutral - Actor453: tree10 + Actor491: tree10 Location: 93,9 Owner: Neutral - Actor454: tree15 + Actor492: tree15 Location: 99,9 Owner: Neutral - Actor455: tree22 + Actor493: tree22 Location: 110,9 Owner: Neutral - Actor456: tree25 + Actor494: tree25 Location: 119,9 Owner: Neutral - Actor457: tree22 + Actor495: tree22 Location: 132,9 Owner: Neutral - Actor458: tree19 + Actor496: tree19 Location: 148,9 Owner: Neutral - Actor459: tree22 + Actor497: tree22 Location: 150,9 Owner: Neutral - Actor460: tree21 + Actor498: tree21 Location: 71,10 Owner: Neutral - Actor461: tree04 + Actor499: tree04 Location: 106,10 Owner: Neutral - Actor462: tree21 + Actor500: tree21 Location: 128,10 Owner: Neutral - Actor463: tree08 + Actor501: tree08 Location: 32,11 Owner: Neutral - Actor464: tree08 + Actor502: tree08 Location: 37,11 Owner: Neutral - Actor465: tree24 + Actor503: tree24 Location: 56,11 Owner: Neutral - Actor466: tree19 + Actor504: tree19 Location: 73,12 Owner: Neutral - Actor467: tree16 + Actor505: tree16 Location: 138,12 Owner: Neutral - Actor468: tree23 + Actor506: tree23 Location: 48,13 Owner: Neutral - Actor469: tibtre01 + Actor507: tibtre01 Location: 124,13 Owner: Neutral - Actor470: tree23 + Actor508: tree23 Location: 132,13 Owner: Neutral - Actor471: tree07 + Actor509: tree07 Location: 18,14 Owner: Neutral - Actor472: tree16 + Actor510: tree16 Location: 80,14 Owner: Neutral - Actor473: tree05 + Actor511: tree05 Location: 99,14 Owner: Neutral - Actor474: tree21 + Actor512: tree21 Location: 115,14 Owner: Neutral - Actor475: tree20 + Actor513: tree20 Location: 136,14 Owner: Neutral - Actor476: tree12 + Actor514: tree12 Location: 150,14 Owner: Neutral - Actor477: tree13 + Actor515: tree13 Location: 148,15 Owner: Neutral - Actor478: tree07 + Actor516: tree07 Location: 37,16 Owner: Neutral - Actor479: tree04 + Actor517: tree04 Location: 89,16 Owner: Neutral - Actor480: tree08 + Actor518: tree08 Location: 95,16 Owner: Neutral - Actor481: tree16 + Actor519: tree16 Location: 103,16 Owner: Neutral - Actor482: tree19 + Actor520: tree19 Location: 112,16 Owner: Neutral - Actor483: tree11 + Actor521: tree11 Location: 33,18 Owner: Neutral - Actor484: tree22 + Actor522: tree22 Location: 73,18 Owner: Neutral - Actor485: tree14 + Actor523: tree14 Location: 98,18 Owner: Neutral - Actor486: tree22 + Actor524: tree22 Location: 31,19 Owner: Neutral - Actor487: tree19 + Actor525: tree19 Location: 44,19 Owner: Neutral - Actor488: tree12 + Actor526: tree12 Location: 93,19 Owner: Neutral - Actor489: tree13 + Actor527: tree13 Location: 117,19 Owner: Neutral - Actor490: tibtre03 + Actor528: tibtre03 Location: 136,19 Owner: Neutral - Actor491: tree20 + Actor529: tree20 Location: 47,20 Owner: Neutral - Actor492: tree06 + Actor530: tree06 Location: 68,20 Owner: Neutral - Actor493: tree10 + Actor531: tree10 Location: 76,20 Owner: Neutral - Actor494: tree19 + Actor532: tree19 Location: 144,20 Owner: Neutral - Actor495: tree05 + Actor533: tree05 Location: 40,21 Owner: Neutral - Actor496: tree11 + Actor534: tree11 Location: 103,21 Owner: Neutral - Actor497: tree15 + Actor535: tree15 Location: 28,22 Owner: Neutral - Actor498: tree06 + Actor536: tree06 Location: 36,22 Owner: Neutral - Actor499: tree07 + Actor537: tree07 Location: 91,22 Owner: Neutral - Actor500: tree06 + Actor538: tree06 Location: 98,22 Owner: Neutral - Actor501: tree21 + Actor539: tree21 Location: 125,23 Owner: Neutral - Actor502: tree14 + Actor540: tree14 Location: 32,24 Owner: Neutral - Actor503: tree25 + Actor541: tree25 Location: 53,25 Owner: Neutral - Actor504: tree22 + Actor542: tree22 Location: 88,25 Owner: Neutral - Actor505: tree13 + Actor543: tree13 Location: 94,25 Owner: Neutral - Actor506: tree12 + Actor544: tree12 Location: 49,26 Owner: Neutral - Actor507: tree17 + Actor545: tree17 Location: 131,26 Owner: Neutral - Actor508: tree18 + Actor546: tree18 Location: 136,26 Owner: Neutral - Actor509: tree04 + Actor547: tree04 Location: 42,27 Owner: Neutral - Actor510: tree05 + Actor548: tree05 Location: 69,27 Owner: Neutral - Actor511: tree09 + Actor549: tree09 Location: 77,27 Owner: Neutral - Actor512: tree22 + Actor550: tree22 Location: 119,28 Owner: Neutral - Actor513: tree18 + Actor551: tree18 Location: 52,29 Owner: Neutral - Actor514: tree06 + Actor552: tree06 Location: 63,29 Owner: Neutral - Actor515: tree11 + Actor553: tree11 Location: 75,29 Owner: Neutral - Actor516: tree20 + Actor554: tree20 Location: 94,29 Owner: Neutral - Actor517: tree17 + Actor555: tree17 Location: 59,31 Owner: Neutral - Actor518: tree12 + Actor556: tree12 Location: 73,31 Owner: Neutral - Actor519: tree07 + Actor557: tree07 Location: 37,32 Owner: Neutral - Actor520: tree11 + Actor558: tree11 Location: 130,32 Owner: Neutral - Actor521: tibtre01 + Actor559: tibtre01 Location: 85,33 Owner: Neutral - Actor522: tree17 + Actor560: tree17 Location: 89,33 Owner: Neutral - Actor523: tree24 + Actor561: tree24 Location: 133,33 Owner: Neutral - Actor524: tree11 + Actor562: tree11 Location: 54,34 Owner: Neutral - Actor525: tree04 + Actor563: tree04 Location: 72,34 Owner: Neutral - Actor526: tree25 + Actor564: tree25 Location: 106,34 Owner: Neutral - Actor527: tree07 + Actor565: tree07 Location: 58,35 Owner: Neutral - Actor528: tree16 + Actor566: tree16 Location: 98,35 Owner: Neutral - Actor529: tree20 + Actor567: tree20 Location: 127,35 Owner: Neutral - Actor530: tree14 + Actor568: tree14 Location: 130,35 Owner: Neutral - Actor531: tree13 + Actor569: tree13 Location: 60,36 Owner: Neutral - Actor532: tree09 + Actor570: tree09 Location: 44,37 Owner: Neutral - Actor533: tree09 + Actor571: tree09 Location: 55,37 Owner: Neutral - Actor534: tree10 + Actor572: tree10 Location: 64,37 Owner: Neutral - Actor535: tree14 + Actor573: tree14 Location: 76,37 Owner: Neutral - Actor536: tree19 + Actor574: tree19 Location: 96,38 Owner: Neutral - Actor537: tree15 + Actor575: tree15 Location: 99,40 Owner: Neutral - Actor538: tree16 + Actor576: tree16 Location: 83,41 Owner: Neutral - Actor539: tree19 + Actor577: tree19 Location: 89,41 Owner: Neutral - Actor540: tree24 + Actor578: tree24 Location: 120,41 Owner: Neutral - Actor541: tree10 + Actor579: tree10 Location: 47,42 Owner: Neutral - Actor542: tree19 + Actor580: tree19 Location: 65,43 Owner: Neutral - Actor543: tree16 + Actor581: tree16 Location: 86,44 Owner: Neutral - Actor544: tree25 + Actor582: tree25 Location: 91,44 Owner: Neutral - Actor545: tree07 + Actor583: tree07 Location: 97,44 Owner: Neutral - Actor546: tree14 + Actor584: tree14 Location: 100,44 Owner: Neutral - Actor547: tree05 + Actor585: tree05 Location: 53,46 Owner: Neutral - Actor548: tree23 + Actor586: tree23 Location: 106,46 Owner: Neutral - Actor549: tree12 + Actor587: tree12 Location: 111,46 Owner: Neutral - Actor550: tree12 + Actor588: tree12 Location: 51,47 Owner: Neutral - Actor551: tree23 + Actor589: tree23 Location: 87,47 Owner: Neutral - Actor552: tree17 + Actor590: tree17 Location: 83,49 Owner: Neutral - Actor553: tree05 + Actor591: tree05 Location: 98,49 Owner: Neutral - Actor554: tree11 + Actor592: tree11 Location: 117,49 Owner: Neutral - Actor555: tree18 + Actor593: tree18 Location: 92,50 Owner: Neutral - Actor556: tree13 + Actor594: tree13 Location: 106,50 Owner: Neutral - Actor557: tree17 + Actor595: tree17 Location: 61,51 Owner: Neutral - Actor558: tibtre03 + Actor596: tibtre03 Location: 67,52 Owner: Neutral - Actor559: tree20 + Actor597: tree20 Location: 74,53 Owner: Neutral - Actor560: tree04 + Actor598: tree04 Location: 97,53 Owner: Neutral - Actor561: tree22 + Actor599: tree22 Location: 82,54 Owner: Neutral - Actor562: tree08 + Actor600: tree08 Location: 103,56 Owner: Neutral - Actor563: tree06 + Actor601: tree06 Location: 102,57 Owner: Neutral - Actor564: tree10 + Actor602: tree10 Location: 110,57 Owner: Neutral - Actor565: tree21 + Actor603: tree21 Location: 68,58 Owner: Neutral - Actor566: tree16 + Actor604: tree16 Location: 83,59 Owner: Neutral - Actor567: tree24 + Actor605: tree24 Location: 65,61 Owner: Neutral - Actor568: tree09 + Actor606: tree09 Location: 101,63 Owner: Neutral - Actor569: tree23 + Actor607: tree23 Location: 73,64 Owner: Neutral - Actor570: tree24 + Actor608: tree24 Location: 95,66 Owner: Neutral - Actor571: tibtre02 + Actor609: tibtre02 Location: 87,67 Owner: Neutral - Actor572: tree17 + Actor610: tree17 Location: 97,69 Owner: Neutral - Actor573: tree13 + Actor611: tree13 Location: 95,72 Owner: Neutral - Actor574: tree25 + Actor612: tree25 Location: 82,76 Owner: Neutral - Actor575: tree19 + Actor613: tree19 Location: 89,77 Owner: Neutral - Actor576: tree11 + Actor614: tree11 Location: 85,81 Owner: Neutral - Actor577: mpspawn + Actor615: mpspawn Location: 116,34 Owner: Neutral - Actor578: mpspawn + Actor616: mpspawn Location: 87,-52 Owner: Neutral - Actor579: crat01 + Actor617: crat01 Location: 55,-40 Owner: Neutral - Actor580: drum02 + Actor618: drum02 Location: 57,-41 Owner: Neutral - Actor581: srock01 + Actor619: srock01 Location: 65,-49 Owner: Neutral - Actor582: palet04 + Actor620: palet04 Location: 48,-31 Owner: Neutral - Actor583: trock03 + Actor621: trock03 Location: 24,-6 Owner: Neutral - Actor584: srock04 + Actor622: srock04 Location: 94,-75 Owner: Neutral - Actor585: crat03 + Actor623: crat03 Location: 56,-36 Owner: Neutral - Actor586: crat04 + Actor624: crat04 Location: 59,-38 Owner: Neutral - Actor587: trock03 + Actor625: trock03 Location: 88,-67 Owner: Neutral - Actor588: trock02 + Actor626: trock02 Location: 82,-60 Owner: Neutral - Actor589: trock05 + Actor627: trock05 Location: 35,-12 Owner: Neutral - Actor590: trock01 + Actor628: trock01 Location: 19,5 Owner: Neutral - Actor591: trock03 + Actor629: trock03 Location: 43,-19 Owner: Neutral - Actor592: srock04 + Actor630: srock04 Location: 45,-20 Owner: Neutral - Actor593: palet02 + Actor631: palet02 Location: 57,-32 Owner: Neutral - Actor594: palet03 + Actor632: palet03 Location: 59,-31 Owner: Neutral - Actor595: trock01 + Actor633: trock01 Location: 93,-63 Owner: Neutral - Actor596: crat03 + Actor634: crat03 Location: 108,-76 Owner: Neutral - Actor597: srock05 + Actor635: srock05 Location: 105,-70 Owner: Neutral - Actor598: palet01 + Actor636: palet01 Location: 111,-76 Owner: Neutral - Actor599: bridge2 + Actor637: bridge2 Location: 61,-25 Owner: Neutral - Actor600: bridge2 + Actor638: bridge2 Location: 61,-24 Owner: Neutral - Actor601: bridge2 + Actor639: bridge2 Location: 61,-23 Owner: Neutral - Actor602: bridge2 + Actor640: bridge2 Location: 61,-22 Owner: Neutral - Actor603: trock02 + Actor641: trock02 Location: 41,-1 Owner: Neutral - Actor604: bridge2 + Actor642: bridge2 Location: 61,-21 Owner: Neutral - Actor605: srock05 + Actor643: srock05 Location: 67,-27 Owner: Neutral - Actor606: bridge2 + Actor644: bridge2 Location: 61,-20 Owner: Neutral - Actor607: srock02 + Actor645: srock02 Location: 101,-60 Owner: Neutral - Actor608: bridge2 + Actor646: bridge2 Location: 61,-19 Owner: Neutral - Actor609: srock04 + Actor647: srock04 Location: 72,-30 Owner: Neutral - Actor610: srock05 + Actor648: srock05 Location: 30,16 Owner: Neutral - Actor611: srock01 + Actor649: srock01 Location: 44,2 Owner: Neutral - Actor612: trock04 + Actor650: trock04 Location: 36,17 Owner: Neutral - Actor613: srock03 + Actor651: srock03 Location: 34,21 Owner: Neutral - Actor614: srock03 + Actor652: srock03 Location: 98,-42 Owner: Neutral - Actor615: srock02 + Actor653: srock02 Location: 81,-23 Owner: Neutral - Actor616: trock03 + Actor654: trock03 Location: 79,-20 Owner: Neutral - Actor617: srock03 + Actor655: srock03 Location: 78,-15 Owner: Neutral - Actor618: palet03 + Actor656: palet03 Location: 60,5 Owner: Neutral - Actor619: trock01 + Actor657: trock01 Location: 82,-17 Owner: Neutral - Actor620: trock04 + Actor658: trock04 Location: 101,-35 Owner: Neutral - Actor621: crat04 + Actor659: crat04 Location: 59,8 Owner: Neutral - Actor622: srock01 + Actor660: srock01 Location: 130,-63 Owner: Neutral - Actor623: trock01 + Actor661: trock01 Location: 43,25 Owner: Neutral - Actor624: srock04 + Actor662: srock04 Location: 46,22 Owner: Neutral - Actor625: veinhole + Actor663: veinhole Location: 87,-17 Owner: Neutral - Actor626: srock04 + Actor664: srock04 Location: 125,-54 Owner: Neutral - Actor627: palet03 + Actor665: palet03 Location: 76,-4 Owner: Neutral - Actor628: palet04 + Actor666: palet04 Location: 73,0 Owner: Neutral - Actor629: trock05 + Actor667: trock05 Location: 107,-30 Owner: Neutral - Actor630: trock02 + Actor668: trock02 Location: 59,22 Owner: Neutral - Actor631: trock03 + Actor669: trock03 Location: 70,12 Owner: Neutral - Actor632: drum01 + Actor670: drum01 Location: 136,-54 Owner: Neutral - Actor633: trock02 + Actor671: trock02 Location: 87,-4 Owner: Neutral - Actor634: palet04 + Actor672: palet04 Location: 135,-48 Owner: Neutral - Actor635: srock05 + Actor673: srock05 Location: 53,35 Owner: Neutral - Actor636: trock02 + Actor674: trock02 Location: 109,-21 Owner: Neutral - Actor637: palet01 + Actor675: palet01 Location: 137,-49 Owner: Neutral - Actor638: palet02 + Actor676: palet02 Location: 73,17 Owner: Neutral - Actor639: srock03 + Actor677: srock03 Location: 88,2 Owner: Neutral - Actor640: trock01 + Actor678: trock01 Location: 127,-37 Owner: Neutral - Actor641: trock03 + Actor679: trock03 Location: 56,35 Owner: Neutral - Actor642: trock01 + Actor680: trock01 Location: 106,-15 Owner: Neutral - Actor643: srock01 + Actor681: srock01 Location: 111,-12 Owner: Neutral - Actor644: trock03 + Actor682: trock03 Location: 108,-7 Owner: Neutral - Actor645: trock05 + Actor683: trock05 Location: 55,50 Owner: Neutral - Actor646: trock04 + Actor684: trock04 Location: 92,14 Owner: Neutral - Actor647: srock04 + Actor685: srock04 Location: 109,-3 Owner: Neutral - Actor648: srock05 + Actor686: srock05 Location: 64,47 Owner: Neutral - Actor649: srock04 + Actor687: srock04 Location: 80,31 Owner: Neutral - Actor650: trock01 + Actor688: trock01 Location: 85,26 Owner: Neutral - Actor651: srock05 + Actor689: srock05 Location: 88,23 Owner: Neutral - Actor652: veinhole + Actor690: veinhole Location: 120,-8 Owner: Neutral - Actor653: srock05 + Actor691: srock05 Location: 133,-21 Owner: Neutral - Actor654: trock05 + Actor692: trock05 Location: 102,12 Owner: Neutral - Actor655: trock02 + Actor693: trock02 Location: 157,-41 Owner: Neutral - Actor656: trock05 + Actor694: trock05 Location: 143,-26 Owner: Neutral - Actor657: drum02 + Actor695: drum02 Location: 110,8 Owner: Neutral - Actor658: trock05 + Actor696: trock05 Location: 127,-5 Owner: Neutral - Actor659: crat01 + Actor697: crat01 Location: 135,-13 Owner: Neutral - Actor660: srock01 + Actor698: srock01 Location: 87,36 Owner: Neutral - Actor661: trock03 + Actor699: trock03 Location: 166,-43 Owner: Neutral - Actor662: crat03 + Actor700: crat03 Location: 111,14 Owner: Neutral - Actor663: drum01 + Actor701: drum01 Location: 149,-22 Owner: Neutral - Actor664: trock01 + Actor702: trock01 Location: 155,-28 Owner: Neutral - Actor665: trock02 + Actor703: trock02 Location: 162,-34 Owner: Neutral - Actor666: srock03 + Actor704: srock03 Location: 70,59 Owner: Neutral - Actor667: srock04 + Actor705: srock04 Location: 116,13 Owner: Neutral - Actor668: srock02 + Actor706: srock02 Location: 83,47 Owner: Neutral - Actor669: crat04 + Actor707: crat04 Location: 153,-23 Owner: Neutral - Actor670: srock05 + Actor708: srock05 Location: 165,-35 Owner: Neutral - Actor671: bridge2 + Actor709: bridge2 Location: 140,-9 Owner: Neutral - Actor672: bridge2 + Actor710: bridge2 Location: 140,-8 Owner: Neutral - Actor673: bridge2 + Actor711: bridge2 Location: 140,-7 Owner: Neutral - Actor674: bridge2 + Actor712: bridge2 Location: 140,-6 Owner: Neutral - Actor675: drum01 + Actor713: drum01 Location: 109,26 Owner: Neutral - Actor676: bridge2 + Actor714: bridge2 Location: 140,-5 Owner: Neutral - Actor677: trock04 + Actor715: trock04 Location: 155,-20 Owner: Neutral - Actor678: bridge2 + Actor716: bridge2 Location: 140,-4 Owner: Neutral - Actor679: srock05 + Actor717: srock05 Location: 144,-8 Owner: Neutral - Actor680: lobrdg_r_nw - Location: 152,-17 + Actor718: lobrdg_r_nw + Location: 152,-16 Owner: Neutral - Actor681: bridge2 + Actor719: bridge2 Location: 140,-3 Owner: Neutral - Actor682: lobrdg_b - Location: 153,-17 + Actor720: lobrdg_b + Location: 153,-16 Owner: Neutral Health: 50 - Actor683: srock04 + Actor721: srock04 Location: 145,-7 Owner: Neutral - Actor684: lobrdg_b - Location: 154,-17 + Actor722: lobrdg_b + Location: 154,-16 Owner: Neutral Health: 25 - Actor685: crat01 + Actor723: crat01 Location: 115,24 Owner: Neutral - Actor686: srock03 + Actor724: srock03 Location: 132,7 Owner: Neutral - Actor687: bridge2 + Actor725: bridge2 Location: 140,-1 Owner: Neutral - Actor688: srock04 + Actor726: srock04 Location: 92,48 Owner: Neutral - Actor689: srock05 + Actor727: srock05 Location: 102,38 Owner: Neutral - Actor690: srock02 + Actor728: srock02 Location: 120,20 Owner: Neutral - Actor691: bridge2 + Actor729: bridge2 Location: 140,0 Owner: Neutral - Actor692: bridge2 + Actor730: bridge2 Location: 140,1 Owner: Neutral - Actor693: srock01 + Actor731: srock01 Location: 174,-33 Owner: Neutral - Actor694: trock04 + Actor732: trock04 Location: 80,62 Owner: Neutral - Actor695: bridge2 + Actor733: bridge2 Location: 140,2 Owner: Neutral - Actor696: bridge2 + Actor734: bridge2 Location: 140,3 Owner: Neutral - Actor697: bridge2 + Actor735: bridge2 Location: 140,4 Owner: Neutral - Actor698: bridge2 + Actor736: bridge2 Location: 140,5 Owner: Neutral - Actor699: bridge2 + Actor737: bridge2 Location: 140,6 Owner: Neutral - Actor700: trock02 + Actor738: trock02 Location: 143,3 Owner: Neutral - Actor701: trock01 + Actor739: trock01 Location: 178,-32 Owner: Neutral - Actor702: bridge2 + Actor740: bridge2 Location: 140,7 Owner: Neutral - Actor703: palet03 + Actor741: palet03 Location: 181,-34 Owner: Neutral - Actor704: trock03 + Actor742: trock03 Location: 153,-5 Owner: Neutral - Actor705: srock03 + Actor743: srock03 Location: 102,47 Owner: Neutral - Actor706: trock02 + Actor744: trock02 Location: 79,72 Owner: Neutral - Actor707: trock02 + Actor745: trock02 Location: 163,-12 Owner: Neutral - Actor708: crat03 + Actor746: crat03 Location: 177,-26 Owner: Neutral - Actor709: crat02 + Actor747: crat02 Location: 172,-20 Owner: Neutral - Actor710: palet02 + Actor748: palet02 Location: 173,-21 Owner: Neutral - Actor711: trock03 + Actor749: trock03 Location: 97,56 Owner: Neutral - Actor712: trock03 + Actor750: trock03 Location: 162,-8 Owner: Neutral - Actor713: trock01 + Actor751: trock01 Location: 93,62 Owner: Neutral - Actor714: palet01 + Actor752: palet01 Location: 102,53 Owner: Neutral - Actor715: crat03 + Actor753: crat03 Location: 105,50 Owner: Neutral - Actor716: lobrdg_r_se - Location: 171,-17 + Actor754: lobrdg_r_se + Location: 171,-16 Owner: Neutral Health: 50 - Actor717: trock05 + Actor755: trock05 Location: 189,-34 Owner: Neutral - Actor718: trock04 + Actor756: trock04 Location: 150,6 Owner: Neutral - Actor719: srock04 + Actor757: srock04 Location: 180,-23 Owner: Neutral - Actor720: crat03 + Actor758: crat03 Location: 141,18 Owner: Neutral - Actor721: drum02 + Actor759: drum02 Location: 108,52 Owner: Neutral - Actor722: drum02 + Actor760: drum02 Location: 171,-11 Owner: Neutral - Actor723: palet03 + Actor761: palet03 Location: 113,48 Owner: Neutral - Actor724: srock04 + Actor762: srock04 Location: 134,27 Owner: Neutral - Actor725: srock01 + Actor763: srock01 Location: 157,4 Owner: Neutral - Actor726: srock03 + Actor764: srock03 Location: 167,-6 Owner: Neutral - Actor727: crat04 + Actor765: crat04 Location: 115,48 Owner: Neutral - Actor728: drum01 + Actor766: drum01 Location: 116,47 Owner: Neutral - Actor729: drum01 + Actor767: drum01 Location: 143,20 Owner: Neutral - Actor730: palet04 + Actor768: palet04 Location: 108,56 Owner: Neutral - Actor731: srock01 + Actor769: srock01 Location: 133,31 Owner: Neutral - Actor732: palet04 + Actor770: palet04 Location: 171,-7 Owner: Neutral - Actor733: srock01 + Actor771: srock01 Location: 91,74 Owner: Neutral - Actor734: palet02 + Actor772: palet02 Location: 121,44 Owner: Neutral - Actor735: trock02 + Actor773: trock02 Location: 125,41 Owner: Neutral - Actor736: jfish - Owner: Creeps - Location: 121,-90 - Facing: 92 - Actor739: jfish - Owner: Creeps - Location: 74,60 - Facing: 92 - Actor740: jfish - Owner: Creeps - Location: 170,-38 - Facing: 92 - Actor737: jfish - Owner: Creeps - Location: 58,23 - Facing: 92 - Actor741: tuntop04 - Owner: Neutral - Location: 183,-43 - Actor742: lobrdg_b_d - Owner: Neutral - Location: 155,-17 - Actor743: lobrdg_b_d - Owner: Neutral - Location: 170,-17 Rules: rules.yaml diff -Nru openra-20200503/mods/ts/maps/sunstroke/rules.yaml openra-20210321/mods/ts/maps/sunstroke/rules.yaml --- openra-20200503/mods/ts/maps/sunstroke/rules.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/sunstroke/rules.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -10,14 +10,17 @@ Height: 5 Orientation: Y Length: 19 - GlobalLightingPaletteEffect: - Red: 1.6 - Blue: 0.9 - Green: 1.2 - Ambient: 0.3 LuaScript: Scripts: sunstroke.lua +^BaseWorld: + TerrainLighting: + RedTint: 1.6 + GreenTint: 1.2 + BlueTint: 0.9 + Intensity: 0.3 + HeightStep: 0.002 + GAOLDCC2: CaptureManager: Capturable: @@ -49,3 +52,43 @@ Voice: Attack Armament: Weapon: Sniper + +GRENLAMP: + TerrainLightSource: + RedTint: -0.15 + BlueTint: 0 + GreenTint: 0.2 + Intensity: 0.1 + Range: 10c760 + +INYELWLAMP: + TerrainLightSource: + RedTint: 0.1 + BlueTint: 0 + GreenTint: 0.15 + Intensity: 0.1 + Range: 19c544 + +INGRNLMP: + TerrainLightSource: + RedTint: -0.1 + BlueTint: 0 + GreenTint: 0.25 + Intensity: 0.15 + Range: 15c640 + +INREDLMP: + TerrainLightSource: + RedTint: 0.25 + BlueTint: -0.1 + GreenTint: 0.1 + Intensity: 0.2 + Range: 15c640 + +INBLULMP: + TerrainLightSource: + RedTint: -0.25 + BlueTint: 0.1 + GreenTint: 0.1 + Intensity: -0.1 + Range: 11c736 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/tactical/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/tactical/map.png differ diff -Nru openra-20200503/mods/ts/maps/tactical/map.yaml openra-20210321/mods/ts/maps/tactical/map.yaml --- openra-20200503/mods/ts/maps/tactical/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/tactical/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -57,750 +57,806 @@ Actor0: cabhut Location: 271,4 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor1: cabhut Location: 260,8 Owner: Neutral - Health: 100 - Facing: 96 - Actor2: tree01 + Facing: 896 + Actor2: ingrnlmp + Location: 105,-50 + Owner: Neutral + Facing: 896 + Actor3: ingrnlmp + Location: 85,-23 + Owner: Neutral + Facing: 896 + Actor4: ingrnlmp + Location: 55,-20 + Owner: Neutral + Facing: 896 + Actor5: ingrnlmp + Location: 173,-67 + Owner: Neutral + Facing: 896 + Actor6: ingrnlmp + Location: 155,-4 + Owner: Neutral + Facing: 896 + Actor7: ingrnlmp + Location: 175,-20 + Owner: Neutral + Facing: 896 + Actor8: ingrnlmp + Location: 249,-38 + Owner: Neutral + Facing: 896 + Actor9: ingrnlmp + Location: 229,35 + Owner: Neutral + Facing: 896 + Actor10: tree01 Location: 245,-8 Owner: Neutral - Actor3: tree01 + Actor11: tree01 Location: 240,26 Owner: Neutral - Actor4: tree01 + Actor12: tree01 Location: 204,32 Owner: Neutral - Actor5: tree01 + Actor13: tree01 Location: 190,67 Owner: Neutral - Actor6: tree01 + Actor14: tree01 Location: 152,77 Owner: Neutral - Actor7: tree01 + Actor15: tree01 Location: 96,49 Owner: Neutral - Actor8: tree05 + Actor16: tree05 Location: 106,-80 Owner: Neutral - Actor9: tree06 + Actor17: tree06 Location: 106,-83 Owner: Neutral - Actor10: tree11 + Actor18: tree11 Location: 90,-47 Owner: Neutral - Actor11: tree17 + Actor19: tree17 Location: 87,-44 Owner: Neutral - Actor12: tree14 + Actor20: tree14 Location: 80,-35 Owner: Neutral - Actor13: tree13 + Actor21: tree13 Location: 123,-22 Owner: Neutral - Actor14: tree04 + Actor22: tree04 Location: 69,29 Owner: Neutral - Actor15: tree05 + Actor23: tree05 Location: 69,28 Owner: Neutral - Actor16: tree06 + Actor24: tree06 Location: 70,27 Owner: Neutral - Actor17: tree07 + Actor25: tree07 Location: 70,26 Owner: Neutral - Actor18: tree10 + Actor26: tree10 Location: 74,23 Owner: Neutral - Actor19: tree12 + Actor27: tree12 Location: 71,24 Owner: Neutral - Actor20: tree13 + Actor28: tree13 Location: 70,25 Owner: Neutral - Actor21: tree14 + Actor29: tree14 Location: 72,24 Owner: Neutral - Actor22: tree16 + Actor30: tree16 Location: 69,27 Owner: Neutral - Actor23: tree11 + Actor31: tree11 Location: 182,61 Owner: Neutral - Actor24: tree11 + Actor32: tree11 Location: 135,44 Owner: Neutral - Actor25: tree11 + Actor33: tree11 Location: 99,36 Owner: Neutral - Actor26: tree11 + Actor34: tree11 Location: 91,3 Owner: Neutral - Actor27: tree11 + Actor35: tree11 Location: 90,-32 Owner: Neutral - Actor28: tree11 + Actor36: tree11 Location: 111,-67 Owner: Neutral - Actor29: tree11 + Actor37: tree11 Location: 129,-88 Owner: Neutral - Actor30: tree11 + Actor38: tree11 Location: 162,-110 Owner: Neutral - Actor31: tree11 + Actor39: tree11 Location: 191,-89 Owner: Neutral - Actor32: tree11 + Actor40: tree11 Location: 229,-43 Owner: Neutral - Actor33: tree12 + Actor41: tree12 Location: 234,-33 Owner: Neutral - Actor34: tree12 + Actor42: tree12 Location: 230,-9 Owner: Neutral - Actor35: tree17 + Actor43: tree17 Location: 240,-10 Owner: Neutral - Actor36: tree16 + Actor44: tree16 Location: 228,12 Owner: Neutral - Actor37: tree16 + Actor45: tree16 Location: 271,9 Owner: Neutral - Actor38: tree18 + Actor46: tree18 Location: 279,11 Owner: Neutral - Actor39: tree17 + Actor47: tree17 Location: 278,11 Owner: Neutral - Actor40: tree20 + Actor48: tree20 Location: 268,-15 Owner: Neutral - Actor41: tree21 + Actor49: tree21 Location: 257,-4 Owner: Neutral - Actor42: tree22 + Actor50: tree22 Location: 239,3 Owner: Neutral - Actor43: tree23 + Actor51: tree23 Location: 230,24 Owner: Neutral - Actor44: tree08 + Actor52: tree08 Location: 208,44 Owner: Neutral - Actor45: tree11 + Actor53: tree11 Location: 222,29 Owner: Neutral - Actor46: tree11 + Actor54: tree11 Location: 178,13 Owner: Neutral - Actor47: tree11 + Actor55: tree11 Location: 121,43 Owner: Neutral - Actor48: tree12 + Actor56: tree12 Location: 100,51 Owner: Neutral - Actor49: tree13 + Actor57: tree13 Location: 119,69 Owner: Neutral - Actor50: tree14 + Actor58: tree14 Location: 106,80 Owner: Neutral - Actor51: tree15 + Actor59: tree15 Location: 87,79 Owner: Neutral - Actor52: tree16 + Actor60: tree16 Location: 90,58 Owner: Neutral - Actor53: tree16 + Actor61: tree16 Location: 72,3 Owner: Neutral - Actor54: tree16 + Actor62: tree16 Location: 64,-35 Owner: Neutral - Actor55: tree17 + Actor63: tree17 Location: 73,-38 Owner: Neutral - Actor56: tree18 + Actor64: tree18 Location: 98,-33 Owner: Neutral - Actor57: tree19 + Actor65: tree19 Location: 99,-33 Owner: Neutral - Actor58: tree20 + Actor66: tree20 Location: 97,-33 Owner: Neutral - Actor59: tree21 + Actor67: tree21 Location: 99,-32 Owner: Neutral - Actor60: tree21 + Actor68: tree21 Location: 111,-66 Owner: Neutral - Actor61: tree23 + Actor69: tree23 Location: 111,-65 Owner: Neutral - Actor62: tree24 + Actor70: tree24 Location: 110,-66 Owner: Neutral - Actor63: tree18 + Actor71: tree18 Location: 140,-73 Owner: Neutral - Actor64: tree15 + Actor72: tree15 Location: 138,-73 Owner: Neutral - Actor65: tree14 + Actor73: tree14 Location: 138,-72 Owner: Neutral - Actor66: tree13 + Actor74: tree13 Location: 139,-100 Owner: Neutral - Actor67: tree11 + Actor75: tree11 Location: 141,-99 Owner: Neutral - Actor68: tree09 + Actor76: tree09 Location: 140,-98 Owner: Neutral - Actor69: tree08 + Actor77: tree08 Location: 141,-97 Owner: Neutral - Actor70: tree07 + Actor78: tree07 Location: 140,-100 Owner: Neutral - Actor71: tree06 + Actor79: tree06 Location: 139,-101 Owner: Neutral - Actor72: tree06 + Actor80: tree06 Location: 183,-72 Owner: Neutral - Actor73: tree05 + Actor81: tree05 Location: 185,-71 Owner: Neutral - Actor74: tree04 + Actor82: tree04 Location: 182,-74 Owner: Neutral - Actor75: tree03 + Actor83: tree03 Location: 192,-61 Owner: Neutral - Actor76: tree02 + Actor84: tree02 Location: 194,-60 Owner: Neutral - Actor77: tree05 + Actor85: tree05 Location: 194,-62 Owner: Neutral - Actor78: tree06 + Actor86: tree06 Location: 193,-61 Owner: Neutral - Actor79: tree07 + Actor87: tree07 Location: 212,-47 Owner: Neutral - Actor80: tree09 + Actor88: tree09 Location: 212,-48 Owner: Neutral - Actor81: tree08 + Actor89: tree08 Location: 213,-47 Owner: Neutral - Actor82: tree08 + Actor90: tree08 Location: 264,-14 Owner: Neutral - Actor83: tree06 + Actor91: tree06 Location: 265,-13 Owner: Neutral - Actor84: tree05 + Actor92: tree05 Location: 265,-12 Owner: Neutral - Actor85: tree05 + Actor93: tree05 Location: 254,-1 Owner: Neutral - Actor86: tree04 + Actor94: tree04 Location: 255,-1 Owner: Neutral - Actor87: tree03 + Actor95: tree03 Location: 255,0 Owner: Neutral - Actor88: tree02 + Actor96: tree02 Location: 254,1 Owner: Neutral - Actor89: tree02 + Actor97: tree02 Location: 267,-4 Owner: Neutral - Actor90: tree04 + Actor98: tree04 Location: 269,-3 Owner: Neutral - Actor91: tree06 + Actor99: tree06 Location: 269,-4 Owner: Neutral - Actor92: tree08 + Actor100: tree08 Location: 269,-5 Owner: Neutral - Actor93: tree10 + Actor101: tree10 Location: 219,34 Owner: Neutral - Actor94: tree12 + Actor102: tree12 Location: 219,35 Owner: Neutral - Actor95: tree13 + Actor103: tree13 Location: 220,35 Owner: Neutral - Actor96: tree15 + Actor104: tree15 Location: 220,36 Owner: Neutral - Actor97: tree16 + Actor105: tree16 Location: 200,56 Owner: Neutral - Actor98: tree18 + Actor106: tree18 Location: 200,55 Owner: Neutral - Actor99: tree20 + Actor107: tree20 Location: 199,55 Owner: Neutral - Actor100: tree21 + Actor108: tree21 Location: 200,57 Owner: Neutral - Actor101: tree22 + Actor109: tree22 Location: 199,56 Owner: Neutral - Actor102: tree16 + Actor110: tree16 Location: 198,56 Owner: Neutral - Actor103: tree15 + Actor111: tree15 Location: 200,58 Owner: Neutral - Actor104: tree14 + Actor112: tree14 Location: 167,44 Owner: Neutral - Actor105: tree12 + Actor113: tree12 Location: 166,44 Owner: Neutral - Actor106: tree10 + Actor114: tree10 Location: 168,43 Owner: Neutral - Actor107: tree08 + Actor115: tree08 Location: 167,43 Owner: Neutral - Actor108: tree06 + Actor116: tree06 Location: 168,42 Owner: Neutral - Actor109: tree04 + Actor117: tree04 Location: 167,40 Owner: Neutral - Actor110: tree02 + Actor118: tree02 Location: 165,43 Owner: Neutral - Actor111: tree02 + Actor119: tree02 Location: 131,47 Owner: Neutral - Actor112: tree04 + Actor120: tree04 Location: 132,46 Owner: Neutral - Actor113: tree05 + Actor121: tree05 Location: 131,46 Owner: Neutral - Actor114: tree06 + Actor122: tree06 Location: 130,47 Owner: Neutral - Actor115: tree06 + Actor123: tree06 Location: 110,28 Owner: Neutral - Actor116: tree04 + Actor124: tree04 Location: 110,29 Owner: Neutral - Actor117: tree06 + Actor125: tree06 Location: 111,30 Owner: Neutral - Actor118: tree07 + Actor126: tree07 Location: 112,30 Owner: Neutral - Actor119: tree08 + Actor127: tree08 Location: 111,31 Owner: Neutral - Actor120: tree08 + Actor128: tree08 Location: 86,9 Owner: Neutral - Actor121: tree09 + Actor129: tree09 Location: 86,10 Owner: Neutral - Actor122: tree10 + Actor130: tree10 Location: 87,9 Owner: Neutral - Actor123: tree11 + Actor131: tree11 Location: 91,15 Owner: Neutral - Actor124: tree12 + Actor132: tree12 Location: 91,14 Owner: Neutral - Actor125: tree13 + Actor133: tree13 Location: 90,15 Owner: Neutral - Actor126: tree13 + Actor134: tree13 Location: 43,17 Owner: Neutral - Actor127: tree14 + Actor135: tree14 Location: 44,18 Owner: Neutral - Actor128: tree15 + Actor136: tree15 Location: 44,17 Owner: Neutral - Actor129: tree16 + Actor137: tree16 Location: 45,18 Owner: Neutral - Actor130: tree14 + Actor138: tree14 Location: 32,13 Owner: Neutral - Actor131: tree13 + Actor139: tree13 Location: 33,15 Owner: Neutral - Actor132: tree12 + Actor140: tree12 Location: 32,16 Owner: Neutral - Actor133: tree11 + Actor141: tree11 Location: 33,14 Owner: Neutral - Actor134: tree11 + Actor142: tree11 Location: 32,-15 Owner: Neutral - Actor135: tree10 + Actor143: tree10 Location: 44,-19 Owner: Neutral - Actor136: tree09 + Actor144: tree09 Location: 45,-19 Owner: Neutral - Actor137: tree08 + Actor145: tree08 Location: 46,-17 Owner: Neutral - Actor138: tree07 + Actor146: tree07 Location: 46,-19 Owner: Neutral - Actor139: tree06 + Actor147: tree06 Location: 47,-19 Owner: Neutral - Actor140: tree05 + Actor148: tree05 Location: 47,-18 Owner: Neutral - Actor141: tree05 + Actor149: tree05 Location: 65,-21 Owner: Neutral - Actor142: tree06 + Actor150: tree06 Location: 65,-19 Owner: Neutral - Actor143: tree07 + Actor151: tree07 Location: 66,-20 Owner: Neutral - Actor144: tree07 + Actor152: tree07 Location: 104,-56 Owner: Neutral - Actor145: tree08 + Actor153: tree08 Location: 104,-57 Owner: Neutral - Actor146: tree09 + Actor154: tree09 Location: 105,-56 Owner: Neutral - Actor147: tree10 + Actor155: tree10 Location: 105,-57 Owner: Neutral - Actor148: tree11 + Actor156: tree11 Location: 105,-58 Owner: Neutral - Actor149: tree12 + Actor157: tree12 Location: 104,-55 Owner: Neutral - Actor150: tree13 + Actor158: tree13 Location: 106,-54 Owner: Neutral - Actor151: tree08 + Actor159: tree08 Location: 117,-71 Owner: Neutral - Actor152: tree09 + Actor160: tree09 Location: 118,-71 Owner: Neutral - Actor153: tree10 + Actor161: tree10 Location: 118,-72 Owner: Neutral - Actor154: tree07 + Actor162: tree07 Location: 116,-71 Owner: Neutral - Actor155: tree07 + Actor163: tree07 Location: 141,-81 Owner: Neutral - Actor156: tree06 + Actor164: tree06 Location: 141,-82 Owner: Neutral - Actor157: tree05 + Actor165: tree05 Location: 142,-82 Owner: Neutral - Actor158: tree04 + Actor166: tree04 Location: 163,-53 Owner: Neutral - Actor159: tree05 + Actor167: tree05 Location: 161,-54 Owner: Neutral - Actor160: tree06 + Actor168: tree06 Location: 162,-54 Owner: Neutral - Actor161: tree06 + Actor169: tree06 Location: 147,-53 Owner: Neutral - Actor162: tree07 + Actor170: tree07 Location: 146,-53 Owner: Neutral - Actor163: tree08 + Actor171: tree08 Location: 146,-54 Owner: Neutral - Actor164: tree08 + Actor172: tree08 Location: 120,-33 Owner: Neutral - Actor165: tree08 + Actor173: tree08 Location: 129,-17 Owner: Neutral - Actor166: tree09 + Actor174: tree09 Location: 128,-18 Owner: Neutral - Actor167: tree11 + Actor175: tree11 Location: 127,-18 Owner: Neutral - Actor168: tree12 + Actor176: tree12 Location: 128,-17 Owner: Neutral - Actor169: tree13 + Actor177: tree13 Location: 128,-16 Owner: Neutral - Actor170: tree14 + Actor178: tree14 Location: 128,-15 Owner: Neutral - Actor171: tree15 + Actor179: tree15 Location: 129,-16 Owner: Neutral - Actor172: tree15 + Actor180: tree15 Location: 123,56 Owner: Neutral - Actor173: tree16 + Actor181: tree16 Location: 122,55 Owner: Neutral - Actor174: tree17 + Actor182: tree17 Location: 121,56 Owner: Neutral - Actor175: tree18 + Actor183: tree18 Location: 122,56 Owner: Neutral - Actor176: tree19 + Actor184: tree19 Location: 145,70 Owner: Neutral - Actor177: tree21 + Actor185: tree21 Location: 145,69 Owner: Neutral - Actor178: tree23 + Actor186: tree23 Location: 146,69 Owner: Neutral - Actor179: tree19 + Actor187: tree19 Location: 143,68 Owner: Neutral - Actor180: tree18 + Actor188: tree18 Location: 144,68 Owner: Neutral - Actor181: tree17 + Actor189: tree17 Location: 144,69 Owner: Neutral - Actor182: tree15 + Actor190: tree15 Location: 139,82 Owner: Neutral - Actor183: tree13 + Actor191: tree13 Location: 140,83 Owner: Neutral - Actor184: tree11 + Actor192: tree11 Location: 138,82 Owner: Neutral - Actor185: tree10 + Actor193: tree10 Location: 138,92 Owner: Neutral - Actor186: tree09 + Actor194: tree09 Location: 138,91 Owner: Neutral - Actor187: tree07 + Actor195: tree07 Location: 138,90 Owner: Neutral - Actor188: tree06 + Actor196: tree06 Location: 137,92 Owner: Neutral - Actor189: tree05 + Actor197: tree05 Location: 137,90 Owner: Neutral - Actor190: tree01 + Actor198: tree01 Location: 151,59 Owner: Neutral - Actor191: tree02 + Actor199: tree02 Location: 155,60 Owner: Neutral - Actor192: tree20 + Actor200: tree20 Location: 168,-15 Owner: Neutral - Actor193: tree20 + Actor201: tree20 Location: 189,-1 Owner: Neutral - Actor194: tree21 + Actor202: tree21 Location: 189,-2 Owner: Neutral - Actor195: tree22 + Actor203: tree22 Location: 190,-1 Owner: Neutral - Actor196: tree22 + Actor204: tree22 Location: 177,-21 Owner: Neutral - Actor197: tree23 + Actor205: tree23 Location: 178,-20 Owner: Neutral - Actor198: tree23 + Actor206: tree23 Location: 148,-33 Owner: Neutral - Actor199: tree24 + Actor207: tree24 Location: 145,-41 Owner: Neutral - Actor200: tree25 + Actor208: tree25 Location: 139,-15 Owner: Neutral - Actor201: tree18 + Actor209: tree18 Location: 160,10 Owner: Neutral - Actor202: tree17 + Actor210: tree17 Location: 160,9 Owner: Neutral - Actor203: tree16 + Actor211: tree16 Location: 157,20 Owner: Neutral - Actor204: tree15 + Actor212: tree15 Location: 152,23 Owner: Neutral - Actor205: tree14 + Actor213: tree14 Location: 148,17 Owner: Neutral - Actor206: tree13 + Actor214: tree13 Location: 148,12 Owner: Neutral - Actor207: tree12 + Actor215: tree12 Location: 150,8 Owner: Neutral - Actor208: tibtre02 + Actor216: tibtre02 Location: 56,-19 Owner: Neutral - Actor209: tibtre01 + Actor217: tibtre01 Location: 86,-22 Owner: Neutral - Actor210: tibtre01 + Actor218: tibtre01 Location: 156,-3 Owner: Neutral - Actor211: tibtre01 + Actor219: tibtre01 Location: 250,-37 Owner: Neutral - Actor212: tibtre02 + Actor220: tibtre02 Location: 230,36 Owner: Neutral - Actor213: tibtre03 + Actor221: tibtre03 Location: 144,133 Owner: Neutral - Actor214: tibtre02 + Actor222: tibtre02 Location: 176,-19 Owner: Neutral - Actor215: tibtre02 + Actor223: tibtre02 Location: 174,-66 Owner: Neutral - Actor216: tibtre02 + Actor224: tibtre02 Location: 106,-48 Owner: Neutral - Actor217: tibtre03 + Actor225: tibtre03 Location: 30,0 Owner: Neutral - Actor218: mpspawn + Actor226: mpspawn Location: 21,5 Owner: Neutral - Actor219: mpspawn + Actor227: mpspawn Location: 254,-24 Owner: Neutral - Actor220: mpspawn + Actor228: mpspawn Location: 154,-123 Owner: Neutral - Actor221: mpspawn + Actor229: mpspawn Location: 135,121 Owner: Neutral - Actor222: mpspawn + Actor230: mpspawn Location: 170,-7 Owner: Neutral - Actor223: waypoint + Actor231: waypoint Location: 150,0 Owner: Neutral - Actor224: waypoint + Actor232: waypoint Location: 150,0 Owner: Neutral - Actor225: trock01 - Location: 152,-103 - Owner: Neutral - Actor226: trock03 + Actor233: trock03 Location: 151,-103 Owner: Neutral - Actor227: trock02 + Actor234: trock01 + Location: 152,-103 + Owner: Neutral + Actor235: trock02 Location: 88,6 Owner: Neutral - Actor228: trock01 + Actor236: trock01 Location: 154,-16 Owner: Neutral - Actor229: trock02 + Actor237: trock02 Location: 144,13 Owner: Neutral - Actor230: trock04 + Actor238: trock04 Location: 122,42 Owner: Neutral - Actor231: trock02 + Actor239: trock02 Location: 122,43 Owner: Neutral - Actor232: trock03 + Actor240: trock03 Location: 123,43 Owner: Neutral - Actor233: trock02 + Actor241: trock02 Location: 139,51 Owner: Neutral - Actor234: trock02 + Actor242: trock02 Location: 140,67 Owner: Neutral - Actor235: trock05 + Actor243: trock05 Location: 184,29 Owner: Neutral - Actor236: trock05 - Location: 154,75 + Actor244: trock02 + Location: 152,76 Owner: Neutral - Actor237: trock03 + Actor245: trock03 Location: 153,76 Owner: Neutral - Actor238: trock02 - Location: 152,76 + Actor246: trock05 + Location: 154,75 Owner: Neutral - Actor239: trock05 - Location: 155,75 + Actor247: trock01 + Location: 153,77 Owner: Neutral - Actor240: trock04 + Actor248: trock04 Location: 154,76 Owner: Neutral - Actor241: trock01 - Location: 153,77 + Actor249: trock05 + Location: 155,75 Owner: Neutral - Actor242: trock02 + Actor250: trock02 Location: 134,98 Owner: Neutral - Actor243: trock04 + Actor251: trock04 Location: 180,64 Owner: Neutral - Actor244: trock03 + Actor252: trock03 Location: 151,95 Owner: Neutral - Actor245: trock03 + Actor253: trock03 Location: 146,103 Owner: Neutral - Actor246: trock04 + Actor254: trock04 Location: 167,83 Owner: Neutral + Actor255: bridge1 + Location: 263,6 + Owner: Neutral + Actor256: bridge1 + Location: 264,6 + Owner: Neutral + Actor257: bridge1 + Location: 265,6 + Owner: Neutral + Actor258: bridge1 + Location: 266,6 + Owner: Neutral + Actor259: bridge1 + Location: 267,6 + Owner: Neutral + Actor260: bridge1 + Location: 268,6 + Owner: Neutral Rules: - World: - GlobalLightingPaletteEffect: - Ambient: 0.85 + ^BaseWorld: + TerrainLighting: + Intensity: 0.825 + HeightStep: 0.05 + INGRNLMP: + TerrainLightSource: + Range: 7c832 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.7 + BlueTint: 0.01 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/terrace/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/terrace/map.png differ diff -Nru openra-20200503/mods/ts/maps/terrace/map.yaml openra-20210321/mods/ts/maps/terrace/map.yaml --- openra-20200503/mods/ts/maps/terrace/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/terrace/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -49,467 +49,519 @@ Enemies: Creeps Actors: - Actor0: tibtre01 + Actor0: ingrnlmp + Location: 205,-13 + Owner: Neutral + Facing: 896 + Actor1: ingrnlmp + Location: 186,18 + Owner: Neutral + Facing: 896 + Actor2: ingrnlmp + Location: 143,60 + Owner: Neutral + Facing: 896 + Actor3: ingrnlmp + Location: 117,102 + Owner: Neutral + Facing: 896 + Actor4: ingrnlmp + Location: 82,23 + Owner: Neutral + Facing: 896 + Actor5: ingrnlmp + Location: 118,-2 + Owner: Neutral + Facing: 896 + Actor6: ingrnlmp + Location: 150,-42 + Owner: Neutral + Facing: 896 + Actor7: ingrnlmp + Location: 136,-84 + Owner: Neutral + Facing: 896 + Actor8: ingrnlmp + Location: 103,-46 + Owner: Neutral + Facing: 896 + Actor9: ingrnlmp + Location: 35,9 + Owner: Neutral + Facing: 896 + Actor10: ingrnlmp + Location: 141,12 + Owner: Neutral + Facing: 896 + Actor11: tibtre01 Location: 83,24 Owner: Neutral - Actor1: tibtre02 + Actor12: tibtre02 Location: 144,61 Owner: Neutral - Actor2: tibtre03 + Actor13: tibtre03 Location: 187,19 Owner: Neutral - Actor3: tibtre01 + Actor14: tibtre01 Location: 137,-83 Owner: Neutral - Actor4: tibtre01 + Actor15: tibtre01 Location: 119,-1 Owner: Neutral - Actor5: tibtre01 + Actor16: tibtre01 Location: 104,-45 Owner: Neutral - Actor6: tibtre02 + Actor17: tibtre02 Location: 151,-41 Owner: Neutral - Actor7: tree04 + Actor18: tree04 Location: 114,-74 Owner: Neutral - Actor8: tree05 + Actor19: tree05 Location: 114,-73 Owner: Neutral - Actor9: tree06 + Actor20: tree06 Location: 115,-73 Owner: Neutral - Actor10: tree06 + Actor21: tree06 Location: 85,-53 Owner: Neutral - Actor11: tree07 + Actor22: tree07 Location: 86,-53 Owner: Neutral - Actor12: tree08 + Actor23: tree08 Location: 86,-52 Owner: Neutral - Actor13: tree09 + Actor24: tree09 Location: 86,-54 Owner: Neutral - Actor14: tree10 + Actor25: tree10 Location: 85,-54 Owner: Neutral - Actor15: tree10 + Actor26: tree10 Location: 55,23 Owner: Neutral - Actor16: tree11 + Actor27: tree11 Location: 56,23 Owner: Neutral - Actor17: tree12 + Actor28: tree12 Location: 57,24 Owner: Neutral - Actor18: tree13 + Actor29: tree13 Location: 57,25 Owner: Neutral - Actor19: tree14 + Actor30: tree14 Location: 58,25 Owner: Neutral - Actor20: tree14 + Actor31: tree14 Location: 116,56 Owner: Neutral - Actor21: tree15 + Actor32: tree15 Location: 117,57 Owner: Neutral - Actor22: tree16 + Actor33: tree16 Location: 117,56 Owner: Neutral - Actor23: tree17 + Actor34: tree17 Location: 118,56 Owner: Neutral - Actor24: tree18 + Actor35: tree18 Location: 118,55 Owner: Neutral - Actor25: tree18 + Actor36: tree18 Location: 152,40 Owner: Neutral - Actor26: tree19 + Actor37: tree19 Location: 153,41 Owner: Neutral - Actor27: tree20 + Actor38: tree20 Location: 152,41 Owner: Neutral - Actor28: tree12 + Actor39: tree12 Location: 160,70 Owner: Neutral - Actor29: tree13 + Actor40: tree13 Location: 161,70 Owner: Neutral - Actor30: tree14 + Actor41: tree14 Location: 161,69 Owner: Neutral - Actor31: tree15 + Actor42: tree15 Location: 162,69 Owner: Neutral - Actor32: tree15 + Actor43: tree15 Location: 168,47 Owner: Neutral - Actor33: tree16 + Actor44: tree16 Location: 169,48 Owner: Neutral - Actor34: tree17 + Actor45: tree17 Location: 169,49 Owner: Neutral - Actor35: tree18 + Actor46: tree18 Location: 170,50 Owner: Neutral - Actor36: tree19 + Actor47: tree19 Location: 170,49 Owner: Neutral - Actor37: tree20 + Actor48: tree20 Location: 171,50 Owner: Neutral - Actor38: tree21 + Actor49: tree21 Location: 171,49 Owner: Neutral - Actor39: tree22 + Actor50: tree22 Location: 172,30 Owner: Neutral - Actor40: tree23 + Actor51: tree23 Location: 173,30 Owner: Neutral - Actor41: tree24 + Actor52: tree24 Location: 172,29 Owner: Neutral - Actor42: tree25 + Actor53: tree25 Location: 174,28 Owner: Neutral - Actor43: tibtre01 + Actor54: tibtre01 Location: 141,13 Owner: Neutral - Actor44: tree01 + Actor55: tree01 Location: 149,34 Owner: Neutral - Actor45: tree01 + Actor56: tree01 Location: 149,35 Owner: Neutral - Actor46: tree01 + Actor57: tree01 Location: 149,36 Owner: Neutral - Actor47: tree03 + Actor58: tree03 Location: 150,35 Owner: Neutral - Actor48: tree04 + Actor59: tree04 Location: 151,36 Owner: Neutral - Actor49: tree05 + Actor60: tree05 Location: 148,35 Owner: Neutral - Actor50: tree06 + Actor61: tree06 Location: 148,34 Owner: Neutral - Actor51: tree09 + Actor62: tree09 Location: 107,17 Owner: Neutral - Actor52: tree10 + Actor63: tree10 Location: 106,16 Owner: Neutral - Actor53: tree10 + Actor64: tree10 Location: 107,-17 Owner: Neutral - Actor54: tree11 + Actor65: tree11 Location: 106,-19 Owner: Neutral - Actor55: tree12 + Actor66: tree12 Location: 107,-18 Owner: Neutral - Actor56: tree13 + Actor67: tree13 Location: 108,-18 Owner: Neutral - Actor57: tree14 + Actor68: tree14 Location: 108,-19 Owner: Neutral - Actor58: tree14 + Actor69: tree14 Location: 89,-16 Owner: Neutral - Actor59: tree15 + Actor70: tree15 Location: 89,-18 Owner: Neutral - Actor60: tree16 + Actor71: tree16 Location: 88,-18 Owner: Neutral - Actor61: tree17 + Actor72: tree17 Location: 89,-19 Owner: Neutral - Actor62: tree18 + Actor73: tree18 Location: 90,-20 Owner: Neutral - Actor63: tree10 + Actor74: tree10 Location: 122,-8 Owner: Neutral - Actor64: tree11 + Actor75: tree11 Location: 123,-8 Owner: Neutral - Actor65: tree12 + Actor76: tree12 Location: 123,-9 Owner: Neutral - Actor66: tree13 + Actor77: tree13 Location: 124,-9 Owner: Neutral - Actor67: tree13 + Actor78: tree13 Location: 145,16 Owner: Neutral - Actor68: tree14 + Actor79: tree14 Location: 146,17 Owner: Neutral - Actor69: tree15 + Actor80: tree15 Location: 146,16 Owner: Neutral - Actor70: tree15 + Actor81: tree15 Location: 99,2 Owner: Neutral - Actor71: tree16 + Actor82: tree16 Location: 99,1 Owner: Neutral - Actor72: tree17 + Actor83: tree17 Location: 100,1 Owner: Neutral - Actor73: tree18 + Actor84: tree18 Location: 99,0 Owner: Neutral - Actor74: tree19 + Actor85: tree19 Location: 100,0 Owner: Neutral - Actor75: tree19 + Actor86: tree19 Location: 175,-21 Owner: Neutral - Actor76: tree21 + Actor87: tree21 Location: 176,-20 Owner: Neutral - Actor77: tree22 + Actor88: tree22 Location: 176,-21 Owner: Neutral - Actor78: tree23 + Actor89: tree23 Location: 176,-22 Owner: Neutral - Actor79: tree24 + Actor90: tree24 Location: 175,-22 Owner: Neutral - Actor80: tree01 + Actor91: tree01 Location: 101,36 Owner: Neutral - Actor81: tree03 + Actor92: tree03 Location: 102,37 Owner: Neutral - Actor82: tree05 + Actor93: tree05 Location: 103,36 Owner: Neutral - Actor83: tree06 + Actor94: tree06 Location: 103,35 Owner: Neutral - Actor84: tree07 + Actor95: tree07 Location: 104,35 Owner: Neutral - Actor85: tree25 + Actor96: tree25 Location: 172,-33 Owner: Neutral - Actor86: tree24 + Actor97: tree24 Location: 173,-33 Owner: Neutral - Actor87: tree23 + Actor98: tree23 Location: 152,-23 Owner: Neutral - Actor88: tree22 + Actor99: tree22 Location: 153,-23 Owner: Neutral - Actor89: tree21 + Actor100: tree21 Location: 153,-22 Owner: Neutral - Actor90: tree21 + Actor101: tree21 Location: 168,12 Owner: Neutral - Actor91: tree20 + Actor102: tree20 Location: 167,11 Owner: Neutral - Actor92: tree19 + Actor103: tree19 Location: 168,11 Owner: Neutral - Actor93: tree19 + Actor104: tree19 Location: 136,42 Owner: Neutral - Actor94: tree18 + Actor105: tree18 Location: 137,43 Owner: Neutral - Actor95: tree17 + Actor106: tree17 Location: 137,44 Owner: Neutral - Actor96: tree16 + Actor107: tree16 Location: 138,44 Owner: Neutral - Actor97: tree15 + Actor108: tree15 Location: 138,43 Owner: Neutral - Actor98: tree14 + Actor109: tree14 Location: 139,44 Owner: Neutral - Actor99: tree13 + Actor110: tree13 Location: 139,43 Owner: Neutral - Actor100: tree12 + Actor111: tree12 Location: 139,42 Owner: Neutral - Actor101: tree12 + Actor112: tree12 Location: 99,67 Owner: Neutral - Actor102: tree11 + Actor113: tree11 Location: 100,66 Owner: Neutral - Actor103: tree10 + Actor114: tree10 Location: 101,67 Owner: Neutral - Actor104: tree09 + Actor115: tree09 Location: 101,65 Owner: Neutral - Actor105: tree08 + Actor116: tree08 Location: 60,-10 Owner: Neutral - Actor106: tree08 + Actor117: tree08 Location: 134,0 Owner: Neutral - Actor107: tree07 + Actor118: tree07 Location: 136,0 Owner: Neutral - Actor108: tree06 + Actor119: tree06 Location: 135,-2 Owner: Neutral - Actor109: tree05 + Actor120: tree05 Location: 136,-2 Owner: Neutral - Actor110: tree05 + Actor121: tree05 Location: 176,33 Owner: Neutral - Actor111: tree05 + Actor122: tree05 Location: 130,67 Owner: Neutral - Actor112: tree04 + Actor123: tree04 Location: 130,65 Owner: Neutral - Actor113: tree03 + Actor124: tree03 Location: 132,67 Owner: Neutral - Actor114: tree03 + Actor125: tree03 Location: 114,92 Owner: Neutral - Actor115: tree02 + Actor126: tree02 Location: 115,90 Owner: Neutral - Actor116: tree01 + Actor127: tree01 Location: 115,91 Owner: Neutral - Actor117: tree06 + Actor128: tree06 Location: 116,93 Owner: Neutral - Actor118: tree06 + Actor129: tree06 Location: 93,-36 Owner: Neutral - Actor119: tree07 + Actor130: tree07 Location: 93,-39 Owner: Neutral - Actor120: tree08 + Actor131: tree08 Location: 94,-38 Owner: Neutral - Actor121: tree09 + Actor132: tree09 Location: 94,-37 Owner: Neutral - Actor122: tree09 + Actor133: tree09 Location: 115,-57 Owner: Neutral - Actor123: tree10 + Actor134: tree10 Location: 116,-57 Owner: Neutral - Actor124: tree11 + Actor135: tree11 Location: 116,-58 Owner: Neutral - Actor125: tree12 + Actor136: tree12 Location: 117,-58 Owner: Neutral - Actor126: tree13 + Actor137: tree13 Location: 119,-57 Owner: Neutral - Actor127: tree13 + Actor138: tree13 Location: 156,-6 Owner: Neutral - Actor128: tree14 + Actor139: tree14 Location: 158,-6 Owner: Neutral - Actor129: tree15 + Actor140: tree15 Location: 158,-4 Owner: Neutral - Actor130: tree16 + Actor141: tree16 Location: 160,-5 Owner: Neutral - Actor131: tree17 + Actor142: tree17 Location: 160,-6 Owner: Neutral - Actor132: tree17 + Actor143: tree17 Location: 147,-4 Owner: Neutral - Actor133: tree18 + Actor144: tree18 Location: 148,-4 Owner: Neutral - Actor134: tree19 + Actor145: tree19 Location: 146,-3 Owner: Neutral - Actor135: tree20 + Actor146: tree20 Location: 145,-3 Owner: Neutral - Actor136: tree20 + Actor147: tree20 Location: 140,-15 Owner: Neutral - Actor137: tree21 + Actor148: tree21 Location: 140,-16 Owner: Neutral - Actor138: tree22 + Actor149: tree22 Location: 141,-16 Owner: Neutral - Actor139: tree23 + Actor150: tree23 Location: 140,-17 Owner: Neutral - Actor140: tibtre02 + Actor151: tibtre02 Location: 206,-12 Owner: Neutral - Actor141: tibtre03 + Actor152: tibtre03 Location: 118,103 Owner: Neutral - Actor142: tibtre02 + Actor153: tibtre02 Location: 36,10 Owner: Neutral - Actor143: mpspawn + Actor154: mpspawn Location: 34,-2 Owner: Neutral - Actor144: mpspawn + Actor155: mpspawn Location: 187,-10 Owner: Neutral - Actor145: mpspawn + Actor156: mpspawn Location: 113,79 Owner: Neutral - Actor146: mpspawn + Actor157: mpspawn Location: 129,-91 Owner: Neutral - Actor147: waypoint + Actor158: waypoint Location: 120,0 Owner: Neutral - Actor148: waypoint + Actor159: waypoint Location: 120,0 Owner: Neutral - Actor149: trock04 + Actor160: trock04 Location: 61,51 Owner: Neutral - Actor150: trock02 + Actor161: trock02 Location: 69,52 Owner: Neutral - Actor151: trock03 + Actor162: trock03 Location: 81,60 Owner: Neutral - Actor152: trock05 + Actor163: trock05 Location: 84,60 Owner: Neutral Rules: - World: - GlobalLightingPaletteEffect: - Ambient: 0.63 + ^BaseWorld: + TerrainLighting: + Intensity: 0.605 + HeightStep: 0.05 + INGRNLMP: + TerrainLightSource: + Range: 7c832 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.7 + BlueTint: 0.01 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/t_garden/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/t_garden/map.png differ diff -Nru openra-20200503/mods/ts/maps/t_garden/map.yaml openra-20210321/mods/ts/maps/t_garden/map.yaml --- openra-20200503/mods/ts/maps/t_garden/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/t_garden/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -57,780 +57,850 @@ Actor0: gaoldcc1 Location: 65,54 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor1: gaoldcc4 Location: 67,53 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor2: gaoldcc1 Location: 138,-22 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor3: gaoldcc2 Location: 142,-21 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor4: gaoldcc3 Location: 99,83 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor5: gaoldcc4 Location: 165,10 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor6: gaoldcc6 Location: 167,12 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor7: gaoldcc5 Location: 169,12 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor8: gaoldcc4 Location: 76,-42 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor9: gaoldcc6 Location: 79,-39 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor10: cacrsh01 Location: 73,25 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor11: cacrsh02 Location: 102,69 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor12: cacrsh05 Location: 124,-26 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor13: cacrsh05 Location: 100,1 Owner: Neutral - Health: 100 - Facing: 96 - Actor14: visc_lrg + Facing: 896 + Actor14: ingrnlmp + Location: 77,5 + Owner: Neutral + Health: 99 + Facing: 896 + Actor15: ingrnlmp + Location: 99,29 + Owner: Neutral + Health: 99 + Facing: 896 + Actor16: ingrnlmp + Location: 98,-13 + Owner: Neutral + Health: 99 + Facing: 896 + Actor17: ingrnlmp + Location: 109,-3 + Owner: Neutral + Health: 99 + Facing: 896 + Actor18: ingrnlmp + Location: 120,-3 + Owner: Neutral + Health: 99 + Facing: 896 + Actor19: ingrnlmp + Location: 79,23 + Owner: Neutral + Health: 99 + Facing: 896 + Actor20: ingrnlmp + Location: 23,8 + Owner: Neutral + Health: 99 + Facing: 896 + Actor21: ingrnlmp + Location: 36,11 + Owner: Neutral + Health: 99 + Facing: 896 + Actor22: ingrnlmp + Location: 62,-33 + Owner: Neutral + Health: 99 + Facing: 896 + Actor23: ingrnlmp + Location: 71,-42 + Owner: Neutral + Health: 99 + Facing: 896 + Actor24: ingrnlmp + Location: 87,-61 + Owner: Neutral + Health: 99 + Facing: 896 + Actor25: ingrnlmp + Location: 111,-56 + Owner: Neutral + Health: 99 + Facing: 896 + Actor26: ingrnlmp + Location: 174,6 + Owner: Neutral + Health: 99 + Facing: 896 + Actor27: ingrnlmp + Location: 160,18 + Owner: Neutral + Health: 99 + Facing: 896 + Actor28: ingrnlmp + Location: 125,54 + Owner: Neutral + Health: 99 + Facing: 896 + Actor29: ingrnlmp + Location: 107,56 + Owner: Neutral + Health: 99 + Facing: 896 + Actor30: inblulmp + Location: 91,1 + Owner: Neutral + Facing: 896 + Actor31: visc_lrg Location: 81,22 Owner: Creeps Health: 62 - Facing: 0 - Actor15: visc_lrg + Facing: 256 + Actor32: visc_lrg Location: 102,2 Owner: Creeps Health: 77 - Facing: 128 - Actor16: visc_lrg + Facing: 768 + Actor33: visc_lrg Location: 35,-6 Owner: Creeps - Health: 100 - Facing: 0 - Actor17: visc_lrg + Facing: 256 + Actor34: visc_lrg Location: 148,-2 Owner: Creeps - Health: 100 - Facing: 128 - Actor18: doggie + Facing: 768 + Actor35: doggie Location: 141,-23 Owner: Creeps - Health: 100 - Facing: 100 - Actor19: doggie + Facing: 880 + Actor36: doggie Location: 167,11 Owner: Creeps - Health: 100 - Facing: 100 - Actor20: doggie + Facing: 880 + Actor37: doggie Location: 99,81 Owner: Creeps - Health: 100 - Facing: 99 - Actor21: doggie + Facing: 884 + Actor38: doggie Location: 70,53 Owner: Creeps - Health: 100 - Facing: 99 - Actor22: doggie + Facing: 884 + Actor39: doggie Location: 79,-41 Owner: Creeps - Health: 100 - Facing: 99 - Actor23: tibtre01 + Facing: 884 + Actor40: tibtre01 Location: 63,-32 Owner: Neutral - Actor24: tibtre02 + Actor41: tibtre02 Location: 72,-41 Owner: Neutral - Actor25: tibtre02 + Actor42: tibtre02 Location: 88,-60 Owner: Neutral - Actor26: tibtre01 + Actor43: tibtre01 Location: 112,-55 Owner: Neutral - Actor27: tibtre02 + Actor44: tibtre02 Location: 172,4 Owner: Neutral - Actor28: tibtre03 + Actor45: tibtre03 Location: 158,16 Owner: Neutral - Actor29: tibtre03 + Actor46: tibtre03 Location: 105,54 Owner: Neutral - Actor30: tibtre01 + Actor47: tibtre01 Location: 123,52 Owner: Neutral - Actor31: tree01 + Actor48: tree01 Location: 85,43 Owner: Neutral - Actor32: tree05 + Actor49: tree05 Location: 85,45 Owner: Neutral - Actor33: tree06 + Actor50: tree06 Location: 83,44 Owner: Neutral - Actor34: tree07 + Actor51: tree07 Location: 81,43 Owner: Neutral - Actor35: tree08 + Actor52: tree08 Location: 79,43 Owner: Neutral - Actor36: tree09 + Actor53: tree09 Location: 86,51 Owner: Neutral - Actor37: tree10 + Actor54: tree10 Location: 86,50 Owner: Neutral - Actor38: tree08 + Actor55: tree08 Location: 85,52 Owner: Neutral - Actor39: tree11 + Actor56: tree11 Location: 84,52 Owner: Neutral - Actor40: tree12 + Actor57: tree12 Location: 84,54 Owner: Neutral - Actor41: tree13 + Actor58: tree13 Location: 83,54 Owner: Neutral - Actor42: tree14 + Actor59: tree14 Location: 82,53 Owner: Neutral - Actor43: tree15 + Actor60: tree15 Location: 81,53 Owner: Neutral - Actor44: tree17 + Actor61: tree17 Location: 76,42 Owner: Neutral - Actor45: tree18 + Actor62: tree18 Location: 77,43 Owner: Neutral - Actor46: tree19 + Actor63: tree19 Location: 77,42 Owner: Neutral - Actor47: tree20 + Actor64: tree20 Location: 26,-8 Owner: Neutral - Actor48: tree02 + Actor65: tree02 Location: 27,-8 Owner: Neutral - Actor49: tree03 + Actor66: tree03 Location: 28,-8 Owner: Neutral - Actor50: tree04 + Actor67: tree04 Location: 28,-7 Owner: Neutral - Actor51: tree06 + Actor68: tree06 Location: 29,-8 Owner: Neutral - Actor52: tree06 + Actor69: tree06 Location: 31,-7 Owner: Neutral - Actor53: tree08 + Actor70: tree08 Location: 29,-7 Owner: Neutral - Actor54: tree09 + Actor71: tree09 Location: 30,-7 Owner: Neutral - Actor55: tree10 + Actor72: tree10 Location: 31,-6 Owner: Neutral - Actor56: tree11 + Actor73: tree11 Location: 31,-4 Owner: Neutral - Actor57: tree12 + Actor74: tree12 Location: 31,-5 Owner: Neutral - Actor58: tree13 + Actor75: tree13 Location: 31,-3 Owner: Neutral - Actor59: tree14 + Actor76: tree14 Location: 54,23 Owner: Neutral - Actor60: tree15 + Actor77: tree15 Location: 55,22 Owner: Neutral - Actor61: tree16 + Actor78: tree16 Location: 56,23 Owner: Neutral - Actor62: tree17 + Actor79: tree17 Location: 56,24 Owner: Neutral - Actor63: tree18 + Actor80: tree18 Location: 57,26 Owner: Neutral - Actor64: tree19 + Actor81: tree19 Location: 57,24 Owner: Neutral - Actor65: tree20 + Actor82: tree20 Location: 54,21 Owner: Neutral - Actor66: tree21 + Actor83: tree21 Location: 53,21 Owner: Neutral - Actor67: tree22 + Actor84: tree22 Location: 57,23 Owner: Neutral - Actor68: tree01 + Actor85: tree01 Location: 52,-4 Owner: Neutral - Actor69: tree02 + Actor86: tree02 Location: 52,-3 Owner: Neutral - Actor70: tree03 + Actor87: tree03 Location: 53,-3 Owner: Neutral - Actor71: tree05 + Actor88: tree05 Location: 54,-2 Owner: Neutral - Actor72: tree06 + Actor89: tree06 Location: 55,-3 Owner: Neutral - Actor73: tree07 + Actor90: tree07 Location: 54,-3 Owner: Neutral - Actor74: tree08 + Actor91: tree08 Location: 52,-6 Owner: Neutral - Actor75: tree09 + Actor92: tree09 Location: 53,-5 Owner: Neutral - Actor76: tree10 + Actor93: tree10 Location: 55,-4 Owner: Neutral - Actor77: tree11 + Actor94: tree11 Location: 56,-4 Owner: Neutral - Actor78: tree12 + Actor95: tree12 Location: 82,-38 Owner: Neutral - Actor79: tree13 + Actor96: tree13 Location: 82,-39 Owner: Neutral - Actor80: tree14 + Actor97: tree14 Location: 82,-40 Owner: Neutral - Actor81: tree14 + Actor98: tree14 Location: 78,-44 Owner: Neutral - Actor82: tree15 + Actor99: tree15 Location: 79,-44 Owner: Neutral - Actor83: tree16 + Actor100: tree16 Location: 80,-44 Owner: Neutral - Actor84: tree17 + Actor101: tree17 Location: 80,-43 Owner: Neutral - Actor85: tree18 + Actor102: tree18 Location: 81,-42 Owner: Neutral - Actor86: tree19 + Actor103: tree19 Location: 80,-40 Owner: Neutral - Actor87: tree20 + Actor104: tree20 Location: 79,-42 Owner: Neutral - Actor88: tree21 + Actor105: tree21 Location: 94,71 Owner: Neutral - Actor89: tree22 + Actor106: tree22 Location: 96,72 Owner: Neutral - Actor90: tree23 + Actor107: tree23 Location: 95,72 Owner: Neutral - Actor91: tree24 + Actor108: tree24 Location: 95,71 Owner: Neutral - Actor92: tree25 + Actor109: tree25 Location: 97,72 Owner: Neutral - Actor93: tree01 + Actor110: tree01 Location: 140,47 Owner: Neutral - Actor94: tree02 + Actor111: tree02 Location: 139,46 Owner: Neutral - Actor95: tree03 + Actor112: tree03 Location: 141,47 Owner: Neutral - Actor96: tree04 + Actor113: tree04 Location: 139,44 Owner: Neutral - Actor97: tree05 + Actor114: tree05 Location: 140,44 Owner: Neutral - Actor98: tree06 + Actor115: tree06 Location: 140,43 Owner: Neutral - Actor99: tree07 + Actor116: tree07 Location: 140,42 Owner: Neutral - Actor100: tree08 + Actor117: tree08 Location: 140,41 Owner: Neutral - Actor101: tree09 + Actor118: tree09 Location: 142,39 Owner: Neutral - Actor102: tree10 + Actor119: tree10 Location: 141,40 Owner: Neutral - Actor103: tree11 + Actor120: tree11 Location: 142,38 Owner: Neutral - Actor104: tree12 + Actor121: tree12 Location: 143,45 Owner: Neutral - Actor105: tree12 + Actor122: tree12 Location: 142,44 Owner: Neutral - Actor106: tree13 + Actor123: tree13 Location: 142,43 Owner: Neutral - Actor107: tree14 + Actor124: tree14 Location: 141,42 Owner: Neutral - Actor108: tree16 + Actor125: tree16 Location: 142,45 Owner: Neutral - Actor109: tree16 + Actor126: tree16 Location: 76,-56 Owner: Neutral - Actor110: tree17 + Actor127: tree17 Location: 75,-57 Owner: Neutral - Actor111: tree18 + Actor128: tree18 Location: 76,-58 Owner: Neutral - Actor112: tree19 + Actor129: tree19 Location: 75,-58 Owner: Neutral - Actor113: tree20 + Actor130: tree20 Location: 77,-57 Owner: Neutral - Actor114: tree22 + Actor131: tree22 Location: 79,-56 Owner: Neutral - Actor115: tree24 + Actor132: tree24 Location: 79,-57 Owner: Neutral - Actor116: tree25 + Actor133: tree25 Location: 78,-59 Owner: Neutral - Actor117: tree01 + Actor134: tree01 Location: 78,-58 Owner: Neutral - Actor118: tree03 + Actor135: tree03 Location: 80,-59 Owner: Neutral - Actor119: tree04 + Actor136: tree04 Location: 81,-60 Owner: Neutral - Actor120: tree05 + Actor137: tree05 Location: 80,-61 Owner: Neutral - Actor121: tree06 + Actor138: tree06 Location: 80,-62 Owner: Neutral - Actor122: tree09 + Actor139: tree09 Location: 82,-62 Owner: Neutral - Actor123: tree11 + Actor140: tree11 Location: 82,-55 Owner: Neutral - Actor124: tree12 + Actor141: tree12 Location: 85,-50 Owner: Neutral - Actor125: tree13 + Actor142: tree13 Location: 86,-49 Owner: Neutral - Actor126: tree14 + Actor143: tree14 Location: 84,-52 Owner: Neutral - Actor127: tree01 + Actor144: tree01 Location: 151,-14 Owner: Neutral - Actor128: tree03 + Actor145: tree03 Location: 152,-15 Owner: Neutral - Actor129: tree04 + Actor146: tree04 Location: 151,-13 Owner: Neutral - Actor130: tree05 + Actor147: tree05 Location: 149,-14 Owner: Neutral - Actor131: tree06 + Actor148: tree06 Location: 149,-15 Owner: Neutral - Actor132: tree07 + Actor149: tree07 Location: 149,-16 Owner: Neutral - Actor133: tree08 + Actor150: tree08 Location: 152,-19 Owner: Neutral - Actor134: tree09 + Actor151: tree09 Location: 151,-20 Owner: Neutral - Actor135: tree10 + Actor152: tree10 Location: 149,-21 Owner: Neutral - Actor136: tree11 + Actor153: tree11 Location: 151,-17 Owner: Neutral - Actor137: tree12 + Actor154: tree12 Location: 145,-13 Owner: Neutral - Actor138: tree13 + Actor155: tree13 Location: 145,-12 Owner: Neutral - Actor139: tree14 + Actor156: tree14 Location: 144,-13 Owner: Neutral - Actor140: tree15 + Actor157: tree15 Location: 144,-12 Owner: Neutral - Actor141: tree16 + Actor158: tree16 Location: 143,-14 Owner: Neutral - Actor142: tree17 + Actor159: tree17 Location: 140,-13 Owner: Neutral - Actor143: tree19 + Actor160: tree19 Location: 141,-13 Owner: Neutral - Actor144: tibtre01 + Actor161: tibtre01 Location: 21,7 Owner: Neutral - Actor145: tibtre03 + Actor162: tibtre03 Location: 35,10 Owner: Neutral - Actor146: tree02 + Actor163: tree02 Location: 66,53 Owner: Neutral - Actor147: tree03 + Actor164: tree03 Location: 67,56 Owner: Neutral - Actor148: tree04 + Actor165: tree04 Location: 68,56 Owner: Neutral - Actor149: tree05 + Actor166: tree05 Location: 69,53 Owner: Neutral - Actor150: tree07 + Actor167: tree07 Location: 70,55 Owner: Neutral - Actor151: tree08 + Actor168: tree08 Location: 69,57 Owner: Neutral - Actor152: tree08 + Actor169: tree08 Location: 65,41 Owner: Neutral - Actor153: tibtre01 + Actor170: tibtre01 Location: 78,22 Owner: Neutral - Actor154: tibtre02 + Actor171: tibtre02 Location: 75,5 Owner: Neutral - Actor155: tibtre03 + Actor172: tibtre03 Location: 107,-4 Owner: Neutral - Actor156: tibtre01 + Actor173: tibtre01 Location: 97,-13 Owner: Neutral - Actor157: tibtre03 + Actor174: tibtre03 Location: 98,28 Owner: Neutral - Actor158: tibtre02 + Actor175: tibtre02 Location: 118,-4 Owner: Neutral - Actor159: tree03 + Actor176: tree03 Location: 140,-20 Owner: Neutral - Actor160: tree04 + Actor177: tree04 Location: 144,-21 Owner: Neutral - Actor161: tree05 + Actor178: tree05 Location: 141,-22 Owner: Neutral - Actor162: tree06 + Actor179: tree06 Location: 143,-19 Owner: Neutral - Actor163: tree07 + Actor180: tree07 Location: 138,-23 Owner: Neutral - Actor164: tree08 + Actor181: tree08 Location: 138,-24 Owner: Neutral - Actor165: tree09 + Actor182: tree09 Location: 139,-25 Owner: Neutral - Actor166: tree10 + Actor183: tree10 Location: 142,-19 Owner: Neutral - Actor167: tree11 + Actor184: tree11 Location: 141,-19 Owner: Neutral - Actor168: tree03 + Actor185: tree03 Location: 98,-50 Owner: Neutral - Actor169: tree04 + Actor186: tree04 Location: 98,-51 Owner: Neutral - Actor170: tree05 + Actor187: tree05 Location: 99,-51 Owner: Neutral - Actor171: tree06 + Actor188: tree06 Location: 99,-50 Owner: Neutral - Actor172: tree07 + Actor189: tree07 Location: 100,-50 Owner: Neutral - Actor173: tree08 + Actor190: tree08 Location: 101,-50 Owner: Neutral - Actor174: tree09 + Actor191: tree09 Location: 102,-49 Owner: Neutral - Actor175: tree03 + Actor192: tree03 Location: 72,-24 Owner: Neutral - Actor176: tree04 + Actor193: tree04 Location: 72,-26 Owner: Neutral - Actor177: tree05 + Actor194: tree05 Location: 72,-30 Owner: Neutral - Actor178: tree06 + Actor195: tree06 Location: 74,-30 Owner: Neutral - Actor179: tree07 + Actor196: tree07 Location: 75,-32 Owner: Neutral - Actor180: tree08 + Actor197: tree08 Location: 75,-33 Owner: Neutral - Actor181: tree09 + Actor198: tree09 Location: 74,-33 Owner: Neutral - Actor182: tree04 + Actor199: tree04 Location: 121,35 Owner: Neutral - Actor183: tree05 + Actor200: tree05 Location: 120,35 Owner: Neutral - Actor184: tree06 + Actor201: tree06 Location: 120,34 Owner: Neutral - Actor185: tree06 + Actor202: tree06 Location: 113,35 Owner: Neutral - Actor186: tree07 + Actor203: tree07 Location: 113,34 Owner: Neutral - Actor187: tree08 + Actor204: tree08 Location: 114,34 Owner: Neutral - Actor188: tree09 + Actor205: tree09 Location: 115,34 Owner: Neutral - Actor189: tree10 + Actor206: tree10 Location: 117,34 Owner: Neutral - Actor190: tree11 + Actor207: tree11 Location: 121,37 Owner: Neutral - Actor191: tree12 + Actor208: tree12 Location: 121,40 Owner: Neutral - Actor192: tree23 + Actor209: tree23 Location: 101,80 Owner: Neutral - Actor193: tree24 + Actor210: tree24 Location: 104,81 Owner: Neutral - Actor194: tree25 + Actor211: tree25 Location: 96,79 Owner: Neutral - Actor195: tree21 + Actor212: tree21 Location: 102,84 Owner: Neutral - Actor196: tree20 + Actor213: tree20 Location: 98,84 Owner: Neutral - Actor197: tree18 + Actor214: tree18 Location: 100,82 Owner: Neutral - Actor198: tree16 + Actor215: tree16 Location: 97,76 Owner: Neutral - Actor199: tree15 + Actor216: tree15 Location: 97,75 Owner: Neutral - Actor200: tree04 + Actor217: tree04 Location: 168,11 Owner: Neutral - Actor201: tree05 + Actor218: tree05 Location: 167,10 Owner: Neutral - Actor202: tree06 + Actor219: tree06 Location: 169,15 Owner: Neutral - Actor203: tree07 + Actor220: tree07 Location: 169,16 Owner: Neutral - Actor204: tree08 + Actor221: tree08 Location: 170,17 Owner: Neutral - Actor205: tree09 + Actor222: tree09 Location: 163,9 Owner: Neutral - Actor206: tree10 + Actor223: tree10 Location: 162,10 Owner: Neutral - Actor207: tree11 + Actor224: tree11 Location: 165,7 Owner: Neutral - Actor208: tree12 + Actor225: tree12 Location: 166,7 Owner: Neutral - Actor209: tree14 + Actor226: tree14 Location: 166,8 Owner: Neutral - Actor210: mpspawn + Actor227: mpspawn Location: 115,60 Owner: Neutral - Actor211: mpspawn + Actor228: mpspawn Location: 56,43 Owner: Neutral - Actor212: mpspawn + Actor229: mpspawn Location: 53,-19 Owner: Neutral - Actor213: mpspawn + Actor230: mpspawn Location: 112,-46 Owner: Neutral - Actor214: mpspawn + Actor231: mpspawn Location: 151,20 Owner: Neutral - Actor215: waypoint + Actor232: waypoint Location: 91,21 Owner: Neutral - Actor216: waypoint + Actor233: waypoint Location: 82,8 Owner: Neutral - Actor217: waypoint + Actor234: waypoint Location: 86,-7 Owner: Neutral - Actor218: waypoint + Actor235: waypoint Location: 93,-18 Owner: Neutral - Actor219: waypoint + Actor236: waypoint Location: 109,-11 Owner: Neutral - Actor220: waypoint + Actor237: waypoint Location: 116,0 Owner: Neutral - Actor221: waypoint + Actor238: waypoint Location: 104,7 Owner: Neutral - Actor222: waypoint + Actor239: waypoint Location: 97,14 Owner: Neutral - Actor223: waypoint + Actor240: waypoint Location: 92,41 Owner: Neutral - Actor224: waypoint + Actor241: waypoint Location: 70,24 Owner: Neutral - Actor225: waypoint + Actor242: waypoint Location: 54,3 Owner: Neutral - Actor226: waypoint + Actor243: waypoint Location: 87,-33 Owner: Neutral - Actor227: waypoint + Actor244: waypoint Location: 119,-12 Owner: Neutral - Actor228: waypoint + Actor245: waypoint Location: 112,26 Owner: Neutral - Actor229: waypoint + Actor246: waypoint Location: 92,4 Owner: Neutral - Actor230: waypoint + Actor247: waypoint Location: 92,4 Owner: Neutral - Actor231: trock02 + Actor248: trock02 Location: 35,4 Owner: Neutral - Actor232: trock04 + Actor249: trock04 Location: 100,-48 Owner: Neutral - Actor233: trock05 + Actor250: trock05 Location: 89,-34 Owner: Neutral - Actor234: trock01 + Actor251: trock01 Location: 62,-6 Owner: Neutral - Actor235: trock03 + Actor252: trock03 Location: 129,-36 Owner: Neutral - Actor236: veinhole + Actor253: veinhole Location: 101,-6 Owner: Neutral - Actor237: veinhole + Actor254: veinhole Location: 86,18 Owner: Neutral - Actor238: trock03 + Actor255: trock03 Location: 80,60 Owner: Neutral - Actor239: trock02 + Actor256: trock02 Location: 156,0 Owner: Neutral - Actor240: trock01 + Actor257: trock01 Location: 153,4 Owner: Neutral - Actor241: trock05 + Actor258: trock05 Location: 139,33 Owner: Neutral - Actor242: trock04 + Actor259: trock04 Location: 99,74 Owner: Neutral Rules: - World: - GlobalLightingPaletteEffect: - Ambient: 0.79 + ^BaseWorld: + TerrainLighting: + Intensity: 0.79 + INGRNLMP: + TerrainLightSource: + Range: 7c832 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.7 + BlueTint: 0.01 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/ThePit/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/ThePit/map.png differ diff -Nru openra-20200503/mods/ts/maps/ThePit/map.yaml openra-20210321/mods/ts/maps/ThePit/map.yaml --- openra-20200503/mods/ts/maps/ThePit/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/ThePit/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1173,27 +1173,27 @@ Actor434: car Owner: Neutral Location: 82,-56 - Facing: 32 + Facing: 128 Actor433: pick Owner: Neutral Location: 74,64 - Facing: 92 + Facing: 368 Actor432: car Owner: Neutral Location: 77,58 - Facing: 32 + Facing: 128 Actor435: pick Owner: Neutral Location: 101,-48 - Facing: -32 + Facing: 896 Actor436: bus Owner: Neutral Location: 29,0 - Facing: 32 + Facing: 128 Actor437: truckb Owner: Neutral Location: 130,1 - Facing: 160 + Facing: 640 Actor431: trock03 Owner: Neutral Location: 29,3 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/tiers/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/tiers/map.png differ diff -Nru openra-20200503/mods/ts/maps/tiers/map.yaml openra-20210321/mods/ts/maps/tiers/map.yaml --- openra-20200503/mods/ts/maps/tiers/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/tiers/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -39,374 +39,429 @@ Enemies: Creeps Actors: - Actor0: tibtre01 + Actor0: inblulmp + Location: 71,-45 + Owner: Neutral + Facing: 896 + Actor1: inblulmp + Location: 62,-45 + Owner: Neutral + Facing: 896 + Actor2: inblulmp + Location: 71,17 + Owner: Neutral + Facing: 896 + Actor3: inblulmp + Location: 66,33 + Owner: Neutral + Facing: 896 + Actor4: ingrnlmp + Location: 85,-14 + Owner: Neutral + Facing: 896 + Actor5: ingrnlmp + Location: 49,7 + Owner: Neutral + Facing: 896 + Actor6: ingrnlmp + Location: 51,-15 + Owner: Neutral + Facing: 896 + Actor7: ingrnlmp + Location: 80,7 + Owner: Neutral + Facing: 896 + Actor8: ingrnlmp + Location: 57,44 + Owner: Neutral + Facing: 896 + Actor9: ingrnlmp + Location: 78,-26 + Owner: Neutral + Facing: 896 + Actor10: tibtre01 Location: 57,44 Owner: Neutral - Actor1: tibtre02 + Actor11: tibtre02 Location: 80,7 Owner: Neutral - Actor2: tibtre03 + Actor12: tibtre03 Location: 49,7 Owner: Neutral - Actor3: tibtre01 + Actor13: tibtre01 Location: 51,-15 Owner: Neutral - Actor4: tibtre02 + Actor14: tibtre02 Location: 78,-26 Owner: Neutral - Actor5: tibtre03 + Actor15: tibtre03 Location: 85,-14 Owner: Neutral - Actor6: fona01 + Actor16: fona01 Location: 62,35 Owner: Neutral - Actor7: fona02 + Actor17: fona02 Location: 63,28 Owner: Neutral - Actor8: fona03 + Actor18: fona03 Location: 73,34 Owner: Neutral - Actor9: fona04 + Actor19: fona04 Location: 71,29 Owner: Neutral - Actor10: fona05 + Actor20: fona05 Location: 69,20 Owner: Neutral - Actor11: fona01 + Actor21: fona01 Location: 81,22 Owner: Neutral - Actor12: fona02 + Actor22: fona02 Location: 78,18 Owner: Neutral - Actor13: fona03 + Actor23: fona03 Location: 80,29 Owner: Neutral - Actor14: fona04 + Actor24: fona04 Location: 69,13 Owner: Neutral - Actor15: fona11 + Actor25: fona11 Location: 66,30 Owner: Neutral - Actor16: fona12 + Actor26: fona12 Location: 79,31 Owner: Neutral - Actor17: fona13 + Actor27: fona13 Location: 63,35 Owner: Neutral - Actor18: fona14 + Actor28: fona14 Location: 78,16 Owner: Neutral - Actor19: fona15 + Actor29: fona15 Location: 80,25 Owner: Neutral - Actor20: fona01 + Actor30: fona01 Location: 57,-45 Owner: Neutral - Actor21: fona02 + Actor31: fona02 Location: 57,-40 Owner: Neutral - Actor22: fona03 + Actor32: fona03 Location: 66,-40 Owner: Neutral - Actor23: fona04 + Actor33: fona04 Location: 70,-36 Owner: Neutral - Actor24: fona05 + Actor34: fona05 Location: 74,-40 Owner: Neutral - Actor25: fona11 + Actor35: fona11 Location: 68,-39 Owner: Neutral - Actor26: fona12 + Actor36: fona12 Location: 72,-39 Owner: Neutral - Actor27: fona13 + Actor37: fona13 Location: 55,-40 Owner: Neutral - Actor28: fona14 + Actor38: fona14 Location: 67,-46 Owner: Neutral - Actor29: fona15 + Actor39: fona15 Location: 72,-47 Owner: Neutral - Actor30: fona06 + Actor40: fona06 Location: 50,25 Owner: Neutral - Actor31: fona07 + Actor41: fona07 Location: 54,26 Owner: Neutral - Actor32: fona08 + Actor42: fona08 Location: 46,18 Owner: Neutral - Actor33: fona09 + Actor43: fona09 Location: 52,19 Owner: Neutral - Actor34: fona10 + Actor44: fona10 Location: 48,17 Owner: Neutral - Actor35: fona08 + Actor45: fona08 Location: 48,21 Owner: Neutral - Actor36: fona06 + Actor46: fona06 Location: 68,6 Owner: Neutral - Actor37: fona07 + Actor47: fona07 Location: 70,5 Owner: Neutral - Actor38: fona08 + Actor48: fona08 Location: 72,3 Owner: Neutral - Actor39: fona09 + Actor49: fona09 Location: 74,0 Owner: Neutral - Actor40: fona10 + Actor50: fona10 Location: 57,-10 Owner: Neutral - Actor41: fona08 + Actor51: fona08 Location: 54,-8 Owner: Neutral - Actor42: fona07 + Actor52: fona07 Location: 56,-7 Owner: Neutral - Actor43: fona06 + Actor53: fona06 Location: 58,-28 Owner: Neutral - Actor44: fona08 + Actor54: fona08 Location: 59,-30 Owner: Neutral - Actor45: fona07 + Actor55: fona07 Location: 57,-22 Owner: Neutral - Actor46: fona09 + Actor56: fona09 Location: 54,-22 Owner: Neutral - Actor47: fona10 + Actor57: fona10 Location: 53,-22 Owner: Neutral - Actor48: tree01 + Actor58: tree01 Location: 16,9 Owner: Neutral - Actor49: tree03 + Actor59: tree03 Location: 14,6 Owner: Neutral - Actor50: tree04 + Actor60: tree04 Location: 19,5 Owner: Neutral - Actor51: tree05 + Actor61: tree05 Location: 18,7 Owner: Neutral - Actor52: tree06 + Actor62: tree06 Location: 19,13 Owner: Neutral - Actor53: tree07 + Actor63: tree07 Location: 31,-10 Owner: Neutral - Actor54: tree08 + Actor64: tree08 Location: 34,-12 Owner: Neutral - Actor55: tree09 + Actor65: tree09 Location: 30,-8 Owner: Neutral - Actor56: tree10 + Actor66: tree10 Location: 36,-11 Owner: Neutral - Actor57: tree11 + Actor67: tree11 Location: 32,-11 Owner: Neutral - Actor58: tree12 + Actor68: tree12 Location: 36,28 Owner: Neutral - Actor59: tree13 + Actor69: tree13 Location: 38,28 Owner: Neutral - Actor60: tree14 + Actor70: tree14 Location: 37,30 Owner: Neutral - Actor61: tree15 + Actor71: tree15 Location: 28,22 Owner: Neutral - Actor62: tree15 + Actor72: tree15 Location: 73,24 Owner: Neutral - Actor63: tree16 + Actor73: tree16 Location: 65,43 Owner: Neutral - Actor64: tree17 + Actor74: tree17 Location: 67,45 Owner: Neutral - Actor65: tree18 + Actor75: tree18 Location: 90,14 Owner: Neutral - Actor66: tree19 + Actor76: tree19 Location: 90,16 Owner: Neutral - Actor67: tree20 + Actor77: tree20 Location: 92,16 Owner: Neutral - Actor68: tree02 + Actor78: tree02 Location: 90,15 Owner: Neutral - Actor69: tree03 + Actor79: tree03 Location: 98,13 Owner: Neutral - Actor70: tree04 + Actor80: tree04 Location: 98,15 Owner: Neutral - Actor71: tree05 + Actor81: tree05 Location: 92,19 Owner: Neutral - Actor72: tree06 + Actor82: tree06 Location: 94,18 Owner: Neutral - Actor73: tree06 + Actor83: tree06 Location: 39,-17 Owner: Neutral - Actor74: tree07 + Actor84: tree07 Location: 41,-16 Owner: Neutral - Actor75: tree08 + Actor85: tree08 Location: 37,-16 Owner: Neutral - Actor76: tree09 + Actor86: tree09 Location: 41,-23 Owner: Neutral - Actor77: tree10 + Actor87: tree10 Location: 43,-21 Owner: Neutral - Actor78: tree11 + Actor88: tree11 Location: 41,-15 Owner: Neutral - Actor79: tree12 + Actor89: tree12 Location: 38,-20 Owner: Neutral - Actor80: tree12 + Actor90: tree12 Location: 114,-8 Owner: Neutral - Actor81: tree12 + Actor91: tree12 Location: 113,-8 Owner: Neutral - Actor82: tree13 + Actor92: tree13 Location: 113,-7 Owner: Neutral - Actor83: tree14 + Actor93: tree14 Location: 115,-6 Owner: Neutral - Actor84: tree15 + Actor94: tree15 Location: 113,-10 Owner: Neutral - Actor85: tree01 + Actor95: tree01 Location: 81,-34 Owner: Neutral - Actor86: tree02 + Actor96: tree02 Location: 79,-43 Owner: Neutral - Actor87: tree03 + Actor97: tree03 Location: 85,-35 Owner: Neutral - Actor88: tree04 + Actor98: tree04 Location: 89,-34 Owner: Neutral - Actor89: tree05 + Actor99: tree05 Location: 86,-36 Owner: Neutral - Actor90: tree06 + Actor100: tree06 Location: 77,-46 Owner: Neutral - Actor91: tree07 + Actor101: tree07 Location: 83,-35 Owner: Neutral - Actor92: tree08 + Actor102: tree08 Location: 89,-32 Owner: Neutral - Actor93: tree09 + Actor103: tree09 Location: 70,-25 Owner: Neutral - Actor94: tree09 + Actor104: tree09 Location: 61,-50 Owner: Neutral - Actor95: tree10 + Actor105: tree10 Location: 63,-51 Owner: Neutral - Actor96: tree11 + Actor106: tree11 Location: 66,-50 Owner: Neutral - Actor97: tree12 + Actor107: tree12 Location: 58,-47 Owner: Neutral - Actor98: tree13 + Actor108: tree13 Location: 62,-50 Owner: Neutral - Actor99: tree14 + Actor109: tree14 Location: 63,-49 Owner: Neutral - Actor100: tree14 + Actor110: tree14 Location: 70,-51 Owner: Neutral - Actor101: tree15 + Actor111: tree15 Location: 72,-51 Owner: Neutral - Actor102: tree16 + Actor112: tree16 Location: 72,-50 Owner: Neutral - Actor103: tree17 + Actor113: tree17 Location: 74,-48 Owner: Neutral - Actor104: tree18 + Actor114: tree18 Location: 57,9 Owner: Neutral - Actor105: tree20 + Actor115: tree20 Location: 62,11 Owner: Neutral - Actor106: tree21 + Actor116: tree21 Location: 65,-2 Owner: Neutral - Actor107: tree22 + Actor117: tree22 Location: 56,-4 Owner: Neutral - Actor108: tree23 + Actor118: tree23 Location: 69,1 Owner: Neutral - Actor109: tree24 + Actor119: tree24 Location: 65,-13 Owner: Neutral - Actor110: tree25 + Actor120: tree25 Location: 72,-7 Owner: Neutral - Actor111: bigblue3 + Actor121: bigblue3 Location: 66,33 Owner: Neutral - Actor112: bigblue3 + Actor122: bigblue3 Location: 71,17 Owner: Neutral - Actor113: bigblue3 + Actor123: bigblue3 Location: 62,-45 Owner: Neutral - Actor114: bigblue3 + Actor124: bigblue3 Location: 71,-45 Owner: Neutral - Actor115: mpspawn + Actor125: mpspawn Location: 40,5 Owner: Neutral - Actor116: mpspawn + Actor126: mpspawn Location: 97,-10 Owner: Neutral - Actor117: waypoint + Actor127: waypoint Location: 55,-5 Owner: Neutral - Actor118: waypoint + Actor128: waypoint Location: 55,-5 Owner: Neutral - Actor119: veinhole + Actor129: veinhole Location: 61,-18 Owner: Neutral - Actor120: veinhole + Actor130: veinhole Location: 72,-11 Owner: Neutral - Actor121: veinhole + Actor131: veinhole Location: 62,1 Owner: Neutral Rules: - World: - GlobalLightingPaletteEffect: - Ambient: 0.79 + ^BaseWorld: + TerrainLighting: + Intensity: 0.79 + HeightStep: 0.014 + INGRNLMP: + TerrainLightSource: + Range: 7c832 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.7 + BlueTint: 0.01 + INBLULMP: + TerrainLightSource: + Range: 9c784 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.01 + BlueTint: 0.7 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/tread_l/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/tread_l/map.png differ diff -Nru openra-20200503/mods/ts/maps/tread_l/map.yaml openra-20210321/mods/ts/maps/tread_l/map.yaml --- openra-20200503/mods/ts/maps/tread_l/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/tread_l/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -72,1647 +72,1739 @@ Actor0: aban01 Location: 116,21 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor1: aban05 Location: 117,16 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor2: aban06 Location: 119,20 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor3: aban07 Location: 123,20 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor4: aban09 Location: 121,17 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor5: aban11 Location: 125,18 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor6: aban12 Location: 119,24 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor7: aban13 Location: 122,25 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor8: aban14 Location: 124,24 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor9: aban15 Location: 121,31 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor10: aban02 Location: 92,-47 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor11: aban12 Location: 100,-45 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor12: aban15 Location: 168,-143 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor13: aban05 Location: 205,-112 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor14: aban09 Location: 206,-115 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor15: aban12 Location: 263,-50 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor16: aban13 Location: 266,-52 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor17: aban15 Location: 266,-47 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor18: aban11 Location: 267,-50 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor19: aban16 Location: 182,31 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor20: aban17 Location: 185,31 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor21: aban17 Location: 185,32 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor22: aban18 Location: 186,30 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 + Actor23: cabhut + Location: 112,15 + Owner: Neutral + Facing: 896 + Actor24: cabhut + Location: 116,-9 + Owner: Neutral + Facing: 896 + Actor25: cabhut + Location: 96,34 + Owner: Neutral + Facing: 896 + Actor26: cabhut + Location: 121,44 + Owner: Neutral + Facing: 896 + Actor27: cabhut + Location: 126,30 + Owner: Neutral + Facing: 896 + Actor28: cabhut + Location: 85,11 + Owner: Neutral + Facing: 896 + Actor29: cabhut + Location: 130,-13 + Owner: Neutral + Facing: 896 + Actor30: cabhut + Location: 146,-9 + Owner: Neutral + Facing: 896 + Actor31: cabhut + Location: 151,-25 + Owner: Neutral + Facing: 896 + Actor32: cabhut + Location: 155,-42 + Owner: Neutral + Facing: 896 Actor33: cabhut Location: 145,-66 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 + Actor34: cabhut + Location: 159,-69 + Owner: Neutral + Facing: 896 + Actor35: cabhut + Location: 173,-66 + Owner: Neutral + Facing: 896 + Actor36: cabhut + Location: 181,-34 + Owner: Neutral + Facing: 896 Actor37: cabhut Location: 163,-137 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor38: cabhut Location: 159,-128 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor39: aban05 Location: 158,-61 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor40: aban06 Location: 150,-61 Owner: Neutral Health: 50 - Facing: 96 + Facing: 896 Actor41: aban13 Location: 156,-55 Owner: Neutral - Health: 100 - Facing: 96 + Facing: 896 Actor42: aban09 Location: 155,-60 Owner: Neutral Health: 50 - Facing: 96 - Actor43: tstlamp + Facing: 896 + Actor43: ingrnlmp + Location: 27,0 + Owner: Neutral + Health: 99 + Facing: 896 + Actor44: ingrnlmp + Location: 119,-90 + Owner: Neutral + Health: 99 + Facing: 896 + Actor45: ingrnlmp + Location: 172,-122 + Owner: Neutral + Health: 99 + Facing: 896 + Actor46: ingrnlmp + Location: 186,-92 + Owner: Neutral + Health: 99 + Facing: 896 + Actor47: ingrnlmp + Location: 222,-36 + Owner: Neutral + Health: 99 + Facing: 896 + Actor48: ingrnlmp + Location: 182,16 + Owner: Neutral + Health: 99 + Facing: 896 + Actor49: ingrnlmp + Location: 114,70 + Owner: Neutral + Health: 99 + Facing: 896 + Actor50: ingrnlmp + Location: 53,38 + Owner: Neutral + Health: 99 + Facing: 896 + Actor51: ingrnlmp + Location: 111,35 + Owner: Neutral + Health: 99 + Facing: 896 + Actor52: ingrnlmp + Location: 103,18 + Owner: Neutral + Health: 99 + Facing: 896 + Actor53: ingrnlmp + Location: 159,-10 + Owner: Neutral + Health: 99 + Facing: 896 + Actor54: ingrnlmp + Location: 164,-50 + Owner: Neutral + Health: 99 + Facing: 896 + Actor55: ingrnlmp + Location: 165,-61 + Owner: Neutral + Health: 99 + Facing: 896 + Actor56: ingrnlmp + Location: 114,-20 + Owner: Neutral + Health: 99 + Facing: 896 + Actor57: inblulmp + Location: 185,-142 + Owner: Neutral + Facing: 896 + Actor58: inblulmp + Location: 246,-81 + Owner: Neutral + Facing: 896 + Actor59: tstlamp Location: 96,-43 Owner: Neutral - Health: 100 - Facing: 96 - Actor44: tstlamp + Facing: 896 + Actor60: tstlamp Location: 208,-109 Owner: Neutral - Health: 100 - Facing: 96 - Actor45: tstlamp + Facing: 896 + Actor61: tstlamp Location: 268,-46 Owner: Neutral - Health: 100 - Facing: 96 - Actor46: tstlamp + Facing: 896 + Actor62: tstlamp Location: 183,34 Owner: Neutral - Health: 100 - Facing: 96 - Actor47: tstlamp + Facing: 896 + Actor63: tstlamp Location: 122,23 Owner: Neutral - Health: 100 - Facing: 96 - Actor48: tstlamp + Facing: 896 + Actor64: tstlamp Location: 116,16 Owner: Neutral - Health: 100 - Facing: 96 - Actor49: tstlamp + Facing: 896 + Actor65: tstlamp Location: 155,-57 Owner: Neutral - Health: 100 - Facing: 96 - Actor50: tstlamp + Facing: 896 + Actor66: tstlamp Location: 159,-66 Owner: Neutral - Health: 100 - Facing: 96 - Actor51: pick + Facing: 896 + Actor67: pick Location: 167,-142 Owner: Neutral - Health: 100 - Facing: 160 - Actor52: car + Facing: 640 + Actor68: car Location: 204,-114 Owner: Neutral Health: 25 - Facing: 128 - Actor53: car + Facing: 768 + Actor69: car Location: 265,-50 Owner: Neutral - Health: 100 - Facing: 96 - Actor54: trucka + Facing: 896 + Actor70: trucka Location: 268,-48 Owner: Neutral - Health: 100 - Facing: 32 - Actor55: car + Facing: 128 + Actor71: car Location: 185,33 Owner: Neutral - Health: 100 - Facing: 32 - Actor56: pick + Facing: 128 + Actor72: pick Location: 155,-62 Owner: Neutral - Health: 100 - Facing: 224 - Actor57: tibtre01 + Facing: 384 + Actor73: tibtre01 Location: 165,-49 Owner: Neutral - Actor58: tibtre02 + Actor74: tibtre02 Location: 166,-60 Owner: Neutral - Actor59: tibtre02 + Actor75: tibtre02 Location: 112,36 Owner: Neutral - Actor60: tibtre03 + Actor76: tibtre03 Location: 104,19 Owner: Neutral - Actor61: tibtre03 + Actor77: tibtre03 Location: 115,-19 Owner: Neutral - Actor62: tibtre02 + Actor78: tibtre02 Location: 160,-9 Owner: Neutral - Actor63: tree01 + Actor79: tree01 Location: 51,29 Owner: Neutral - Actor64: tree02 + Actor80: tree02 Location: 52,30 Owner: Neutral - Actor65: tree03 + Actor81: tree03 Location: 52,29 Owner: Neutral - Actor66: tree04 + Actor82: tree04 Location: 54,29 Owner: Neutral - Actor67: tree05 + Actor83: tree05 Location: 73,38 Owner: Neutral - Actor68: tree06 + Actor84: tree06 Location: 75,38 Owner: Neutral - Actor69: tree08 + Actor85: tree08 Location: 77,40 Owner: Neutral - Actor70: tree10 + Actor86: tree10 Location: 81,44 Owner: Neutral - Actor71: tree09 + Actor87: tree09 Location: 82,45 Owner: Neutral - Actor72: tree11 + Actor88: tree11 Location: 83,48 Owner: Neutral - Actor73: tree12 + Actor89: tree12 Location: 82,46 Owner: Neutral - Actor74: tree13 + Actor90: tree13 Location: 98,60 Owner: Neutral - Actor75: tree15 + Actor91: tree15 Location: 97,60 Owner: Neutral - Actor76: tree16 + Actor92: tree16 Location: 97,61 Owner: Neutral - Actor77: tree17 + Actor93: tree17 Location: 94,68 Owner: Neutral - Actor78: tree18 + Actor94: tree18 Location: 95,67 Owner: Neutral - Actor79: tree20 + Actor95: tree20 Location: 89,68 Owner: Neutral - Actor80: tree19 + Actor96: tree19 Location: 90,68 Owner: Neutral - Actor81: tree22 + Actor97: tree22 Location: 91,68 Owner: Neutral - Actor82: tree21 + Actor98: tree21 Location: 92,68 Owner: Neutral - Actor83: tree15 + Actor99: tree15 Location: 88,68 Owner: Neutral - Actor84: tree18 + Actor100: tree18 Location: 90,67 Owner: Neutral - Actor85: tree25 + Actor101: tree25 Location: 86,60 Owner: Neutral - Actor86: tree01 + Actor102: tree01 Location: 136,58 Owner: Neutral - Actor87: tree02 + Actor103: tree02 Location: 138,59 Owner: Neutral - Actor88: tree03 + Actor104: tree03 Location: 141,58 Owner: Neutral - Actor89: tree04 + Actor105: tree04 Location: 143,60 Owner: Neutral - Actor90: tree05 + Actor106: tree05 Location: 145,63 Owner: Neutral - Actor91: tree06 + Actor107: tree06 Location: 148,64 Owner: Neutral - Actor92: tree07 + Actor108: tree07 Location: 150,64 Owner: Neutral - Actor93: tree09 + Actor109: tree09 Location: 155,69 Owner: Neutral - Actor94: tree10 + Actor110: tree10 Location: 157,69 Owner: Neutral - Actor95: tree11 + Actor111: tree11 Location: 160,69 Owner: Neutral - Actor96: tree12 + Actor112: tree12 Location: 163,69 Owner: Neutral - Actor97: tree13 + Actor113: tree13 Location: 162,69 Owner: Neutral - Actor98: tree14 + Actor114: tree14 Location: 139,58 Owner: Neutral - Actor99: tree15 + Actor115: tree15 Location: 143,59 Owner: Neutral - Actor100: tree16 + Actor116: tree16 Location: 143,62 Owner: Neutral - Actor101: tree17 + Actor117: tree17 Location: 147,64 Owner: Neutral - Actor102: tree18 + Actor118: tree18 Location: 151,65 Owner: Neutral - Actor103: tree19 + Actor119: tree19 Location: 152,64 Owner: Neutral - Actor104: tree20 + Actor120: tree20 Location: 153,69 Owner: Neutral - Actor105: tree22 + Actor121: tree22 Location: 154,68 Owner: Neutral - Actor106: tree23 + Actor122: tree23 Location: 159,70 Owner: Neutral - Actor107: tree24 + Actor123: tree24 Location: 158,69 Owner: Neutral - Actor108: tree25 + Actor124: tree25 Location: 152,66 Owner: Neutral - Actor109: tree05 + Actor125: tree05 Location: 86,77 Owner: Neutral - Actor110: tree06 + Actor126: tree06 Location: 87,76 Owner: Neutral - Actor111: tree15 + Actor127: tree15 Location: 87,75 Owner: Neutral - Actor112: tree25 + Actor128: tree25 Location: 88,75 Owner: Neutral - Actor113: tree15 + Actor129: tree15 Location: 121,22 Owner: Neutral - Actor114: tree16 + Actor130: tree16 Location: 120,15 Owner: Neutral - Actor115: tree17 + Actor131: tree17 Location: 126,16 Owner: Neutral - Actor116: tree18 + Actor132: tree18 Location: 127,15 Owner: Neutral - Actor117: tree19 + Actor133: tree19 Location: 127,17 Owner: Neutral - Actor118: tree07 + Actor134: tree07 Location: 127,16 Owner: Neutral - Actor119: tree06 + Actor135: tree06 Location: 126,24 Owner: Neutral - Actor120: tree05 + Actor136: tree05 Location: 126,23 Owner: Neutral - Actor121: tree03 + Actor137: tree03 Location: 123,26 Owner: Neutral - Actor122: tree02 + Actor138: tree02 Location: 119,30 Owner: Neutral - Actor123: tree01 + Actor139: tree01 Location: 120,32 Owner: Neutral - Actor124: tree12 + Actor140: tree12 Location: 121,33 Owner: Neutral - Actor125: tree19 + Actor141: tree19 Location: 116,18 Owner: Neutral - Actor126: tree02 + Actor142: tree02 Location: 30,-9 Owner: Neutral - Actor127: tree13 + Actor143: tree13 Location: 26,-8 Owner: Neutral - Actor128: tree18 + Actor144: tree18 Location: 52,6 Owner: Neutral - Actor129: tree21 + Actor145: tree21 Location: 63,0 Owner: Neutral - Actor130: tree25 + Actor146: tree25 Location: 64,-20 Owner: Neutral - Actor131: tree24 + Actor147: tree24 Location: 52,-36 Owner: Neutral - Actor132: tree11 + Actor148: tree11 Location: 61,-34 Owner: Neutral - Actor133: tree11 + Actor149: tree11 Location: 86,18 Owner: Neutral - Actor134: tree02 + Actor150: tree02 Location: 98,-13 Owner: Neutral - Actor135: tree04 + Actor151: tree04 Location: 98,-12 Owner: Neutral - Actor136: tree14 + Actor152: tree14 Location: 99,-11 Owner: Neutral - Actor137: tree15 + Actor153: tree15 Location: 101,-11 Owner: Neutral - Actor138: tree12 + Actor154: tree12 Location: 100,-10 Owner: Neutral - Actor139: tree17 + Actor155: tree17 Location: 107,-8 Owner: Neutral - Actor140: tree20 + Actor156: tree20 Location: 105,-8 Owner: Neutral - Actor141: tree01 + Actor157: tree01 Location: 124,-23 Owner: Neutral - Actor142: tree02 + Actor158: tree02 Location: 125,-22 Owner: Neutral - Actor143: tree03 + Actor159: tree03 Location: 128,-23 Owner: Neutral - Actor144: tree04 + Actor160: tree04 Location: 129,-22 Owner: Neutral - Actor145: tree05 + Actor161: tree05 Location: 109,-10 Owner: Neutral - Actor146: tree06 + Actor162: tree06 Location: 125,-8 Owner: Neutral - Actor147: tree10 + Actor163: tree10 Location: 130,-3 Owner: Neutral - Actor148: tree17 + Actor164: tree17 Location: 131,-3 Owner: Neutral - Actor149: tree18 + Actor165: tree18 Location: 132,-4 Owner: Neutral - Actor150: tree04 + Actor166: tree04 Location: 90,-50 Owner: Neutral - Actor151: tree05 + Actor167: tree05 Location: 92,-50 Owner: Neutral - Actor152: tree06 + Actor168: tree06 Location: 89,-47 Owner: Neutral - Actor153: tree14 + Actor169: tree14 Location: 89,-48 Owner: Neutral - Actor154: tree17 + Actor170: tree17 Location: 90,-49 Owner: Neutral - Actor155: tree18 + Actor171: tree18 Location: 101,-46 Owner: Neutral - Actor156: tree23 + Actor172: tree23 Location: 104,-51 Owner: Neutral - Actor157: tree25 + Actor173: tree25 Location: 104,-48 Owner: Neutral - Actor158: tree15 + Actor174: tree15 Location: 92,-72 Owner: Neutral - Actor159: tree17 + Actor175: tree17 Location: 93,-72 Owner: Neutral - Actor160: tree18 + Actor176: tree18 Location: 96,-72 Owner: Neutral - Actor161: tree21 + Actor177: tree21 Location: 99,-78 Owner: Neutral - Actor162: tree24 + Actor178: tree24 Location: 104,-88 Owner: Neutral - Actor163: tree25 + Actor179: tree25 Location: 111,-94 Owner: Neutral - Actor164: tree05 + Actor180: tree05 Location: 142,-83 Owner: Neutral - Actor165: tree06 + Actor181: tree06 Location: 143,-84 Owner: Neutral - Actor166: tree03 + Actor182: tree03 Location: 143,-86 Owner: Neutral - Actor167: tree05 + Actor183: tree05 Location: 155,-95 Owner: Neutral - Actor168: tree06 + Actor184: tree06 Location: 157,-97 Owner: Neutral - Actor169: tree07 + Actor185: tree07 Location: 157,-104 Owner: Neutral - Actor170: tree08 + Actor186: tree08 Location: 164,-94 Owner: Neutral - Actor171: tree09 + Actor187: tree09 Location: 164,-96 Owner: Neutral - Actor172: tree10 + Actor188: tree10 Location: 163,-97 Owner: Neutral - Actor173: tree12 + Actor189: tree12 Location: 165,-97 Owner: Neutral - Actor174: tree13 + Actor190: tree13 Location: 168,-109 Owner: Neutral - Actor175: tree02 + Actor191: tree02 Location: 167,-145 Owner: Neutral - Actor176: tree03 + Actor192: tree03 Location: 169,-144 Owner: Neutral - Actor177: tree05 + Actor193: tree05 Location: 173,-147 Owner: Neutral - Actor178: tree06 + Actor194: tree06 Location: 174,-147 Owner: Neutral - Actor179: tree07 + Actor195: tree07 Location: 175,-145 Owner: Neutral - Actor180: tree17 + Actor196: tree17 Location: 179,-140 Owner: Neutral - Actor181: tree18 + Actor197: tree18 Location: 170,-144 Owner: Neutral - Actor182: tree21 + Actor198: tree21 Location: 164,-138 Owner: Neutral - Actor183: tree25 + Actor199: tree25 Location: 139,-112 Owner: Neutral - Actor184: tree20 + Actor200: tree20 Location: 137,-112 Owner: Neutral - Actor185: tree12 + Actor201: tree12 Location: 143,-110 Owner: Neutral - Actor186: tree06 + Actor202: tree06 Location: 203,-118 Owner: Neutral - Actor187: tree07 + Actor203: tree07 Location: 207,-116 Owner: Neutral - Actor188: tree08 + Actor204: tree08 Location: 202,-109 Owner: Neutral - Actor189: tree10 + Actor205: tree10 Location: 202,-107 Owner: Neutral - Actor190: tree13 + Actor206: tree13 Location: 213,-102 Owner: Neutral - Actor191: tree21 + Actor207: tree21 Location: 212,-103 Owner: Neutral - Actor192: tree04 + Actor208: tree04 Location: 208,-60 Owner: Neutral - Actor193: tree05 + Actor209: tree05 Location: 189,-76 Owner: Neutral - Actor194: tree17 + Actor210: tree17 Location: 189,-78 Owner: Neutral - Actor195: tree18 + Actor211: tree18 Location: 217,-73 Owner: Neutral - Actor196: tree20 + Actor212: tree20 Location: 216,-74 Owner: Neutral - Actor197: tree21 + Actor213: tree21 Location: 217,-74 Owner: Neutral - Actor198: tree25 + Actor214: tree25 Location: 219,-73 Owner: Neutral - Actor199: tree12 + Actor215: tree12 Location: 221,-73 Owner: Neutral - Actor200: tree11 + Actor216: tree11 Location: 221,-74 Owner: Neutral - Actor201: tree10 + Actor217: tree10 Location: 220,-75 Owner: Neutral - Actor202: tree07 + Actor218: tree07 Location: 220,-77 Owner: Neutral - Actor203: tree05 + Actor219: tree05 Location: 220,-103 Owner: Neutral - Actor204: tree04 + Actor220: tree04 Location: 219,-102 Owner: Neutral - Actor205: tree11 + Actor221: tree11 Location: 220,-100 Owner: Neutral - Actor206: tree15 + Actor222: tree15 Location: 220,-101 Owner: Neutral - Actor207: tree16 + Actor223: tree16 Location: 221,-101 Owner: Neutral - Actor208: tree17 + Actor224: tree17 Location: 234,-84 Owner: Neutral - Actor209: tree18 + Actor225: tree18 Location: 234,-85 Owner: Neutral - Actor210: tree21 + Actor226: tree21 Location: 235,-86 Owner: Neutral - Actor211: tree24 + Actor227: tree24 Location: 225,-92 Owner: Neutral - Actor212: tree11 + Actor228: tree11 Location: 226,-92 Owner: Neutral - Actor213: tree01 + Actor229: tree01 Location: 260,-46 Owner: Neutral - Actor214: tree02 + Actor230: tree02 Location: 252,-49 Owner: Neutral - Actor215: tree03 + Actor231: tree03 Location: 253,-47 Owner: Neutral - Actor216: tree04 + Actor232: tree04 Location: 264,-58 Owner: Neutral - Actor217: tree05 + Actor233: tree05 Location: 273,-41 Owner: Neutral - Actor218: tree06 + Actor234: tree06 Location: 275,-47 Owner: Neutral - Actor219: tree07 + Actor235: tree07 Location: 263,-46 Owner: Neutral - Actor220: tree08 + Actor236: tree08 Location: 264,-48 Owner: Neutral - Actor221: tree10 + Actor237: tree10 Location: 265,-51 Owner: Neutral - Actor222: tree11 + Actor238: tree11 Location: 268,-52 Owner: Neutral - Actor223: tree12 + Actor239: tree12 Location: 269,-50 Owner: Neutral - Actor224: tree13 + Actor240: tree13 Location: 270,-46 Owner: Neutral - Actor225: tree16 + Actor241: tree16 Location: 266,-45 Owner: Neutral - Actor226: tree25 + Actor242: tree25 Location: 258,-52 Owner: Neutral - Actor227: tree02 + Actor243: tree02 Location: 211,-19 Owner: Neutral - Actor228: tree03 + Actor244: tree03 Location: 232,-20 Owner: Neutral - Actor229: tree04 + Actor245: tree04 Location: 230,-28 Owner: Neutral - Actor230: tree05 + Actor246: tree05 Location: 244,-15 Owner: Neutral - Actor231: tree06 + Actor247: tree06 Location: 245,-15 Owner: Neutral - Actor232: tree07 + Actor248: tree07 Location: 230,-48 Owner: Neutral - Actor233: tree08 + Actor249: tree08 Location: 230,-49 Owner: Neutral - Actor234: tree15 + Actor250: tree15 Location: 229,-48 Owner: Neutral - Actor235: tree16 + Actor251: tree16 Location: 190,0 Owner: Neutral - Actor236: tree17 + Actor252: tree17 Location: 190,-2 Owner: Neutral - Actor237: tree21 + Actor253: tree21 Location: 187,-2 Owner: Neutral - Actor238: tree10 + Actor254: tree10 Location: 186,1 Owner: Neutral - Actor239: tree07 + Actor255: tree07 Location: 198,-7 Owner: Neutral - Actor240: tree12 + Actor256: tree12 Location: 203,-7 Owner: Neutral - Actor241: tree25 + Actor257: tree25 Location: 201,-8 Owner: Neutral - Actor242: tree24 + Actor258: tree24 Location: 212,3 Owner: Neutral - Actor243: tree17 + Actor259: tree17 Location: 216,5 Owner: Neutral - Actor244: tree06 + Actor260: tree06 Location: 216,4 Owner: Neutral - Actor245: tree07 + Actor261: tree07 Location: 222,9 Owner: Neutral - Actor246: tree09 + Actor262: tree09 Location: 180,32 Owner: Neutral - Actor247: tree06 + Actor263: tree06 Location: 180,34 Owner: Neutral - Actor248: tree04 + Actor264: tree04 Location: 185,35 Owner: Neutral - Actor249: tree14 + Actor265: tree14 Location: 188,30 Owner: Neutral - Actor250: tree15 + Actor266: tree15 Location: 180,42 Owner: Neutral - Actor251: tree17 + Actor267: tree17 Location: 168,35 Owner: Neutral - Actor252: tree18 + Actor268: tree18 Location: 159,13 Owner: Neutral - Actor253: tree21 + Actor269: tree21 Location: 166,14 Owner: Neutral - Actor254: tree24 + Actor270: tree24 Location: 156,23 Owner: Neutral - Actor255: tree25 + Actor271: tree25 Location: 155,33 Owner: Neutral - Actor256: tree08 + Actor272: tree08 Location: 159,36 Owner: Neutral - Actor257: tree06 + Actor273: tree06 Location: 160,39 Owner: Neutral - Actor258: tree07 + Actor274: tree07 Location: 161,40 Owner: Neutral - Actor259: tree08 + Actor275: tree08 Location: 161,38 Owner: Neutral - Actor260: tree04 + Actor276: tree04 Location: 160,41 Owner: Neutral - Actor261: tree01 + Actor277: tree01 Location: 190,14 Owner: Neutral - Actor262: tree02 + Actor278: tree02 Location: 190,13 Owner: Neutral - Actor263: tree03 + Actor279: tree03 Location: 192,14 Owner: Neutral - Actor264: tree04 + Actor280: tree04 Location: 194,19 Owner: Neutral - Actor265: tree05 + Actor281: tree05 Location: 193,16 Owner: Neutral - Actor266: tree07 + Actor282: tree07 Location: 195,19 Owner: Neutral - Actor267: tree08 + Actor283: tree08 Location: 196,20 Owner: Neutral - Actor268: tree09 + Actor284: tree09 Location: 198,21 Owner: Neutral - Actor269: tree10 + Actor285: tree10 Location: 196,21 Owner: Neutral - Actor270: tree11 + Actor286: tree11 Location: 199,23 Owner: Neutral - Actor271: tree12 + Actor287: tree12 Location: 200,23 Owner: Neutral - Actor272: tree13 + Actor288: tree13 Location: 191,14 Owner: Neutral - Actor273: tree14 + Actor289: tree14 Location: 192,16 Owner: Neutral - Actor274: tree15 + Actor290: tree15 Location: 194,18 Owner: Neutral - Actor275: tree16 + Actor291: tree16 Location: 195,17 Owner: Neutral - Actor276: tree17 + Actor292: tree17 Location: 195,20 Owner: Neutral - Actor277: tree18 + Actor293: tree18 Location: 197,21 Owner: Neutral - Actor278: tree19 + Actor294: tree19 Location: 198,22 Owner: Neutral - Actor279: tree20 + Actor295: tree20 Location: 196,22 Owner: Neutral - Actor280: tree21 + Actor296: tree21 Location: 197,23 Owner: Neutral - Actor281: tree22 + Actor297: tree22 Location: 197,22 Owner: Neutral - Actor282: tree23 + Actor298: tree23 Location: 200,25 Owner: Neutral - Actor283: tree24 + Actor299: tree24 Location: 198,23 Owner: Neutral - Actor284: tree25 + Actor300: tree25 Location: 191,16 Owner: Neutral - Actor285: tree02 + Actor301: tree02 Location: 45,-2 Owner: Neutral - Actor286: tree03 + Actor302: tree03 Location: 46,0 Owner: Neutral - Actor287: tree03 + Actor303: tree03 Location: 118,-66 Owner: Neutral - Actor288: tree04 + Actor304: tree04 Location: 118,-65 Owner: Neutral - Actor289: tree17 + Actor305: tree17 Location: 117,-65 Owner: Neutral - Actor290: tree01 + Actor306: tree01 Location: 195,-98 Owner: Neutral - Actor291: tree02 + Actor307: tree02 Location: 196,-97 Owner: Neutral - Actor292: tree04 + Actor308: tree04 Location: 195,-96 Owner: Neutral - Actor293: tree05 + Actor309: tree05 Location: 194,-97 Owner: Neutral - Actor294: tree08 + Actor310: tree08 Location: 196,-94 Owner: Neutral - Actor295: tree14 + Actor311: tree14 Location: 196,-95 Owner: Neutral - Actor296: tree15 + Actor312: tree15 Location: 195,-95 Owner: Neutral - Actor297: tree16 + Actor313: tree16 Location: 197,-96 Owner: Neutral - Actor298: tree17 + Actor314: tree17 Location: 196,-98 Owner: Neutral - Actor299: tree18 + Actor315: tree18 Location: 197,-97 Owner: Neutral - Actor300: tree19 + Actor316: tree19 Location: 197,-95 Owner: Neutral - Actor301: tree20 + Actor317: tree20 Location: 196,-96 Owner: Neutral - Actor302: tree21 + Actor318: tree21 Location: 194,-95 Owner: Neutral - Actor303: tree22 + Actor319: tree22 Location: 194,-96 Owner: Neutral - Actor304: tree03 + Actor320: tree03 Location: 148,84 Owner: Neutral - Actor305: tree04 + Actor321: tree04 Location: 148,83 Owner: Neutral - Actor306: tree05 + Actor322: tree05 Location: 149,84 Owner: Neutral - Actor307: tree06 + Actor323: tree06 Location: 151,84 Owner: Neutral - Actor308: tree08 + Actor324: tree08 Location: 147,87 Owner: Neutral - Actor309: tree13 + Actor325: tree13 Location: 147,86 Owner: Neutral - Actor310: tree14 + Actor326: tree14 Location: 148,85 Owner: Neutral - Actor311: tree15 + Actor327: tree15 Location: 149,86 Owner: Neutral - Actor312: tree16 + Actor328: tree16 Location: 147,85 Owner: Neutral - Actor313: tree17 + Actor329: tree17 Location: 150,84 Owner: Neutral - Actor314: tree18 + Actor330: tree18 Location: 150,83 Owner: Neutral - Actor315: tree19 + Actor331: tree19 Location: 152,83 Owner: Neutral - Actor316: tree20 + Actor332: tree20 Location: 151,83 Owner: Neutral - Actor317: tree21 + Actor333: tree21 Location: 153,83 Owner: Neutral - Actor318: tree03 + Actor334: tree03 Location: 74,64 Owner: Neutral - Actor319: tree04 + Actor335: tree04 Location: 74,62 Owner: Neutral - Actor320: tree05 + Actor336: tree05 Location: 78,63 Owner: Neutral - Actor321: tree12 + Actor337: tree12 Location: 79,65 Owner: Neutral - Actor322: tree13 + Actor338: tree13 Location: 76,64 Owner: Neutral - Actor323: tibtre01 + Actor339: tibtre01 Location: 28,1 Owner: Neutral - Actor324: tibtre02 + Actor340: tibtre02 Location: 120,-89 Owner: Neutral - Actor325: tibtre02 + Actor341: tibtre02 Location: 173,-121 Owner: Neutral - Actor326: tibtre03 + Actor342: tibtre03 Location: 187,-91 Owner: Neutral - Actor327: tibtre03 + Actor343: tibtre03 Location: 223,-35 Owner: Neutral - Actor328: tibtre02 + Actor344: tibtre02 Location: 183,17 Owner: Neutral - Actor329: tibtre01 + Actor345: tibtre01 Location: 115,71 Owner: Neutral - Actor330: tibtre02 + Actor346: tibtre02 Location: 54,39 Owner: Neutral - Actor331: mpspawn + Actor347: mpspawn Location: 74,50 Owner: Neutral - Actor332: mpspawn + Actor348: mpspawn Location: 46,-9 Owner: Neutral - Actor333: mpspawn + Actor349: mpspawn Location: 135,-90 Owner: Neutral - Actor334: mpspawn + Actor350: mpspawn Location: 150,-116 Owner: Neutral - Actor335: mpspawn + Actor351: mpspawn Location: 207,-84 Owner: Neutral - Actor336: mpspawn + Actor352: mpspawn Location: 246,-38 Owner: Neutral - Actor337: mpspawn + Actor353: mpspawn Location: 199,6 Owner: Neutral - Actor338: mpspawn + Actor354: mpspawn Location: 139,72 Owner: Neutral - Actor339: waypoint + Actor355: waypoint Location: 138,-28 Owner: Neutral - Actor340: waypoint + Actor356: waypoint Location: 138,-28 Owner: Neutral - Actor341: lobrdg_r_ne + Actor357: lobrdg_r_ne Location: 160,-137 Owner: Neutral - Actor342: lobrdg_a + Actor358: lobrdg_a Location: 160,-136 Owner: Neutral - Actor343: lobrdg_a + Actor359: lobrdg_a Location: 160,-135 Owner: Neutral - Actor344: lobrdg_a + Actor360: lobrdg_a Location: 160,-134 Owner: Neutral - Actor345: lobrdg_a + Actor361: lobrdg_a Location: 160,-133 Owner: Neutral - Actor346: lobrdg_a + Actor362: lobrdg_a Location: 160,-132 Owner: Neutral - Actor347: lobrdg_a + Actor363: lobrdg_a Location: 160,-131 Owner: Neutral - Actor348: lobrdg_a + Actor364: lobrdg_a Location: 160,-130 Owner: Neutral - Actor349: lobrdg_a + Actor365: lobrdg_a Location: 160,-129 Owner: Neutral - Actor350: lobrdg_r_sw + Actor366: lobrdg_r_sw Location: 160,-128 Owner: Neutral - Actor351: bridge1 + Actor367: bridge1 Location: 129,-64 Owner: Neutral - Actor352: bridge1 + Actor368: bridge1 Location: 130,-64 Owner: Neutral - Actor353: bridge1 + Actor369: bridge1 Location: 131,-64 Owner: Neutral - Actor354: bridge1 + Actor370: bridge1 Location: 132,-64 Owner: Neutral - Actor355: bridge2 + Actor371: bridge2 Location: 161,-90 Owner: Neutral - Actor356: bridge2 + Actor372: bridge2 Location: 161,-89 Owner: Neutral - Actor357: bridge2 + Actor373: bridge2 Location: 161,-88 Owner: Neutral - Actor358: bridge2 + Actor374: bridge2 Location: 161,-87 Owner: Neutral - Actor359: bridge2 + Actor375: bridge2 Location: 161,-86 Owner: Neutral - Actor360: bridge1 + Actor376: bridge1 Location: 63,13 Owner: Neutral - Actor361: bridge1 + Actor377: bridge1 Location: 140,-64 Owner: Neutral - Actor362: bridge1 + Actor378: bridge1 Location: 141,-64 Owner: Neutral - Actor363: bridge1 + Actor379: bridge1 Location: 142,-64 Owner: Neutral - Actor364: bridge2 + Actor380: bridge2 Location: 161,-75 Owner: Neutral - Actor365: bridge2 + Actor381: bridge2 Location: 161,-74 Owner: Neutral - Actor366: bridge2 + Actor382: bridge2 Location: 161,-73 Owner: Neutral - Actor367: bridge2 + Actor383: bridge2 Location: 161,-72 Owner: Neutral - Actor368: bridge1 + Actor384: bridge1 Location: 80,13 Owner: Neutral - Actor369: bridge1 + Actor385: bridge1 Location: 81,13 Owner: Neutral - Actor370: bridge1 + Actor386: bridge1 Location: 82,13 Owner: Neutral - Actor371: crat03 + Actor387: crat03 Location: 158,-61 Owner: Neutral - Actor372: bridge2 + Actor388: bridge2 Location: 114,-6 Owner: Neutral - Actor373: bridge1 + Actor389: bridge1 Location: 176,-68 Owner: Neutral - Actor374: bridge2 + Actor390: bridge2 Location: 114,-5 Owner: Neutral - Actor375: bridge1 + Actor391: bridge1 Location: 177,-68 Owner: Neutral - Actor376: bridge2 + Actor392: bridge2 Location: 114,-4 Owner: Neutral - Actor377: bridge1 + Actor393: bridge1 Location: 178,-68 Owner: Neutral - Actor378: bridge2 + Actor394: bridge2 Location: 114,-3 Owner: Neutral - Actor379: bridge2 + Actor395: bridge2 Location: 114,-2 Owner: Neutral - Actor380: bridge2 + Actor396: bridge2 Location: 114,-1 Owner: Neutral - Actor381: bridge2 + Actor397: bridge2 Location: 114,0 Owner: Neutral - Actor382: bridge2 + Actor398: bridge2 Location: 153,-39 Owner: Neutral - Actor383: bridge2 + Actor399: bridge2 Location: 114,1 Owner: Neutral - Actor384: bridge2 + Actor400: bridge2 Location: 153,-38 Owner: Neutral - Actor385: bridge1 + Actor401: bridge1 Location: 183,-68 Owner: Neutral - Actor386: bridge2 + Actor402: bridge2 Location: 114,2 Owner: Neutral - Actor387: bridge2 + Actor403: bridge2 Location: 153,-37 Owner: Neutral - Actor388: bridge1 + Actor404: bridge1 Location: 184,-68 Owner: Neutral - Actor389: bridge2 + Actor405: bridge2 Location: 153,-36 Owner: Neutral - Actor390: bridge2 + Actor406: bridge2 Location: 114,4 Owner: Neutral - Actor391: bridge2 + Actor407: bridge2 Location: 153,-35 Owner: Neutral - Actor392: bridge2 + Actor408: bridge2 Location: 114,5 Owner: Neutral - Actor393: bridge2 + Actor409: bridge2 Location: 153,-34 Owner: Neutral - Actor394: bridge2 + Actor410: bridge2 Location: 114,6 Owner: Neutral - Actor395: bridge2 + Actor411: bridge2 Location: 153,-33 Owner: Neutral - Actor396: bridge2 + Actor412: bridge2 Location: 114,7 Owner: Neutral - Actor397: bridge2 + Actor413: bridge2 Location: 153,-32 Owner: Neutral - Actor398: bridge2 + Actor414: bridge2 Location: 114,8 Owner: Neutral - Actor399: bridge1 + Actor415: bridge1 Location: 133,-11 Owner: Neutral - Actor400: bridge2 + Actor416: bridge2 Location: 153,-31 Owner: Neutral - Actor401: bridge2 + Actor417: bridge2 Location: 114,9 Owner: Neutral - Actor402: bridge1 + Actor418: bridge1 Location: 134,-11 Owner: Neutral - Actor403: bridge2 + Actor419: bridge2 Location: 153,-30 Owner: Neutral - Actor404: bridge2 + Actor420: bridge2 Location: 114,10 Owner: Neutral - Actor405: bridge1 + Actor421: bridge1 Location: 135,-11 Owner: Neutral - Actor406: bridge2 + Actor422: bridge2 Location: 153,-29 Owner: Neutral - Actor407: bridge2 + Actor423: bridge2 Location: 114,11 Owner: Neutral - Actor408: bridge1 + Actor424: bridge1 Location: 136,-11 Owner: Neutral - Actor409: bridge2 + Actor425: bridge2 Location: 153,-28 Owner: Neutral - Actor410: bridge2 + Actor426: bridge2 Location: 114,12 Owner: Neutral - Actor411: bridge1 + Actor427: bridge1 Location: 137,-11 Owner: Neutral - Actor412: bridge1 + Actor428: bridge1 Location: 138,-11 Owner: Neutral - Actor413: bridge1 + Actor429: bridge1 Location: 139,-11 Owner: Neutral - Actor414: bridge1 + Actor430: bridge1 Location: 140,-11 Owner: Neutral - Actor415: bridge1 + Actor431: bridge1 Location: 141,-11 Owner: Neutral - Actor416: bridge2 + Actor432: bridge2 Location: 94,37 Owner: Neutral - Actor417: bridge1 + Actor433: bridge1 Location: 142,-11 Owner: Neutral - Actor418: bridge2 + Actor434: bridge2 Location: 94,38 Owner: Neutral - Actor419: bridge1 + Actor435: bridge1 Location: 143,-11 Owner: Neutral - Actor420: bridge2 + Actor436: bridge2 Location: 94,39 Owner: Neutral - Actor421: bridge2 + Actor437: bridge2 Location: 94,40 Owner: Neutral - Actor422: bridge2 + Actor438: bridge2 Location: 94,41 Owner: Neutral - Actor423: bridge2 + Actor439: bridge2 Location: 94,42 Owner: Neutral - Actor424: crat01 + Actor440: crat01 Location: 123,20 Owner: Neutral - Actor425: bridge2 + Actor441: bridge2 Location: 94,54 Owner: Neutral - Actor426: bridge2 + Actor442: bridge2 Location: 94,55 Owner: Neutral - Actor427: bridge2 + Actor443: bridge2 Location: 94,56 Owner: Neutral - Actor428: bridge2 + Actor444: bridge2 Location: 94,57 Owner: Neutral - Actor429: bridge1 + Actor445: bridge1 Location: 184,-32 Owner: Neutral - Actor430: bridge1 + Actor446: bridge1 Location: 185,-32 Owner: Neutral - Actor431: bridge1 + Actor447: bridge1 Location: 186,-32 Owner: Neutral - Actor432: bridge1 + Actor448: bridge1 Location: 187,-32 Owner: Neutral - Actor433: bridge1 + Actor449: bridge1 Location: 129,28 Owner: Neutral - Actor434: bridge1 + Actor450: bridge1 Location: 130,28 Owner: Neutral - Actor435: bridge1 + Actor451: bridge1 Location: 131,28 Owner: Neutral - Actor436: bridge1 + Actor452: bridge1 Location: 132,28 Owner: Neutral - Actor437: bridge1 + Actor453: bridge1 Location: 133,28 Owner: Neutral - Actor438: bridge1 + Actor454: bridge1 Location: 193,-32 Owner: Neutral - Actor439: bridge1 + Actor455: bridge1 Location: 134,28 Owner: Neutral - Actor440: bridge1 + Actor456: bridge1 Location: 194,-32 Owner: Neutral - Actor441: bridge1 + Actor457: bridge1 Location: 135,28 Owner: Neutral - Actor442: bridge1 + Actor458: bridge1 Location: 195,-32 Owner: Neutral - Actor443: bridge1 + Actor459: bridge1 Location: 196,-32 Owner: Neutral - Actor444: bridge1 + Actor460: bridge1 Location: 197,-32 Owner: Neutral - Actor445: bridge2 + Actor461: bridge2 Location: 123,47 Owner: Neutral - Actor446: bridge2 + Actor462: bridge2 Location: 123,48 Owner: Neutral - Actor447: bridge2 + Actor463: bridge2 Location: 123,49 Owner: Neutral - Actor448: bridge2 + Actor464: bridge2 Location: 123,50 Owner: Neutral - Actor449: bridge1 + Actor465: bridge1 Location: 145,28 Owner: Neutral - Actor450: bridge2 + Actor466: bridge2 Location: 123,51 Owner: Neutral - Actor451: bridge1 + Actor467: bridge1 Location: 146,28 Owner: Neutral - Actor452: bridge1 + Actor468: bridge1 Location: 147,28 Owner: Neutral - Actor453: bridge1 + Actor469: bridge1 Location: 148,28 Owner: Neutral - Actor454: bridge2 + Actor470: bridge2 Location: 123,61 Owner: Neutral - Actor455: bridge2 + Actor471: bridge2 Location: 123,62 Owner: Neutral - Actor456: bridge2 + Actor472: bridge2 Location: 123,63 Owner: Neutral - Actor457: bridge2 + Actor473: bridge2 Location: 123,64 Owner: Neutral - Actor458: bridge2 + Actor474: bridge2 Location: 123,65 Owner: Neutral - Actor459: bridge2 + Actor475: bridge2 Location: 123,66 Owner: Neutral - Actor460: bridge2 - Location: 123,67 - Owner: Neutral - Actor461: bridge1 - Owner: Neutral - Location: 74,13 - Actor462: bridge1 - Owner: Neutral - Location: 75,13 - Actor463: bridge1 - Owner: Neutral - Location: 76,13 - Actor464: bridge1 - Owner: Neutral - Location: 77,13 - Actor465: bridge1 - Owner: Neutral - Location: 78,13 - Actor466: bridge1 - Owner: Neutral - Location: 79,13 - Actor467: bridge1 - Owner: Neutral - Location: 64,13 - Actor468: bridge1 - Owner: Neutral - Location: 65,13 - Actor469: bridge1 - Owner: Neutral - Location: 66,13 - Actor470: bridge1 - Owner: Neutral - Location: 67,13 - Actor471: bridge1 - Owner: Neutral - Location: 68,13 - Actor472: bridge1 - Owner: Neutral - Location: 69,13 - Actor473: bridge1 - Owner: Neutral - Location: 70,13 - Actor474: bridge1 - Owner: Neutral - Location: 71,13 - Actor475: bridge1 - Owner: Neutral - Location: 72,13 Actor476: bridge2 + Location: 123,67 Owner: Neutral - Location: 94,43 - Actor477: bridge2 + Actor477: bridge1 Owner: Neutral - Location: 94,44 - Actor478: bridge2 + Location: 188,-32 + Actor478: bridge1 Owner: Neutral - Location: 94,45 - Actor479: bridge2 + Location: 189,-32 + Actor479: bridge1 Owner: Neutral - Location: 94,46 - Actor480: bridge2 + Location: 190,-32 + Actor480: bridge1 Owner: Neutral - Location: 94,48 - Actor481: bridge2 + Location: 191,-32 + Actor481: bridge1 Owner: Neutral - Location: 94,49 - Actor482: bridge2 + Location: 192,-32 + Actor482: bridge1 Owner: Neutral - Location: 94,50 - Actor483: bridge2 + Location: 144,28 + Actor483: bridge1 Owner: Neutral - Location: 94,51 - Actor484: bridge2 + Location: 143,28 + Actor484: bridge1 Owner: Neutral - Location: 94,52 - Actor485: bridge2 + Location: 142,28 + Actor485: bridge1 Owner: Neutral - Location: 94,53 - Actor486: bridge2 + Location: 141,28 + Actor486: bridge1 Owner: Neutral - Location: 123,52 - Actor487: bridge2 + Location: 140,28 + Actor487: bridge1 Owner: Neutral - Location: 123,53 - Actor488: bridge2 + Location: 139,28 + Actor488: bridge1 Owner: Neutral - Location: 123,54 - Actor489: bridge2 + Location: 137,28 + Actor489: bridge1 Owner: Neutral - Location: 123,55 - Actor490: bridge2 + Location: 136,28 + Actor490: bridge1 Owner: Neutral - Location: 123,56 - Actor491: bridge2 + Location: 74,13 + Actor491: bridge1 Owner: Neutral - Location: 123,57 - Actor492: bridge2 + Location: 75,13 + Actor492: bridge1 Owner: Neutral - Location: 123,58 - Actor493: bridge2 + Location: 76,13 + Actor493: bridge1 Owner: Neutral - Location: 123,59 - Actor494: bridge2 + Location: 77,13 + Actor494: bridge1 Owner: Neutral - Location: 123,60 + Location: 78,13 Actor495: bridge1 Owner: Neutral - Location: 136,28 + Location: 79,13 Actor496: bridge1 Owner: Neutral - Location: 137,28 + Location: 64,13 Actor497: bridge1 Owner: Neutral - Location: 139,28 + Location: 65,13 Actor498: bridge1 Owner: Neutral - Location: 140,28 + Location: 66,13 Actor499: bridge1 Owner: Neutral - Location: 141,28 + Location: 67,13 Actor500: bridge1 Owner: Neutral - Location: 142,28 + Location: 68,13 Actor501: bridge1 Owner: Neutral - Location: 143,28 + Location: 69,13 Actor502: bridge1 Owner: Neutral - Location: 144,28 + Location: 70,13 Actor503: bridge1 Owner: Neutral - Location: 188,-32 + Location: 71,13 Actor504: bridge1 Owner: Neutral - Location: 189,-32 + Location: 72,13 Actor505: bridge1 Owner: Neutral - Location: 190,-32 - Actor506: bridge1 - Owner: Neutral - Location: 191,-32 + Location: 133,-64 Actor507: bridge1 Owner: Neutral - Location: 192,-32 - Actor508: bridge2 + Location: 134,-64 + Actor508: bridge1 + Owner: Neutral + Location: 135,-64 + Actor509: bridge1 + Owner: Neutral + Location: 136,-64 + Actor510: bridge1 + Owner: Neutral + Location: 137,-64 + Actor511: bridge1 + Owner: Neutral + Location: 138,-64 + Actor512: bridge1 + Owner: Neutral + Location: 138,-64 + Actor513: bridge1 + Owner: Neutral + Location: 139,-64 + Actor514: bridge1 + Owner: Neutral + Location: 181,-68 + Actor515: bridge1 + Owner: Neutral + Location: 182,-68 + Actor516: bridge1 + Owner: Neutral + Location: 179,-68 + Actor517: bridge1 + Owner: Neutral + Location: 180,-68 + Actor518: bridge2 Owner: Neutral Location: 161,-85 - Actor509: bridge2 + Actor519: bridge2 Owner: Neutral Location: 161,-84 - Actor510: bridge2 + Actor520: bridge2 Owner: Neutral Location: 161,-83 - Actor511: bridge2 + Actor521: bridge2 Owner: Neutral Location: 161,-82 - Actor512: bridge2 + Actor522: bridge2 Owner: Neutral Location: 161,-81 - Actor513: bridge2 + Actor523: bridge2 Owner: Neutral Location: 161,-80 - Actor514: bridge2 + Actor524: bridge2 Owner: Neutral Location: 161,-79 - Actor515: bridge2 + Actor528: bridge2 + Owner: Neutral + Location: 161,-76 + Actor525: bridge2 Owner: Neutral Location: 161,-78 - Actor516: bridge2 + Actor526: bridge2 Owner: Neutral Location: 161,-77 - Actor517: bridge2 + Actor527: bridge2 Owner: Neutral - Location: 161,-76 - Actor518: bridge1 + Location: 123,52 + Actor529: bridge2 Owner: Neutral - Location: 133,-64 - Actor519: bridge1 + Location: 123,53 + Actor530: bridge2 Owner: Neutral - Location: 134,-64 - Actor520: bridge1 + Location: 123,54 + Actor531: bridge2 Owner: Neutral - Location: 135,-64 - Actor521: bridge1 + Location: 123,55 + Actor532: bridge2 Owner: Neutral - Location: 136,-64 - Actor522: bridge1 + Location: 123,56 + Actor533: bridge2 Owner: Neutral - Location: 137,-64 - Actor523: bridge1 + Location: 123,57 + Actor534: bridge2 Owner: Neutral - Location: 137,-64 - Actor524: bridge1 + Location: 123,58 + Actor535: bridge2 Owner: Neutral - Location: 138,-64 - Actor525: bridge1 + Location: 123,59 + Actor536: bridge2 Owner: Neutral - Location: 139,-64 - Actor526: bridge1 + Location: 123,60 + Actor537: bridge2 Owner: Neutral - Location: 179,-68 - Actor527: bridge1 + Location: 94,53 + Actor538: bridge2 Owner: Neutral - Location: 180,-68 - Actor528: bridge1 + Location: 94,51 + Actor539: bridge2 Owner: Neutral - Location: 181,-68 - Actor529: bridge1 + Location: 94,52 + Actor540: bridge2 Owner: Neutral - Location: 182,-68 + Location: 94,50 + Actor541: bridge2 + Owner: Neutral + Location: 94,49 + Actor542: bridge2 + Owner: Neutral + Location: 94,48 + Actor543: bridge2 + Owner: Neutral + Location: 94,46 + Actor544: bridge2 + Owner: Neutral + Location: 94,45 + Actor545: bridge2 + Owner: Neutral + Location: 94,44 + Actor546: bridge2 + Owner: Neutral + Location: 94,43 Rules: World: - GlobalLightingPaletteEffect: - Ambient: 0.75 ElevatedBridgeLayer: ElevatedBridgePlaceholder@a: Location: 62, 12 @@ -1774,3 +1866,14 @@ Height: 6 Orientation: X Length: 15 + ^BaseWorld: + TerrainLighting: + Intensity: 0.725 + HeightStep: 0.014 + INGRNLMP: + TerrainLightSource: + Range: 5c880 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.7 + BlueTint: 0.01 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/ts_rift/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/ts_rift/map.png differ diff -Nru openra-20200503/mods/ts/maps/ts_rift/map.yaml openra-20210321/mods/ts/maps/ts_rift/map.yaml --- openra-20200503/mods/ts/maps/ts_rift/map.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/maps/ts_rift/map.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -43,87 +43,87 @@ Location: 156,34 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor3: ca0007 Location: 160,36 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor4: ca0006 Location: 160,32 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor5: ca0003 Location: 161,28 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor6: ca0018 Location: 164,37 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor7: ca0020 Location: 164,35 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor8: ca0020 Location: 167,35 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor9: ca0019 Location: 167,37 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor10: ca0015 Location: 164,27 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor11: ca0008 Location: 153,-21 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor12: ca0009 Location: 106,22 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor13: ca0015 Location: 150,-23 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor14: ca0016 Location: 157,-21 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor15: ca0017 Location: 107,28 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor16: ca0013 Location: 101,22 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor17: ca0012 Location: 110,27 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor18: ca0011 Location: 150,-27 Owner: Neutral Health: 100 - Facing: 160 + Facing: 640 Actor22: tree21 Location: 104,-54 Owner: Neutral @@ -1685,37 +1685,37 @@ Owner: Neutral Location: 167,30 SubCell: 2 - Facing: 92 + Facing: 368 Actor549: civ1 Owner: Neutral Location: 161,41 SubCell: 1 - Facing: 92 + Facing: 368 Actor550: civ2 Owner: Neutral Location: 159,34 SubCell: 2 - Facing: 92 + Facing: 368 Actor551: civ2 Owner: Neutral Location: 162,31 SubCell: 2 - Facing: 92 + Facing: 368 Actor552: civ3 Owner: Neutral Location: 162,33 SubCell: 2 - Facing: 92 + Facing: 368 Actor553: civ2 Owner: Neutral Location: 155,-20 SubCell: 2 - Facing: 92 + Facing: 368 Actor554: civ2 Owner: Neutral Location: 108,25 SubCell: 2 - Facing: 92 + Facing: 368 Actor555: fona11 Owner: Neutral Location: 105,-31 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/maps/uganda/map.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/maps/uganda/map.png differ diff -Nru openra-20200503/mods/ts/metrics.yaml openra-20210321/mods/ts/metrics.yaml --- openra-20200503/mods/ts/metrics.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/metrics.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -3,11 +3,3 @@ ColorPickerActorType: mmch.colorpicker ColorPickerRemapIndices: 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 TextfieldColorHighlight: 1a1a1a - ChatLineSound: ChatLine - ClickDisabledSound: ClickDisabledSound - ClickSound: ClickSound - ChatMessageColor: FFFFFF - SystemMessageColor: FFFF00 - NormalSelectionColor: FFFFFF - AltSelectionColor: 00FFFF - CtrlSelectionColor: FFFF00 diff -Nru openra-20200503/mods/ts/mod.yaml openra-20210321/mods/ts/mod.yaml --- openra-20200503/mods/ts/mod.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/mod.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -7,11 +7,11 @@ PackageFormats: Mix Packages: - ~^Content/ts - ~^Content/ts/firestorm - . + ~^SupportDir|Content/ts + ~^SupportDir|Content/ts/firestorm + ^EngineDir $ts: ts - ./mods/common: common + ^EngineDir|mods/common: common # Tiberian Sun ~scores.mix @@ -51,7 +51,7 @@ MapFolders: ts|maps: System - ~^maps/ts/{DEV_VERSION}: User + ~^SupportDir|maps/ts/{DEV_VERSION}: User Rules: ts|rules/ai.yaml @@ -124,8 +124,8 @@ ts|chrome.yaml Assemblies: - common|OpenRA.Mods.Common.dll - common|OpenRA.Mods.Cnc.dll + ^BinDir|OpenRA.Mods.Common.dll + ^BinDir|OpenRA.Mods.Cnc.dll ChromeLayout: common|chrome/ingame.yaml @@ -293,28 +293,26 @@ TeamColorPresets: f70606, ff7a22, f8d3b3, f8e947, 94b319, f335a0, a64d6c, ce08f9, f5b2db, 12b572, 4A1948, 1d06f7, 328dff, 78dbf8, cef6b1, 391d1d ModContent: - InstallPromptMessage: Tiberian Sun requires artwork and audio from the original game.\n\nQuick Install will automatically download this content (without music\nor videos) from a mirror of the 2012 Tiberian Sun freeware release.\n\nAdvanced Install includes options for downloading the music and for\ncopying the videos and other content from an original game disc. + InstallPromptMessage: Tiberian Sun requires artwork and audio from the original game.\n\nQuick Install will automatically download this content (without music\nor videos) from a mirror of the 2012 Tiberian Sun freeware release.\n\nAdvanced Install includes options for copying the music, videos, and\nother content from an original game disc or digital installation. QuickDownload: quickinstall HeaderMessage: Game content may be extracted from the original game discs or an\nexisting digital install. OpenRA can also download the base game\nfiles from an online mirror of the 2012 freeware release of TS. Packages: tibsun: Base Game Files - TestFiles: ^Content/ts/cache.mix, ^Content/ts/conquer.mix, ^Content/ts/isosnow.mix, ^Content/ts/isotemp.mix, ^Content/ts/local.mix, ^Content/ts/sidec01.mix, ^Content/ts/sidec02.mix, ^Content/ts/sno.mix, ^Content/ts/snow.mix, ^Content/ts/sounds.mix, ^Content/ts/speech01.mix, ^Content/ts/tem.mix, ^Content/ts/temperat.mix + TestFiles: ^SupportDir|Content/ts/cache.mix, ^SupportDir|Content/ts/conquer.mix, ^SupportDir|Content/ts/isosnow.mix, ^SupportDir|Content/ts/isotemp.mix, ^SupportDir|Content/ts/local.mix, ^SupportDir|Content/ts/sidec01.mix, ^SupportDir|Content/ts/sidec02.mix, ^SupportDir|Content/ts/sno.mix, ^SupportDir|Content/ts/snow.mix, ^SupportDir|Content/ts/sounds.mix, ^SupportDir|Content/ts/speech01.mix, ^SupportDir|Content/ts/tem.mix, ^SupportDir|Content/ts/temperat.mix Sources: tibsun, tibsun-linux, tfd, origin Required: true Download: basefiles tibsun-music: Base Game Music - TestFiles: ^Content/ts/scores.mix + TestFiles: ^SupportDir|Content/ts/scores.mix Sources: tibsun, tibsun-linux, tfd, origin - Download: tibsun-music fstorm: Expansion Freeware Content - TestFiles: ^Content/ts/firestorm/e01sc01.mix, ^Content/ts/firestorm/e01sc02.mix, ^Content/ts/firestorm/e01vox01.mix, ^Content/ts/firestorm/e01vox02.mix + TestFiles: ^SupportDir|Content/ts/firestorm/e01sc01.mix, ^SupportDir|Content/ts/firestorm/e01sc02.mix, ^SupportDir|Content/ts/firestorm/e01vox01.mix, ^SupportDir|Content/ts/firestorm/e01vox02.mix Sources: tfd, origin, fstorm Required: true Download: fstorm fstorm-music: Expansion Freeware Music Sources: tfd, origin, fstorm - TestFiles: ^Content/ts/firestorm/linkup.aud, ^Content/ts/firestorm/hacker.aud - Download: fstorm-music + TestFiles: ^SupportDir|Content/ts/firestorm/linkup.aud, ^SupportDir|Content/ts/firestorm/hacker.aud Downloads: ts|installer/downloads.yaml Sources: @@ -323,3 +321,6 @@ ts|installer/firstdecade.yaml ts|installer/origin.yaml ts|installer/tibsun.yaml + +DiscordService: + ApplicationId: 712713986558394399 diff -Nru openra-20200503/mods/ts/rules/aircraft.yaml openra-20210321/mods/ts/rules/aircraft.yaml --- openra-20200503/mods/ts/rules/aircraft.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/aircraft.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,15 +1,17 @@ DPOD: Inherits: ^Aircraft Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 10 Tooltip: Name: Drop Pod Aircraft: IdleBehavior: Land - TurnSpeed: 5 + Pitch: 0 + Roll: 0 + TurnSpeed: 20 Speed: 149 - InitialFacing: 0 Health: HP: 6000 Armor: @@ -17,7 +19,6 @@ Cargo: Types: Infantry MaxWeight: 1 - PipCount: 1 UnloadVoice: Move EjectOnDeath: true Armament: @@ -26,13 +27,64 @@ Voice: Attack AmmoPool: Ammo: 5 - PipCount: 5 - PipType: Ammo - PipTypeEmpty: AmmoEmpty -SpawnActorOnDeath: + WithAmmoPipsDecoration: + Position: BottomLeft + RequiresSelection: true + Margin: 4, 5 + FullSequence: pip-ammo + EmptySequence: pip-ammoempty + Palette: pips + +DPOD2: + Inherits@2: ^ExistsInWorld + Valued: + Cost: 10 + Tooltip: + Name: Drop Pod + Health: + HP: 6000 + Armor: + Type: Light + Aircraft: + TurnSpeed: 20 + Speed: 300 + CruiseAltitude: 16c0 + MaximumPitch: 110 + LandableTerrainTypes: Clear, Road, Rail, DirtRoad, Rough + HiddenUnderFog: + Type: CenterPosition + BodyOrientation: + UseClassicPerspectiveFudge: False + RenderSprites: + Image: pod + WithFacingSpriteBody: + QuantizeFacingsFromSequence: + HitShape: + Interactable: + WithShadow: + SmokeTrailWhenDamaged: + Sprite: largesmoke + MinDamage: Undamaged + FallsToEarth: + Explosion: DropPodExplode + Moves: true + Velocity: 768 + MaximumSpinSpeed: 0 + +DPOD2E1: + Inherits: DPOD2 + SpawnActorOnDeath: + Actor: E1R3 + +DPOD2E2: + Inherits: DPOD2 + SpawnActorOnDeath: + Actor: E2R3 DSHP: Inherits: ^Aircraft + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 1000 Tooltip: @@ -41,9 +93,10 @@ AddToArmyValue: true Aircraft: IdleBehavior: Land - TurnSpeed: 5 + Pitch: 0 + Roll: 0 + TurnSpeed: 20 Speed: 168 - InitialFacing: 0 TakeoffSounds: dropup1.aud LandingSounds: dropdwn1.aud IdealSeparation: 1275 @@ -60,7 +113,6 @@ Cargo: Types: Infantry MaxWeight: 5 - PipCount: 5 UnloadVoice: Move EjectOnDeath: true SpawnActorOnDeath: @@ -84,7 +136,7 @@ Selectable: Bounds: 30,24 Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 186 TakeoffSounds: orcaup1.aud LandingSounds: orcadwn1.aud @@ -102,16 +154,13 @@ Weapon: Hellfire PauseOnCondition: !ammo AttackAircraft: - FacingTolerance: 20 + FacingTolerance: 80 PersistentTargeting: false Voice: Attack PauseOnCondition: empdisable AttackType: Hover AmmoPool: Ammo: 5 - PipCount: 5 - PipType: Ammo - PipTypeEmpty: AmmoEmpty AmmoCondition: ammo RenderSprites: SpawnActorOnDeath: @@ -122,6 +171,13 @@ RequiresCondition: empdisable Rearmable: RearmActors: gahpad, nahpad + WithAmmoPipsDecoration: + Position: BottomLeft + RequiresSelection: true + Margin: 4, 5 + FullSequence: pip-ammo + EmptySequence: pip-ammoempty + Palette: pips ORCAB: Inherits: ^EMPableAircraft @@ -142,8 +198,10 @@ Bounds: 30,24 Aircraft: CruiseAltitude: 5c512 - TurnSpeed: 3 + TurnSpeed: 12 + IdleTurnSpeed: 4 Speed: 96 + IdleSpeed: 72 CruisingCondition: cruising TakeoffSounds: orcaup1.aud LandingSounds: orcadwn1.aud @@ -161,16 +219,13 @@ PauseOnCondition: !ammo AttackAircraft: Voice: Attack - FacingTolerance: 20 + FacingTolerance: 80 PersistentTargeting: false PauseOnCondition: empdisable AmmoPool: Ammo: 10 - PipCount: 2 ReloadCount: 5 ReloadDelay: 200 - PipType: Ammo - PipTypeEmpty: AmmoEmpty AmmoCondition: ammo RenderSprites: Hovers@CRUISING: @@ -183,9 +238,18 @@ RequiresCondition: empdisable Rearmable: RearmActors: gahpad, nahpad + WithAmmoPipsDecoration: + Position: BottomLeft + RequiresSelection: true + Margin: 4, 5 + PipCount: 2 + FullSequence: pip-ammo + EmptySequence: pip-ammoempty + Palette: pips ORCATRAN: Inherits: ^EMPableAircraft + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 1200 Tooltip: @@ -198,9 +262,8 @@ Prerequisites: ~disabled RenderSprites: Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 84 - InitialFacing: 0 LandableTerrainTypes: Clear, Road, Rail, DirtRoad, Rough, Tiberium, BlueTiberium, Veins Crushes: crate, infantry TakeoffSounds: orcaup1.aud @@ -216,7 +279,6 @@ Cargo: Types: Infantry MaxWeight: 5 - PipCount: 5 UnloadVoice: Move EjectOnDeath: true AfterUnloadDelay: 40 @@ -241,9 +303,10 @@ Prerequisites: ~gahpad, gadept Description: VTOL aircraft capable of lifting\nand transporting vehicles.\n Unarmed Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 149 - InitialFacing: 0 + Pitch: 0 + Roll: 0 TakeoffSounds: dropup1.aud LandingSounds: dropdwn1.aud Carryall: @@ -289,8 +352,10 @@ VoiceSet: Scrin Aircraft: CruiseAltitude: 5c0 - TurnSpeed: 3 - Speed: 168 + TurnSpeed: 15 + Speed: 200 + IdleTurnSpeed: 6 + IdleSpeed: 100 TakeoffSounds: dropup1.aud LandingSounds: dropdwn1.aud CanHover: false @@ -307,15 +372,12 @@ PauseOnCondition: !ammo AttackAircraft: Voice: Attack - FacingTolerance: 20 + FacingTolerance: 80 PersistentTargeting: false PauseOnCondition: empdisable AmmoPool: Ammo: 15 - PipCount: 3 ReloadCount: 5 - PipType: Ammo - PipTypeEmpty: AmmoEmpty AmmoCondition: ammo RenderSprites: DeathSounds: @@ -327,6 +389,14 @@ RequiresCondition: empdisable Rearmable: RearmActors: gahpad, nahpad + WithAmmoPipsDecoration: + Position: BottomLeft + RequiresSelection: true + Margin: 4, 5 + PipCount: 3 + FullSequence: pip-ammo + EmptySequence: pip-ammoempty + Palette: pips APACHE: Inherits: ^EMPableAircraft @@ -346,7 +416,11 @@ Selectable: Bounds: 30,24 Aircraft: - TurnSpeed: 5 + Pitch: -32 + PitchSpeed: 8 + Roll: 16 + RollSpeed: 8 + TurnSpeed: 20 Speed: 130 CanSlide: false TakeOffOnResupply: true @@ -361,16 +435,13 @@ Weapon: HarpyClaw PauseOnCondition: !ammo AttackAircraft: - FacingTolerance: 20 + FacingTolerance: 80 PersistentTargeting: false Voice: Attack PauseOnCondition: empdisable AttackType: Hover AmmoPool: Ammo: 12 - PipCount: 4 - PipType: Ammo - PipTypeEmpty: AmmoEmpty AmmoCondition: ammo WithIdleOverlay@ROTORAIR: Offset: 85,0,598 @@ -389,6 +460,17 @@ RequiresCondition: empdisable Rearmable: RearmActors: gahpad, nahpad + WithAmmoPipsDecoration: + Position: BottomLeft + RequiresSelection: true + Margin: 4, 5 + PipCount: 4 + FullSequence: pip-ammo + EmptySequence: pip-ammoempty + Palette: pips + WithShadow: + WithVoxelBody: + ShowShadow: False HUNTER: Inherits@2: ^ExistsInWorld @@ -401,13 +483,15 @@ Armor: Type: Light Aircraft: - TurnSpeed: 16 + TurnSpeed: 64 Speed: 355 + Pitch: 0 + Roll: 0 CruiseAltitude: 3c128 CruisingCondition: cruising MoveIntoShroud: true AttackAircraft: - FacingTolerance: 128 + FacingTolerance: 512 AttackType: Hover Armament@PRIMARY: Weapon: SuicideBomb @@ -427,12 +511,9 @@ Hovers@CRUISING: RequiresCondition: cruising QuantizeFacingsFromSequence: - DrawLineToTarget: AppearsOnRadar: UseLocation: true Interactable: - SelectionDecorations: - Palette: pips HitShape: MapEditorData: Categories: System diff -Nru openra-20200503/mods/ts/rules/ai.yaml openra-20210321/mods/ts/rules/ai.yaml --- openra-20200503/mods/ts/rules/ai.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/ai.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -17,10 +17,10 @@ ExcessPowerIncreaseThreshold: 4 ConstructionYardTypes: gacnst RefineryTypes: proc - PowerTypes: gapowr, napowr, naapwr + PowerTypes: gapowr, gapowrup, napowr, naapwr BarracksTypes: gapile, nahand VehiclesFactoryTypes: gaweap, naweap - ProductionTypes: gapile, nahand, gaweap, naweap + ProductionTypes: gapile, nahand, gaweap, naweap, gahpad, nahpad SiloTypes: gasilo BuildingLimits: proc: 4 @@ -36,9 +36,12 @@ gatech: 1 natech: 1 nastlh: 1 + gahpad: 3 + nahpad: 3 gavulc: 8 garock: 2 gacsam: 4 + gactwr: 14 naobel: 2 nalasr: 8 nasam: 4 @@ -53,10 +56,13 @@ gatech: 1 natech: 1 nastlh: 1 + gahpad: 1 + nahpad: 1 nalasr: 10 gavulc: 10 garock: 3 gacsam: 6 + gactwr: 18 nasam: 6 naobel: 3 BuildingRepairBotModule: @@ -68,6 +74,7 @@ ConstructionYardTypes: gacnst UnitBuilderBotModule@test: RequiresCondition: enable-test-ai + UnitQueues: Vehicle, Infantry, Air UnitsToBuild: e1: 80 e2: 25 @@ -86,6 +93,10 @@ subtank: 10 sonic: 10 stnk: 8 + orca: 5 + orcab: 4 + apache: 5 + scrin: 4 UnitLimits: harv: 12 medic: 3 diff -Nru openra-20200503/mods/ts/rules/bridges.yaml openra-20210321/mods/ts/rules/bridges.yaml --- openra-20200503/mods/ts/rules/bridges.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/bridges.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,10 @@ Palette: player Targetable: TargetTypes: C4 - -SelectionDecorations: + -IsometricSelectable: + -IsometricSelectionDecorations: + Interactable: + SelectionDecorations: -Demolishable: -Explodes: -FrozenUnderFog: diff -Nru openra-20200503/mods/ts/rules/civilian-infantry.yaml openra-20210321/mods/ts/rules/civilian-infantry.yaml --- openra-20200503/mods/ts/rules/civilian-infantry.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/civilian-infantry.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -71,12 +71,12 @@ Disguise: DisguisedCondition: disguise WithDecoration@disguise: + RequiresCondition: disguise + Position: TopRight + Margin: 6, 10 Image: pips Sequence: pip-disguise Palette: pips - ReferencePoint: Top, Right - ZOffset: 256 - RequiresCondition: disguise Infiltrates: Types: SpyInfiltrate Notification: BuildingInfiltrated @@ -226,16 +226,29 @@ Weapon: Pistola AttackFrontal: Voice: Attack + Voiced: + VoiceSet: Civilian1 CIV2: Inherits: ^CivilianInfantry + Voiced: + VoiceSet: Civilian2 CIV3: Inherits: ^CivilianInfantry + Voiced: + VoiceSet: Civilian3 + +CTECH: + Inherits: CIV3 Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove + RenderSprites: + Image: civ3 WithInfantryBody: DefaultAttackSequence: attack Armament: Weapon: Pistola AttackFrontal: Voice: Attack + Voiced: + VoiceSet: CivilianTechnician diff -Nru openra-20200503/mods/ts/rules/civilian-structures.yaml openra-20210321/mods/ts/rules/civilian-structures.yaml --- openra-20200503/mods/ts/rules/civilian-structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/civilian-structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -16,6 +16,8 @@ Pieces: 5, 9 ThrowsShrapnel@LARGE: Pieces: 2, 4 + IsometricSelectable: + Height: 72 ABAN02: Inherits: ^CivBuilding @@ -35,6 +37,8 @@ Pieces: 5, 9 ThrowsShrapnel@LARGE: Pieces: 2, 4 + IsometricSelectable: + Height: 48 ABAN03: Inherits: ^CivBuilding @@ -54,6 +58,8 @@ Pieces: 5, 9 ThrowsShrapnel@LARGE: Pieces: 2, 4 + IsometricSelectable: + Height: 48 ABAN04: Inherits: ^CivBuilding @@ -582,6 +588,8 @@ Type: light Health: HP: 10000 + IsometricSelectable: + Height: 36 CA0013: Inherits: ^CivBuilding @@ -595,6 +603,8 @@ Type: heavy Health: HP: 30000 + IsometricSelectable: + Height: 48 CA0014: Inherits: ^CivBuilding @@ -607,6 +617,8 @@ Type: heavy Health: HP: 30000 + IsometricSelectable: + Height: 48 CA0015: Inherits: ^CivBuilding @@ -631,6 +643,8 @@ Type: light Health: HP: 30000 + IsometricSelectable: + Height: 48 CA0017: Inherits: ^CivBuilding @@ -643,6 +657,8 @@ Type: heavy Health: HP: 30000 + IsometricSelectable: + Height: 48 CA0018: Inherits: ^CivBuilding @@ -659,6 +675,8 @@ Type: light Health: HP: 20000 + IsometricSelectable: + Height: 48 CA0019: Inherits: ^CivBuilding @@ -675,6 +693,8 @@ Type: light Health: HP: 20000 + IsometricSelectable: + Height: 48 CA0020: Inherits: ^CivBuilding @@ -691,6 +711,8 @@ Type: light Health: HP: 20000 + IsometricSelectable: + Height: 48 CA0021: Inherits: ^CivBuilding @@ -707,6 +729,8 @@ Type: light Health: HP: 20000 + IsometricSelectable: + Height: 48 CAARAY: Inherits: ^CivBuilding @@ -734,6 +758,8 @@ Pieces: 5, 7 ThrowsShrapnel@LARGE: Pieces: 2, 4 + IsometricSelectable: + Height: 72 CAARMR: Inherits: ^CivBuilding @@ -783,10 +809,10 @@ Name: Civilian Hospital TooltipDescription@ally: Description: Provides infantry with self-healing. - ValidStances: Ally + ValidRelationships: Ally TooltipDescription@other: Description: Capture to enable self-healing for infantry. - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy Building: Footprint: XxX xxx xxx xxx Dimensions: 3, 4 @@ -807,6 +833,8 @@ Pieces: 2, 4 MapEditorData: Categories: Civilian building + IsometricSelectable: + Height: 48 CAPYR01: Inherits: ^CivBuilding @@ -822,6 +850,8 @@ HP: 40000 MapEditorData: ExcludeTilesets: SNOW + IsometricSelectable: + Height: 48 CAPYR02: Inherits: ^CivBuilding @@ -841,6 +871,8 @@ Pieces: 6, 9 ThrowsShrapnel@LARGE: Pieces: 3, 4 + IsometricSelectable: + Height: 96 CAPYR03: Inherits: ^CivBuilding @@ -860,6 +892,8 @@ Pieces: 6, 9 ThrowsShrapnel@LARGE: Pieces: 3, 4 + IsometricSelectable: + Height: 96 CITY01: Inherits: ^CivBuilding @@ -879,6 +913,8 @@ Pieces: 5, 9 ThrowsShrapnel@LARGE: Pieces: 2, 4 + IsometricSelectable: + Height: 72 CITY02: Inherits: ^CivBuilding @@ -898,6 +934,8 @@ Pieces: 5, 9 ThrowsShrapnel@LARGE: Pieces: 2, 4 + IsometricSelectable: + Height: 72 CITY03: Inherits: ^CivBuilding @@ -917,6 +955,8 @@ Pieces: 5, 9 ThrowsShrapnel@LARGE: Pieces: 2, 4 + IsometricSelectable: + Height: 48 CITY04: Inherits: ^CivBuilding @@ -936,6 +976,8 @@ Pieces: 5, 9 ThrowsShrapnel@LARGE: Pieces: 2, 4 + IsometricSelectable: + Height: 72 CITY05: Inherits: ^CivBuilding @@ -955,6 +997,8 @@ Pieces: 5, 9 ThrowsShrapnel@LARGE: Pieces: 2, 4 + IsometricSelectable: + Height: 96 CITY06: Inherits: ^CivBuilding @@ -974,6 +1018,8 @@ Pieces: 7, 9 ThrowsShrapnel@LARGE: Pieces: 3, 4 + IsometricSelectable: + Height: 72 CITY07: Inherits: ^CivBuilding @@ -993,6 +1039,8 @@ Pieces: 7, 9 ThrowsShrapnel@LARGE: Pieces: 3, 4 + IsometricSelectable: + Height: 60 CITY08: Inherits: ^CivBuilding @@ -1023,6 +1071,8 @@ HP: 40000 MapEditorData: RequireTilesets: TEMPERATE + IsometricSelectable: + Height: 48 CITY10: Inherits: ^CivBuilding @@ -1038,6 +1088,8 @@ HP: 30000 MapEditorData: RequireTilesets: TEMPERATE + IsometricSelectable: + Height: 48 CITY11: Inherits: ^CivBuilding @@ -1053,6 +1105,8 @@ HP: 50000 MapEditorData: RequireTilesets: TEMPERATE + IsometricSelectable: + Height: 96 CITY12: Inherits: ^CivBuilding @@ -1068,6 +1122,8 @@ HP: 60000 MapEditorData: RequireTilesets: TEMPERATE + IsometricSelectable: + Height: 96 CITY13: Inherits: ^CivBuilding @@ -1083,6 +1139,8 @@ HP: 50000 MapEditorData: RequireTilesets: TEMPERATE + IsometricSelectable: + Height: 96 CITY14: Inherits: ^CivBuilding @@ -1097,6 +1155,8 @@ HP: 60000 MapEditorData: RequireTilesets: TEMPERATE + IsometricSelectable: + Height: 96 CITY15: Inherits: ^CivBuilding @@ -1135,6 +1195,8 @@ Pieces: 7, 9 ThrowsShrapnel@LARGE: Pieces: 3, 4 + IsometricSelectable: + Height: 72 CITY17: Inherits: ^CivBuilding @@ -1154,6 +1216,8 @@ Pieces: 7, 9 ThrowsShrapnel@LARGE: Pieces: 3, 4 + IsometricSelectable: + Height: 108 CITY18: Inherits: ^CivBuilding @@ -1173,6 +1237,8 @@ Pieces: 8, 12 ThrowsShrapnel@LARGE: Pieces: 5, 7 + IsometricSelectable: + Height: 72 CITY19: Inherits: ^CivBuilding @@ -1231,6 +1297,8 @@ HP: 10000 MapEditorData: RequireTilesets: TEMPERATE + IsometricSelectable: + Height: 72 CTDAM: Inherits: ^CivBuilding @@ -1278,6 +1346,8 @@ Pieces: 7, 9 ThrowsShrapnel@LARGE: Pieces: 3, 4 + IsometricSelectable: + Height: 72 GAKODK: Inherits: ^CivBuilding @@ -1313,16 +1383,22 @@ Name: Old Temple Building: Footprint: xx xX + IsometricSelectable: + Height: 36 GAOLDCC3: Inherits: ^OldBase Tooltip: Name: Old Weapons Factory + IsometricSelectable: + Height: 36 GAOLDCC4: Inherits: ^OldBase Tooltip: Name: Old Refinery + IsometricSelectable: + Height: 36 GAOLDCC5: Inherits: ^OldBase @@ -1371,9 +1447,6 @@ Building: Footprint: x Dimensions: 1, 1 - Selectable: - Bounds: 48, 30, 0, -4 - DecorationBounds: 48, 82, 0, -25 Power: Amount: -10 Armor: @@ -1385,9 +1458,10 @@ MaxHeightDelta: 3 WithIdleOverlay@LIGHTS: Sequence: idle-lights - SelectionDecorations: MapEditorData: Categories: Civilian building + IsometricSelectable: + Height: 72 GALITE: Inherits: ^Building @@ -1396,6 +1470,7 @@ Tooltip: Name: Light Post RenderSprites: + Image: galite Palette: terraindecoration -WithMakeAnimation: -WithDeathAnimation: @@ -1410,14 +1485,12 @@ MaxHeightDelta: 3 Power: Amount: 0 - # TODO: should use terrain lighting instead, depends on https://github.com/OpenRA/OpenRA/issues/3605 - WithIdleOverlay@LIGHTING: - Sequence: lighting - Palette: alpha - Selectable: - Bounds: 24, 24, 0, -4 - DecorationBounds: 25, 35, 0, -12 - SelectionDecorations: + TerrainLightSource: + Range: 19c544 + Intensity: 0.2 + RedTint: 0.05 + GreenTint: 0.05 + BlueTint: 0.01 -Cloak@EXTERNALCLOAK: -ExternalCondition@CLOAKGENERATOR: -ExternalCondition@CRATE-CLOAK: @@ -1426,11 +1499,179 @@ Capturable: -RequiresCondition: -TSTLAMP: - Inherits: GALITE - RenderSprites: +INGALITE: + Interactable: + EditorOnlyTooltip: + Name: (Invisible Light Post) + AlwaysVisible: + Immobile: + OccupiesSpace: false + RenderSpritesEditorOnly: Image: galite + Palette: terrainalpha + WithSpriteBody: + BodyOrientation: + QuantizedFacings: 1 + MapEditorData: + Categories: System + RequiresSpecificOwners: + ValidOwnerNames: Neutral + TerrainLightSource: + Range: 19c544 + Intensity: 0.2 + RedTint: 0.05 + GreenTint: 0.05 + BlueTint: 0.01 + +NEGLAMP: + Inherits: INGALITE + EditorOnlyTooltip: + Name: (Invisible Negative Light Post) + TerrainLightSource: + Range: 13c688 + Intensity: -0.15 + RedTint: 0.03 + GreenTint: 0.04 + BlueTint: 0.04 + +REDLAMP: + Inherits: GALITE + Tooltip: + Name: Red Light Post + TerrainLightSource: + Range: 15c640 + Intensity: 0.01 + RedTint: 1.5 + GreenTint: 0.01 + BlueTint: 0.01 + +NEGRED: + Inherits: GALITE + Tooltip: + Name: Negative Red Light Post + TerrainLightSource: + Range: 15c640 + Intensity: -0.05 + RedTint: -1.5 + GreenTint: 0.01 + BlueTint: 0.01 + +GRENLAMP: + Inherits: GALITE Tooltip: + Name: Green Light Post + TerrainLightSource: + Range: 15c640 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 1.5 + BlueTint: 0.01 + +BLUELAMP: + Inherits: GALITE + Tooltip: + Name: Blue Light Post + TerrainLightSource: + Range: 15c640 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.01 + BlueTint: 0.7 + +YELWLAMP: + Inherits: GALITE + Tooltip: + Name: Yellow Light Post + TerrainLightSource: + Range: 15c640 + Intensity: 0.01 + RedTint: 1.5 + GreenTint: 1.5 + BlueTint: 0.01 + +INYELWLAMP: + Inherits: INGALITE + EditorOnlyTooltip: + Name: (Invisible Yellow Light Post) + TerrainLightSource: + Range: 15c640 + Intensity: 0.01 + RedTint: 1.5 + GreenTint: 1.5 + BlueTint: 0.01 + +PURPLAMP: + Inherits: GALITE + Tooltip: + Name: Purple Light Post + TerrainLightSource: + Range: 11c736 + Intensity: 0.01 + RedTint: 2.0 + GreenTint: 0.01 + BlueTint: 2.0 + +INPURPLAMP: + Inherits: INGALITE + EditorOnlyTooltip: + Name: (Invisible Purple Light Post) + TerrainLightSource: + Range: 11c736 + Intensity: 0.01 + RedTint: 2.0 + GreenTint: 0.01 + BlueTint: 2.0 + +INORANLAMP: + Inherits: INGALITE + EditorOnlyTooltip: + Name: (Invisible Orange Light Post) + TerrainLightSource: + Range: 11c736 + Intensity: 0.01 + RedTint: 2.0 + GreenTint: 1.4 + BlueTint: 0.3 + +INGRNLMP: + Inherits: INGALITE + EditorOnlyTooltip: + Name: (Invisible Green Light Post) + TerrainLightSource: + Range: 15c640 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 1.5 + BlueTint: 0.01 + +INREDLMP: + Inherits: INGALITE + EditorOnlyTooltip: + Name: (Invisible Red Light Post) + TerrainLightSource: + Range: 15c640 + Intensity: 0.01 + RedTint: 1.5 + GreenTint: 0.01 + BlueTint: 0.01 + +INBLULMP: + Inherits: INGALITE + EditorOnlyTooltip: + Name: (Invisible Blue Light Post) + TerrainLightSource: + Range: 15c640 + Intensity: 0.01 + RedTint: 0.01 + GreenTint: 0.01 + BlueTint: 0.7 + +TSTLAMP: + Inherits: GALITE + -TerrainLightSource: + WithIdleOverlay@LIGHTING: + Sequence: lighting + Palette: alpha GAICBM: Inherits: ^Building @@ -1449,12 +1690,14 @@ Transforms: IntoActor: icbm Offset: 1,1 - Facing: 96 + Facing: 384 TransformSounds: place2.aud NoTransformSounds: -WithDeathAnimation: MapEditorData: Categories: Vehicle + IsometricSelectable: + Height: 48 NAMNTK: Inherits: ^CivBuilding @@ -1472,6 +1715,8 @@ Palette: player WithIdleOverlay@LIGHTS: Sequence: idle-lights + IsometricSelectable: + Height: 36 NTPYRA: Inherits: ^CivBuilding @@ -1495,6 +1740,8 @@ Pieces: 7, 9 ThrowsShrapnel@LARGE: Pieces: 3, 5 + IsometricSelectable: + Height: 72 UFO: Inherits: ^CivBuilding @@ -1504,9 +1751,6 @@ Footprint: xxxxxx xxxxxx xxxxxx xxxxxx RenderSprites: Palette: terraindecoration - Selectable: - Bounds: 144, 72, 0, 0 - DecorationBounds: 144, 72, 0, 0 Tooltip: Name: Scrin Ship Health: @@ -1515,8 +1759,9 @@ Type: Heavy MapEditorData: RequireTilesets: TEMPERATE - SelectionDecorations: ThrowsShrapnel@SMALL: Pieces: 9, 12 ThrowsShrapnel@LARGE: Pieces: 6, 8 + IsometricSelectable: + Height: 144 diff -Nru openra-20200503/mods/ts/rules/civilian-vehicles.yaml openra-20210321/mods/ts/rules/civilian-vehicles.yaml --- openra-20200503/mods/ts/rules/civilian-vehicles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/civilian-vehicles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,7 @@ Name: Mammoth Tank Mobile: Speed: 56 - TurnSpeed: 5 + TurnSpeed: 20 Health: HP: 60000 Armor: @@ -19,7 +19,7 @@ MaxHeightDelta: 3 RequiresCondition: !inside-tunnel Turreted: - TurnSpeed: 3 + TurnSpeed: 12 Armament@PRIMARY: Weapon: 120mmx LocalOffset: 707,85,509, 707,-120,509 @@ -31,10 +31,10 @@ AttackTurreted: Voice: Attack PauseOnCondition: empdisable - SelfHealing: + ChangesHealth: Step: 500 Delay: 10 - HealIfBelow: 50 + StartIfBelow: 50 DamageCooldown: 200 WithVoxelTurret: WithVoxelBarrel: @@ -77,7 +77,7 @@ Type: Light Mobile: Speed: 85 - TurnSpeed: 5 + TurnSpeed: 20 RevealsShroud: RequiresCondition: !inside-tunnel Range: 7c0 @@ -85,19 +85,20 @@ Transforms: IntoActor: gaicbm Offset: -1,-1 - Facing: 96 + Facing: 384 TransformSounds: NoTransformSounds: Voice: Move BUS: Inherits: ^CivilianVoxelCrusher + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 800 Tooltip: Name: School Bus Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 113 PauseOnCondition: empdisable || loading || being-captured || carried Health: @@ -111,19 +112,19 @@ Cargo: Types: Infantry MaxWeight: 20 - PipCount: 5 UnloadVoice: Unload LoadingCondition: loading EjectOnDeath: true PICK: Inherits: ^CivilianVoxelVehicle + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 800 Tooltip: Name: Pickup Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 113 PauseOnCondition: empdisable || loading || being-captured || carried Health: @@ -137,19 +138,19 @@ Cargo: Types: Infantry MaxWeight: 2 - PipCount: 5 UnloadVoice: Unload LoadingCondition: loading EjectOnDeath: true CAR: Inherits: ^CivilianVoxelVehicle + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 800 Tooltip: Name: Automobile Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 113 PauseOnCondition: empdisable || loading || being-captured || carried Health: @@ -163,19 +164,19 @@ Cargo: Types: Infantry MaxWeight: 4 - PipCount: 5 UnloadVoice: Unload LoadingCondition: loading EjectOnDeath: true WINI: Inherits: ^CivilianVoxelVehicle + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 800 Tooltip: Name: Recreational Vehicle Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 113 PauseOnCondition: empdisable || loading || being-captured || carried Health: @@ -189,40 +190,39 @@ Cargo: Types: Infantry MaxWeight: 5 - PipCount: 5 UnloadVoice: Unload LoadingCondition: loading EjectOnDeath: true LOCOMOTIVE: Inherits: ^Train + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 800 Tooltip: Name: Train Locomotive Cargo: MaxWeight: 2 - PipCount: 2 EjectOnDeath: true TRAINCAR: Inherits: ^Train + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 800 Tooltip: Name: Passenger Car Cargo: MaxWeight: 10 - PipCount: 5 EjectOnDeath: true CARGOCAR: Inherits: ^Train + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 800 Tooltip: Name: Cargo Car Cargo: MaxWeight: 10 - PipCount: 5 EjectOnDeath: true diff -Nru openra-20200503/mods/ts/rules/critters.yaml openra-20210321/mods/ts/rules/critters.yaml --- openra-20200503/mods/ts/rules/critters.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/critters.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -22,7 +22,7 @@ Voiced: VoiceSet: Fiend Targetable: - TargetTypes: Ground + TargetTypes: Ground, Creep Armament: Weapon: FiendShard AttackFrontal: diff -Nru openra-20200503/mods/ts/rules/defaults.yaml openra-20210321/mods/ts/rules/defaults.yaml --- openra-20200503/mods/ts/rules/defaults.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/defaults.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -5,7 +5,6 @@ GivesExperience: PlayerExperienceModifier: 1 ScriptTriggers: - ConditionManager: RenderDebugState: ^SpriteActor: @@ -52,26 +51,26 @@ ReloadDelayMultiplier@ELITE: RequiresCondition: rank-elite Modifier: 75 - SelfHealing@ELITE: + ChangesHealth@ELITE: Step: 200 Delay: 100 - HealIfBelow: 100 + StartIfBelow: 100 DamageCooldown: 125 RequiresCondition: rank-elite WithDecoration@VETERAN: + RequiresCondition: rank-veteran + Position: BottomRight + Margin: 3, 4 Image: rank Sequence: veteran Palette: ra - ReferencePoint: Bottom, Right - RequiresCondition: rank-veteran - ZOffset: 256 WithDecoration@ELITE: + RequiresCondition: rank-elite + Position: BottomRight + Margin: 3, 4 Image: rank Sequence: elite Palette: ra - ReferencePoint: Bottom, Right - RequiresCondition: rank-elite - ZOffset: 256 ^InfantryExperienceHospitalOverrides: WithDecoration@VETERAN: @@ -184,6 +183,11 @@ AttackMove: AssaultMoveCondition: assault-move +^PlayerHandicaps: + HandicapFirepowerMultiplier: + HandicapDamageMultiplier: + HandicapProductionTimeMultiplier: + ^2x1Shape: HitShape: Type: Rectangle @@ -303,10 +307,8 @@ Inherits@2: ^SpriteActor Inherits@3: ^Cloakable Inherits@selection: ^SelectableBuilding + Inherits@handicaps: ^PlayerHandicaps Huntable: - WithTextControlGroupDecoration: - SelectionDecorations: - Palette: pips Targetable: TargetTypes: Ground, Building, C4 HitShape: @@ -397,7 +399,7 @@ WithBuildingRepairDecoration: Image: allyrepair Sequence: repair - ReferencePoint: Center + Position: Center Palette: mouse ^CivBuilding: @@ -505,7 +507,6 @@ RequiresCondition: !being-demolished SellSounds: cashturn.aud ScriptTriggers: - ConditionManager: Health: HitShape: Type: Rectangle @@ -543,13 +544,11 @@ Inherits@4: ^Cloakable Inherits@CRATESTATS: ^CrateStatModifiers Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill DeathTypes: BulletDeath - DrawLineToTarget: - QueuedLineWidth: 2 - QueuedMarkerWidth: 3 Health: HP: 5000 Armor: @@ -563,10 +562,9 @@ Mobile: Voice: Move Speed: 71 + AlwaysTurnInPlace: true Locomotor: foot - WithTextControlGroupDecoration: - SelectionDecorations: - Palette: pips + TurnOnIdle: Selectable: DecorationBounds: 15,23,0,-9 Bounds: 24,24,0,-9 @@ -600,10 +598,10 @@ Guard: Voice: Move Guardable: - SelfHealing@HOSPITAL: + ChangesHealth@HOSPITAL: Step: 500 Delay: 100 - HealIfBelow: 100 + StartIfBelow: 100 DamageCooldown: 125 RequiresCondition: hospitalheal GrantConditionOnPrerequisite@HOSPITAL: @@ -616,11 +614,12 @@ RequiresCondition: hospital && damaged Condition: hospitalheal WithDecoration@REDCROSS: + RequiresCondition: hospitalheal + Position: BottomRight + Margin: 3, 4 Image: pips Sequence: medic Palette: pips - ReferencePoint: Bottom, Right - RequiresCondition: hospitalheal BlinkInterval: 32 BlinkPattern: Off, On RevealOnFire: @@ -633,6 +632,13 @@ Categories: Infantry GrantConditionOnTunnelLayer: Condition: inside-tunnel + WithDecoration@UNDERGROUND: + RequiresCondition: inside-tunnel + Position: Center + Image: typeglyphs + Sequence: infantry + Palette: player + IsPlayerPalette: true ^RegularInfantryDeath: WithDeathAnimation@normal: @@ -755,22 +761,17 @@ Inherits@5: ^DamagedByVeins Inherits@CRATESTATS: ^CrateStatModifiers Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill - DrawLineToTarget: - QueuedLineWidth: 2 - QueuedMarkerWidth: 3 Mobile: PauseOnCondition: empdisable || being-captured || carried Locomotor: wheeled - TurnSpeed: 5 + TurnSpeed: 20 Voice: Move Selectable: Bounds: 40,24 - WithTextControlGroupDecoration: - SelectionDecorations: - Palette: pips Voiced: VoiceSet: Vehicle Targetable: @@ -834,6 +835,13 @@ Categories: Vehicle GrantConditionOnTunnelLayer: Condition: inside-tunnel + WithDecoration@UNDERGROUND: + RequiresCondition: inside-tunnel + Position: Center + Image: typeglyphs + Sequence: vehicle + Palette: player + IsPlayerPalette: true ^Tank: Inherits: ^Vehicle @@ -860,12 +868,10 @@ Inherits@2: ^ExistsInWorld Inherits@3: ^Cloakable Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: OwnerLostAction: Action: Kill - DrawLineToTarget: - QueuedLineWidth: 2 - QueuedMarkerWidth: 3 AppearsOnRadar: UseLocation: true Targetable@GROUND: @@ -874,15 +880,10 @@ Targetable@AIRBORNE: TargetTypes: Air RequiresCondition: airborne - Selectable: - WithTextControlGroupDecoration: - SelectionDecorations: - Palette: pips Repairable: RepairActors: gadept Voice: Move Aircraft: - InitialFacing: 224 AirborneCondition: airborne CruisingCondition: cruising CruiseAltitude: 4c704 @@ -896,6 +897,10 @@ CanHover: true CanSlide: true VTOL: true + Pitch: -64 + PitchSpeed: 16 + Roll: 56 + RollSpeed: 14 Voiced: VoiceSet: Heli HiddenUnderFog: @@ -946,7 +951,7 @@ Type: Heavy HiddenUnderFog: Type: GroundPosition - AlwaysVisibleStances: None + AlwaysVisibleRelationships: None ScriptTriggers: Interactable: Tooltip: @@ -954,7 +959,7 @@ FallsToEarth: Moves: true Velocity: 112 - MaximumSpinSpeed: 10 + MaximumSpinSpeed: 40 HitShape: ^Visceroid: @@ -962,20 +967,15 @@ Inherits@2: ^SpriteActor Inherits@3: ^HealsOnTiberium Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: - DrawLineToTarget: - QueuedLineWidth: 2 - QueuedMarkerWidth: 3 Health: Armor: Type: Light Mobile: Speed: 113 - TurnSpeed: 16 + TurnSpeed: 64 Locomotor: visceroid - WithTextControlGroupDecoration: - SelectionDecorations: - Palette: pips Selectable: Bounds: 26,26,0,-3 Targetable: @@ -1017,6 +1017,7 @@ ResourceType: Tiberium Interval: 55 WithIdleAnimation: + Interval: 500, 1000 MapEditorData: Categories: Resource spawn @@ -1117,15 +1118,13 @@ Inherits@2: ^ExistsInWorld Inherits@3: ^Cloakable Inherits@selection: ^SelectableCombatUnit + Inherits@handicaps: ^PlayerHandicaps Huntable: RenderVoxels: RenderSprites: WithVoxelBody: - DrawLineToTarget: - QueuedLineWidth: 2 - QueuedMarkerWidth: 3 Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Voice: Move Speed: 113 PauseOnCondition: empdisable @@ -1143,9 +1142,6 @@ RequiresCondition: !inside-tunnel Selectable: Bounds: 40,24 - WithTextControlGroupDecoration: - SelectionDecorations: - Palette: pips Voiced: VoiceSet: Vehicle Targetable: @@ -1324,7 +1320,7 @@ Sequence: offline Palette: mouse RequiresCondition: powerdown - ReferencePoint: Center + Position: Center Offsets: repairing: 12, 0 PowerMultiplier@POWERDOWN: @@ -1343,25 +1339,66 @@ RequiresCondition: lowpower || powerdown Condition: disabled +^Selectable: + Selectable: + SelectionDecorations: + WithTextControlGroupDecoration: + Margin: 2, 0 + DrawLineToTarget: + QueuedLineWidth: 2 + QueuedMarkerWidth: 3 + ^SelectableCombatUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 10 PriorityModifiers: Ctrl ^SelectableSupportUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 8 PriorityModifiers: Ctrl, Alt ^SelectableEconomicUnit: + Inherits@selectiondecorations: ^Selectable Selectable: Priority: 6 PriorityModifiers: Ctrl, Alt -^SelectableCombatBuilding: - Selectable: - Priority: 4 +^CargoPips: + WithCargoPipsDecoration: + Position: BottomLeft + RequiresSelection: true + Palette: pips + Margin: 5, 2 + CustomPipSequences: + red: pip-red + green: pip-green + yellow: pip-yellow ^SelectableBuilding: - Selectable: + IsometricSelectable: Priority: 2 + IsometricSelectionDecorations: + WithTextControlGroupDecoration: + Margin: 1, 1 + DrawLineToTarget: + QueuedLineWidth: 2 + QueuedMarkerWidth: 3 + +^SelectableCombatBuilding: + Inherits@selectiondecorations: ^SelectableBuilding + IsometricSelectable: + Priority: 4 + +^PrimaryBuilding: + PrimaryBuilding: + PrimaryCondition: primary + SelectionNotification: PrimaryBuildingSelected + WithTextDecoration@primary: + RequiresCondition: primary + Position: Top + RequiresSelection: true + Text: PRIMARY + Color: E0D048 diff -Nru openra-20200503/mods/ts/rules/gdi-infantry.yaml openra-20210321/mods/ts/rules/gdi-infantry.yaml --- openra-20200503/mods/ts/rules/gdi-infantry.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/gdi-infantry.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -33,6 +33,15 @@ ProducibleWithLevel: Prerequisites: barracks.upgraded +E2R3: + Inherits: E2 + RenderSprites: + Image: E2 + ProducibleWithLevel: + Prerequisites: techlevel.low + InitialLevels: 3 + -Buildable: + MEDIC: Inherits: ^Soldier Inherits@EXPERIENCE: ^GainsExperience @@ -60,8 +69,8 @@ CrushSound: squishy2.aud Armament: Weapon: Heal - TargetStances: Ally - ForceTargetStances: None + TargetRelationships: Ally + ForceTargetRelationships: None Cursor: heal OutsideRangeCursor: heal AutoTarget: @@ -70,11 +79,11 @@ AttackFrontal: WithInfantryBody: DefaultAttackSequence: heal - SelfHealing: + ChangesHealth: Step: 500 Delay: 60 Passenger: - PipType: Red + CustomPipType: red JUMPJET: Inherits: ^Soldier @@ -102,7 +111,7 @@ Armor: Type: Light Passenger: - PipType: Green + CustomPipType: green RevealsShroud: Range: 6c0 Armament: @@ -182,7 +191,6 @@ Sequence: die-falling Health: HitShape: - ConditionManager: GrantConditionOnTerrain: TerrainTypes: Water Condition: water-death diff -Nru openra-20200503/mods/ts/rules/gdi-structures.yaml openra-20210321/mods/ts/rules/gdi-structures.yaml --- openra-20200503/mods/ts/rules/gdi-structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/gdi-structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -29,9 +29,6 @@ RequiresCondition: !build-incomplete PauseOnCondition: empdisable Sequence: idle-plug - Selectable: - Bounds: 90, 48, 0, -6 - DecorationBounds: 90, 84, 0, -12 Power: Amount: 100 RequiresCondition: !empdisable @@ -45,6 +42,8 @@ powrup: powrup.a Requirements: powrup: !build-incomplete && !powrup.a + EditorOptions: + powrup: Power Turbine Power@pluga: RequiresCondition: !empdisable && powrup.a Amount: 50 @@ -58,6 +57,8 @@ powrup: powrup.b Requirements: powrup: !build-incomplete && !powrup.b + EditorOptions: + powrup: Power Turbine WithIdleOverlay@plugb: RequiresCondition: !build-incomplete && powrup.b PauseOnCondition: empdisable @@ -66,14 +67,41 @@ RequiresCondition: !empdisable && powrup.b Amount: 50 ProvidesPrerequisite@buildingname: - SelectionDecorations: + ProvidesPrerequisite@pluggable: + RequiresCondition: !powrup.a || !powrup.b + Prerequisite: gapowr.socket + IsometricSelectable: + Height: 48 + +GAPOWR.SOCKET: + AlwaysVisible: + Interactable: + Tooltip: + Name: GDI Power Plant socket + +GAPOWRUP: + Inherits: ^BuildingPlug + Valued: + Cost: 150 + Tooltip: + Name: Power Turbine + Buildable: + Queue: Building + BuildPaletteOrder: 100 + Prerequisites: gapowr.socket, ~structures.gdi, ~techlevel.medium + Description: Provides extra power generation. + Plug: + Type: powrup + Power: + Amount: 50 GAPILE: Inherits: ^Building Inherits@SHAPE: ^2x2Shape + Inherits@PRIMARY: ^PrimaryBuilding Buildable: Queue: Building - BuildPaletteOrder: 30 + BuildPaletteOrder: 20 Prerequisites: anypower, ~structures.gdi, ~techlevel.low Description: Produces infantry. Valued: @@ -85,9 +113,6 @@ Building: Footprint: xx xx Dimensions: 2,2 - Selectable: - Bounds: 88, 48, 0, -8 - DecorationBounds: 88, 56, 0, -8 Health: HP: 80000 Armor: @@ -141,9 +166,6 @@ Production: Produces: Infantry PauseOnCondition: empdisable - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Infantry WithIdleOverlay@LIGHTS: @@ -158,18 +180,11 @@ Power: Amount: -20 ProvidesPrerequisite@buildingname: - SelectionDecorations: - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - Color: E0D048 - ZOffset: 256 - RequiresCondition: primary GAWEAP: Inherits: ^Building Inherits@SHAPE: ^4x3FactoryWithBibShape + Inherits@PRIMARY: ^PrimaryBuilding Valued: Cost: 2000 Tooltip: @@ -178,15 +193,12 @@ Prerequisite: factory Buildable: Queue: Building - BuildPaletteOrder: 60 + BuildPaletteOrder: 50 Prerequisites: proc, ~structures.gdi, ~techlevel.low Description: Produces vehicles. Building: Footprint: xxX+ xxX+ xxX+ Dimensions: 4,3 - Selectable: - Bounds: 154, 96, -2, -12 - DecorationBounds: 154, 100, -2, -12 Health: HP: 100000 RevealsShroud: @@ -206,9 +218,6 @@ Production: Produces: Vehicle PauseOnCondition: empdisable - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Vehicle WithIdleOverlay@ROOF: @@ -231,24 +240,19 @@ Power: Amount: -30 ProvidesPrerequisite@buildingname: - SelectionDecorations: - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - Color: E0D048 - ZOffset: 256 - RequiresCondition: primary + IsometricSelectable: + Height: 48 GAHPAD: Inherits: ^Building Inherits@SHAPE: ^2x2Shape + Inherits@PRIMARY: ^PrimaryBuilding Valued: Cost: 500 Tooltip: Name: Helipad Buildable: - BuildPaletteOrder: 130 + BuildPaletteOrder: 80 Queue: Building Prerequisites: garadr, ~structures.gdi, ~techlevel.medium Description: Produces, rearms and\nrepairs helicopters. @@ -262,6 +266,7 @@ MaxHeightDelta: 3 Exit@1: SpawnOffset: 0,-256,0 + Facing: 896 ExitsDebugOverlay: RallyPoint: Palette: mouse @@ -270,9 +275,6 @@ Production: Produces: Air PauseOnCondition: empdisable - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected Reservable: RepairsUnits: HpPerStep: 1000 @@ -292,18 +294,7 @@ UseDeathTypeSuffix: false Power: Amount: -10 - Selectable: - Bounds: 88, 66, 0, -5 - DecorationBounds: 88, 66, 0, -5 ProvidesPrerequisite@buildingname: - SelectionDecorations: - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - Color: E0D048 - ZOffset: 256 - RequiresCondition: primary GADEPT: Inherits: ^Building @@ -313,16 +304,13 @@ Tooltip: Name: Service Depot Buildable: - BuildPaletteOrder: 110 + BuildPaletteOrder: 70 Prerequisites: factory, ~structures.gdi, ~techlevel.medium Queue: Building Description: Repairs vehicles. Building: Footprint: =+= x++ x+= Dimensions: 3,3 - Selectable: - Bounds: 96, 64, -6, -6 - DecorationBounds: 98, 68, -6, -6 Health: HP: 110000 RevealsShroud: @@ -362,7 +350,6 @@ Power: Amount: -30 ProvidesPrerequisite@buildingname: - SelectionDecorations: RenderSprites: Image: gadept.gdi FactionImages: @@ -375,7 +362,7 @@ Inherits@SHAPE: ^2x2Shape Buildable: Queue: Building - BuildPaletteOrder: 80 + BuildPaletteOrder: 40 Prerequisites: proc, ~structures.gdi, ~techlevel.low Description: Provides an overview of the battlefield.\nCan detect cloaked units.\nRequires power to operate. Valued: @@ -387,9 +374,6 @@ Building: Footprint: xx xx Dimensions: 2,2 - Selectable: - Bounds: 96, 48, 0, -6 - DecorationBounds: 96, 118, 0, -38 Health: HP: 100000 Armor: @@ -412,7 +396,8 @@ Power: Amount: -50 ProvidesPrerequisite@buildingname: - SelectionDecorations: + IsometricSelectable: + Height: 72 GATECH: Inherits: ^Building @@ -420,7 +405,7 @@ Inherits@SHAPE: ^3x2Shape Buildable: Queue: Building - BuildPaletteOrder: 150 + BuildPaletteOrder: 90 Prerequisites: gaweap, garadr, ~structures.gdi, ~techlevel.medium Description: Provides access to advanced GDI technologies. Valued: @@ -432,9 +417,6 @@ Building: Footprint: xxx xxx Dimensions: 3,2 - Selectable: - Bounds: 110, 60, 3, -4 - DecorationBounds: 110, 60, 3, -4 Health: HP: 50000 Armor: @@ -448,7 +430,8 @@ Power: Amount: -150 ProvidesPrerequisite@buildingname: - SelectionDecorations: + IsometricSelectable: + Height: 48 GAPLUG: Inherits: ^Building @@ -458,11 +441,8 @@ Cost: 1000 Tooltip: Name: GDI Upgrade Center - Selectable: - Bounds: 115,72,0,-12 - DecorationBounds: 115,104,0,-24 Buildable: - BuildPaletteOrder: 170 + BuildPaletteOrder: 110 Prerequisites: proc, gatech, ~structures.gdi, ~techlevel.superweapons Queue: Building Description: Can be upgraded for additional technology. @@ -502,6 +482,18 @@ SelectTargetSpeechNotification: SelectTarget DisplayRadarPing: True CameraActor: camera + DropPodsPower: + Cursor: ioncannon + PauseOnCondition: disabled || empdisable + RequiresCondition: plug.droppoda || plug.droppodb + Icon: droppods + Description: Drop Pods + LongDesc: Drop Pod reinforcements.\nSmall team of elite soldiers orbital drops\nto target location. + SelectTargetSpeechNotification: SelectTarget + DisplayRadarPing: true + ChargeInterval: 10000 + UnitTypes: DPOD2E1, DPOD2E2 + CameraActor: camera ProduceActorPower: PauseOnCondition: disabled || empdisable RequiresCondition: plug.hunterseekera || plug.hunterseekerb @@ -520,19 +512,28 @@ Power: Amount: -150 Power@ioncannon: - RequiresCondition: (plug.ioncannona || plug.ioncannonb) + RequiresCondition: plug.ioncannona || plug.ioncannonb Amount: -100 Power@hunterseeker: - RequiresCondition: (plug.hunterseekera || plug.hunterseekerb) + RequiresCondition: plug.hunterseekera || plug.hunterseekerb Amount: -50 + Power@droppod: + RequiresCondition: plug.droppoda || plug.droppodb + Amount: -20 Pluggable@pluga: Offset: 0,2 Conditions: plug.ioncannon: plug.ioncannona plug.hunterseeker: plug.hunterseekera + plug.droppod: plug.droppoda Requirements: - plug.ioncannon: !build-incomplete && !plug.ioncannonb && !plug.ioncannona && !plug.hunterseekera - plug.hunterseeker: !build-incomplete && !plug.hunterseekerb && !plug.ioncannona && !plug.hunterseekera + plug.ioncannon: !build-incomplete && !plug.ioncannonb && !plug.ioncannona && !plug.hunterseekera && !plug.droppoda + plug.hunterseeker: !build-incomplete && !plug.hunterseekerb && !plug.ioncannona && !plug.hunterseekera && !plug.droppoda + plug.droppod: !build-incomplete && !plug.droppodb && !plug.ioncannona && !plug.hunterseekera && !plug.droppoda + EditorOptions: + plug.ioncannon: Ion Cannon + plug.hunterseeker: Hunter Seeker + plug.droppod: Drop Pod Reinforcements WithIdleOverlay@ioncannona: RequiresCondition: !build-incomplete && plug.ioncannona PauseOnCondition: disabled @@ -541,14 +542,24 @@ RequiresCondition: !build-incomplete && plug.hunterseekera PauseOnCondition: disabled Sequence: idle-hunterseekera + WithIdleOverlay@droppoda: + RequiresCondition: !build-incomplete && plug.droppoda + PauseOnCondition: disabled + Sequence: idle-droppoda Pluggable@plugb: Offset: 1,2 Conditions: plug.ioncannon: plug.ioncannonb plug.hunterseeker: plug.hunterseekerb + plug.droppod: plug.droppodb Requirements: - plug.ioncannon: !build-incomplete && !plug.ioncannona && !plug.ioncannonb && !plug.hunterseekerb - plug.hunterseeker: !build-incomplete && !plug.hunterseekera && !plug.ioncannonb && !plug.hunterseekerb + plug.ioncannon: !build-incomplete && !plug.ioncannona && !plug.ioncannonb && !plug.hunterseekerb && !plug.droppodb + plug.hunterseeker: !build-incomplete && !plug.hunterseekera && !plug.ioncannonb && !plug.hunterseekerb && !plug.droppodb + plug.droppod: !build-incomplete && !plug.droppoda && !plug.ioncannonb && !plug.hunterseekerb && !plug.droppodb + EditorOptions: + plug.ioncannon: Ion Cannon + plug.hunterseeker: Hunter Seeker + plug.droppod: Drop Pod Reinforcements WithIdleOverlay@ioncannonb: RequiresCondition: !build-incomplete && plug.ioncannonb PauseOnCondition: disabled @@ -557,5 +568,76 @@ RequiresCondition: !build-incomplete && plug.hunterseekerb PauseOnCondition: disabled Sequence: idle-hunterseekerb + WithIdleOverlay@droppodb: + RequiresCondition: plug.droppodb + PauseOnCondition: disabled + Sequence: idle-droppodb ProvidesPrerequisite@buildingname: - SelectionDecorations: + ProvidesPrerequisite@pluggableion: + RequiresCondition: !plug.ioncannona && !plug.ioncannonb + Prerequisite: gaplug.socket.ioncannon + ProvidesPrerequisite@pluggablehunter: + RequiresCondition: !plug.hunterseekera && !plug.hunterseekerb + Prerequisite: gaplug.socket.hunterseeker + IsometricSelectable: + Height: 48 + +GAPLUG.SOCKET.IONCANNON: + AlwaysVisible: + Interactable: + Tooltip: + Name: GDI Upgrade Center socket + +GAPLUG.SOCKET.HUNTERSEEKER: + AlwaysVisible: + Interactable: + Tooltip: + Name: GDI Upgrade Center socket + +GAPLUG2: + Inherits: ^BuildingPlug + Valued: + Cost: 1000 + Tooltip: + Name: Seeker Control + Buildable: + Queue: Building + BuildPaletteOrder: 110 + Prerequisites: gaplug.socket.hunterseeker, gatech, gaweap, ~structures.gdi, ~techlevel.superweapons + Description: Enables use of the hunter-seeker droid. + Plug: + Type: plug.hunterseeker + Power: + Amount: -50 + +GAPLUG3: + Inherits: ^BuildingPlug + Valued: + Cost: 1500 + Tooltip: + Name: Ion Cannon Uplink + Buildable: + Queue: Building + BuildPaletteOrder: 120 + Prerequisites: gaplug.socket.ioncannon, gatech, ~structures.gdi, ~techlevel.superweapons + Description: Enables use of the Ion Cannon. + Plug: + Type: plug.ioncannon + Power: + Amount: -100 + +GAPLUG4: + Inherits: ^BuildingPlug + Valued: + Cost: 1000 + Tooltip: + Name: Drop Pod Node + Buildable: + Queue: Building + BuildPaletteOrder: 180 + Prerequisites: gaplug, gatech, ~structures.gdi, ~techlevel.superweapons + Description: Enables use of the Drop Pod Reinforcements. + Plug: + Type: plug.droppod + Power: + Amount: -20 diff -Nru openra-20200503/mods/ts/rules/gdi-support.yaml openra-20210321/mods/ts/rules/gdi-support.yaml --- openra-20200503/mods/ts/rules/gdi-support.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/gdi-support.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -45,8 +45,13 @@ Inherits: ^Defense Inherits@IDISABLE: ^DisableOnPowerDown Inherits@AUTOTARGET: ^AutoTargetAll - -WithSpriteBody: + WithMakeAnimation: + BodyNames: make + WithSpriteBody: + Name: make + Sequence: invisible WithWallSpriteBody: + RequiresCondition: !build-incomplete Type: wall Valued: Cost: 200 @@ -57,9 +62,6 @@ BuildPaletteOrder: 70 Prerequisites: gapile, ~structures.gdi, ~techlevel.low Description: Modular tower for base defenses. - Selectable: - Bounds: 48, 36, 0, -6 - DecorationBounds: 48, 48, 0, -12 Health: HP: 50000 Armor: @@ -71,8 +73,9 @@ DetectCloaked: RequiresCondition: !empdisable && !disabled && (tower.vulcan || tower.rocket || tower.sam) Turreted: - TurnSpeed: 10 - InitialFacing: 224 + TurnSpeed: 40 + InitialFacing: 896 + RealignDelay: -1 AttackTurreted: RequiresCondition: !build-incomplete && (tower.vulcan || tower.rocket || tower.sam) PauseOnCondition: empdisable || disabled @@ -94,7 +97,6 @@ LocalOffset: 588,120,1358 MuzzleSequence: muzzle MuzzlePalette: effect-ignore-lighting - MuzzleSplitFacings: 8 Armament@VULCSECONDARY: RequiresCondition: tower.vulcan Name: secondary @@ -102,7 +104,6 @@ LocalOffset: 588,-120,1358 MuzzleSequence: muzzle MuzzlePalette: effect-ignore-lighting - MuzzleSplitFacings: 8 Armament@ROCKET: RequiresCondition: tower.rocket Weapon: RPGTower @@ -136,10 +137,24 @@ tower.vulcan: !build-incomplete && !tower.vulcan && !tower.rocket && !tower.sam tower.rocket: !build-incomplete && !tower.rocket && !tower.vulcan && !tower.sam tower.sam: !build-incomplete && !tower.vulcan && !tower.rocket && !tower.sam + EditorOptions: + tower.vulcan: Vulcan Tower + tower.rocket: RPG Upgrade + tower.sam: SAM Upgrade ProvidesPrerequisite@buildingname: - SelectionDecorations: + ProvidesPrerequisite@pluggable: + RequiresCondition: !build-incomplete && !tower.vulcan && !tower.rocket && !tower.sam + Prerequisite: gactwr.socket Replacement: ReplaceableTypes: GDITower + IsometricSelectable: + Height: 48 + +GACTWR.SOCKET: + AlwaysVisible: + Interactable: + Tooltip: + Name: Component Tower (unupgraded) GAVULC: Inherits: ^BuildingPlug @@ -149,8 +164,8 @@ Name: Vulcan Tower Buildable: Queue: Defense - BuildPaletteOrder: 120 - Prerequisites: gactwr, gapile, ~structures.gdi, ~techlevel.low + BuildPaletteOrder: 80 + Prerequisites: gactwr.socket, gapile, ~structures.gdi, ~techlevel.low Description: Basic base defense.\nDoes not require power to operate.\n Strong vs Infantry, Light armor\n Weak vs Aircraft Plug: Type: tower.vulcan @@ -165,8 +180,8 @@ Name: RPG Upgrade Buildable: Queue: Defense - BuildPaletteOrder: 130 - Prerequisites: gactwr, gapile, ~structures.gdi, ~techlevel.high + BuildPaletteOrder: 90 + Prerequisites: gactwr.socket, gapile, ~structures.gdi, ~techlevel.high Description: GDI Advanced base defense.\nDoes not require power to operate.\n Strong vs Armored ground units\n Weak vs Aircraft Plug: Type: tower.rocket @@ -181,58 +196,10 @@ Name: SAM Upgrade Buildable: Queue: Defense - BuildPaletteOrder: 140 - Prerequisites: gactwr, garadr, ~structures.gdi, ~techlevel.medium + BuildPaletteOrder: 100 + Prerequisites: gactwr.socket, garadr, ~structures.gdi, ~techlevel.medium Description: GDI Anti-Air base defense.\nDoes not require power to operate.\n Strong vs Aircraft\n Weak vs Ground units Plug: Type: tower.sam Power: Amount: -30 - -GAPOWRUP: - Inherits: ^BuildingPlug - Valued: - Cost: 150 - Tooltip: - Name: Power Turbine - Buildable: - Queue: Defense - BuildPaletteOrder: 80 - Prerequisites: gapowr, ~structures.gdi, ~techlevel.medium - Description: Provides extra power generation. - Plug: - Type: powrup - Power: - Amount: 50 - -GAPLUG2: - Inherits: ^BuildingPlug - Valued: - Cost: 1000 - Tooltip: - Name: Seeker Control - Buildable: - Queue: Defense - BuildPaletteOrder: 170 - Prerequisites: gaplug, gatech, gaweap, ~structures.gdi, ~techlevel.superweapons - Description: Enables use of the hunter-seeker droid. - Plug: - Type: plug.hunterseeker - Power: - Amount: -50 - -GAPLUG3: - Inherits: ^BuildingPlug - Valued: - Cost: 1500 - Tooltip: - Name: Ion Cannon Uplink - Buildable: - Queue: Defense - BuildPaletteOrder: 180 - Prerequisites: gaplug, gatech, ~structures.gdi, ~techlevel.superweapons - Description: Enables use of the Ion Cannon. - Plug: - Type: plug.ioncannon - Power: - Amount: -100 diff -Nru openra-20200503/mods/ts/rules/gdi-vehicles.yaml openra-20210321/mods/ts/rules/gdi-vehicles.yaml --- openra-20200503/mods/ts/rules/gdi-vehicles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/gdi-vehicles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1,6 +1,7 @@ APC: Inherits: ^Tank Inherits@VOXELS: ^VoxelActor + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 800 Tooltip: @@ -13,7 +14,7 @@ Prerequisites: ~gaweap, gapile, ~techlevel.medium Description: Armored infantry transport.\nCan move on water.\n Unarmed Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 113 PauseOnCondition: empdisable || loading || being-captured || carried Locomotor: amphibious @@ -28,7 +29,6 @@ Cargo: Types: Infantry MaxWeight: 5 - PipCount: 5 UnloadVoice: Unload LoadingCondition: loading EjectOnDeath: true @@ -81,7 +81,7 @@ Weapon: HoverMissile LocalOffset: 0,242,543, 0,-242,543 Turreted: - TurnSpeed: 7 + TurnSpeed: 28 Offset: -128,0,85 AttackTurreted: Voice: Attack @@ -120,8 +120,9 @@ Prerequisites: ~gaweap, ~techlevel.low Description: Anti-personnel walker.\n Strong vs Infantry, Light armor\n Weak vs Vehicles, Aircraft Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 99 + AlwaysTurnInPlace: true Health: HP: 17500 Armor: @@ -167,8 +168,9 @@ Prerequisites: ~gaweap, ~techlevel.medium Description: General purpose mechanized walker.\n Strong vs Vehicles\n Weak vs Infantry, Aircraft Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 56 + AlwaysTurnInPlace: true Health: HP: 40000 Armor: @@ -186,7 +188,7 @@ MoveSequence: walk ValidMovementTypes: Horizontal, Turn Turreted: - TurnSpeed: 5 + TurnSpeed: 20 AttackTurreted: Voice: Attack PauseOnCondition: empdisable @@ -230,11 +232,11 @@ BuildLimit: 1 Description: Slow heavy walker.\nArmed with dual railguns and rocket launchers.\n Strong vs Infantry, Vehicles, Aircraft and Buildings\n Weak vs Nothing\nMaximum 1 can be built. Mobile: - TurnSpeed: 3 + TurnSpeed: 12 Speed: 42 Health: HP: 80000 - SelfHealing: + ChangesHealth: Step: 500 Armor: Type: Heavy @@ -278,7 +280,7 @@ Targetable: TargetTypes: Ground, Vehicle, Disruptor Mobile: - TurnSpeed: 4 + TurnSpeed: 16 Speed: 56 Health: HP: 50000 @@ -296,7 +298,7 @@ PauseOnCondition: empdisable OpportunityFire: False Turreted: - TurnSpeed: 5 + TurnSpeed: 20 Offset: -170,0,0 WithVoxelTurret: Explodes: @@ -331,7 +333,8 @@ Type: Light Mobile: Speed: 71 - TurnSpeed: 5 + TurnSpeed: 20 + AlwaysTurnInPlace: true ImmovableCondition: !undeployed RequireForceMoveCondition: !undeployed RevealsShroud: @@ -346,7 +349,7 @@ BodyNames: body, deployedbody WithFacingSpriteBody: Sequence: stand - RequiresCondition: undeployed + RequiresCondition: !deployed WithMoveAnimation: MoveSequence: walk ValidMovementTypes: Horizontal, Turn @@ -356,7 +359,7 @@ UndeployedCondition: undeployed UndeployOnMove: true UndeployOnPickup: true - Facing: 96 + Facing: 384 AllowedTerrainTypes: Clear, Road, DirtRoad, Rough DeploySounds: place2.aud UndeploySounds: clicky1.aud @@ -372,12 +375,12 @@ QuantizeFacingsFromSequence: Sequence: turret WithSpriteBody@deployed: - RequiresCondition: !undeployed && real-actor + RequiresCondition: deployed && real-actor Name: deployedbody Turreted: Turret: deployed - TurnSpeed: 5 - InitialFacing: 96 + TurnSpeed: 20 + InitialFacing: 384 Offset: -153,-17,633 RealignDelay: -1 WithVoxelBarrel: @@ -409,6 +412,5 @@ WithMuzzleOverlay: RevealOnFire: ArmamentNames: deployed - SelectionDecorations: Selectable: DecorationBounds: 48,40,0,-8 diff -Nru openra-20200503/mods/ts/rules/husks.yaml openra-20210321/mods/ts/rules/husks.yaml --- openra-20200503/mods/ts/rules/husks.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/husks.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -3,7 +3,7 @@ Tooltip: Name: Dropship Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 168 -RenderSprites: RenderVoxels: @@ -14,7 +14,7 @@ Tooltip: Name: Orca Fighter Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 186 RenderSprites: Image: orca @@ -30,10 +30,10 @@ Tooltip: Name: Orca Bomber Aircraft: - TurnSpeed: 3 + TurnSpeed: 12 Speed: 96 FallsToEarth: - MaximumSpinSpeed: 6 + MaximumSpinSpeed: 24 RenderSprites: Image: orcab RenderVoxels: @@ -48,7 +48,7 @@ Tooltip: Name: Orca Transport Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 84 RenderSprites: Image: orcatran @@ -64,7 +64,7 @@ Tooltip: Name: Carryall Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 149 RenderSprites: Image: trnsport @@ -80,10 +80,10 @@ Tooltip: Name: Banshee Fighter Aircraft: - TurnSpeed: 3 + TurnSpeed: 12 Speed: 168 FallsToEarth: - MaximumSpinSpeed: 6 + MaximumSpinSpeed: 24 RenderSprites: Image: scrin RenderVoxels: @@ -98,7 +98,7 @@ Tooltip: Name: Harpy Aircraft: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 130 WithIdleOverlay: Offset: 85,0,598 diff -Nru openra-20200503/mods/ts/rules/misc.yaml openra-20210321/mods/ts/rules/misc.yaml --- openra-20200503/mods/ts/rules/misc.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/misc.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -31,9 +31,9 @@ mmch.colorpicker: Inherits: MMCH Mobile: - InitialFacing: 160 + InitialFacing: 640 Turreted: - InitialFacing: 160 + InitialFacing: 640 WithFacingSpriteBody: Sequence: walk -Buildable: @@ -77,7 +77,7 @@ HideMapCrateAction: SelectionShares: 5 Sequence: hide-map - HealUnitsCrateAction: + HealActorsCrateAction: SelectionShares: 2 Sequence: heal RevealMapCrateAction: diff -Nru openra-20200503/mods/ts/rules/nod-infantry.yaml openra-20210321/mods/ts/rules/nod-infantry.yaml --- openra-20200503/mods/ts/rules/nod-infantry.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/nod-infantry.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -68,7 +68,6 @@ Weapon: Vulcan3 AttackFrontal: Voice: Attack - SelectionDecorations: ProducibleWithLevel: Prerequisites: barracks.upgraded @@ -108,7 +107,6 @@ LocalOffset: 240,120,966 AttackFrontal: Voice: Attack - SelectionDecorations: ProducibleWithLevel: Prerequisites: barracks.upgraded diff -Nru openra-20200503/mods/ts/rules/nod-structures.yaml openra-20210321/mods/ts/rules/nod-structures.yaml --- openra-20200503/mods/ts/rules/nod-structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/nod-structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -3,7 +3,7 @@ Inherits@SHAPE: ^2x2Shape Buildable: Queue: Building - BuildPaletteOrder: 20 + BuildPaletteOrder: 10 Prerequisites: ~structures.nod, ~techlevel.low Description: Provides power for other structures. Valued: @@ -15,9 +15,6 @@ Building: Footprint: xx xx Dimensions: 2,2 - Selectable: - Bounds: 88, 48, 2, -6 - DecorationBounds: 88, 80, 2, -12 Health: HP: 75000 Armor: @@ -35,14 +32,15 @@ TargetTypes: Ground, Building, C4, SpyInfiltrate ScalePowerWithHealth: PowerTooltip: - SelectionDecorations: + IsometricSelectable: + Height: 48 NAAPWR: Inherits: ^Building Inherits@SHAPE: ^2x3Shape Buildable: Queue: Building - BuildPaletteOrder: 120 + BuildPaletteOrder: 70 Prerequisites: factory, ~structures.nod, ~techlevel.medium Description: Provides twice as much power as\nthe normal Power Plant. Valued: @@ -54,9 +52,6 @@ Building: Footprint: xxx xxx Dimensions: 2,3 - Selectable: - Bounds: 100, 54, 0, -4 - DecorationBounds: 100, 74, 0, -12 Health: HP: 75000 Armor: @@ -74,15 +69,17 @@ TargetTypes: Ground, Building, C4, SpyInfiltrate ScalePowerWithHealth: PowerTooltip: - SelectionDecorations: ProvidesPrerequisite@buildingname: + IsometricSelectable: + Height: 48 NAHAND: Inherits: ^Building Inherits@SHAPE: ^3x2Shape + Inherits@PRIMARY: ^PrimaryBuilding Buildable: Queue: Building - BuildPaletteOrder: 40 + BuildPaletteOrder: 20 Prerequisites: anypower, ~structures.nod, ~techlevel.low Description: Produces infantry. Valued: @@ -94,9 +91,6 @@ Building: Footprint: xxx xxx Dimensions: 3,2 - Selectable: - Bounds: 116, 60, 3, -6 - DecorationBounds: 116, 78, 3, -8 Health: HP: 80000 Armor: @@ -156,9 +150,6 @@ Production: Produces: Infantry PauseOnCondition: empdisable - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Infantry WithIdleOverlay@LIGHTS: @@ -170,18 +161,11 @@ Power: Amount: -20 ProvidesPrerequisite@buildingname: - SelectionDecorations: - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - Color: E0D048 - ZOffset: 256 - RequiresCondition: primary NAWEAP: Inherits: ^Building Inherits@SHAPE: ^4x3FactoryWithBibShape + Inherits@PRIMARY: ^PrimaryBuilding Valued: Cost: 2000 Tooltip: @@ -190,15 +174,12 @@ Prerequisite: factory Buildable: Queue: Building - BuildPaletteOrder: 70 + BuildPaletteOrder: 50 Prerequisites: proc, ~structures.nod, ~techlevel.low Description: Produces vehicles. Building: Footprint: xxX+ xxX+ xxX+ Dimensions: 4,3 - Selectable: - Bounds: 149, 80, -3, -10 - DecorationBounds: 149, 116, -3, -20 Health: HP: 100000 Armor: @@ -218,9 +199,6 @@ Production: Produces: Vehicle PauseOnCondition: empdisable - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected ProductionBar: ProductionType: Vehicle WithIdleOverlay@ROOF: @@ -237,24 +215,19 @@ Power: Amount: -30 ProvidesPrerequisite@buildingname: - SelectionDecorations: - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - Color: E0D048 - ZOffset: 256 - RequiresCondition: primary + IsometricSelectable: + Height: 48 NAHPAD: Inherits: ^Building Inherits@SHAPE: ^2x2Shape + Inherits@PRIMARY: ^PrimaryBuilding Valued: Cost: 500 Tooltip: Name: Helipad Buildable: - BuildPaletteOrder: 140 + BuildPaletteOrder: 80 Queue: Building Prerequisites: naradr, ~structures.nod, ~techlevel.medium Description: Produces, rearms and\nrepairs helicopters. @@ -268,6 +241,7 @@ MaxHeightDelta: 3 Exit@1: SpawnOffset: 0,-256,0 + Facing: 896 ExitsDebugOverlay: RallyPoint: Palette: mouse @@ -276,9 +250,6 @@ Production: Produces: Air PauseOnCondition: empdisable - PrimaryBuilding: - PrimaryCondition: primary - SelectionNotification: PrimaryBuildingSelected Reservable: RepairsUnits: HpPerStep: 1000 @@ -298,18 +269,9 @@ UseDeathTypeSuffix: false Power: Amount: -10 - Selectable: - Bounds: 78, 48, 0, -6 - DecorationBounds: 78, 54, 0, -8 ProvidesPrerequisite@buildingname: - SelectionDecorations: - WithTextDecoration@primary: - RequiresSelection: true - Text: PRIMARY - ReferencePoint: Top - Color: E0D048 - ZOffset: 256 - RequiresCondition: primary + IsometricSelectable: + Height: 36 NARADR: Inherits: ^Building @@ -317,7 +279,7 @@ Inherits@SHAPE: ^2x2Shape Buildable: Queue: Building - BuildPaletteOrder: 90 + BuildPaletteOrder: 40 Prerequisites: proc, ~structures.nod, ~techlevel.low Description: Provides an overview of the battlefield.\nCan detect cloaked units.\nRequires power to operate. Valued: @@ -329,9 +291,6 @@ Building: Footprint: xx xx Dimensions: 2,2 - Selectable: - Bounds: 96, 48, 0, -6 - DecorationBounds: 96, 72, 0, -12 Health: HP: 100000 Armor: @@ -354,7 +313,8 @@ Power: Amount: -40 ProvidesPrerequisite@buildingname: - SelectionDecorations: + IsometricSelectable: + Height: 72 NATECH: Inherits: ^Building @@ -362,7 +322,7 @@ Inherits@SHAPE: ^2x2Shape Buildable: Queue: Building - BuildPaletteOrder: 160 + BuildPaletteOrder: 90 Prerequisites: naweap, naradr, ~structures.nod, ~techlevel.medium Description: Provides access to advanced Nod technologies. Valued: @@ -374,9 +334,6 @@ Building: Footprint: xx xx Dimensions: 2,2 - Selectable: - Bounds: 86, 48, 0, -4 - DecorationBounds: 86, 58, 0, -4 Health: HP: 50000 Armor: @@ -390,7 +347,47 @@ Power: Amount: -150 ProvidesPrerequisite@buildingname: - SelectionDecorations: + +NASTLH: + Inherits: ^Building + Inherits@IDISABLED: ^DisableOnLowPowerOrPowerDown + Inherits@SHAPE: ^3x2Shape + HitShape: + TargetableOffsets: 250,0,0, 600,-864,0 + Valued: + Cost: 2500 + Tooltip: + Name: Stealth Generator + Buildable: + Queue: Building + BuildPaletteOrder: 100 + Prerequisites: proc, natech, ~structures.nod, ~techlevel.high + Description: Generates a cloaking field\nto hide your forces from the enemy. + Building: + Footprint: xxx XXX + Dimensions: 3,2 + Health: + HP: 60000 + Armor: + Type: Wood + RevealsShroud: + Range: 6c0 + MaxHeightDelta: 3 + WithIdleOverlay@pulse: + RequiresCondition: !build-incomplete && !empdisable && !disabled + Sequence: pulse + WithRangeCircle: + Range: 12c0 + Type: cloakgenerator + Power: + Amount: -350 + ProximityExternalCondition: + RequiresCondition: !empdisable && !disabled + Condition: cloakgenerator + Range: 12c0 + EnableSound: cloak5.aud + DisableSound: cloak5.aud + AffectsParent: true NATMPL: Inherits: ^Building @@ -400,7 +397,7 @@ TargetableOffsets: -1280,363,0 Buildable: Queue: Building - BuildPaletteOrder: 180 + BuildPaletteOrder: 110 Prerequisites: natech, ~structures.nod, ~techlevel.high Description: Provides access to advanced Nod technologies. ProvidesPrerequisite@buildingname: @@ -413,8 +410,6 @@ Dimensions: 4,3 RequiresBuildableArea: Adjacent: 3 - Selectable: - Bounds: 134, 120, 12, -12 Health: HP: 100000 Armor: @@ -441,3 +436,119 @@ PauseOnCondition: empdisable Exit@1: ExitsDebugOverlay: + IsometricSelectable: + Height: 60 + +NAMISL: + Inherits: ^Building + Inherits@IDISABLE: ^DisableOnLowPowerOrPowerDown + Inherits@SHAPE: ^2x2Shape + Buildable: + Queue: Building + BuildPaletteOrder: 120 + Prerequisites: natech, ~structures.nod, ~techlevel.superweapons + BuildLimit: 1 + Description: Launches a devastating missile\nat a target location.\nRequires power to operate.\nMaximum 1 can be built. + Valued: + Cost: 1300 + Tooltip: + Name: Nod Missile Silo + ProvidesPrerequisite: + Prerequisite: tech + Building: + Footprint: xx xx + Dimensions: 2,2 + Health: + HP: 100000 + Armor: + Type: Wood + RevealsShroud: + Range: 4c0 + WithIdleOverlay@LIGHTS: + RequiresCondition: !build-incomplete && !disabled + Sequence: idle-lights + Power: + Amount: -50 + ProvidesPrerequisite@buildingname: + SupportPowerChargeBar: + NukePower: + PauseOnCondition: empdisable || disabled + Cursor: nuke + Icon: clustermissile + ChargeInterval: 13500 + Description: Cluster Missile + LongDesc: Launches an explosive cluster warhead\nat a target location. + EndChargeSpeechNotification: ClusterMissileReady + SelectTargetSpeechNotification: SelectTarget + IncomingSpeechNotification: MissileLaunchDetected + LaunchSound: icbm1.aud + MissileWeapon: ClusterMissile + MissileDelay: 10 + DetonationAltitude: 5c0 + SpawnOffset: 72,72,0 + DisplayTimerRelationships: None + DisplayBeacon: False + DisplayRadarPing: True + BeaconPoster: + CameraRange: 10c0 + FlightVelocity: 1c0 + TrailImage: small_smoke_trail + TrailPalette: effectalpha75 + TrailInterval: 0 + TrailSequences: idle + WithSupportPowerActivationOverlay: + +NAWAST: + Inherits: ^Building + HitShape: + Type: Rectangle + TopLeft: -1536, -1536 + BottomRight: 512, 1536 + Valued: + Cost: 1600 + Tooltip: + Name: Waste Refinery + Buildable: + Queue: Buildig + BuildPaletteOrder: 130 + Prerequisites: namisl, ~structures.nod, ~techlevel.superweapons + BuildLimit: 1 + Description: Processes Veins\ninto useable resources.\nMaximum 1 can be built. + Building: + Footprint: Xx+ xx+ Xx+ + Dimensions: 3,3 + Health: + HP: 40000 + RevealsShroud: + Range: 6c0 + MaxHeightDelta: 3 + TiberianSunRefinery: + DockAngle: 640 + DockOffset: 2,1 + StoresResources: + Capacity: 56 + Power: + Amount: -40 + FreeActor: + Actor: WEED + SpawnOffset: 3,1 + Facing: 640 + WithIdleOverlay@GLOW: + RequiresCondition: !build-incomplete + Sequence: idle-glow + WithIdleOverlay@LIGHTS: + RequiresCondition: !build-incomplete + Sequence: idle-lights + WithIdleOverlay@BIB: + RequiresCondition: !build-incomplete + Sequence: bib + ProvidesPrerequisite@buildingname: + WithResourceStoragePipsDecoration: + Position: BottomLeft + RequiresSelection: true + Margin: 8, 2 + FullSequence: pip-red-building + EmptySequence: pip-empty-building + PipStride: 4, 2 + PipCount: 15 + Palette: pips diff -Nru openra-20200503/mods/ts/rules/nod-support.yaml openra-20210321/mods/ts/rules/nod-support.yaml --- openra-20200503/mods/ts/rules/nod-support.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/nod-support.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -63,8 +63,6 @@ NodeTypes: laserfencenode SegmentType: nafnce SegmentsRequireNode: true - Selectable: - Bounds: 42, 44, 0, -12 LineBuildNode: Types: laserfencenode Power: @@ -156,9 +154,6 @@ Prerequisites: nahand, ~structures.nod, ~techlevel.low BuildPaletteOrder: 90 Description: Basic base defense.\nRequires power to operate.\n Strong vs Ground units\n Weak vs Aircraft - Selectable: - Bounds: 40, 30, -8, -6 - DecorationBounds: 40, 36, -8, -8 Health: HP: 50000 Armor: @@ -168,9 +163,10 @@ DetectCloaked: Range: 3c0 Turreted: - TurnSpeed: 10 - InitialFacing: 224 + TurnSpeed: 40 + InitialFacing: 896 Offset: 298,-171,288 + RealignDelay: -1 AttackTurreted: RequiresCondition: !build-incomplete PauseOnCondition: empdisable || disabled @@ -182,7 +178,6 @@ RequiresCondition: !build-incomplete Power: Amount: -40 - SelectionDecorations: BodyOrientation: QuantizedFacings: 0 @@ -203,9 +198,6 @@ Building: Footprint: xx xx Dimensions: 2,2 - Selectable: - Bounds: 88, 42, 0, -6 - DecorationBounds: 88, 72, 0, -12 Health: HP: 72500 Armor: @@ -233,7 +225,6 @@ Sequence: idle-lights Power: Amount: -150 - SelectionDecorations: NASAM: Inherits: ^Defense @@ -248,9 +239,6 @@ Prerequisites: naradr, ~structures.nod, ~techlevel.medium BuildPaletteOrder: 100 Description: Nod Anti-Air base defense.\nRequires power to operate.\n Strong vs Aircraft\n Weak vs Ground units - Selectable: - Bounds: 40, 30, -3, -8 - DecorationBounds: 40, 36, -3, -8 Health: HP: 60000 Armor: @@ -260,8 +248,9 @@ RenderRangeCircle: RangeCircleType: aa Turreted: - TurnSpeed: 10 - InitialFacing: 224 + TurnSpeed: 40 + InitialFacing: 896 + RealignDelay: -1 AttackTurreted: RequiresCondition: !build-incomplete PauseOnCondition: empdisable || disabled @@ -273,164 +262,3 @@ LocalOffset: 543,0,815 Power: Amount: -30 - SelectionDecorations: - -NASTLH: - Inherits: ^Building - Inherits@IDISABLED: ^DisableOnLowPowerOrPowerDown - Inherits@SHAPE: ^3x2Shape - HitShape: - TargetableOffsets: 250,0,0, 600,-864,0 - Valued: - Cost: 2500 - Tooltip: - Name: Stealth Generator - Buildable: - Queue: Defense - BuildPaletteOrder: 170 - Prerequisites: proc, natech, ~structures.nod, ~techlevel.high - Description: Generates a cloaking field\nto hide your forces from the enemy. - Building: - Footprint: xxx XXX - Dimensions: 3,2 - Health: - HP: 60000 - Armor: - Type: Wood - RevealsShroud: - Range: 6c0 - MaxHeightDelta: 3 - WithIdleOverlay@pulse: - RequiresCondition: !build-incomplete && !empdisable && !disabled - Sequence: pulse - WithRangeCircle: - Range: 12c0 - Type: cloakgenerator - Power: - Amount: -350 - ProximityExternalCondition: - RequiresCondition: !empdisable && !disabled - Condition: cloakgenerator - Range: 12c0 - EnableSound: cloak5.aud - DisableSound: cloak5.aud - AffectsParent: true - Selectable: - Bounds: 106, 48, 8, -6 - DecorationBounds: 106, 60, 8, -15 - SelectionDecorations: - -NAMISL: - Inherits: ^Building - Inherits@IDISABLE: ^DisableOnLowPowerOrPowerDown - Inherits@SHAPE: ^2x2Shape - Buildable: - Queue: Defense - BuildPaletteOrder: 180 - Prerequisites: natech, ~structures.nod, ~techlevel.superweapons - BuildLimit: 1 - Description: Launches a devastating missile\nat a target location.\nRequires power to operate.\nMaximum 1 can be built. - Valued: - Cost: 1300 - Tooltip: - Name: Nod Missile Silo - ProvidesPrerequisite: - Prerequisite: tech - Building: - Footprint: xx xx - Dimensions: 2,2 - Selectable: - Bounds: 75,48 - DecorationBounds: 75,48 - Health: - HP: 100000 - Armor: - Type: Wood - RevealsShroud: - Range: 4c0 - WithIdleOverlay@LIGHTS: - RequiresCondition: !build-incomplete && !disabled - Sequence: idle-lights - Power: - Amount: -50 - ProvidesPrerequisite@buildingname: - SupportPowerChargeBar: - NukePower: - PauseOnCondition: empdisable || disabled - Cursor: nuke - Icon: clustermissile - ChargeInterval: 13500 - Description: Cluster Missile - LongDesc: Launches an explosive cluster warhead\nat a target location. - EndChargeSpeechNotification: ClusterMissileReady - SelectTargetSpeechNotification: SelectTarget - IncomingSpeechNotification: MissileLaunchDetected - LaunchSound: icbm1.aud - MissileWeapon: ClusterMissile - MissileDelay: 10 - DetonationAltitude: 5c0 - SpawnOffset: 72,72,0 - DisplayTimerStances: None - DisplayBeacon: False - DisplayRadarPing: True - BeaconPoster: - CameraRange: 10c0 - FlightVelocity: 1c0 - TrailImage: small_smoke_trail - TrailPalette: effectalpha75 - TrailInterval: 0 - TrailSequences: idle - WithNukeLaunchOverlay: - SelectionDecorations: - -NAWAST: - Inherits: ^Building - HitShape: - Type: Rectangle - TopLeft: -1536, -1536 - BottomRight: 512, 1536 - Valued: - Cost: 1600 - Tooltip: - Name: Waste Refinery - Buildable: - Queue: Defense - BuildPaletteOrder: 190 - Prerequisites: namisl, ~structures.nod, ~techlevel.superweapons - BuildLimit: 1 - Description: Processes Veins\ninto useable resources.\nMaximum 1 can be built. - Building: - Footprint: Xx= xx= Xx= - Dimensions: 3,3 - Selectable: - Bounds: 100, 60, 5, -5 - DecorationBounds: 100, 60, 5, -5 - Health: - HP: 40000 - RevealsShroud: - Range: 6c0 - MaxHeightDelta: 3 - TiberianSunRefinery: - DockAngle: 160 - DockOffset: 2,1 - StoresResources: - PipColor: Red - PipCount: 15 - Capacity: 56 - Power: - Amount: -40 - FreeActor: - Actor: WEED - SpawnOffset: 3,1 - Facing: 160 - WithIdleOverlay@GLOW: - RequiresCondition: !build-incomplete - Sequence: idle-glow - WithIdleOverlay@LIGHTS: - RequiresCondition: !build-incomplete - Sequence: idle-lights - WithIdleOverlay@BIB: - RequiresCondition: !build-incomplete - Sequence: bib - ProvidesPrerequisite@buildingname: - SelectionDecorations: diff -Nru openra-20200503/mods/ts/rules/nod-vehicles.yaml openra-20210321/mods/ts/rules/nod-vehicles.yaml --- openra-20200503/mods/ts/rules/nod-vehicles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/nod-vehicles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ Prerequisites: ~naweap, ~techlevel.low Description: Fast scout and anti-infantry vehicle.\n Strong vs Infantry, Light armor\n Weak vs Vehicles, Aircraft Mobile: - TurnSpeed: 8 + TurnSpeed: 32 Speed: 142 Health: HP: 22000 @@ -30,7 +30,6 @@ LocalOffset: 0,-61,543, 0,61,543 MuzzleSequence: muzzle MuzzlePalette: effect-ignore-lighting - MuzzleSplitFacings: 8 AttackFrontal: Voice: Attack PauseOnCondition: empdisable @@ -55,7 +54,7 @@ Prerequisites: ~naweap, ~techlevel.low Description: Fast scout vehicle, armed with\nrockets.\n Strong vs Vehicles\n Weak vs Infantry, Aircraft Mobile: - TurnSpeed: 8 + TurnSpeed: 32 Speed: 170 Health: HP: 15000 @@ -102,7 +101,7 @@ Prerequisites: ~naweap, ~techlevel.medium Description: Nod's main battle tank.\nCan deploy to gain extra protection.\n Strong vs Vehicles\n Weak vs Infantry, Aircraft Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 85 ImmovableCondition: !undeployed RequireForceMoveCondition: !undeployed @@ -137,7 +136,7 @@ UndeployedCondition: undeployed UndeployOnMove: true UndeployOnPickup: true - Facing: 160 + Facing: 640 AllowedTerrainTypes: Clear, Road, DirtRoad, Rough DeploySounds: place2.aud UndeploySounds: clicky1.aud @@ -159,9 +158,9 @@ RequiresCondition: undeployed PauseOnCondition: empdisable Turreted: - TurnSpeed: 6 + TurnSpeed: 24 Turret: deployed - InitialFacing: 160 + InitialFacing: 640 Offset: -20, -130, 128 RealignDelay: -1 WithVoxelBarrel: @@ -232,7 +231,7 @@ Type: Light Mobile: Speed: 71 - TurnSpeed: 2 + TurnSpeed: 8 ImmovableCondition: !undeployed RequireForceMoveCondition: !undeployed RevealsShroud: @@ -250,7 +249,7 @@ UndeployedCondition: undeployed UndeployOnMove: true UndeployOnPickup: true - Facing: 96 + Facing: 384 AllowedTerrainTypes: Clear, Road, DirtRoad, Rough DeploySounds: place2.aud UndeploySounds: clicky1.aud @@ -269,8 +268,8 @@ RequiresCondition: !undeployed && real-actor Turreted: Turret: deployed - TurnSpeed: 5 - InitialFacing: 96 + TurnSpeed: 20 + InitialFacing: 384 Offset: 0,0,256 RealignDelay: -1 WithVoxelBarrel: @@ -320,7 +319,7 @@ HP: 20000 Mobile: Speed: 85 - TurnSpeed: 5 + TurnSpeed: 20 RevealsShroud: RequiresCondition: !inside-tunnel Range: 5c0 @@ -329,8 +328,8 @@ Weapon: Repair Cursor: repair OutsideRangeCursor: repair - TargetStances: Ally - ForceTargetStances: None + TargetRelationships: Ally + ForceTargetRelationships: None AttackFrontal: Voice: Attack PauseOnCondition: empdisable @@ -365,13 +364,13 @@ DeliverVoice: Move Mobile: Speed: 71 - TurnSpeed: 5 + TurnSpeed: 20 Health: HP: 60000 - SelfHealing: + ChangesHealth: Step: 500 Delay: 10 - HealIfBelow: 50 + StartIfBelow: 50 DamageCooldown: 200 Armor: Type: Heavy @@ -383,10 +382,18 @@ WithVoxelUnloadBody: -DamagedByTerrain@VEINS: -LeavesTrails@VEINS: + WithHarvesterPipsDecoration: + Position: BottomLeft + RequiresSelection: true + Margin: 5, 2 + FullSequence: pip-red + Palette: pips + PipCount: 7 SAPC: Inherits: ^Tank Inherits@VOXELS: ^VoxelActor + Inherits@CARGOPIPS: ^CargoPips Valued: Cost: 800 Tooltip: @@ -399,7 +406,7 @@ Prerequisites: ~naweap, natech, ~techlevel.medium Description: Troop transport that can move\nunderground to avoid detection.\n Unarmed Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 71 PauseOnCondition: empdisable || loading || being-captured || carried Locomotor: subterranean @@ -414,7 +421,6 @@ Cargo: Types: Infantry MaxWeight: 5 - PipCount: 5 UnloadVoice: Unload LoadingCondition: loading EjectOnDeath: true @@ -432,6 +438,8 @@ SubterraneanTransitionSound: subdril1.aud Carryable: RequiresCondition: !submerged + WithDecoration@UNDERGROUND: + RequiresCondition: inside-tunnel || submerged SUBTANK: Inherits: ^Tank @@ -450,7 +458,7 @@ Prerequisites: ~naweap, natech, ~techlevel.high Description: Subterranean Flame Tank.\nIs able to move underground.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft Mobile: - TurnSpeed: 6 + TurnSpeed: 24 Speed: 71 Locomotor: subterranean Health: @@ -480,6 +488,8 @@ SubterraneanTransitionSound: subdril1.aud Carryable: RequiresCondition: !submerged + WithDecoration@UNDERGROUND: + RequiresCondition: inside-tunnel || submerged STNK: Inherits: ^Tank @@ -498,7 +508,7 @@ Queue: Vehicle Description: Lightly armoured tank equipped with a personal\nstealth generator. Armed with missiles.\nCan be spotted by infantry at close range.\n Strong vs Vehicles, Aircraft\n Weak vs Infantry Mobile: - TurnSpeed: 5 + TurnSpeed: 20 Speed: 85 Health: HP: 18000 diff -Nru openra-20200503/mods/ts/rules/palettes.yaml openra-20210321/mods/ts/rules/palettes.yaml --- openra-20200503/mods/ts/rules/palettes.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/palettes.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -131,12 +131,12 @@ FixedColorPalette@GreenTiberium: Base: player Name: greentiberium - Color: 20CF08 + Color: 00FF00 RemapIndex: 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 FixedColorPalette@BlueTiberium: Base: player Name: bluetiberium - Color: 4040E8 + Color: 0024FF RemapIndex: 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 PlayerColorPalette: BasePalette: player diff -Nru openra-20200503/mods/ts/rules/player.yaml openra-20210321/mods/ts/rules/player.yaml --- openra-20200503/mods/ts/rules/player.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/player.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -122,6 +122,5 @@ Id: unrestricted ResourceStorageWarning: PlayerExperience: - ConditionManager: GameSaveViewportManager: PlayerRadarTerrain: diff -Nru openra-20200503/mods/ts/rules/shared-infantry.yaml openra-20210321/mods/ts/rules/shared-infantry.yaml --- openra-20200503/mods/ts/rules/shared-infantry.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/shared-infantry.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -38,6 +38,15 @@ RevealsShroud: Range: 5c0 +E1R3: + Inherits: E1 + RenderSprites: + Image: e1.gdi + ProducibleWithLevel: + Prerequisites: techlevel.low + InitialLevels: 3 + -Buildable: + ENGINEER: Inherits: ^Soldier Inherits@selection: ^SelectableSupportUnit @@ -59,7 +68,7 @@ Health: HP: 10000 Passenger: - PipType: Yellow + CustomPipType: yellow EngineerRepair: RepairsBridges: RepairNotification: BridgeRepaired @@ -84,9 +93,9 @@ IdleSequences: run Health: HP: 16000 - SelfHealing: + ChangesHealth: Step: -1000 - HealIfBelow: 101 + StartIfBelow: 101 ScaredyCat: PanicSequencePrefix: WithDeathAnimation: diff -Nru openra-20200503/mods/ts/rules/shared-structures.yaml openra-20210321/mods/ts/rules/shared-structures.yaml --- openra-20200503/mods/ts/rules/shared-structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/shared-structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -32,7 +32,7 @@ PauseOnCondition: empdisable || being-demolished || build-incomplete IntoActor: mcv Offset: 1,1 - Facing: 96 + Facing: 384 DeployCursor: undeploy TransformsIntoMobile: RequiresCondition: factundeploy @@ -75,16 +75,14 @@ RequiresCondition: !build-incomplete Power: Amount: 0 - Selectable: - Bounds: 144, 60, 0, -6 - DecorationBounds: 144, 80, 0, -12 ProvidesPrerequisite@gdi: Factions: gdi Prerequisite: structures.gdi ProvidesPrerequisite@nod: Factions: nod Prerequisite: structures.nod - SelectionDecorations: + IsometricSelectable: + Height: 36 PROC: Inherits: ^Building @@ -95,34 +93,29 @@ Name: Tiberium Refinery Buildable: Queue: Building - BuildPaletteOrder: 50 + BuildPaletteOrder: 30 Prerequisites: anypower, ~techlevel.low Description: Processes raw Tiberium\ninto useable resources. Building: Footprint: xxX+ xx++ xxX+ Dimensions: 4,3 - Selectable: - Bounds: 134, 96, 0, -12 - DecorationBounds: 134, 122, 0, -18 Health: HP: 90000 RevealsShroud: Range: 6c0 MaxHeightDelta: 3 TiberianSunRefinery: - DockAngle: 160 + DockAngle: 640 DockOffset: 2,1 DiscardExcessResources: true StoresResources: - PipColor: Green - PipCount: 10 Capacity: 2000 CustomSellValue: Value: 600 FreeActor: Actor: HARV SpawnOffset: 2,1 - Facing: 160 + Facing: 640 WithIdleOverlay@REDLIGHTS: RequiresCondition: !build-incomplete Sequence: idle-redlights @@ -138,7 +131,6 @@ Power: Amount: -30 ProvidesPrerequisite@buildingname: - SelectionDecorations: RenderSprites: Image: proc.gdi FactionImages: @@ -149,13 +141,22 @@ Explodes: RequiresCondition: contains-tiberium Weapon: TiberiumExplosion + WithResourceStoragePipsDecoration: + Position: BottomLeft + RequiresSelection: true + Margin: 8, 2 + FullSequence: pip-green-building + EmptySequence: pip-empty-building + PipStride: 4, 2 + PipCount: 25 + Palette: pips GASILO: Inherits: ^Building Inherits@SHAPE: ^2x2Shape Buildable: Queue: Building - BuildPaletteOrder: 100 + BuildPaletteOrder: 60 Prerequisites: proc, ~techlevel.low Description: Stores excess Tiberium. Valued: @@ -165,9 +166,6 @@ Building: Footprint: xx xx Dimensions: 2, 2 - Selectable: - Bounds: 80, 48, -5, 0 - DecorationBounds: 80, 48, -5, 0 -GivesBuildableArea: Health: HP: 30000 @@ -190,17 +188,23 @@ RequiresCondition: !build-incomplete Sequence: idle-lights StoresResources: - PipColor: Green - PipCount: 5 Capacity: 1500 Power: Amount: -10 - SelectionDecorations: GrantConditionOnPlayerResources: Condition: contains-tiberium Explodes: RequiresCondition: contains-tiberium Weapon: TiberiumExplosion + WithResourceStoragePipsDecoration: + Position: BottomLeft + RequiresSelection: true + Margin: 8, 2 + FullSequence: pip-green-building + EmptySequence: pip-empty-building + PipStride: 4, 2 + PipCount: 12 + Palette: pips ANYPOWER: AlwaysVisible: diff -Nru openra-20200503/mods/ts/rules/shared-support.yaml openra-20210321/mods/ts/rules/shared-support.yaml --- openra-20200503/mods/ts/rules/shared-support.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/shared-support.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -14,9 +14,6 @@ Building: Footprint: xx xx Dimensions: 2,2 - Selectable: - Bounds: 78, 54, 0, -12 - DecorationBounds: 78, 54, 0, -12 Health: HP: 50000 Armor: @@ -24,8 +21,9 @@ RevealsShroud: Range: 8c0 Turreted: - TurnSpeed: 10 - InitialFacing: 224 + TurnSpeed: 40 + InitialFacing: 896 + RealignDelay: -1 AttackTurreted: RequiresCondition: !build-incomplete && !empdisable && !disabled Armament: @@ -37,7 +35,6 @@ Sequence: turret Power: Amount: -150 - SelectionDecorations: RenderSprites: Image: napuls.gdi FactionImages: diff -Nru openra-20200503/mods/ts/rules/shared-vehicles.yaml openra-20210321/mods/ts/rules/shared-vehicles.yaml --- openra-20200503/mods/ts/rules/shared-vehicles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/shared-vehicles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -30,11 +30,10 @@ PauseOnCondition: empdisable || being-captured IntoActor: gacnst Offset: -1,-1 - Facing: 96 + Facing: 384 TransformSounds: place2.aud NoTransformSounds: Voice: Move - SelectionDecorations: RenderSprites: Image: mcv.gdi FactionImages: @@ -73,10 +72,10 @@ Speed: 71 Health: HP: 100000 - SelfHealing: + ChangesHealth: Step: 500 Delay: 10 - HealIfBelow: 50 + StartIfBelow: 50 DamageCooldown: 200 Armor: Type: Heavy @@ -92,7 +91,6 @@ WithHarvestOverlay: LocalOffset: 543,0,0 Palette: effect - SelectionDecorations: RenderSprites: Image: harv.gdi FactionImages: @@ -100,6 +98,17 @@ nod: harv.nod -DamagedByTerrain@VEINS: -LeavesTrails@VEINS: + WithHarvesterPipsDecoration: + Position: BottomLeft + RequiresSelection: true + Margin: 5, 2 + PipCount: 7 + Palette: pips + ResourceSequences: + Tiberium: pip-green + BlueTiberium: pip-blue + WithDecoration@UNDERGROUND: + Sequence: harvester LPST: Inherits: ^Tank @@ -125,7 +134,7 @@ Type: Wood Mobile: Speed: 85 - TurnSpeed: 5 + TurnSpeed: 20 ImmovableCondition: !undeployed RequireForceMoveCondition: !undeployed RevealsShroud: @@ -150,7 +159,7 @@ UndeployedCondition: undeployed UndeployOnMove: true UndeployOnPickup: true - Facing: 160 + Facing: 640 AllowedTerrainTypes: Clear, Road, DirtRoad, Rough DeploySounds: place2.aud UndeploySounds: clicky1.aud diff -Nru openra-20200503/mods/ts/rules/trees.yaml openra-20210321/mods/ts/rules/trees.yaml --- openra-20200503/mods/ts/rules/trees.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/trees.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -125,6 +125,8 @@ ^TibFlora: Inherits: ^Tree + MapEditorData: + RequireTilesets: TEMPERATE Tooltip: Name: Tiberian Flora diff -Nru openra-20200503/mods/ts/rules/world.yaml openra-20210321/mods/ts/rules/world.yaml --- openra-20200503/mods/ts/rules/world.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/rules/world.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -8,6 +8,7 @@ VictoryMusic: score DefeatMusic: maps TerrainRenderer: + TerrainLighting: ShroudRenderer: Index: 255, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 20, 40, 56, 65, 97, 130, 148, 194, 24, 33, 66, 132, 28, 41, 67, 134, 1, 2, 4, 8, 3, 6, 12, 9, 7, 14, 13, 11, 5, 10, 15, 255 UseExtendedIndex: true @@ -200,7 +201,6 @@ ResourceType@Tiberium: Type: Tiberium Name: Tiberium - PipColor: Green ResourceType: 1 Palette: greentiberium Sequences: tib01, tib02, tib03, tib04, tib05, tib06, tib07, tib08, tib09, tib10, tib11, tib12 @@ -212,7 +212,6 @@ ResourceType@BlueTiberium: Type: BlueTiberium Name: Tiberium - PipColor: Blue ResourceType: 2 Palette: bluetiberium Sequences: tib01, tib02, tib03, tib04, tib05, tib06, tib07, tib08, tib09, tib10, tib11, tib12 @@ -224,7 +223,6 @@ ResourceType@Veins: Type: Veins Name: Veins - PipColor: Red ResourceType: 3 Palette: player Sequences: veins @@ -239,6 +237,8 @@ CliffBackImpassabilityLayer: SubterraneanActorLayer: JumpjetActorLayer: + ResourceRenderer: + RenderTypes: Tiberium, BlueTiberium, Veins World: Inherits: ^BaseWorld @@ -254,33 +254,31 @@ SmudgeLayer@SMALLSCORCH: Type: SmallScorch Sequence: smallscorches - SmokeType: smallfire - SmokePercentage: 50 + SmokeImage: smallfire + SmokeSequences: idle + SmokeChance: 50 SmudgeLayer@MEDIUMSCORCH: Type: MediumScorch Sequence: mediumscorches - SmokeType: mediumfire - SmokePercentage: 75 + SmokeImage: mediumfire + SmokeSequences: idle + SmokeChance: 75 SmudgeLayer@LARGESCORCH: Type: LargeScorch Sequence: largescorches - SmokeType: largefire - SmokePercentage: 100 + SmokeImage: largefire + SmokeSequences: idle + SmokeChance: 100 SmudgeLayer@SMALLCRATER: Type: SmallCrater - SmokeType: smallsmoke Sequence: smallcraters SmudgeLayer@MEDIUMCRATER: Type: MediumCrater - SmokeType: smallsmoke Sequence: mediumcraters SmudgeLayer@LARGECRATER: Type: LargeCrater - SmokeType: largesmoke Sequence: largecraters ResourceLayer: - ResourceRenderer: - RenderTypes: Tiberium, BlueTiberium, Veins BridgeLayer: CustomTerrainDebugOverlay: ResourceClaimLayer: diff -Nru openra-20200503/mods/ts/sequences/aircraft.yaml openra-20210321/mods/ts/sequences/aircraft.yaml --- openra-20200503/mods/ts/sequences/aircraft.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/sequences/aircraft.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -17,16 +17,24 @@ apache: Inherits: ^VehicleOverlays icon: apchicon - rotor: lrotor - Length: 4 + rotor: harpyrotor + Start: 32 + Length: 31 Offset: 0, 0, 16 ZRamp: 1 - slow-rotor: lrotor - Start: 4 - Length: 8 + Tick: 25 + slow-rotor: harpyrotor + Length: 31 Offset: 0, 0, 16 ZRamp: 1 + Tick: 50 orcatran: Inherits: ^VehicleOverlays icon: crryicon + +pod: + Inherits: ^VehicleOverlays + idle: + Facings: 1 + Length: 1 diff -Nru openra-20200503/mods/ts/sequences/civilian.yaml openra-20210321/mods/ts/sequences/civilian.yaml --- openra-20200503/mods/ts/sequences/civilian.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/sequences/civilian.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -653,9 +653,11 @@ lighting: alphatst BlendMode: DoubleMultiplicative UseTilesetCode: false + IgnoreWorldTint: true -DepthSprite: - Offset: 0, 0, 0.5 + Offset: 0, 0, 240 ZRamp: 1 + ZOffset: 10240 emp-overlay: emp_fx01 Length: * Offset: 0, 0 diff -Nru openra-20200503/mods/ts/sequences/misc.yaml openra-20210321/mods/ts/sequences/misc.yaml --- openra-20200503/mods/ts/sequences/misc.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/sequences/misc.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -211,6 +211,18 @@ small_grey_explosion: xgrysml2 medium_grey_explosion: xgrymed1 large_grey_explosion: xgrymed2 + droppod_explosion: droppod + Length: 8 + Tick: 360 + droppod2_explosion: droppod2 + Length: 8 + Tick: 360 + droppody_explosion: droppody + Length: 8 + Tick: 360 + droppody2_explosion: droppody2 + Length: 8 + Tick: 360 discus: idle: @@ -323,6 +335,7 @@ ZOffset: -512 ZRamp: 1 Offset: 0, 0, 1 + BlendMode: Translucent resources: Defaults: @@ -331,6 +344,7 @@ ShadowStart: 12 Offset: 0, -12, 1.5 ZRamp: 1 + IgnoreWorldTint: true tib01: tib01 tib02: tib02 tib03: tib03 @@ -357,6 +371,7 @@ ShadowStart: -1 Tick: 180 Offset: 0, -12, 2.5 + IgnoreWorldTint: false veins: idle: veinatac @@ -439,6 +454,7 @@ ioncannon: ioncicon hunterseeker: detnicon emp: pulsicon + droppods: podsicon clustermissile: up: mltimisl-placeholder # TODO: use voxel @@ -643,3 +659,19 @@ Length: * ZOffset: 511 Offset: 0, 0, 24 + +typeglyphs: + infantry: + vehicle: + Start: 1 + helicopter: + Start: 2 + harvester: + Start: 3 + structure: + Start: 4 + +podring: + idle: + Frames: 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 + Length: * diff -Nru openra-20200503/mods/ts/sequences/structures.yaml openra-20210321/mods/ts/sequences/structures.yaml --- openra-20200503/mods/ts/sequences/structures.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/sequences/structures.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -1192,6 +1192,8 @@ Start: 2 ShadowStart: 5 Tick: 400 + invisible: null + UseTilesetCode: false idle-lights: gtctwr_a Length: 6 Tick: 200 @@ -1208,36 +1210,26 @@ UseTilesetCode: false turret-sam: gtctwr_d Facings: 32 - muzzle0: mgun-n - Length: * - Offset: 0, 0, 12 - UseTilesetCode: false - muzzle1: mgun-nw - Length: * - Offset: 0, 0, 12 - UseTilesetCode: false - muzzle2: mgun-w - Length: * - Offset: 0, 0, 12 - UseTilesetCode: false - muzzle3: mgun-sw - Length: * - Offset: 0, 0, 12 - UseTilesetCode: false - muzzle4: mgun-s - Length: * - Offset: 0, 0, 12 - UseTilesetCode: false - muzzle5: mgun-se - Length: * - Offset: 0, 0, 12 - UseTilesetCode: false - muzzle6: mgun-e - Length: * - Offset: 0, 0, 12 - UseTilesetCode: false - muzzle7: mgun-ne - Length: * + muzzle: + Combine: + mgun-n: + Length: 6 + mgun-nw: + Length: 6 + mgun-w: + Length: 6 + mgun-sw: + Length: 6 + mgun-s: + Length: 6 + mgun-se: + Length: 6 + mgun-e: + Length: 6 + mgun-ne: + Length: 6 + Facings: 8 + Length: 6 Offset: 0, 0, 12 UseTilesetCode: false emp-overlay: emp_fx01 @@ -1975,6 +1967,13 @@ Length: 15 Reverses: true Tick: 120 + idle-droppoda: gaplug_d + Length: 15 + Tick: 120 + Offset: -12, -42, 30 + idle-droppodb: gaplug_d + Length: 15 + Tick: 120 make: gtplugmk Length: 17 ShadowStart: 17 @@ -2007,3 +2006,12 @@ Length: 14 Tick: 120 icon: rad3icon + +gaplug4: + place: gtplug_d + Offset: 24,-48, 48 + UseTilesetCode: true + Reverses: true + Length: 14 + Tick: 120 + icon: rad1icon diff -Nru openra-20200503/mods/ts/sequences/trees.yaml openra-20210321/mods/ts/sequences/trees.yaml --- openra-20200503/mods/ts/sequences/trees.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/sequences/trees.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -123,50 +123,70 @@ tree25: Inherits: ^tree -fona01: +^fona: Inherits: ^tree + idle: + AddExtension: false + +fona01: + Inherits: ^fona + Defaults: fona01.tem fona02: - Inherits: ^tree + Inherits: ^fona + Defaults: fona02.tem fona03: - Inherits: ^tree + Inherits: ^fona + Defaults: fona03.tem fona04: - Inherits: ^tree + Inherits: ^fona + Defaults: fona04.tem fona05: - Inherits: ^tree + Inherits: ^fona + Defaults: fona05.tem fona06: - Inherits: ^tree + Inherits: ^fona + Defaults: fona06.tem fona07: - Inherits: ^tree + Inherits: ^fona + Defaults: fona07.tem fona08: - Inherits: ^tree + Inherits: ^fona + Defaults: fona08.tem fona09: - Inherits: ^tree + Inherits: ^fona + Defaults: fona09.tem fona10: - Inherits: ^tree + Inherits: ^fona + Defaults: fona10.tem fona11: - Inherits: ^tree + Inherits: ^fona + Defaults: fona11.tem fona12: - Inherits: ^tree + Inherits: ^fona + Defaults: fona12.tem fona13: - Inherits: ^tree + Inherits: ^fona + Defaults: fona13.tem fona14: - Inherits: ^tree + Inherits: ^fona + Defaults: fona14.tem fona15: - Inherits: ^tree + Inherits: ^fona + Defaults: fona15.tem veinhole: idle: diff -Nru openra-20200503/mods/ts/sequences/vehicles.yaml openra-20210321/mods/ts/sequences/vehicles.yaml --- openra-20200503/mods/ts/sequences/vehicles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/sequences/vehicles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -105,16 +105,27 @@ bggy: Inherits: ^VehicleOverlays Defaults: - Length: * Offset: 0, 0, 24 - muzzle0: mgun-n - muzzle1: mgun-nw - muzzle2: mgun-w - muzzle3: mgun-sw - muzzle4: mgun-s - muzzle5: mgun-se - muzzle6: mgun-e - muzzle7: mgun-ne + muzzle: + Combine: + mgun-n: + Length: 6 + mgun-nw: + Length: 6 + mgun-w: + Length: 6 + mgun-sw: + Length: 6 + mgun-s: + Length: 6 + mgun-se: + Length: 6 + mgun-e: + Length: 6 + mgun-ne: + Length: 6 + Facings: 8 + Length: 6 icon: bggyicon Offset: 0, 0 diff -Nru openra-20200503/mods/ts/sequences/voxels.yaml openra-20210321/mods/ts/sequences/voxels.yaml --- openra-20200503/mods/ts/sequences/voxels.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/sequences/voxels.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -49,7 +49,7 @@ stnk: idle: - + orca: idle: @@ -173,4 +173,4 @@ # idle: dpod: - idle: \ No newline at end of file + idle: diff -Nru openra-20200503/mods/ts/tilesets/snow.yaml openra-20210321/mods/ts/tilesets/snow.yaml --- openra-20200503/mods/ts/tilesets/snow.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/tilesets/snow.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -5,6 +5,8 @@ EditorTemplateOrder: Bendy Dirt Roads, Blank, Bridges, Civilian Buildings, Clear, Clear/Rough LAT, Cliff Pieces, Cliff Set, Cliff/Water pieces, Dead Oil Tanker, Destroyable Cliffs, Dirt Road Junctions, Dirt Road Slopes, DirtTrackTunnel Floor, DirtTunnel Floor, Grey/Clear LAT, House, Ice 01, Ice 02, Ice 03, Ice Flow, Ice Ramps, Ice shore, Misc Buildings, Monorail Slopes, Paved Road Ends, Paved Road Slopes, Paved Roads, Pavement, Pavement (Use for LAT), Pavement/Clear LAT, Ramp edge fixup, Rough ground, Rough lat, Ruins, Shore Pieces, Slope Set Pieces, Straight Dirt Roads, TrackTunnel Floor, TrainBridges, Tunnel Side, Tunnels, Water, Water slopes, Waterfalls, Waterfalls-B, Waterfalls-C, Waterfalls-D SheetSize: 2048 EnableDepth: true + MinHeightColorBrightness: 0.8 + MaxHeightColorBrightness: 1.0 Terrain: TerrainType@Clear: @@ -86,8 +88,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: C0DBF2 - RightColor: C2DDF3 + MinColor: C0DBF2 + MaxColor: C2DDF3 ZOffset: -12 ZRamp: 0 Template@1: @@ -97,8 +99,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 76818C - RightColor: 5F686E + MinColor: 76818C + MaxColor: 5F686E ZOffset: -12 ZRamp: 0 Template@2: @@ -108,23 +110,23 @@ Size: 2, 2 Tiles: 0: Rough - LeftColor: 7C8387 - RightColor: 778087 + MinColor: 7C8387 + MaxColor: 778087 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 6B7278 - RightColor: 7D8C99 + MinColor: 6B7278 + MaxColor: 7D8C99 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 95A4AF - RightColor: 707880 + MinColor: 95A4AF + MaxColor: 707880 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 8C9DAB - RightColor: 899BAA + MinColor: 8C9DAB + MaxColor: 899BAA ZOffset: -12 ZRamp: 0 Template@3: @@ -134,48 +136,48 @@ Size: 3, 3 Tiles: 0: Cliff - LeftColor: 627077 - RightColor: 6C787E + MinColor: 627077 + MaxColor: 6C787E ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 4E5558 - RightColor: 5B666E + MinColor: 4E5558 + MaxColor: 5B666E ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: B1C9E3 - RightColor: C0DBF2 + MinColor: B1C9E3 + MaxColor: C0DBF2 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 757D83 - RightColor: 747F85 + MinColor: 757D83 + MaxColor: 747F85 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6A7175 - RightColor: 545C66 + MinColor: 6A7175 + MaxColor: 545C66 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: B9D4F0 - RightColor: B8D3EF + MinColor: B9D4F0 + MaxColor: B8D3EF ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: BCD7F1 - RightColor: B7CEE3 + MinColor: BCD7F1 + MaxColor: B7CEE3 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: B7CCE1 - RightColor: A3B6CA + MinColor: B7CCE1 + MaxColor: A3B6CA ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: B8D0E9 - RightColor: B5CFEC + MinColor: B8D0E9 + MaxColor: B5CFEC ZOffset: -12 ZRamp: 0 Template@4: @@ -185,8 +187,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B9D5F0 - RightColor: B5D1EF + MinColor: B9D5F0 + MaxColor: B5D1EF ZOffset: -12 ZRamp: 0 Template@5: @@ -196,8 +198,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: BCD7F1 - RightColor: C0DBF2 + MinColor: BCD7F1 + MaxColor: C0DBF2 ZOffset: -12 ZRamp: 0 Template@6: @@ -207,8 +209,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: BBD6F1 - RightColor: BCD8F1 + MinColor: BBD6F1 + MaxColor: BCD8F1 ZOffset: -12 ZRamp: 0 Template@7: @@ -218,8 +220,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: C0DBF2 - RightColor: C2DDF3 + MinColor: C0DBF2 + MaxColor: C2DDF3 ZOffset: -12 ZRamp: 0 Template@8: @@ -229,8 +231,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: C0DBF2 - RightColor: C2DDF3 + MinColor: C0DBF2 + MaxColor: C2DDF3 ZOffset: -12 ZRamp: 0 Template@9: @@ -240,8 +242,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: C0DBF2 - RightColor: C2DDF3 + MinColor: C0DBF2 + MaxColor: C2DDF3 ZOffset: -12 ZRamp: 0 Template@10: @@ -251,183 +253,183 @@ Size: 9, 7 Tiles: 2: Rough - LeftColor: 7F858C - RightColor: 9DADBC + MinColor: 7F858C + MaxColor: 9DADBC ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 848B92 - RightColor: A8BCCC + MinColor: 848B92 + MaxColor: A8BCCC ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: 929CA7 - RightColor: 8B959E + MinColor: 929CA7 + MaxColor: 8B959E ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: ADBFCD - RightColor: 98A8B5 + MinColor: ADBFCD + MaxColor: 98A8B5 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 9CAAB6 - RightColor: A8B7C8 + MinColor: 9CAAB6 + MaxColor: A8B7C8 ZOffset: -12 ZRamp: 0 18: Rough - LeftColor: BCD2E5 - RightColor: B6CBDC + MinColor: BCD2E5 + MaxColor: B6CBDC ZOffset: -12 ZRamp: 0 19: Rough - LeftColor: 72787F - RightColor: 9CABB9 + MinColor: 72787F + MaxColor: 9CABB9 ZOffset: -12 ZRamp: 0 20: Rough - LeftColor: AABAC8 - RightColor: 929AA3 + MinColor: AABAC8 + MaxColor: 929AA3 ZOffset: -12 ZRamp: 0 21: Rough - LeftColor: 9FAEBD - RightColor: 818B96 + MinColor: 9FAEBD + MaxColor: 818B96 ZOffset: -12 ZRamp: 0 22: Rough - LeftColor: 9FACBA - RightColor: ABBCCC + MinColor: 9FACBA + MaxColor: ABBCCC ZOffset: -12 ZRamp: 0 23: Rough - LeftColor: A6B9C9 - RightColor: B9CEE2 + MinColor: A6B9C9 + MaxColor: B9CEE2 ZOffset: -12 ZRamp: 0 24: Rough - LeftColor: 949FA9 - RightColor: B4C8DB + MinColor: 949FA9 + MaxColor: B4C8DB ZOffset: -12 ZRamp: 0 25: Rough - LeftColor: 909CA7 - RightColor: B4CEEA + MinColor: 909CA7 + MaxColor: B4CEEA ZOffset: -12 ZRamp: 0 26: Rough - LeftColor: A0AEBD - RightColor: B7CDE2 + MinColor: A0AEBD + MaxColor: B7CDE2 ZOffset: -12 ZRamp: 0 28: Rough - LeftColor: B5C9DD - RightColor: 8D97A1 + MinColor: B5C9DD + MaxColor: 8D97A1 ZOffset: -12 ZRamp: 0 29: Rough - LeftColor: ABBCCB - RightColor: A2B0C0 + MinColor: ABBCCB + MaxColor: A2B0C0 ZOffset: -12 ZRamp: 0 30: Rough - LeftColor: 80878E - RightColor: 929BA3 + MinColor: 80878E + MaxColor: 929BA3 ZOffset: -12 ZRamp: 0 31: Rough - LeftColor: A7B6C2 - RightColor: A8B9C7 + MinColor: A7B6C2 + MaxColor: A8B9C7 ZOffset: -12 ZRamp: 0 32: Rough - LeftColor: B1C4D3 - RightColor: A9BACA + MinColor: B1C4D3 + MaxColor: A9BACA ZOffset: -12 ZRamp: 0 33: Rough - LeftColor: 9AA6B1 - RightColor: 9EA9B4 + MinColor: 9AA6B1 + MaxColor: 9EA9B4 ZOffset: -12 ZRamp: 0 34: Rough - LeftColor: A1B0BE - RightColor: 919BA6 + MinColor: A1B0BE + MaxColor: 919BA6 ZOffset: -12 ZRamp: 0 35: Rough - LeftColor: 98A2AE - RightColor: B0C3D4 + MinColor: 98A2AE + MaxColor: B0C3D4 ZOffset: -12 ZRamp: 0 38: Rough - LeftColor: 94A0AD - RightColor: 9FACB8 + MinColor: 94A0AD + MaxColor: 9FACB8 ZOffset: -12 ZRamp: 0 39: Rough - LeftColor: 9EADBD - RightColor: 98A3AE + MinColor: 9EADBD + MaxColor: 98A3AE ZOffset: -12 ZRamp: 0 40: Rough - LeftColor: 9BA6B2 - RightColor: A6B6C3 + MinColor: 9BA6B2 + MaxColor: A6B6C3 ZOffset: -12 ZRamp: 0 41: Rough - LeftColor: 9CAAB6 - RightColor: B5C6D4 + MinColor: 9CAAB6 + MaxColor: B5C6D4 ZOffset: -12 ZRamp: 0 42: Rough - LeftColor: B5CBDE - RightColor: BDD7EE + MinColor: B5CBDE + MaxColor: BDD7EE ZOffset: -12 ZRamp: 0 43: Rough - LeftColor: BBD3E9 - RightColor: B2C8DE + MinColor: BBD3E9 + MaxColor: B2C8DE ZOffset: -12 ZRamp: 0 44: Rough - LeftColor: 9FAEC0 - RightColor: AEC0D0 + MinColor: 9FAEC0 + MaxColor: AEC0D0 ZOffset: -12 ZRamp: 0 49: Rough - LeftColor: A9BACA - RightColor: A3B5C7 + MinColor: A9BACA + MaxColor: A3B5C7 ZOffset: -12 ZRamp: 0 50: Rough - LeftColor: B1C2D1 - RightColor: A2ADB8 + MinColor: B1C2D1 + MaxColor: A2ADB8 ZOffset: -12 ZRamp: 0 51: Rough - LeftColor: 98A3AF - RightColor: 9FADB8 + MinColor: 98A3AF + MaxColor: 9FADB8 ZOffset: -12 ZRamp: 0 52: Rough - LeftColor: A0ACB5 - RightColor: A4B2BE + MinColor: A0ACB5 + MaxColor: A4B2BE ZOffset: -12 ZRamp: 0 53: Rough - LeftColor: AABCCD - RightColor: 97A3AD + MinColor: AABCCD + MaxColor: 97A3AD ZOffset: -12 ZRamp: 0 60: Rough - LeftColor: B6CBDF - RightColor: 9BA7B2 + MinColor: B6CBDF + MaxColor: 9BA7B2 ZOffset: -12 ZRamp: 0 61: Rough - LeftColor: 9CACBE - RightColor: A1B0C0 + MinColor: 9CACBE + MaxColor: A1B0C0 ZOffset: -12 ZRamp: 0 Template@11: @@ -437,23 +439,23 @@ Size: 2, 2 Tiles: 0: Cliff - LeftColor: 8B8268 - RightColor: 726D61 + MinColor: 8B8268 + MaxColor: 726D61 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 9EA1A5 - RightColor: 7C7B7B + MinColor: 9EA1A5 + MaxColor: 7C7B7B ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: B6B9B6 - RightColor: 948F7A + MinColor: B6B9B6 + MaxColor: 948F7A ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B8BAB6 - RightColor: 9DA0A5 + MinColor: B8BAB6 + MaxColor: 9DA0A5 ZOffset: -12 ZRamp: 0 Template@12: @@ -463,8 +465,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 282828 - RightColor: 282828 + MinColor: 282828 + MaxColor: 282828 ZOffset: -12 ZRamp: 0 Template@40: @@ -475,8 +477,8 @@ Tiles: 0: Clear RampType: 1 - LeftColor: D2E5F0 - RightColor: CFE3EF + MinColor: D2E5F0 + MaxColor: CFE3EF ZOffset: -12 ZRamp: 0 Template@41: @@ -487,8 +489,8 @@ Tiles: 0: Clear RampType: 2 - LeftColor: A0B8DD - RightColor: 9EB9DC + MinColor: A0B8DD + MaxColor: 9EB9DC ZOffset: -12 ZRamp: 0 Template@42: @@ -499,8 +501,8 @@ Tiles: 0: Clear RampType: 3 - LeftColor: AAC5E3 - RightColor: A2BDDD + MinColor: AAC5E3 + MaxColor: A2BDDD ZOffset: -12 ZRamp: 0 Template@43: @@ -511,8 +513,8 @@ Tiles: 0: Clear RampType: 4 - LeftColor: D6E8F2 - RightColor: D1E3EF + MinColor: D6E8F2 + MaxColor: D1E3EF ZOffset: -12 ZRamp: 0 Template@44: @@ -523,8 +525,8 @@ Tiles: 0: Clear RampType: 5 - LeftColor: C2DDF2 - RightColor: ADC8EB + MinColor: C2DDF2 + MaxColor: ADC8EB ZOffset: -12 ZRamp: 0 Template@45: @@ -535,8 +537,8 @@ Tiles: 0: Clear RampType: 6 - LeftColor: 96B2D8 - RightColor: B6D0EC + MinColor: 96B2D8 + MaxColor: B6D0EC ZOffset: -12 ZRamp: 0 Template@46: @@ -547,8 +549,8 @@ Tiles: 0: Clear RampType: 7 - LeftColor: C7DEF0 - RightColor: C1D9EB + MinColor: C7DEF0 + MaxColor: C1D9EB ZOffset: -12 ZRamp: 0 Template@47: @@ -559,8 +561,8 @@ Tiles: 0: Clear RampType: 8 - LeftColor: C3DBEF - RightColor: DEEBF3 + MinColor: C3DBEF + MaxColor: DEEBF3 ZOffset: -12 ZRamp: 0 Template@48: @@ -571,8 +573,8 @@ Tiles: 0: Clear RampType: 9 - LeftColor: BED9F0 - RightColor: BFD9F0 + MinColor: BED9F0 + MaxColor: BFD9F0 ZOffset: -12 ZRamp: 0 Template@49: @@ -583,8 +585,8 @@ Tiles: 0: Clear RampType: 10 - LeftColor: B8D3ED - RightColor: 91A9D0 + MinColor: B8D3ED + MaxColor: 91A9D0 ZOffset: -12 ZRamp: 0 Template@50: @@ -595,8 +597,8 @@ Tiles: 0: Clear RampType: 11 - LeftColor: BFD8ED - RightColor: C4DCED + MinColor: BFD8ED + MaxColor: C4DCED ZOffset: -12 ZRamp: 0 Template@51: @@ -607,8 +609,8 @@ Tiles: 0: Clear RampType: 12 - LeftColor: DDEBF3 - RightColor: BED9F2 + MinColor: DDEBF3 + MaxColor: BED9F2 ZOffset: -12 ZRamp: 0 Template@52: @@ -619,8 +621,8 @@ Tiles: 0: Clear RampType: 13 - LeftColor: B0CCEC - RightColor: B0CCEC + MinColor: B0CCEC + MaxColor: B0CCEC ZOffset: -12 ZRamp: 0 Template@53: @@ -631,8 +633,8 @@ Tiles: 0: Clear RampType: 14 - LeftColor: 9BB5D8 - RightColor: 91A9D0 + MinColor: 9BB5D8 + MaxColor: 91A9D0 ZOffset: -12 ZRamp: 0 Template@54: @@ -643,8 +645,8 @@ Tiles: 0: Clear RampType: 15 - LeftColor: C5DDEE - RightColor: C0D8EB + MinColor: C5DDEE + MaxColor: C0D8EB ZOffset: -12 ZRamp: 0 Template@55: @@ -655,8 +657,8 @@ Tiles: 0: Clear RampType: 16 - LeftColor: DDEBF3 - RightColor: DEEBF3 + MinColor: DDEBF3 + MaxColor: DEEBF3 ZOffset: -12 ZRamp: 0 Template@56: @@ -667,8 +669,8 @@ Tiles: 0: Rough RampType: 17 - LeftColor: 9AB5D9 - RightColor: DBE9F2 + MinColor: 9AB5D9 + MaxColor: DBE9F2 ZOffset: -12 ZRamp: 0 Template@57: @@ -679,8 +681,8 @@ Tiles: 0: Rough RampType: 18 - LeftColor: D6E5F1 - RightColor: 98B1D6 + MinColor: D6E5F1 + MaxColor: 98B1D6 ZOffset: -12 ZRamp: 0 Template@58: @@ -691,8 +693,8 @@ Tiles: 0: Rough RampType: 17 - LeftColor: 9AB5D9 - RightColor: DBE9F2 + MinColor: 9AB5D9 + MaxColor: DBE9F2 ZOffset: -12 ZRamp: 0 Template@59: @@ -703,8 +705,8 @@ Tiles: 0: Rough RampType: 18 - LeftColor: D6E5F1 - RightColor: 98B1D6 + MinColor: D6E5F1 + MaxColor: 98B1D6 ZOffset: -12 ZRamp: 0 Template@60: @@ -715,24 +717,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 6E808E - RightColor: 8393A0 + MinColor: 6E808E + MaxColor: 8393A0 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 9CB7CD - RightColor: 96ACBF + MinColor: 9CB7CD + MaxColor: 96ACBF ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 5A6C7A - RightColor: 7B8D9B + MinColor: 5A6C7A + MaxColor: 7B8D9B ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: B6CFE4 - RightColor: 9DB4C8 + MinColor: B6CFE4 + MaxColor: 9DB4C8 ZOffset: -12 ZRamp: 0 Template@61: @@ -743,13 +745,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8090A0 - RightColor: 8B9FB2 + MinColor: 8090A0 + MaxColor: 8B9FB2 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 9EB6D1 - RightColor: 93ABC2 + MinColor: 9EB6D1 + MaxColor: 93ABC2 ZOffset: -12 ZRamp: 0 Template@62: @@ -760,24 +762,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 78899A - RightColor: 879AA9 + MinColor: 78899A + MaxColor: 879AA9 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: B3C8DF - RightColor: 94A9C0 + MinColor: B3C8DF + MaxColor: 94A9C0 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 798795 - RightColor: 7D8D9B + MinColor: 798795 + MaxColor: 7D8D9B ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C0DBF2 - RightColor: 98AEC4 + MinColor: C0DBF2 + MaxColor: 98AEC4 ZOffset: -12 ZRamp: 0 Template@63: @@ -788,24 +790,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8798A6 - RightColor: 8EA1B0 + MinColor: 8798A6 + MaxColor: 8EA1B0 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: BBD3E6 - RightColor: A9BECE + MinColor: BBD3E6 + MaxColor: A9BECE ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 8B99A7 - RightColor: 8698A8 + MinColor: 8B99A7 + MaxColor: 8698A8 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C0DBF2 - RightColor: B3CBDF + MinColor: C0DBF2 + MaxColor: B3CBDF ZOffset: -12 ZRamp: 0 Template@64: @@ -816,24 +818,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 7D8D9D - RightColor: 8296A8 + MinColor: 7D8D9D + MaxColor: 8296A8 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 7D8C9E - RightColor: 879CB1 + MinColor: 7D8C9E + MaxColor: 879CB1 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: BAD5F0 - RightColor: AAC0D5 + MinColor: BAD5F0 + MaxColor: AAC0D5 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B6D0E9 - RightColor: A9BED2 + MinColor: B6D0E9 + MaxColor: A9BED2 ZOffset: -12 ZRamp: 0 Template@65: @@ -844,24 +846,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 617487 - RightColor: 8494A5 + MinColor: 617487 + MaxColor: 8494A5 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 647586 - RightColor: 7E91A3 + MinColor: 647586 + MaxColor: 7E91A3 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: BAD4ED - RightColor: 9EB4C7 + MinColor: BAD4ED + MaxColor: 9EB4C7 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B4CDE6 - RightColor: 97AEC4 + MinColor: B4CDE6 + MaxColor: 97AEC4 ZOffset: -12 ZRamp: 0 Template@66: @@ -872,24 +874,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8295A7 - RightColor: 8D9EAF + MinColor: 8295A7 + MaxColor: 8D9EAF ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 889AAA - RightColor: 8B9FB0 + MinColor: 889AAA + MaxColor: 8B9FB0 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: B9D4EF - RightColor: 91A8BB + MinColor: B9D4EF + MaxColor: 91A8BB ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B3CDE4 - RightColor: A6BACB + MinColor: B3CDE4 + MaxColor: A6BACB ZOffset: -12 ZRamp: 0 Template@67: @@ -900,13 +902,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 728497 - RightColor: 8095A7 + MinColor: 728497 + MaxColor: 8095A7 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: ACC4DB - RightColor: 8BA4BA + MinColor: ACC4DB + MaxColor: 8BA4BA ZOffset: -12 ZRamp: 0 Template@68: @@ -917,18 +919,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 90A4B6 - RightColor: 92A6B6 + MinColor: 90A4B6 + MaxColor: 92A6B6 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 9AAEBE - RightColor: 99ADC0 + MinColor: 9AAEBE + MaxColor: 99ADC0 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: A4B8CC - RightColor: A4B9CE + MinColor: A4B8CC + MaxColor: A4B9CE ZOffset: -12 ZRamp: 0 Template@69: @@ -939,18 +941,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 889BAF - RightColor: 889BAC + MinColor: 889BAF + MaxColor: 889BAC ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: A1BCD5 - RightColor: 9CB3CA + MinColor: A1BCD5 + MaxColor: 9CB3CA ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 83A0BC - RightColor: 93ADCC + MinColor: 83A0BC + MaxColor: 93ADCC ZOffset: -12 ZRamp: 0 Template@70: @@ -961,18 +963,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8CA1B4 - RightColor: 8DA2B5 + MinColor: 8CA1B4 + MaxColor: 8DA2B5 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 98B0C3 - RightColor: 8FA9C4 + MinColor: 98B0C3 + MaxColor: 8FA9C4 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 8FA8C0 - RightColor: A8C0D4 + MinColor: 8FA8C0 + MaxColor: A8C0D4 ZOffset: -12 ZRamp: 0 Template@71: @@ -982,8 +984,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: B2C6DB - RightColor: A3B9CE + MinColor: B2C6DB + MaxColor: A3B9CE ZOffset: -12 ZRamp: 0 Template@72: @@ -993,8 +995,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 94ACC4 - RightColor: A6BDD2 + MinColor: 94ACC4 + MaxColor: A6BDD2 ZOffset: -12 ZRamp: 0 Template@73: @@ -1004,8 +1006,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: A8BED1 - RightColor: 83A0B5 + MinColor: A8BED1 + MaxColor: 83A0B5 ZOffset: -12 ZRamp: 0 Template@74: @@ -1016,24 +1018,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 879BAE - RightColor: 7B8D9D + MinColor: 879BAE + MaxColor: 7B8D9D ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 86A3C1 - RightColor: 7997AE + MinColor: 86A3C1 + MaxColor: 7997AE ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 899EB0 - RightColor: 7F909F + MinColor: 899EB0 + MaxColor: 7F909F ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B0CAE5 - RightColor: 819EB5 + MinColor: B0CAE5 + MaxColor: 819EB5 ZOffset: -12 ZRamp: 0 Template@75: @@ -1044,24 +1046,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 778998 - RightColor: 758692 + MinColor: 778998 + MaxColor: 758692 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 98B2C7 - RightColor: 7795AA + MinColor: 98B2C7 + MaxColor: 7795AA ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 8296A9 - RightColor: 768898 + MinColor: 8296A9 + MaxColor: 768898 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: AAC2DC - RightColor: 83A1BA + MinColor: AAC2DC + MaxColor: 83A1BA ZOffset: -12 ZRamp: 0 Template@76: @@ -1072,24 +1074,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 7E92A4 - RightColor: 7D8FA0 + MinColor: 7E92A4 + MaxColor: 7D8FA0 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 93AAC0 - RightColor: 829CB4 + MinColor: 93AAC0 + MaxColor: 829CB4 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 8BA0B4 - RightColor: 708395 + MinColor: 8BA0B4 + MaxColor: 708395 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 9AB1C5 - RightColor: 7991A6 + MinColor: 9AB1C5 + MaxColor: 7991A6 ZOffset: -12 ZRamp: 0 Template@77: @@ -1100,13 +1102,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8395A7 - RightColor: 7B8D9E + MinColor: 8395A7 + MaxColor: 7B8D9E ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 97B2CB - RightColor: 859EB1 + MinColor: 97B2CB + MaxColor: 859EB1 ZOffset: -12 ZRamp: 0 Template@78: @@ -1117,24 +1119,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8A9EAF - RightColor: 8395A6 + MinColor: 8A9EAF + MaxColor: 8395A6 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 657E90 - RightColor: 7F9AAE + MinColor: 657E90 + MaxColor: 7F9AAE ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 889BAD - RightColor: 596C78 + MinColor: 889BAD + MaxColor: 596C78 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: ADC6DE - RightColor: 8EA9C3 + MinColor: ADC6DE + MaxColor: 8EA9C3 ZOffset: -12 ZRamp: 0 Template@79: @@ -1145,24 +1147,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8CA0B4 - RightColor: 8699AB + MinColor: 8CA0B4 + MaxColor: 8699AB ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 768E9F - RightColor: 849EB0 + MinColor: 768E9F + MaxColor: 849EB0 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 8A9FB2 - RightColor: 5B6F7D + MinColor: 8A9FB2 + MaxColor: 5B6F7D ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: B4CEE5 - RightColor: 9CB7D0 + MinColor: B4CEE5 + MaxColor: 9CB7D0 ZOffset: -12 ZRamp: 0 Template@80: @@ -1173,24 +1175,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8090A0 - RightColor: 7F8C98 + MinColor: 8090A0 + MaxColor: 7F8C98 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 8399AD - RightColor: 94AABD + MinColor: 8399AD + MaxColor: 94AABD ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 8DA0B2 - RightColor: 778594 + MinColor: 8DA0B2 + MaxColor: 778594 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: AABFD2 - RightColor: A4BBD1 + MinColor: AABFD2 + MaxColor: A4BBD1 ZOffset: -12 ZRamp: 0 Template@81: @@ -1201,13 +1203,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 879BAC - RightColor: 788794 + MinColor: 879BAC + MaxColor: 788794 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 90A8BC - RightColor: 88A0B4 + MinColor: 90A8BC + MaxColor: 88A0B4 ZOffset: -12 ZRamp: 0 Template@82: @@ -1218,14 +1220,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 879BAE - RightColor: 7C8E9F + MinColor: 879BAE + MaxColor: 7C8E9F ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 8598A8 - RightColor: 738394 + MinColor: 8598A8 + MaxColor: 738394 ZOffset: -12 ZRamp: 0 Template@83: @@ -1236,14 +1238,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8999A8 - RightColor: 707F8F + MinColor: 8999A8 + MaxColor: 707F8F ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 8A9BAC - RightColor: 8393A3 + MinColor: 8A9BAC + MaxColor: 8393A3 ZOffset: -12 ZRamp: 0 Template@84: @@ -1254,14 +1256,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8A9EAF - RightColor: 758896 + MinColor: 8A9EAF + MaxColor: 758896 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 647581 - RightColor: 5A7080 + MinColor: 647581 + MaxColor: 5A7080 ZOffset: -12 ZRamp: 0 Template@85: @@ -1272,8 +1274,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8393A6 - RightColor: 738295 + MinColor: 8393A6 + MaxColor: 738295 ZOffset: -12 ZRamp: 0 Template@86: @@ -1284,20 +1286,20 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 7B8B9D - RightColor: 78879B + MinColor: 7B8B9D + MaxColor: 78879B ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 879CB0 - RightColor: 8295A9 + MinColor: 879CB0 + MaxColor: 8295A9 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 78879D - RightColor: 90A3B4 + MinColor: 78879D + MaxColor: 90A3B4 ZOffset: -12 ZRamp: 0 Template@87: @@ -1308,20 +1310,20 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 768A9C - RightColor: 708495 + MinColor: 768A9C + MaxColor: 708495 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 7E92A4 - RightColor: 798B9B + MinColor: 7E92A4 + MaxColor: 798B9B ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 8798A8 - RightColor: 74879A + MinColor: 8798A8 + MaxColor: 74879A ZOffset: -12 ZRamp: 0 Template@88: @@ -1332,8 +1334,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 7D8C9E - RightColor: 8597A9 + MinColor: 7D8C9E + MaxColor: 8597A9 ZOffset: -12 ZRamp: 0 Template@89: @@ -1344,8 +1346,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8495A4 - RightColor: 738293 + MinColor: 8495A4 + MaxColor: 738293 ZOffset: -12 ZRamp: 0 Template@90: @@ -1356,20 +1358,20 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 778696 - RightColor: 758596 + MinColor: 778696 + MaxColor: 758596 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 808FA0 - RightColor: 7F8FA1 + MinColor: 808FA0 + MaxColor: 7F8FA1 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 8293A4 - RightColor: 798A9B + MinColor: 8293A4 + MaxColor: 798A9B ZOffset: -12 ZRamp: 0 Template@91: @@ -1380,20 +1382,20 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 879BB0 - RightColor: 788C9C + MinColor: 879BB0 + MaxColor: 788C9C ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 8EA2B3 - RightColor: 728492 + MinColor: 8EA2B3 + MaxColor: 728492 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 889CB1 - RightColor: 8397AC + MinColor: 889CB1 + MaxColor: 8397AC ZOffset: -12 ZRamp: 0 Template@92: @@ -1404,8 +1406,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8496AA - RightColor: 8293A7 + MinColor: 8496AA + MaxColor: 8293A7 ZOffset: -12 ZRamp: 0 Template@93: @@ -1416,8 +1418,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 899CAE - RightColor: 8C9FB0 + MinColor: 899CAE + MaxColor: 8C9FB0 ZOffset: -12 ZRamp: 0 Template@94: @@ -1428,14 +1430,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 899AAA - RightColor: 8596A6 + MinColor: 899AAA + MaxColor: 8596A6 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 788899 - RightColor: 8798A9 + MinColor: 788899 + MaxColor: 8798A9 ZOffset: -12 ZRamp: 0 Template@95: @@ -1446,14 +1448,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8293A3 - RightColor: 879AAE + MinColor: 8293A3 + MaxColor: 879AAE ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 798799 - RightColor: 8697A4 + MinColor: 798799 + MaxColor: 8697A4 ZOffset: -12 ZRamp: 0 Template@96: @@ -1464,14 +1466,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 7F91A4 - RightColor: 8A9BAF + MinColor: 7F91A4 + MaxColor: 8A9BAF ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 7F93A8 - RightColor: 8498A9 + MinColor: 7F93A8 + MaxColor: 8498A9 ZOffset: -12 ZRamp: 0 Template@97: @@ -1482,8 +1484,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 778799 - RightColor: 7C8C9E + MinColor: 778799 + MaxColor: 7C8C9E ZOffset: -12 ZRamp: 0 Template@98: @@ -1494,8 +1496,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8A9BAB - RightColor: 869BB1 + MinColor: 8A9BAB + MaxColor: 869BB1 ZOffset: -12 ZRamp: 0 Template@99: @@ -1506,8 +1508,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8BA0B4 - RightColor: 8293A4 + MinColor: 8BA0B4 + MaxColor: 8293A4 ZOffset: -12 ZRamp: 0 Template@100: @@ -1517,48 +1519,48 @@ Size: 3, 3 Tiles: 0: Impassable - LeftColor: 627077 - RightColor: 6D797F + MinColor: 627077 + MaxColor: 6D797F ZOffset: -12 ZRamp: 0 1: Impassable - LeftColor: 4E5558 - RightColor: 5D6870 + MinColor: 4E5558 + MaxColor: 5D6870 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: B2CAE4 - RightColor: C0DBF2 + MinColor: B2CAE4 + MaxColor: C0DBF2 ZOffset: -12 ZRamp: 0 3: Impassable - LeftColor: 757D83 - RightColor: 768187 + MinColor: 757D83 + MaxColor: 768187 ZOffset: -12 ZRamp: 0 4: Impassable - LeftColor: 6A7175 - RightColor: 545C66 + MinColor: 6A7175 + MaxColor: 545C66 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: B9D4F0 - RightColor: B8D3EF + MinColor: B9D4F0 + MaxColor: B8D3EF ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: BCD7F1 - RightColor: B8CFE4 + MinColor: BCD7F1 + MaxColor: B8CFE4 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: B7CCE1 - RightColor: A4B7CA + MinColor: B7CCE1 + MaxColor: A4B7CA ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: B8D0E9 - RightColor: B5D0EC + MinColor: B8D0E9 + MaxColor: B5D0EC ZOffset: -12 ZRamp: 0 Template@101: @@ -1568,13 +1570,13 @@ Size: 1, 2 Tiles: 0: Impassable - LeftColor: A6B8DB - RightColor: AABAD6 + MinColor: A6B8DB + MaxColor: AABAD6 ZOffset: -12 ZRamp: 0 1: Impassable - LeftColor: ACBACE - RightColor: B0CAEC + MinColor: ACBACE + MaxColor: B0CAEC ZOffset: -12 ZRamp: 0 Template@102: @@ -1584,8 +1586,8 @@ Size: 1, 1 Tiles: 0: Impassable - LeftColor: 9AA1A1 - RightColor: 868D90 + MinColor: 9AA1A1 + MaxColor: 868D90 ZOffset: -12 ZRamp: 0 Template@103: @@ -1595,13 +1597,13 @@ Size: 1, 2 Tiles: 0: Impassable - LeftColor: ACBFDE - RightColor: ABBAD4 + MinColor: ACBFDE + MaxColor: ABBAD4 ZOffset: -12 ZRamp: 0 1: Impassable - LeftColor: AFC3DB - RightColor: BCD6EF + MinColor: AFC3DB + MaxColor: BCD6EF ZOffset: -12 ZRamp: 0 Template@104: @@ -1611,18 +1613,18 @@ Size: 2, 2 Tiles: 1: Impassable - LeftColor: 77848C - RightColor: 656D73 + MinColor: 77848C + MaxColor: 656D73 ZOffset: -12 ZRamp: 0 2: Impassable - LeftColor: 768086 - RightColor: 787E84 + MinColor: 768086 + MaxColor: 787E84 ZOffset: -12 ZRamp: 0 3: Impassable - LeftColor: 70767D - RightColor: 666E75 + MinColor: 70767D + MaxColor: 666E75 ZOffset: -12 ZRamp: 0 Template@105: @@ -1632,33 +1634,33 @@ Size: 3, 3 Tiles: 1: Impassable - LeftColor: 70777C - RightColor: 788188 + MinColor: 70777C + MaxColor: 788188 ZOffset: -12 ZRamp: 0 3: Impassable - LeftColor: 8B98A2 - RightColor: 757C81 + MinColor: 8B98A2 + MaxColor: 757C81 ZOffset: -12 ZRamp: 0 4: Impassable - LeftColor: 8FA0AD - RightColor: 97A5B2 + MinColor: 8FA0AD + MaxColor: 97A5B2 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: AEB6BC - RightColor: B3C5D5 + MinColor: AEB6BC + MaxColor: B3C5D5 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: B1C6D8 - RightColor: A8B0B1 + MinColor: B1C6D8 + MaxColor: A8B0B1 ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: B4C6D7 - RightColor: A8B8C7 + MinColor: B4C6D7 + MaxColor: A8B8C7 ZOffset: -12 ZRamp: 0 Template@106: @@ -1668,8 +1670,8 @@ Size: 1, 1 Tiles: 0: Impassable - LeftColor: 6F777E - RightColor: 59626A + MinColor: 6F777E + MaxColor: 59626A ZOffset: -12 ZRamp: 0 Template@107: @@ -1679,13 +1681,13 @@ Size: 1, 2 Tiles: 0: Impassable - LeftColor: 666C6E - RightColor: 6F7981 + MinColor: 666C6E + MaxColor: 6F7981 ZOffset: -12 ZRamp: 0 1: Impassable - LeftColor: 75828C - RightColor: 5A6977 + MinColor: 75828C + MaxColor: 5A6977 ZOffset: -12 ZRamp: 0 Template@108: @@ -1695,23 +1697,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 73828D - RightColor: A0B1C0 + MinColor: 73828D + MaxColor: A0B1C0 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 6E7C87 - RightColor: B1C4D6 + MinColor: 6E7C87 + MaxColor: B1C4D6 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 34444E - RightColor: 8297A6 + MinColor: 34444E + MaxColor: 8297A6 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 344249 - RightColor: 3D4A52 + MinColor: 344249 + MaxColor: 3D4A52 ZOffset: -12 ZRamp: 0 Template@109: @@ -1721,23 +1723,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: B2C5D6 - RightColor: A9B9C9 + MinColor: B2C5D6 + MaxColor: A9B9C9 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 68737E - RightColor: 95A9BA + MinColor: 68737E + MaxColor: 95A9BA ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 394954 - RightColor: 76828F + MinColor: 394954 + MaxColor: 76828F ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 46545C - RightColor: 3F4F5A + MinColor: 46545C + MaxColor: 3F4F5A ZOffset: -12 ZRamp: 0 Template@110: @@ -1747,23 +1749,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: A4B7C8 - RightColor: A0B1C2 + MinColor: A4B7C8 + MaxColor: A0B1C2 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: A2B5C4 - RightColor: B0C6DA + MinColor: A2B5C4 + MaxColor: B0C6DA ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 2D3D46 - RightColor: 53636F + MinColor: 2D3D46 + MaxColor: 53636F ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 4B5A65 - RightColor: 616F7B + MinColor: 4B5A65 + MaxColor: 616F7B ZOffset: -12 ZRamp: 0 Template@111: @@ -1773,13 +1775,13 @@ Size: 1, 2 Tiles: 0: Water - LeftColor: 717D87 - RightColor: ADC1D5 + MinColor: 717D87 + MaxColor: ADC1D5 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 2C3C45 - RightColor: 384856 + MinColor: 2C3C45 + MaxColor: 384856 ZOffset: -12 ZRamp: 0 Template@112: @@ -1789,33 +1791,33 @@ Size: 2, 3 Tiles: 0: Water - LeftColor: 99AABB - RightColor: AABECF + MinColor: 99AABB + MaxColor: AABECF ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 72797F - RightColor: 9BABB7 + MinColor: 72797F + MaxColor: 9BABB7 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 687782 - RightColor: 526877 + MinColor: 687782 + MaxColor: 526877 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 4F5D65 - RightColor: 899CA8 + MinColor: 4F5D65 + MaxColor: 899CA8 ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 293941 - RightColor: 5B6C78 + MinColor: 293941 + MaxColor: 5B6C78 ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 2F3F48 - RightColor: 35424B + MinColor: 2F3F48 + MaxColor: 35424B ZOffset: -12 ZRamp: 0 Template@113: @@ -1825,33 +1827,33 @@ Size: 2, 3 Tiles: 0: Water - LeftColor: A6B5C0 - RightColor: 95A1AB + MinColor: A6B5C0 + MaxColor: 95A1AB ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 828D96 - RightColor: 99AABA + MinColor: 828D96 + MaxColor: 99AABA ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 81909C - RightColor: 7E8C97 + MinColor: 81909C + MaxColor: 7E8C97 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 42525D - RightColor: 4D5E6C + MinColor: 42525D + MaxColor: 4D5E6C ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 324049 - RightColor: 444F58 + MinColor: 324049 + MaxColor: 444F58 ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 313F46 - RightColor: 324048 + MinColor: 313F46 + MaxColor: 324048 ZOffset: -12 ZRamp: 0 Template@114: @@ -1861,23 +1863,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 8E9CAA - RightColor: 8695A3 + MinColor: 8E9CAA + MaxColor: 8695A3 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 415059 - RightColor: 2E3E48 + MinColor: 415059 + MaxColor: 2E3E48 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 36424A - RightColor: 738089 + MinColor: 36424A + MaxColor: 738089 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 3E4E57 - RightColor: 2C3B42 + MinColor: 3E4E57 + MaxColor: 2C3B42 ZOffset: -12 ZRamp: 0 Template@115: @@ -1887,23 +1889,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: A0B1BF - RightColor: 9CADBC + MinColor: A0B1BF + MaxColor: 9CADBC ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 5C656A - RightColor: 2D3C44 + MinColor: 5C656A + MaxColor: 2D3C44 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 34444D - RightColor: 798C9D + MinColor: 34444D + MaxColor: 798C9D ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 576872 - RightColor: 465662 + MinColor: 576872 + MaxColor: 465662 ZOffset: -12 ZRamp: 0 Template@116: @@ -1913,23 +1915,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: AEC1D4 - RightColor: A6B6C4 + MinColor: AEC1D4 + MaxColor: A6B6C4 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 6C7E8B - RightColor: 33424D + MinColor: 6C7E8B + MaxColor: 33424D ZOffset: -12 ZRamp: 0 2: Water - LeftColor: B3C7D9 - RightColor: A1B2C1 + MinColor: B3C7D9 + MaxColor: A1B2C1 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 4A555E - RightColor: 4C606E + MinColor: 4A555E + MaxColor: 4C606E ZOffset: -12 ZRamp: 0 Template@117: @@ -1939,23 +1941,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: A2AFBA - RightColor: BBD0E1 + MinColor: A2AFBA + MaxColor: BBD0E1 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 7D8E9E - RightColor: 2F3E48 + MinColor: 7D8E9E + MaxColor: 2F3E48 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: ADBBC7 - RightColor: 95A0AA + MinColor: ADBBC7 + MaxColor: 95A0AA ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 576774 - RightColor: 5A6B76 + MinColor: 576774 + MaxColor: 5A6B76 ZOffset: -12 ZRamp: 0 Template@118: @@ -1965,23 +1967,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: B4CADF - RightColor: 9EACBB + MinColor: B4CADF + MaxColor: 9EACBB ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 6D7E8A - RightColor: 303D44 + MinColor: 6D7E8A + MaxColor: 303D44 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: C0DBF2 - RightColor: B6CDE4 + MinColor: C0DBF2 + MaxColor: B6CDE4 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 768795 - RightColor: 5B6972 + MinColor: 768795 + MaxColor: 5B6972 ZOffset: -12 ZRamp: 0 Template@119: @@ -1991,13 +1993,13 @@ Size: 2, 1 Tiles: 0: Water - LeftColor: B2C4D6 - RightColor: 9DADB9 + MinColor: B2C4D6 + MaxColor: 9DADB9 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 566672 - RightColor: 475765 + MinColor: 566672 + MaxColor: 475765 ZOffset: -12 ZRamp: 0 Template@120: @@ -2007,33 +2009,33 @@ Size: 3, 2 Tiles: 0: Clear - LeftColor: B6CCE1 - RightColor: B2C3D3 + MinColor: B6CCE1 + MaxColor: B2C3D3 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: B1C2D1 - RightColor: 9CADBD + MinColor: B1C2D1 + MaxColor: 9CADBD ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 6D7C86 - RightColor: 35434B + MinColor: 6D7C86 + MaxColor: 35434B ZOffset: -12 ZRamp: 0 3: Water - LeftColor: A6B6C5 - RightColor: AEBCC7 + MinColor: A6B6C5 + MaxColor: AEBCC7 ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 6C7B88 - RightColor: 606972 + MinColor: 6C7B88 + MaxColor: 606972 ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 45545E - RightColor: 404E56 + MinColor: 45545E + MaxColor: 404E56 ZOffset: -12 ZRamp: 0 Template@121: @@ -2043,33 +2045,33 @@ Size: 3, 2 Tiles: 0: Water - LeftColor: 929CA4 - RightColor: 858F99 + MinColor: 929CA4 + MaxColor: 858F99 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: A1B1C0 - RightColor: 657481 + MinColor: A1B1C0 + MaxColor: 657481 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 8194A5 - RightColor: 445562 + MinColor: 8194A5 + MaxColor: 445562 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: BCD4E9 - RightColor: A2AFBB + MinColor: BCD4E9 + MaxColor: A2AFBB ZOffset: -12 ZRamp: 0 4: Water - LeftColor: A6B7C7 - RightColor: 7C8B99 + MinColor: A6B7C7 + MaxColor: 7C8B99 ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 3C4C57 - RightColor: 3F4C56 + MinColor: 3C4C57 + MaxColor: 3F4C56 ZOffset: -12 ZRamp: 0 Template@122: @@ -2079,23 +2081,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 3A4A54 - RightColor: 2C3B44 + MinColor: 3A4A54 + MaxColor: 2C3B44 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 2D3C44 - RightColor: 2A3A42 + MinColor: 2D3C44 + MaxColor: 2A3A42 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: A5B4C2 - RightColor: 7D92A1 + MinColor: A5B4C2 + MaxColor: 7D92A1 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 3A4952 - RightColor: 2F3F48 + MinColor: 3A4952 + MaxColor: 2F3F48 ZOffset: -12 ZRamp: 0 Template@123: @@ -2105,23 +2107,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 4C5961 - RightColor: 2A3A43 + MinColor: 4C5961 + MaxColor: 2A3A43 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 435059 - RightColor: 293941 + MinColor: 435059 + MaxColor: 293941 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: ADBED0 - RightColor: ACBBCC + MinColor: ADBED0 + MaxColor: ACBBCC ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 3C4952 - RightColor: 445059 + MinColor: 3C4952 + MaxColor: 445059 ZOffset: -12 ZRamp: 0 Template@124: @@ -2131,23 +2133,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 75838E - RightColor: 495760 + MinColor: 75838E + MaxColor: 495760 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 485963 - RightColor: 323F47 + MinColor: 485963 + MaxColor: 323F47 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: ACBBC9 - RightColor: B7C9D8 + MinColor: ACBBC9 + MaxColor: B7C9D8 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: B6CEE3 - RightColor: A5B4C0 + MinColor: B6CEE3 + MaxColor: A5B4C0 ZOffset: -12 ZRamp: 0 Template@125: @@ -2157,23 +2159,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 5B6870 - RightColor: 404D54 + MinColor: 5B6870 + MaxColor: 404D54 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 6E7C85 - RightColor: 485760 + MinColor: 6E7C85 + MaxColor: 485760 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: BACCDC - RightColor: A7B3BE + MinColor: BACCDC + MaxColor: A7B3BE ZOffset: -12 ZRamp: 0 3: Water - LeftColor: B9D3EE - RightColor: A9BAC9 + MinColor: B9D3EE + MaxColor: A9BAC9 ZOffset: -12 ZRamp: 0 Template@126: @@ -2183,23 +2185,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 495860 - RightColor: 2A3941 + MinColor: 495860 + MaxColor: 2A3941 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 40515F - RightColor: 33454F + MinColor: 40515F + MaxColor: 33454F ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 9FB0BF - RightColor: 748088 + MinColor: 9FB0BF + MaxColor: 748088 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 9CACB9 - RightColor: A9BCCC + MinColor: 9CACB9 + MaxColor: A9BCCC ZOffset: -12 ZRamp: 0 Template@127: @@ -2209,13 +2211,13 @@ Size: 1, 2 Tiles: 0: Water - LeftColor: 6E7D85 - RightColor: 435057 + MinColor: 6E7D85 + MaxColor: 435057 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: B9CDDF - RightColor: A5B3BF + MinColor: B9CDDF + MaxColor: A5B3BF ZOffset: -12 ZRamp: 0 Template@128: @@ -2225,33 +2227,33 @@ Size: 2, 3 Tiles: 0: Water - LeftColor: 364248 - RightColor: 334148 + MinColor: 364248 + MaxColor: 334148 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 616D74 - RightColor: 364750 + MinColor: 616D74 + MaxColor: 364750 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 57646A - RightColor: 58666E + MinColor: 57646A + MaxColor: 58666E ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 99A6B0 - RightColor: B0BECA + MinColor: 99A6B0 + MaxColor: B0BECA ZOffset: -12 ZRamp: 0 4: Water - LeftColor: A4B0BC - RightColor: 607079 + MinColor: A4B0BC + MaxColor: 607079 ZOffset: -12 ZRamp: 0 5: Water - LeftColor: A3B3C1 - RightColor: AFC4D6 + MinColor: A3B3C1 + MaxColor: AFC4D6 ZOffset: -12 ZRamp: 0 Template@129: @@ -2261,33 +2263,33 @@ Size: 2, 3 Tiles: 0: Water - LeftColor: 394C55 - RightColor: 3B4B54 + MinColor: 394C55 + MaxColor: 3B4B54 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 8EA2B2 - RightColor: 394953 + MinColor: 8EA2B2 + MaxColor: 394953 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 8E9CA9 - RightColor: 455058 + MinColor: 8E9CA9 + MaxColor: 455058 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 626E77 - RightColor: 60727E + MinColor: 626E77 + MaxColor: 60727E ZOffset: -12 ZRamp: 0 4: Water - LeftColor: A1AFBA - RightColor: 96A3AE + MinColor: A1AFBA + MaxColor: 96A3AE ZOffset: -12 ZRamp: 0 5: Water - LeftColor: A6B5C3 - RightColor: ACBCCA + MinColor: A6B5C3 + MaxColor: ACBCCA ZOffset: -12 ZRamp: 0 Template@130: @@ -2297,23 +2299,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 303C42 - RightColor: 2C3B42 + MinColor: 303C42 + MaxColor: 2C3B42 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 656F77 - RightColor: 51626C + MinColor: 656F77 + MaxColor: 51626C ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 354148 - RightColor: 3C4A53 + MinColor: 354148 + MaxColor: 3C4A53 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 8F9CA8 - RightColor: A8B9CA + MinColor: 8F9CA8 + MaxColor: A8B9CA ZOffset: -12 ZRamp: 0 Template@131: @@ -2323,23 +2325,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 4D5A62 - RightColor: 55636D + MinColor: 4D5A62 + MaxColor: 55636D ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 889AA8 - RightColor: 415159 + MinColor: 889AA8 + MaxColor: 415159 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 31414C - RightColor: 8C9BA6 + MinColor: 31414C + MaxColor: 8C9BA6 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: A6B5C3 - RightColor: B7C9D7 + MinColor: A6B5C3 + MaxColor: B7C9D7 ZOffset: -12 ZRamp: 0 Template@132: @@ -2349,23 +2351,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 5B6974 - RightColor: 8799A5 + MinColor: 5B6974 + MaxColor: 8799A5 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: A6B6C4 - RightColor: ABBDCD + MinColor: A6B6C4 + MaxColor: ABBDCD ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 36454E - RightColor: 889BAA + MinColor: 36454E + MaxColor: 889BAA ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 9BA7B1 - RightColor: AEBCCA + MinColor: 9BA7B1 + MaxColor: AEBCCA ZOffset: -12 ZRamp: 0 Template@133: @@ -2375,23 +2377,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 5E6C74 - RightColor: 667582 + MinColor: 5E6C74 + MaxColor: 667582 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 9AA7B4 - RightColor: B6C9DA + MinColor: 9AA7B4 + MaxColor: B6C9DA ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 35434B - RightColor: 818E99 + MinColor: 35434B + MaxColor: 818E99 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: ABB8C5 - RightColor: ADBECC + MinColor: ABB8C5 + MaxColor: ADBECC ZOffset: -12 ZRamp: 0 Template@134: @@ -2401,23 +2403,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 3F4D56 - RightColor: 51616C + MinColor: 3F4D56 + MaxColor: 51616C ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 828990 - RightColor: 9DABB8 + MinColor: 828990 + MaxColor: 9DABB8 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 38464E - RightColor: 82919D + MinColor: 38464E + MaxColor: 82919D ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 98ABBA - RightColor: B3C9DE + MinColor: 98ABBA + MaxColor: B3C9DE ZOffset: -12 ZRamp: 0 Template@135: @@ -2427,13 +2429,13 @@ Size: 2, 1 Tiles: 0: Water - LeftColor: 36464F - RightColor: 616F76 + MinColor: 36464F + MaxColor: 616F76 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: A5B4C3 - RightColor: B0C5DA + MinColor: A5B4C3 + MaxColor: B0C5DA ZOffset: -12 ZRamp: 0 Template@136: @@ -2443,33 +2445,33 @@ Size: 3, 2 Tiles: 0: Water - LeftColor: 2F3E46 - RightColor: 475863 + MinColor: 2F3E46 + MaxColor: 475863 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 858D94 - RightColor: 9EACB9 + MinColor: 858D94 + MaxColor: 9EACB9 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 94A3B3 - RightColor: B0C5DB + MinColor: 94A3B3 + MaxColor: B0C5DB ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 2C3C45 - RightColor: 35454F + MinColor: 2C3C45 + MaxColor: 35454F ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 53636D - RightColor: 78838D + MinColor: 53636D + MaxColor: 78838D ZOffset: -12 ZRamp: 0 5: Water - LeftColor: A4B5C5 - RightColor: A0B0C1 + MinColor: A4B5C5 + MaxColor: A0B0C1 ZOffset: -12 ZRamp: 0 Template@137: @@ -2479,33 +2481,33 @@ Size: 3, 2 Tiles: 0: Water - LeftColor: 34424A - RightColor: 324048 + MinColor: 34424A + MaxColor: 324048 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 6D7C86 - RightColor: 7A8A95 + MinColor: 6D7C86 + MaxColor: 7A8A95 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: B8C8D6 - RightColor: B9CDDF + MinColor: B8C8D6 + MaxColor: B9CDDF ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 2E3F47 - RightColor: 404A50 + MinColor: 2E3F47 + MaxColor: 404A50 ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 6F7C85 - RightColor: 8A99A4 + MinColor: 6F7C85 + MaxColor: 8A99A4 ZOffset: -12 ZRamp: 0 5: Water - LeftColor: B2C4D3 - RightColor: A9BBCC + MinColor: B2C4D3 + MaxColor: A9BBCC ZOffset: -12 ZRamp: 0 Template@138: @@ -2515,23 +2517,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 506371 - RightColor: 384953 + MinColor: 506371 + MaxColor: 384953 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 606B76 - RightColor: A7B4C0 + MinColor: 606B76 + MaxColor: A7B4C0 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 2D3E47 - RightColor: 4C5E6B + MinColor: 2D3E47 + MaxColor: 4C5E6B ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 323D42 - RightColor: 39474F + MinColor: 323D42 + MaxColor: 39474F ZOffset: -12 ZRamp: 0 Template@139: @@ -2541,23 +2543,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 6B7D90 - RightColor: 4C5963 + MinColor: 6B7D90 + MaxColor: 4C5963 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 6D7A86 - RightColor: B5CADE + MinColor: 6D7A86 + MaxColor: B5CADE ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 2C3D45 - RightColor: 384852 + MinColor: 2C3D45 + MaxColor: 384852 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 2C3C45 - RightColor: 3E4C59 + MinColor: 2C3C45 + MaxColor: 3E4C59 ZOffset: -12 ZRamp: 0 Template@140: @@ -2567,23 +2569,23 @@ Size: 2, 2 Tiles: 0: Clear - LeftColor: C0D8EC - RightColor: C1D6E8 + MinColor: C0D8EC + MaxColor: C1D6E8 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 88929B - RightColor: ADBCC8 + MinColor: 88929B + MaxColor: ADBCC8 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 9EAEBE - RightColor: 9EAEBF + MinColor: 9EAEBE + MaxColor: 9EAEBF ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 495665 - RightColor: 576573 + MinColor: 495665 + MaxColor: 576573 ZOffset: -12 ZRamp: 0 Template@141: @@ -2593,23 +2595,23 @@ Size: 2, 2 Tiles: 0: Clear - LeftColor: BAD0E2 - RightColor: B0C5DC + MinColor: BAD0E2 + MaxColor: B0C5DC ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 798793 - RightColor: 90A1B0 + MinColor: 798793 + MaxColor: 90A1B0 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: B4C8DB - RightColor: 9FAEBC + MinColor: B4C8DB + MaxColor: 9FAEBC ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 51616B - RightColor: 47565F + MinColor: 51616B + MaxColor: 47565F ZOffset: -12 ZRamp: 0 Template@142: @@ -2619,23 +2621,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: B9CDDD - RightColor: 9EACBA + MinColor: B9CDDD + MaxColor: 9EACBA ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 748490 - RightColor: 354650 + MinColor: 748490 + MaxColor: 354650 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: BED7EC - RightColor: ACBDCC + MinColor: BED7EC + MaxColor: ACBDCC ZOffset: -12 ZRamp: 0 3: Water - LeftColor: ADBDCC - RightColor: B2C8DB + MinColor: ADBDCC + MaxColor: B2C8DB ZOffset: -12 ZRamp: 0 Template@143: @@ -2645,23 +2647,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: ACBED0 - RightColor: 92A2B1 + MinColor: ACBED0 + MaxColor: 92A2B1 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 606F7B - RightColor: 5D6E7B + MinColor: 606F7B + MaxColor: 5D6E7B ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: C0DBF2 - RightColor: 929EA9 + MinColor: C0DBF2 + MaxColor: 929EA9 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 98A5B1 - RightColor: AFC1D0 + MinColor: 98A5B1 + MaxColor: AFC1D0 ZOffset: -12 ZRamp: 0 Template@144: @@ -2671,23 +2673,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 778691 - RightColor: 76848E + MinColor: 778691 + MaxColor: 76848E ZOffset: -12 ZRamp: 0 1: Water - LeftColor: A9B8C6 - RightColor: BAD1E5 + MinColor: A9B8C6 + MaxColor: BAD1E5 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: B1C4D5 - RightColor: 97A1AA + MinColor: B1C4D5 + MaxColor: 97A1AA ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: B0C3D7 - RightColor: ABBED2 + MinColor: B0C3D7 + MaxColor: ABBED2 ZOffset: -12 ZRamp: 0 Template@145: @@ -2697,23 +2699,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 728490 - RightColor: 6C7B86 + MinColor: 728490 + MaxColor: 6C7B86 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 868E95 - RightColor: A2B1BE + MinColor: 868E95 + MaxColor: A2B1BE ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 9DAAB7 - RightColor: 9FADBA + MinColor: 9DAAB7 + MaxColor: 9FADBA ZOffset: -12 ZRamp: 0 3: Water - LeftColor: A0B1BF - RightColor: 99A3AE + MinColor: A0B1BF + MaxColor: 99A3AE ZOffset: -12 ZRamp: 0 Template@146: @@ -2723,23 +2725,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: A7B7C6 - RightColor: A5B2BF + MinColor: A7B7C6 + MaxColor: A5B2BF ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: B7CEE4 - RightColor: BDD8F1 + MinColor: B7CEE4 + MaxColor: BDD8F1 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 435058 - RightColor: AABCCB + MinColor: 435058 + MaxColor: AABCCB ZOffset: -12 ZRamp: 0 3: Water - LeftColor: B4C8DB - RightColor: BAD4ED + MinColor: B4C8DB + MaxColor: BAD4ED ZOffset: -12 ZRamp: 0 Template@147: @@ -2749,23 +2751,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 909BA5 - RightColor: 929FAC + MinColor: 909BA5 + MaxColor: 929FAC ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 848D96 - RightColor: 9DADBA + MinColor: 848D96 + MaxColor: 9DADBA ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 43525B - RightColor: 87929B + MinColor: 43525B + MaxColor: 87929B ZOffset: -12 ZRamp: 0 3: Water - LeftColor: B2C8D9 - RightColor: A7B9CC + MinColor: B2C8D9 + MaxColor: A7B9CC ZOffset: -12 ZRamp: 0 Template@148: @@ -2775,108 +2777,108 @@ Size: 6, 4 Tiles: 1: Clear - LeftColor: A5B6C7 - RightColor: B7CEE4 + MinColor: A5B6C7 + MaxColor: B7CEE4 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: ADBAC7 - RightColor: BBD0E1 + MinColor: ADBAC7 + MaxColor: BBD0E1 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 8C96A0 - RightColor: B5C9DE + MinColor: 8C96A0 + MaxColor: B5C9DE ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: B8CDE0 - RightColor: B7CEE4 + MinColor: B8CDE0 + MaxColor: B7CEE4 ZOffset: -12 ZRamp: 0 7: Water - LeftColor: 9DAAB7 - RightColor: 9EACBA + MinColor: 9DAAB7 + MaxColor: 9EACBA ZOffset: -12 ZRamp: 0 8: Water - LeftColor: 81929F - RightColor: 76808B + MinColor: 81929F + MaxColor: 76808B ZOffset: -12 ZRamp: 0 9: Water - LeftColor: 798692 - RightColor: ACBECE + MinColor: 798692 + MaxColor: ACBECE ZOffset: -12 ZRamp: 0 10: Water - LeftColor: 7E8C9E - RightColor: AFC1D0 + MinColor: 7E8C9E + MaxColor: AFC1D0 ZOffset: -12 ZRamp: 0 11: Water - LeftColor: 8B9FAE - RightColor: 374752 + MinColor: 8B9FAE + MaxColor: 374752 ZOffset: -12 ZRamp: 0 12: Water - LeftColor: ABBCCC - RightColor: 99A4B0 + MinColor: ABBCCC + MaxColor: 99A4B0 ZOffset: -12 ZRamp: 0 13: Water - LeftColor: 9FAEBC - RightColor: 8F99A2 + MinColor: 9FAEBC + MaxColor: 8F99A2 ZOffset: -12 ZRamp: 0 14: Water - LeftColor: 4E5A64 - RightColor: 596773 + MinColor: 4E5A64 + MaxColor: 596773 ZOffset: -12 ZRamp: 0 15: Water - LeftColor: 344048 - RightColor: 546975 + MinColor: 344048 + MaxColor: 546975 ZOffset: -12 ZRamp: 0 16: Water - LeftColor: 41525D - RightColor: 4F5C65 + MinColor: 41525D + MaxColor: 4F5C65 ZOffset: -12 ZRamp: 0 17: Water - LeftColor: 39454D - RightColor: 374751 + MinColor: 39454D + MaxColor: 374751 ZOffset: -12 ZRamp: 0 18: Water - LeftColor: B0C2D5 - RightColor: 8B99A7 + MinColor: B0C2D5 + MaxColor: 8B99A7 ZOffset: -12 ZRamp: 0 19: Water - LeftColor: 37444C - RightColor: 46545C + MinColor: 37444C + MaxColor: 46545C ZOffset: -12 ZRamp: 0 20: Water - LeftColor: 2D3B43 - RightColor: 323F47 + MinColor: 2D3B43 + MaxColor: 323F47 ZOffset: -12 ZRamp: 0 21: Water - LeftColor: 2B3A43 - RightColor: 2D3C45 + MinColor: 2B3A43 + MaxColor: 2D3C45 ZOffset: -12 ZRamp: 0 22: Water - LeftColor: 2A3A42 - RightColor: 2E3C44 + MinColor: 2A3A42 + MaxColor: 2E3C44 ZOffset: -12 ZRamp: 0 23: Water - LeftColor: 2C3C44 - RightColor: 2A3941 + MinColor: 2C3C44 + MaxColor: 2A3941 ZOffset: -12 ZRamp: 0 Template@149: @@ -2886,153 +2888,153 @@ Size: 9, 5 Tiles: 2: Water - LeftColor: 7E848A - RightColor: 9BACBB + MinColor: 7E848A + MaxColor: 9BACBB ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 787F84 - RightColor: A9BCCC + MinColor: 787F84 + MaxColor: A9BCCC ZOffset: -12 ZRamp: 0 11: Water - LeftColor: 8A96A1 - RightColor: 646C71 + MinColor: 8A96A1 + MaxColor: 646C71 ZOffset: -12 ZRamp: 0 12: Water - LeftColor: 58646B - RightColor: 75818A + MinColor: 58646B + MaxColor: 75818A ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 9EABB8 - RightColor: AABACA + MinColor: 9EABB8 + MaxColor: AABACA ZOffset: -12 ZRamp: 0 18: Clear - LeftColor: BED6EA - RightColor: B8CDDF + MinColor: BED6EA + MaxColor: B8CDDF ZOffset: -12 ZRamp: 0 19: Water - LeftColor: 5D6368 - RightColor: 8697A5 + MinColor: 5D6368 + MaxColor: 8697A5 ZOffset: -12 ZRamp: 0 20: Water - LeftColor: 3F4F59 - RightColor: 404C54 + MinColor: 3F4F59 + MaxColor: 404C54 ZOffset: -12 ZRamp: 0 21: Water - LeftColor: 303F49 - RightColor: 3C474E + MinColor: 303F49 + MaxColor: 3C474E ZOffset: -12 ZRamp: 0 22: Water - LeftColor: 5A6871 - RightColor: 9EAEBC + MinColor: 5A6871 + MaxColor: 9EAEBC ZOffset: -12 ZRamp: 0 23: Water - LeftColor: 63717B - RightColor: B1C6D9 + MinColor: 63717B + MaxColor: B1C6D9 ZOffset: -12 ZRamp: 0 24: Water - LeftColor: 66737C - RightColor: B6CADC + MinColor: 66737C + MaxColor: B6CADC ZOffset: -12 ZRamp: 0 25: Water - LeftColor: 929EA8 - RightColor: B4CFEA + MinColor: 929EA8 + MaxColor: B4CFEA ZOffset: -12 ZRamp: 0 26: Water - LeftColor: 495660 - RightColor: 2C3B43 + MinColor: 495660 + MaxColor: 2C3B43 ZOffset: -12 ZRamp: 0 28: Water - LeftColor: AEC2D4 - RightColor: 808B94 + MinColor: AEC2D4 + MaxColor: 808B94 ZOffset: -12 ZRamp: 0 29: Water - LeftColor: 606F7A - RightColor: 4E5C65 + MinColor: 606F7A + MaxColor: 4E5C65 ZOffset: -12 ZRamp: 0 30: Water - LeftColor: 2F3F48 - RightColor: 2E3C44 + MinColor: 2F3F48 + MaxColor: 2E3C44 ZOffset: -12 ZRamp: 0 31: Water - LeftColor: 2B3A42 - RightColor: 313F49 + MinColor: 2B3A42 + MaxColor: 313F49 ZOffset: -12 ZRamp: 0 32: Water - LeftColor: 303F49 - RightColor: 33424C + MinColor: 303F49 + MaxColor: 33424C ZOffset: -12 ZRamp: 0 33: Water - LeftColor: 2E3C44 - RightColor: 324049 + MinColor: 2E3C44 + MaxColor: 324049 ZOffset: -12 ZRamp: 0 34: Water - LeftColor: 2E3D45 - RightColor: 35434A + MinColor: 2E3D45 + MaxColor: 35434A ZOffset: -12 ZRamp: 0 35: Water - LeftColor: 2F3F48 - RightColor: 2F3F48 + MinColor: 2F3F48 + MaxColor: 2F3F48 ZOffset: -12 ZRamp: 0 37: Water - LeftColor: B7CBDA - RightColor: A3B4C2 + MinColor: B7CBDA + MaxColor: A3B4C2 ZOffset: -12 ZRamp: 0 38: Water - LeftColor: 47525A - RightColor: 394750 + MinColor: 47525A + MaxColor: 394750 ZOffset: -12 ZRamp: 0 39: Water - LeftColor: 2B3B43 - RightColor: 2C3C44 + MinColor: 2B3B43 + MaxColor: 2C3C44 ZOffset: -12 ZRamp: 0 40: Water - LeftColor: 2C3C45 - RightColor: 2B3B44 + MinColor: 2C3C45 + MaxColor: 2B3B44 ZOffset: -12 ZRamp: 0 41: Water - LeftColor: 2B3B43 - RightColor: 2B3A42 + MinColor: 2B3B43 + MaxColor: 2B3A42 ZOffset: -12 ZRamp: 0 42: Water - LeftColor: 2A3A42 - RightColor: 2A3A42 + MinColor: 2A3A42 + MaxColor: 2A3A42 ZOffset: -12 ZRamp: 0 43: Water - LeftColor: 2B3B43 - RightColor: 2C3C44 + MinColor: 2B3B43 + MaxColor: 2C3C44 ZOffset: -12 ZRamp: 0 44: Water - LeftColor: 2D3D46 - RightColor: 2B3B43 + MinColor: 2D3D46 + MaxColor: 2B3B43 ZOffset: -12 ZRamp: 0 Template@150: @@ -3042,8 +3044,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: BFCFDF - RightColor: AFC1D3 + MinColor: BFCFDF + MaxColor: AFC1D3 ZOffset: -12 ZRamp: 0 Template@151: @@ -3053,8 +3055,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: C0D5E5 - RightColor: BED1E4 + MinColor: C0D5E5 + MaxColor: BED1E4 ZOffset: -12 ZRamp: 0 Template@152: @@ -3064,8 +3066,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: B9C9D8 - RightColor: B8CEE3 + MinColor: B9C9D8 + MaxColor: B8CEE3 ZOffset: -12 ZRamp: 0 Template@153: @@ -3075,8 +3077,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: B1C5D9 - RightColor: C3D8EC + MinColor: B1C5D9 + MaxColor: C3D8EC ZOffset: -12 ZRamp: 0 Template@154: @@ -3086,8 +3088,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: C0D1E2 - RightColor: BDD7EE + MinColor: C0D1E2 + MaxColor: BDD7EE ZOffset: -12 ZRamp: 0 Template@155: @@ -3097,8 +3099,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: BFD3E3 - RightColor: B6C5D7 + MinColor: BFD3E3 + MaxColor: B6C5D7 ZOffset: -12 ZRamp: 0 Template@156: @@ -3108,8 +3110,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: BFD4E6 - RightColor: BAD0E6 + MinColor: BFD4E6 + MaxColor: BAD0E6 ZOffset: -12 ZRamp: 0 Template@157: @@ -3119,8 +3121,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: BED4E6 - RightColor: B3CAE0 + MinColor: BED4E6 + MaxColor: B3CAE0 ZOffset: -12 ZRamp: 0 Template@158: @@ -3130,8 +3132,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: B6CCE0 - RightColor: BCD4EA + MinColor: B6CCE0 + MaxColor: BCD4EA ZOffset: -12 ZRamp: 0 Template@159: @@ -3141,8 +3143,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: C3D6E7 - RightColor: B0C3D4 + MinColor: C3D6E7 + MaxColor: B0C3D4 ZOffset: -12 ZRamp: 0 Template@160: @@ -3152,8 +3154,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: C3D6E7 - RightColor: B8CEE3 + MinColor: C3D6E7 + MaxColor: B8CEE3 ZOffset: -12 ZRamp: 0 Template@161: @@ -3163,8 +3165,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: C0D5E7 - RightColor: BCD2E7 + MinColor: C0D5E7 + MaxColor: BCD2E7 ZOffset: -12 ZRamp: 0 Template@162: @@ -3174,8 +3176,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: BDD1E5 - RightColor: BAD3EB + MinColor: BDD1E5 + MaxColor: BAD3EB ZOffset: -12 ZRamp: 0 Template@163: @@ -3185,8 +3187,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: BCD6EB - RightColor: ADC2D5 + MinColor: BCD6EB + MaxColor: ADC2D5 ZOffset: -12 ZRamp: 0 Template@164: @@ -3196,8 +3198,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: BCD3E6 - RightColor: B9CCDF + MinColor: BCD3E6 + MaxColor: B9CCDF ZOffset: -12 ZRamp: 0 Template@165: @@ -3207,8 +3209,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: C0DAEF - RightColor: C6D9EB + MinColor: C0DAEF + MaxColor: C6D9EB ZOffset: -12 ZRamp: 0 Template@166: @@ -3218,8 +3220,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: BBD1E8 - RightColor: C1D5E8 + MinColor: BBD1E8 + MaxColor: C1D5E8 ZOffset: -12 ZRamp: 0 Template@167: @@ -3230,24 +3232,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 798996 - RightColor: 8B9AA7 + MinColor: 798996 + MaxColor: 8B9AA7 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: A9BDD1 - RightColor: A2B6C6 + MinColor: A9BDD1 + MaxColor: A2B6C6 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 6A7B87 - RightColor: 768894 + MinColor: 6A7B87 + MaxColor: 768894 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 879CBF - RightColor: 93A8BE + MinColor: 879CBF + MaxColor: 93A8BE ZOffset: -12 ZRamp: 0 Template@168: @@ -3258,13 +3260,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8091A1 - RightColor: 8B9FB2 + MinColor: 8091A1 + MaxColor: 8B9FB2 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 90A9C2 - RightColor: 8BA3BB + MinColor: 90A9C2 + MaxColor: 8BA3BB ZOffset: -12 ZRamp: 0 Template@169: @@ -3275,24 +3277,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8393A1 - RightColor: 8C9FAE + MinColor: 8393A1 + MaxColor: 8C9FAE ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 8DA4C8 - RightColor: 96AAC0 + MinColor: 8DA4C8 + MaxColor: 96AAC0 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 788695 - RightColor: 8394A3 + MinColor: 788695 + MaxColor: 8394A3 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 8095B6 - RightColor: 8DA1BF + MinColor: 8095B6 + MaxColor: 8DA1BF ZOffset: -12 ZRamp: 0 Template@170: @@ -3303,24 +3305,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8998A7 - RightColor: 8FA1B1 + MinColor: 8998A7 + MaxColor: 8FA1B1 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: AAC1E2 - RightColor: A7BBCB + MinColor: AAC1E2 + MaxColor: A7BBCB ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 8997A4 - RightColor: 8798A8 + MinColor: 8997A4 + MaxColor: 8798A8 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 889FC4 - RightColor: A1B7CC + MinColor: 889FC4 + MaxColor: A1B7CC ZOffset: -12 ZRamp: 0 Template@171: @@ -3331,24 +3333,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 7D8D9D - RightColor: 8296A8 + MinColor: 7D8D9D + MaxColor: 8296A8 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 7D8C9F - RightColor: 879CB1 + MinColor: 7D8C9F + MaxColor: 879CB1 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 8297BF - RightColor: 8CA6B9 + MinColor: 8297BF + MaxColor: 8CA6B9 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 8A9FBB - RightColor: 93A8BE + MinColor: 8A9FBB + MaxColor: 93A8BE ZOffset: -12 ZRamp: 0 Template@172: @@ -3359,24 +3361,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 798C9E - RightColor: 8596A7 + MinColor: 798C9E + MaxColor: 8596A7 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 627384 - RightColor: 7E91A3 + MinColor: 627384 + MaxColor: 7E91A3 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 7E95B7 - RightColor: A3B7C8 + MinColor: 7E95B7 + MaxColor: A3B7C8 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 96ACC7 - RightColor: A1B6CB + MinColor: 96ACC7 + MaxColor: A1B6CB ZOffset: -12 ZRamp: 0 Template@173: @@ -3387,24 +3389,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8295A7 - RightColor: 8D9EAF + MinColor: 8295A7 + MaxColor: 8D9EAF ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 8E9FAC - RightColor: 8B9FB0 + MinColor: 8E9FAC + MaxColor: 8B9FB0 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 879DC0 - RightColor: 95A8B7 + MinColor: 879DC0 + MaxColor: 95A8B7 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B5C4D8 - RightColor: 96ABBE + MinColor: B5C4D8 + MaxColor: 96ABBE ZOffset: -12 ZRamp: 0 Template@174: @@ -3415,13 +3417,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 728497 - RightColor: 8095A7 + MinColor: 728497 + MaxColor: 8095A7 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 97ADC3 - RightColor: 859CB3 + MinColor: 97ADC3 + MaxColor: 859CB3 ZOffset: -12 ZRamp: 0 Template@175: @@ -3432,18 +3434,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 92A0AD - RightColor: 8693A0 + MinColor: 92A0AD + MaxColor: 8693A0 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 8196B0 - RightColor: 92A8BC + MinColor: 8196B0 + MaxColor: 92A8BC ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: A3B7CE - RightColor: 9AAFC5 + MinColor: A3B7CE + MaxColor: 9AAFC5 ZOffset: -12 ZRamp: 0 Template@176: @@ -3454,23 +3456,23 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8C9EB1 - RightColor: 889BAC + MinColor: 8C9EB1 + MaxColor: 889BAC ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 7287A0 - RightColor: 9EB7D0 + MinColor: 7287A0 + MaxColor: 9EB7D0 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 8CA6C1 - RightColor: 84A0BC + MinColor: 8CA6C1 + MaxColor: 84A0BC ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 7F93B5 - RightColor: 8095B8 + MinColor: 7F93B5 + MaxColor: 8095B8 ZOffset: -12 ZRamp: 0 Template@177: @@ -3481,18 +3483,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 92A1AD - RightColor: 8A9AAA + MinColor: 92A1AD + MaxColor: 8A9AAA ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 9FB4CD - RightColor: 94AEC7 + MinColor: 9FB4CD + MaxColor: 94AEC7 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 94ABC3 - RightColor: AEC4D9 + MinColor: 94ABC3 + MaxColor: AEC4D9 ZOffset: -12 ZRamp: 0 Template@178: @@ -3502,8 +3504,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: ACC0D6 - RightColor: 9DB2C7 + MinColor: ACC0D6 + MaxColor: 9DB2C7 ZOffset: -12 ZRamp: 0 Template@179: @@ -3513,8 +3515,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 9CB3CA - RightColor: A4B9CF + MinColor: 9CB3CA + MaxColor: A4B9CF ZOffset: -12 ZRamp: 0 Template@180: @@ -3524,8 +3526,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: ADC1D4 - RightColor: 8AA3B6 + MinColor: ADC1D4 + MaxColor: 8AA3B6 ZOffset: -12 ZRamp: 0 Template@181: @@ -3536,24 +3538,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 879BAE - RightColor: 7B8D9D + MinColor: 879BAE + MaxColor: 7B8D9D ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6A7F95 - RightColor: 7591AB + MinColor: 6A7F95 + MaxColor: 7591AB ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 899EB0 - RightColor: 7F909F + MinColor: 899EB0 + MaxColor: 7F909F ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 72869B - RightColor: 708BA0 + MinColor: 72869B + MaxColor: 708BA0 ZOffset: -12 ZRamp: 0 Template@182: @@ -3564,24 +3566,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 778998 - RightColor: 758692 + MinColor: 778998 + MaxColor: 758692 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 94A9BF - RightColor: 738FA5 + MinColor: 94A9BF + MaxColor: 738FA5 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 8296A9 - RightColor: 7C8D9C + MinColor: 8296A9 + MaxColor: 7C8D9C ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 8498BC - RightColor: 859EB7 + MinColor: 8498BC + MaxColor: 859EB7 ZOffset: -12 ZRamp: 0 Template@183: @@ -3592,24 +3594,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 7E91A4 - RightColor: 8596A6 + MinColor: 7E91A4 + MaxColor: 8596A6 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 93A6BB - RightColor: 7892AB + MinColor: 93A6BB + MaxColor: 7892AB ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 8BA0B4 - RightColor: 6C7F8F + MinColor: 8BA0B4 + MaxColor: 6C7F8F ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 768A9E - RightColor: 657E90 + MinColor: 768A9E + MaxColor: 657E90 ZOffset: -12 ZRamp: 0 Template@184: @@ -3620,13 +3622,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8395A7 - RightColor: 7B8D9E + MinColor: 8395A7 + MaxColor: 7B8D9E ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 7B90A9 - RightColor: 7F98AC + MinColor: 7B90A9 + MaxColor: 7F98AC ZOffset: -12 ZRamp: 0 Template@185: @@ -3637,24 +3639,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8EA0B1 - RightColor: 8898A9 + MinColor: 8EA0B1 + MaxColor: 8898A9 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 647B8B - RightColor: 7991A6 + MinColor: 647B8B + MaxColor: 7991A6 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 899CAF - RightColor: 63747E + MinColor: 899CAF + MaxColor: 63747E ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 889DBD - RightColor: 889FBD + MinColor: 889DBD + MaxColor: 889FBD ZOffset: -12 ZRamp: 0 Template@186: @@ -3665,24 +3667,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8CA1B4 - RightColor: 8D9FAF + MinColor: 8CA1B4 + MaxColor: 8D9FAF ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 8C9EAA - RightColor: 7C95AB + MinColor: 8C9EAA + MaxColor: 7C95AB ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 8BA0B3 - RightColor: 677987 + MinColor: 8BA0B3 + MaxColor: 677987 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 788CAF - RightColor: 7C94B4 + MinColor: 788CAF + MaxColor: 7C94B4 ZOffset: -12 ZRamp: 0 Template@187: @@ -3693,24 +3695,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 7C8C9A - RightColor: 7A8793 + MinColor: 7C8C9A + MaxColor: 7A8793 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 899FB4 - RightColor: 859BAE + MinColor: 899FB4 + MaxColor: 859BAE ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 8DA0B2 - RightColor: 6F7D8A + MinColor: 8DA0B2 + MaxColor: 6F7D8A ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: A0B4CF - RightColor: 8EA4C4 + MinColor: A0B4CF + MaxColor: 8EA4C4 ZOffset: -12 ZRamp: 0 Template@188: @@ -3721,13 +3723,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8A9EB0 - RightColor: 8091A2 + MinColor: 8A9EB0 + MaxColor: 8091A2 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 8197AF - RightColor: 8BA2B6 + MinColor: 8197AF + MaxColor: 8BA2B6 ZOffset: -12 ZRamp: 0 Template@189: @@ -3738,29 +3740,29 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8597A4 - RightColor: 899BA9 + MinColor: 8597A4 + MaxColor: 899BA9 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 93AEC0 - RightColor: 92AABD + MinColor: 93AEC0 + MaxColor: 92AABD ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 637683 - RightColor: 778D9D + MinColor: 637683 + MaxColor: 778D9D ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 9AABBE - RightColor: B5C2CD + MinColor: 9AABBE + MaxColor: B5C2CD ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 8B9EB5 - RightColor: 91A7BD + MinColor: 8B9EB5 + MaxColor: 91A7BD ZOffset: -12 ZRamp: 0 Template@190: @@ -3770,13 +3772,13 @@ Size: 1, 2 Tiles: 0: Cliff - LeftColor: 96A8BF - RightColor: 92ABBE + MinColor: 96A8BF + MaxColor: 92ABBE ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 8B9FBD - RightColor: ACBFD1 + MinColor: 8B9FBD + MaxColor: ACBFD1 ZOffset: -12 ZRamp: 0 Template@191: @@ -3786,13 +3788,13 @@ Size: 2, 1 Tiles: 0: Cliff - LeftColor: 96ACC3 - RightColor: A4BACF + MinColor: 96ACC3 + MaxColor: A4BACF ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: B2C4D4 - RightColor: 99ABC6 + MinColor: B2C4D4 + MaxColor: 99ABC6 ZOffset: -12 ZRamp: 0 Template@192: @@ -3802,13 +3804,13 @@ Size: 2, 1 Tiles: 0: Cliff - LeftColor: 9EB2C5 - RightColor: 9FB5CA + MinColor: 9EB2C5 + MaxColor: 9FB5CA ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 9BACC4 - RightColor: B2C7DC + MinColor: 9BACC4 + MaxColor: B2C7DC ZOffset: -12 ZRamp: 0 Template@193: @@ -3818,13 +3820,13 @@ Size: 1, 2 Tiles: 0: Cliff - LeftColor: AABDD5 - RightColor: 90A7BC + MinColor: AABDD5 + MaxColor: 90A7BC ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: B6CADC - RightColor: 9BAEC7 + MinColor: B6CADC + MaxColor: 9BAEC7 ZOffset: -12 ZRamp: 0 Template@194: @@ -3835,29 +3837,29 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8090A0 - RightColor: 7F8C98 + MinColor: 8090A0 + MaxColor: 7F8C98 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 9BB0C3 - RightColor: 95ABBF + MinColor: 9BB0C3 + MaxColor: 95ABBF ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: A7BDD3 - RightColor: 98A9BE + MinColor: A7BDD3 + MaxColor: 98A9BE ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 8DA0B2 - RightColor: 778594 + MinColor: 8DA0B2 + MaxColor: 778594 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 92A6BE - RightColor: 9DB5CE + MinColor: 92A6BE + MaxColor: 9DB5CE ZOffset: -12 ZRamp: 0 Template@195: @@ -3867,28 +3869,28 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: C0DBF2 - RightColor: A3B8C7 + MinColor: C0DBF2 + MaxColor: A3B8C7 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 99ADBA - RightColor: 9AAEBB + MinColor: 99ADBA + MaxColor: 9AAEBB ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 97ABB8 - RightColor: 86949B + MinColor: 97ABB8 + MaxColor: 86949B ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: C3DCF0 - RightColor: A9BECE + MinColor: C3DCF0 + MaxColor: A9BECE ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: ACC5D9 - RightColor: 98B0C0 + MinColor: ACC5D9 + MaxColor: 98B0C0 ZOffset: -12 ZRamp: 0 Template@196: @@ -3898,23 +3900,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: B3CBDF - RightColor: 97A8B4 + MinColor: B3CBDF + MaxColor: 97A8B4 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9DADB7 - RightColor: 98A9B5 + MinColor: 9DADB7 + MaxColor: 98A9B5 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: C5DDF1 - RightColor: BAD0E2 + MinColor: C5DDF1 + MaxColor: BAD0E2 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: BCD2E4 - RightColor: 95A5AF + MinColor: BCD2E4 + MaxColor: 95A5AF ZOffset: -12 ZRamp: 0 Template@197: @@ -3924,23 +3926,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: B4CEE6 - RightColor: 9BAEBA + MinColor: B4CEE6 + MaxColor: 9BAEBA ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9CAEBB - RightColor: B5CDE0 + MinColor: 9CAEBB + MaxColor: B5CDE0 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: C2DCF1 - RightColor: B7CFE7 + MinColor: C2DCF1 + MaxColor: B7CFE7 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9BADB9 - RightColor: ABC0D3 + MinColor: 9BADB9 + MaxColor: ABC0D3 ZOffset: -12 ZRamp: 0 Template@198: @@ -3950,18 +3952,18 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: A7BECF - RightColor: 98ADBC + MinColor: A7BECF + MaxColor: 98ADBC ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A4BACB - RightColor: B3CCE1 + MinColor: A4BACB + MaxColor: B3CCE1 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: AAC3D6 - RightColor: BBCFE0 + MinColor: AAC3D6 + MaxColor: BBCFE0 ZOffset: -12 ZRamp: 0 Template@199: @@ -3971,23 +3973,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 94A3AC - RightColor: 9AA8B2 + MinColor: 94A3AC + MaxColor: 9AA8B2 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A0B2C1 - RightColor: B7CFE1 + MinColor: A0B2C1 + MaxColor: B7CFE1 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: ADC4D7 - RightColor: 98AAB5 + MinColor: ADC4D7 + MaxColor: 98AAB5 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: BCD5E7 - RightColor: BCD5EA + MinColor: BCD5E7 + MaxColor: BCD5EA ZOffset: -12 ZRamp: 0 Template@200: @@ -3997,28 +3999,28 @@ Size: 3, 2 Tiles: 1: DirtRoad - LeftColor: 98ADBE - RightColor: 99AAB7 + MinColor: 98ADBE + MaxColor: 99AAB7 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9FB4C2 - RightColor: B4CDE2 + MinColor: 9FB4C2 + MaxColor: B4CDE2 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: C2DDF2 - RightColor: B1CADE + MinColor: C2DDF2 + MaxColor: B1CADE ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: ACC5DB - RightColor: 92A8B7 + MinColor: ACC5DB + MaxColor: 92A8B7 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A3BCD0 - RightColor: A2BCD2 + MinColor: A3BCD0 + MaxColor: A2BCD2 ZOffset: -12 ZRamp: 0 Template@201: @@ -4028,28 +4030,28 @@ Size: 2, 3 Tiles: 0: DirtRoad - LeftColor: B8CFE1 - RightColor: B0C6DA + MinColor: B8CFE1 + MaxColor: B0C6DA ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9DB0BE - RightColor: 8A9CA6 + MinColor: 9DB0BE + MaxColor: 8A9CA6 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: C0D9ED - RightColor: B3CBDF + MinColor: C0D9ED + MaxColor: B3CBDF ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 93A6B2 - RightColor: 99ACBA + MinColor: 93A6B2 + MaxColor: 99ACBA ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: C4DDF1 - RightColor: ABC0CE + MinColor: C4DDF1 + MaxColor: ABC0CE ZOffset: -12 ZRamp: 0 Template@202: @@ -4059,23 +4061,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: BAD3E9 - RightColor: B3CADD + MinColor: BAD3E9 + MaxColor: B3CADD ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8D9EAA - RightColor: 83929A + MinColor: 8D9EAA + MaxColor: 83929A ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: B9D4EE - RightColor: AEC6DA + MinColor: B9D4EE + MaxColor: AEC6DA ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 97A8B4 - RightColor: 8698A1 + MinColor: 97A8B4 + MaxColor: 8698A1 ZOffset: -12 ZRamp: 0 Template@203: @@ -4085,23 +4087,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: BAD3EA - RightColor: A9BFD3 + MinColor: BAD3EA + MaxColor: A9BFD3 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8C9DA7 - RightColor: 89979F + MinColor: 8C9DA7 + MaxColor: 89979F ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: B5CCDE - RightColor: 9AAEBC + MinColor: B5CCDE + MaxColor: 9AAEBC ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9AABB6 - RightColor: A0B3BF + MinColor: 9AABB6 + MaxColor: A0B3BF ZOffset: -12 ZRamp: 0 Template@204: @@ -4111,23 +4113,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 99ABB7 - RightColor: AABFD0 + MinColor: 99ABB7 + MaxColor: AABFD0 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 899BA5 - RightColor: 859399 + MinColor: 899BA5 + MaxColor: 859399 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: ABC4DA - RightColor: 9DB1BE + MinColor: ABC4DA + MaxColor: 9DB1BE ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: BAD3E6 - RightColor: ABBFCD + MinColor: BAD3E6 + MaxColor: ABBFCD ZOffset: -12 ZRamp: 0 Template@205: @@ -4137,28 +4139,28 @@ Size: 3, 2 Tiles: 1: DirtRoad - LeftColor: 9BAEBB - RightColor: A9BECE + MinColor: 9BAEBB + MaxColor: A9BECE ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 8C99A0 - RightColor: 849097 + MinColor: 8C99A0 + MaxColor: 849097 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: B8D1EA - RightColor: ABBFD1 + MinColor: B8D1EA + MaxColor: ABBFD1 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B3CADB - RightColor: 9EB2C0 + MinColor: B3CADB + MaxColor: 9EB2C0 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B2C9DA - RightColor: A4BAC8 + MinColor: B2C9DA + MaxColor: A4BAC8 ZOffset: -12 ZRamp: 0 Template@206: @@ -4168,28 +4170,28 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: BCD6EE - RightColor: A1B4C4 + MinColor: BCD6EE + MaxColor: A1B4C4 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A0B4C3 - RightColor: 9CAEBC + MinColor: A0B4C3 + MaxColor: 9CAEBC ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: A6B7C5 - RightColor: 8B99A1 + MinColor: A6B7C5 + MaxColor: 8B99A1 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: C1DBEF - RightColor: ABC1D1 + MinColor: C1DBEF + MaxColor: ABC1D1 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: BCD5E9 - RightColor: B2CADD + MinColor: BCD5E9 + MaxColor: B2CADD ZOffset: -12 ZRamp: 0 Template@207: @@ -4199,33 +4201,33 @@ Size: 2, 3 Tiles: 0: DirtRoad - LeftColor: ADC7DE - RightColor: AEC6DA + MinColor: ADC7DE + MaxColor: AEC6DA ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 99AEBD - RightColor: ADC5DA + MinColor: 99AEBD + MaxColor: ADC5DA ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: B4CBDC - RightColor: 95ABB8 + MinColor: B4CBDC + MaxColor: 95ABB8 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9BADB9 - RightColor: 99ACB7 + MinColor: 9BADB9 + MaxColor: 99ACB7 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: C3DDF1 - RightColor: B3CADD + MinColor: C3DDF1 + MaxColor: B3CADD ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 9DB0BC - RightColor: 9EB1BE + MinColor: 9DB0BC + MaxColor: 9EB1BE ZOffset: -12 ZRamp: 0 Template@208: @@ -4235,23 +4237,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: B5CDE4 - RightColor: B5CFE8 + MinColor: B5CDE4 + MaxColor: B5CFE8 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9FB2BF - RightColor: ADC4D8 + MinColor: 9FB2BF + MaxColor: ADC4D8 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: ADC4D5 - RightColor: 94A7B5 + MinColor: ADC4D5 + MaxColor: 94A7B5 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 98ACBB - RightColor: 94A8B5 + MinColor: 98ACBB + MaxColor: 94A8B5 ZOffset: -12 ZRamp: 0 Template@209: @@ -4261,18 +4263,18 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 9EB2C1 - RightColor: B1C9DB + MinColor: 9EB2C1 + MaxColor: B1C9DB ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 90A3AF - RightColor: A4BDD3 + MinColor: 90A3AF + MaxColor: A4BDD3 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9CAFBB - RightColor: 9DAFBB + MinColor: 9CAFBB + MaxColor: 9DAFBB ZOffset: -12 ZRamp: 0 Template@210: @@ -4282,18 +4284,18 @@ Size: 2, 2 Tiles: 1: DirtRoad - LeftColor: A2B6C6 - RightColor: AEC6DA + MinColor: A2B6C6 + MaxColor: AEC6DA ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: BAD5EE - RightColor: B3CBDF + MinColor: BAD5EE + MaxColor: B3CBDF ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: B4CCDE - RightColor: 99ACB8 + MinColor: B4CCDE + MaxColor: 99ACB8 ZOffset: -12 ZRamp: 0 Template@211: @@ -4303,33 +4305,33 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: B4CCDF - RightColor: B0C8DD + MinColor: B4CCDF + MaxColor: B0C8DD ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 97AAB9 - RightColor: B3CBE2 + MinColor: 97AAB9 + MaxColor: B3CBE2 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: B6CBDD - RightColor: BDD6ED + MinColor: B6CBDD + MaxColor: BDD6ED ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: ACC2D4 - RightColor: 96A9B5 + MinColor: ACC2D4 + MaxColor: 96A9B5 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: A3B6C4 - RightColor: 95A7B4 + MinColor: A3B6C4 + MaxColor: 95A7B4 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 899BA4 - RightColor: 98A9B6 + MinColor: 899BA4 + MaxColor: 98A9B6 ZOffset: -12 ZRamp: 0 Template@212: @@ -4339,18 +4341,18 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: A2B5C3 - RightColor: B1C6D9 + MinColor: A2B5C3 + MaxColor: B1C6D9 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: AABECF - RightColor: BFDAF2 + MinColor: AABECF + MaxColor: BFDAF2 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8D9BA4 - RightColor: 98AAB8 + MinColor: 8D9BA4 + MaxColor: 98AAB8 ZOffset: -12 ZRamp: 0 Template@213: @@ -4360,23 +4362,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 8898A3 - RightColor: B1C9DE + MinColor: 8898A3 + MaxColor: B1C9DE ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: B4CBE1 - RightColor: BDD6ED + MinColor: B4CBE1 + MaxColor: BDD6ED ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: BECEDC - RightColor: 92A4AF + MinColor: BECEDC + MaxColor: 92A4AF ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 84939B - RightColor: 92A4B1 + MinColor: 84939B + MaxColor: 92A4B1 ZOffset: -12 ZRamp: 0 Template@214: @@ -4386,28 +4388,28 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: A7BDCE - RightColor: A9C1D4 + MinColor: A7BDCE + MaxColor: A9C1D4 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 91A3B0 - RightColor: ACC4D8 + MinColor: 91A3B0 + MaxColor: ACC4D8 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: B7CFE2 - RightColor: BDD7EC + MinColor: B7CFE2 + MaxColor: BDD7EC ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 93A5B1 - RightColor: 829199 + MinColor: 93A5B1 + MaxColor: 829199 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 9FB3C1 - RightColor: B6D0EA + MinColor: 9FB3C1 + MaxColor: B6D0EA ZOffset: -12 ZRamp: 0 Template@215: @@ -4417,23 +4419,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 9FB2BF - RightColor: B6CDE0 + MinColor: 9FB2BF + MaxColor: B6CDE0 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: BAD2E6 - RightColor: BFDAF2 + MinColor: BAD2E6 + MaxColor: BFDAF2 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: A7BCCC - RightColor: 8C9BA4 + MinColor: A7BCCC + MaxColor: 8C9BA4 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 94A7B2 - RightColor: B5CCDD + MinColor: 94A7B2 + MaxColor: B5CCDD ZOffset: -12 ZRamp: 0 Template@216: @@ -4443,18 +4445,18 @@ Size: 2, 2 Tiles: 1: DirtRoad - LeftColor: A7BED1 - RightColor: BDD8F1 + MinColor: A7BED1 + MaxColor: BDD8F1 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: BCD5E7 - RightColor: 9DB0BD + MinColor: BCD5E7 + MaxColor: 9DB0BD ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 96A7B2 - RightColor: ADC4D6 + MinColor: 96A7B2 + MaxColor: ADC4D6 ZOffset: -12 ZRamp: 0 Template@217: @@ -4464,23 +4466,23 @@ Size: 2, 3 Tiles: 1: DirtRoad - LeftColor: ABC1D5 - RightColor: C0DBF2 + MinColor: ABC1D5 + MaxColor: C0DBF2 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9EB4C4 - RightColor: 9AADBA + MinColor: 9EB4C4 + MaxColor: 9AADBA ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9CAEBB - RightColor: ABC1D1 + MinColor: 9CAEBB + MaxColor: ABC1D1 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B1C6D7 - RightColor: B3CADE + MinColor: B1C6D7 + MaxColor: B3CADE ZOffset: -12 ZRamp: 0 Template@218: @@ -4490,28 +4492,28 @@ Size: 2, 3 Tiles: 1: DirtRoad - LeftColor: AABFD1 - RightColor: BFDAF2 + MinColor: AABFD1 + MaxColor: BFDAF2 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 97A9B6 - RightColor: 98ACBA + MinColor: 97A9B6 + MaxColor: 98ACBA ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8C9FAB - RightColor: A4BCD2 + MinColor: 8C9FAB + MaxColor: A4BCD2 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: AEC7DD - RightColor: 99ADBA + MinColor: AEC7DD + MaxColor: 99ADBA ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B8D1E6 - RightColor: B6D0E7 + MinColor: B8D1E6 + MaxColor: B6D0E7 ZOffset: -12 ZRamp: 0 Template@219: @@ -4521,23 +4523,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: A1B8CA - RightColor: 97AAB7 + MinColor: A1B8CA + MaxColor: 97AAB7 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 90A2AD - RightColor: 8EA1AE + MinColor: 90A2AD + MaxColor: 8EA1AE ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: A9BED0 - RightColor: 8B9EAA + MinColor: A9BED0 + MaxColor: 8B9EAA ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 98ABB7 - RightColor: 8EA0AC + MinColor: 98ABB7 + MaxColor: 8EA0AC ZOffset: -12 ZRamp: 0 Template@220: @@ -4547,23 +4549,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: AAC0D2 - RightColor: BDD6EC + MinColor: AAC0D2 + MaxColor: BDD6EC ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A4BCD1 - RightColor: AAC1D5 + MinColor: A4BCD1 + MaxColor: AAC1D5 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9CB1BE - RightColor: A1B7C8 + MinColor: 9CB1BE + MaxColor: A1B7C8 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: B3C9DC - RightColor: A8BFD0 + MinColor: B3C9DC + MaxColor: A8BFD0 ZOffset: -12 ZRamp: 0 Template@221: @@ -4573,23 +4575,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 99ACBA - RightColor: 9FB1BF + MinColor: 99ACBA + MaxColor: 9FB1BF ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A6B9C7 - RightColor: B1C7DA + MinColor: A6B9C7 + MaxColor: B1C7DA ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9DAFBC - RightColor: 8D9CA4 + MinColor: 9DAFBC + MaxColor: 8D9CA4 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: A2B6C4 - RightColor: AEC5D7 + MinColor: A2B6C4 + MaxColor: AEC5D7 ZOffset: -12 ZRamp: 0 Template@222: @@ -4599,23 +4601,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 99A9B3 - RightColor: 95A2AA + MinColor: 99A9B3 + MaxColor: 95A2AA ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 99A8B2 - RightColor: 95A9B7 + MinColor: 99A8B2 + MaxColor: 95A9B7 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: B2C9DA - RightColor: 98AAB6 + MinColor: B2C9DA + MaxColor: 98AAB6 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: ABC0D2 - RightColor: 95A7B2 + MinColor: ABC0D2 + MaxColor: 95A7B2 ZOffset: -12 ZRamp: 0 Template@223: @@ -4625,23 +4627,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 91A3AF - RightColor: 909FA8 + MinColor: 91A3AF + MaxColor: 909FA8 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 889BA7 - RightColor: 98ACBB + MinColor: 889BA7 + MaxColor: 98ACBB ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9DB1BF - RightColor: 8699A4 + MinColor: 9DB1BF + MaxColor: 8699A4 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 93A8B7 - RightColor: 8DA2AD + MinColor: 93A8B7 + MaxColor: 8DA2AD ZOffset: -12 ZRamp: 0 Template@224: @@ -4651,38 +4653,38 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: B2C8DA - RightColor: A6BCCE + MinColor: B2C8DA + MaxColor: A6BCCE ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 879299 - RightColor: 848F93 + MinColor: 879299 + MaxColor: 848F93 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 98ABB8 - RightColor: A7BDCD + MinColor: 98ABB8 + MaxColor: A7BDCD ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8D9DA7 - RightColor: 94A4AE + MinColor: 8D9DA7 + MaxColor: 94A4AE ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 95A4AE - RightColor: 9AABB8 + MinColor: 95A4AE + MaxColor: 9AABB8 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 99AEBD - RightColor: 8E9FAA + MinColor: 99AEBD + MaxColor: 8E9FAA ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 8A9BA5 - RightColor: 8F9EA7 + MinColor: 8A9BA5 + MaxColor: 8F9EA7 ZOffset: -12 ZRamp: 0 Template@225: @@ -4692,33 +4694,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: ACC3D7 - RightColor: C0DBF2 + MinColor: ACC3D7 + MaxColor: C0DBF2 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: A2B7C5 - RightColor: 92A6B4 + MinColor: A2B7C5 + MaxColor: 92A6B4 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8499A5 - RightColor: 8FA2AD + MinColor: 8499A5 + MaxColor: 8FA2AD ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B0C7D7 - RightColor: C1DBF1 + MinColor: B0C7D7 + MaxColor: C1DBF1 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A6BCCC - RightColor: 98ACB9 + MinColor: A6BCCC + MaxColor: 98ACB9 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 95A8B5 - RightColor: 96A8B5 + MinColor: 95A8B5 + MaxColor: 96A8B5 ZOffset: -12 ZRamp: 0 Template@226: @@ -4728,33 +4730,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 8FA3B1 - RightColor: AAC3D6 + MinColor: 8FA3B1 + MaxColor: AAC3D6 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 99AAB5 - RightColor: 8E9FA9 + MinColor: 99AAB5 + MaxColor: 8E9FA9 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9BAFBD - RightColor: 8C9CA6 + MinColor: 9BAFBD + MaxColor: 8C9CA6 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: A1B5C3 - RightColor: A4BBCB + MinColor: A1B5C3 + MaxColor: A4BBCB ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: BCD5E9 - RightColor: B5CEE2 + MinColor: BCD5E9 + MaxColor: B5CEE2 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A7BBCB - RightColor: AEC3D5 + MinColor: A7BBCB + MaxColor: AEC3D5 ZOffset: -12 ZRamp: 0 Template@227: @@ -4764,38 +4766,38 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 8B9EAB - RightColor: A5BDCF + MinColor: 8B9EAB + MaxColor: A5BDCF ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 98A9B4 - RightColor: 8E9FA9 + MinColor: 98A9B4 + MaxColor: 8E9FA9 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: C2DDF2 - RightColor: B9D1E5 + MinColor: C2DDF2 + MaxColor: B9D1E5 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 9DB0BE - RightColor: 83959E + MinColor: 9DB0BE + MaxColor: 83959E ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 97ADBA - RightColor: B0C9DC + MinColor: 97ADBA + MaxColor: B0C9DC ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: C0DBF2 - RightColor: B6CEE1 + MinColor: C0DBF2 + MaxColor: B6CEE1 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 8FA4B0 - RightColor: 91A6B3 + MinColor: 8FA4B0 + MaxColor: 91A6B3 ZOffset: -12 ZRamp: 0 Template@228: @@ -4805,38 +4807,38 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 93A8B6 - RightColor: A4B9CA + MinColor: 93A8B6 + MaxColor: A4B9CA ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 88949B - RightColor: 86959C + MinColor: 88949B + MaxColor: 86959C ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 98ABBA - RightColor: 96A8B4 + MinColor: 98ABBA + MaxColor: 96A8B4 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8A9BA4 - RightColor: 7D8E97 + MinColor: 8A9BA4 + MaxColor: 7D8E97 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 90A0AA - RightColor: 95A5B0 + MinColor: 90A0AA + MaxColor: 95A5B0 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 98ACBA - RightColor: 8D9FAA + MinColor: 98ACBA + MaxColor: 8D9FAA ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 8C9FAA - RightColor: 8D9FAB + MinColor: 8C9FAA + MaxColor: 8D9FAB ZOffset: -12 ZRamp: 0 Template@229: @@ -4846,68 +4848,68 @@ Size: 4, 4 Tiles: 2: DirtRoad - LeftColor: AFC5DA - RightColor: A4B9CB + MinColor: AFC5DA + MaxColor: A4B9CB ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 92A2AD - RightColor: 93A3AD + MinColor: 92A2AD + MaxColor: 93A3AD ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A1B6C3 - RightColor: 99AFBF + MinColor: A1B6C3 + MaxColor: 99AFBF ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 88979F - RightColor: 8E9FAA + MinColor: 88979F + MaxColor: 8E9FAA ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A0B4C2 - RightColor: A6BBC9 + MinColor: A0B4C2 + MaxColor: A6BBC9 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 899CA8 - RightColor: 9FB6C7 + MinColor: 899CA8 + MaxColor: 9FB6C7 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 85939B - RightColor: 818F97 + MinColor: 85939B + MaxColor: 818F97 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 809099 - RightColor: 909CA4 + MinColor: 809099 + MaxColor: 909CA4 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 97A9B5 - RightColor: 9EAFBD + MinColor: 97A9B5 + MaxColor: 9EAFBD ZOffset: -12 ZRamp: 0 12: DirtRoad - LeftColor: B4C9DA - RightColor: 95A7B4 + MinColor: B4C9DA + MaxColor: 95A7B4 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: A5BACB - RightColor: 899BA5 + MinColor: A5BACB + MaxColor: 899BA5 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: A8BED2 - RightColor: 8C9CA6 + MinColor: A8BED2 + MaxColor: 8C9CA6 ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: A2B6C5 - RightColor: 8F9FA8 + MinColor: A2B6C5 + MaxColor: 8F9FA8 ZOffset: -12 ZRamp: 0 Template@230: @@ -4917,48 +4919,48 @@ Size: 4, 4 Tiles: 2: DirtRoad - LeftColor: A1B8C9 - RightColor: A8BDCE + MinColor: A1B8C9 + MaxColor: A8BDCE ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 89959C - RightColor: 87959C + MinColor: 89959C + MaxColor: 87959C ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: ADC4D9 - RightColor: A6BED4 + MinColor: ADC4D9 + MaxColor: A6BED4 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 929FA9 - RightColor: 88959E + MinColor: 929FA9 + MaxColor: 88959E ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: AEC2D3 - RightColor: A5B8C7 + MinColor: AEC2D3 + MaxColor: A5B8C7 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 9CAFBB - RightColor: A6BCCE + MinColor: 9CAFBB + MaxColor: A6BCCE ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 8FA0AB - RightColor: 849299 + MinColor: 8FA0AB + MaxColor: 849299 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: A5B7C3 - RightColor: AABCC9 + MinColor: A5B7C3 + MaxColor: AABCC9 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 96ABBC - RightColor: 9BB1C5 + MinColor: 96ABBC + MaxColor: 9BB1C5 ZOffset: -12 ZRamp: 0 Template@231: @@ -4968,48 +4970,48 @@ Size: 4, 4 Tiles: 2: DirtRoad - LeftColor: A2B7C7 - RightColor: A7B9C8 + MinColor: A2B7C7 + MaxColor: A7B9C8 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8697A0 - RightColor: 8A979F + MinColor: 8697A0 + MaxColor: 8A979F ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A4B8C6 - RightColor: 9BB0BF + MinColor: A4B8C6 + MaxColor: 9BB0BF ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 909EA7 - RightColor: 8A98A0 + MinColor: 909EA7 + MaxColor: 8A98A0 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 9DB3C1 - RightColor: 9FB2BF + MinColor: 9DB3C1 + MaxColor: 9FB2BF ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 95A8B6 - RightColor: A3B9CC + MinColor: 95A8B6 + MaxColor: A3B9CC ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 86949B - RightColor: 87949B + MinColor: 86949B + MaxColor: 87949B ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 9BAFC0 - RightColor: A3B7C3 + MinColor: 9BAFC0 + MaxColor: A3B7C3 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: A0B4C4 - RightColor: A2B8CA + MinColor: A0B4C4 + MaxColor: A2B8CA ZOffset: -12 ZRamp: 0 Template@232: @@ -5019,48 +5021,48 @@ Size: 4, 4 Tiles: 2: DirtRoad - LeftColor: B4CBE0 - RightColor: A6BCCE + MinColor: B4CBE0 + MaxColor: A6BCCE ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 94A6B1 - RightColor: 90A0AA + MinColor: 94A6B1 + MaxColor: 90A0AA ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B6CFE2 - RightColor: B7D0E6 + MinColor: B6CFE2 + MaxColor: B7D0E6 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: A6BBC9 - RightColor: A8BECF + MinColor: A6BBC9 + MaxColor: A8BECF ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: B1CAE0 - RightColor: B0C8D9 + MinColor: B1CAE0 + MaxColor: B0C8D9 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 9DB1BF - RightColor: ABC3D7 + MinColor: 9DB1BF + MaxColor: ABC3D7 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: A7BCCC - RightColor: AFC6D9 + MinColor: A7BCCC + MaxColor: AFC6D9 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: AFC8DE - RightColor: AFC8DD + MinColor: AFC8DE + MaxColor: AFC8DD ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 9DAFBC - RightColor: A6BCCB + MinColor: 9DAFBC + MaxColor: A6BCCB ZOffset: -12 ZRamp: 0 Template@233: @@ -5070,63 +5072,63 @@ Size: 4, 4 Tiles: 0: Clear - LeftColor: B8D1E8 - RightColor: B9D2EB + MinColor: B8D1E8 + MaxColor: B9D2EB ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: A4BCD0 - RightColor: A4BDD3 + MinColor: A4BCD0 + MaxColor: A4BDD3 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 91A2AC - RightColor: 97ACBC + MinColor: 91A2AC + MaxColor: 97ACBC ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8D9DA6 - RightColor: 8C9AA1 + MinColor: 8D9DA6 + MaxColor: 8C9AA1 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: B9D3E6 - RightColor: B4CEE3 + MinColor: B9D3E6 + MaxColor: B4CEE3 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 899BA6 - RightColor: 8B9BA4 + MinColor: 899BA6 + MaxColor: 8B9BA4 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 899AA4 - RightColor: 8697A1 + MinColor: 899AA4 + MaxColor: 8697A1 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A4BACC - RightColor: A6BACB + MinColor: A4BACC + MaxColor: A6BACB ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 99AAB7 - RightColor: 9FB2C0 + MinColor: 99AAB7 + MaxColor: 9FB2C0 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 89979E - RightColor: 81929A + MinColor: 89979E + MaxColor: 81929A ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: A5BAC9 - RightColor: B6CCDE + MinColor: A5BAC9 + MaxColor: B6CCDE ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 9BB0C1 - RightColor: A3B8C6 + MinColor: 9BB0C1 + MaxColor: A3B8C6 ZOffset: -12 ZRamp: 0 Template@234: @@ -5136,33 +5138,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: ADC4D8 - RightColor: A7BDCF + MinColor: ADC4D8 + MaxColor: A7BDCF ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 8FA1AB - RightColor: 8D9DA5 + MinColor: 8FA1AB + MaxColor: 8D9DA5 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9DB0BE - RightColor: A9C1D4 + MinColor: 9DB0BE + MaxColor: A9C1D4 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 9EB2C1 - RightColor: 9FB3C3 + MinColor: 9EB2C1 + MaxColor: 9FB3C3 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B0C7DC - RightColor: ACC2D3 + MinColor: B0C7DC + MaxColor: ACC2D3 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 9BAEBC - RightColor: A2B9CA + MinColor: 9BAEBC + MaxColor: A2B9CA ZOffset: -12 ZRamp: 0 Template@235: @@ -5172,18 +5174,18 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: A7B8C4 - RightColor: AABDCC + MinColor: A7B8C4 + MaxColor: AABDCC ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 91A0A9 - RightColor: 879297 + MinColor: 91A0A9 + MaxColor: 879297 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9CAFBC - RightColor: A3B7C7 + MinColor: 9CAFBC + MaxColor: A3B7C7 ZOffset: -12 ZRamp: 0 Template@236: @@ -5193,18 +5195,18 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: A4B4C0 - RightColor: AABDCE + MinColor: A4B4C0 + MaxColor: AABDCE ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 96A3AB - RightColor: 838E93 + MinColor: 96A3AB + MaxColor: 838E93 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: A0B2BE - RightColor: A6B9C8 + MinColor: A0B2BE + MaxColor: A6B9C8 ZOffset: -12 ZRamp: 0 Template@237: @@ -5214,43 +5216,43 @@ Size: 4, 4 Tiles: 2: Clear - LeftColor: BFD6E9 - RightColor: BED7ED + MinColor: BFD6E9 + MaxColor: BED7ED ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B5CBDB - RightColor: BDD5EA + MinColor: B5CBDB + MaxColor: BDD5EA ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: AFC7DC - RightColor: AFC6DA + MinColor: AFC7DC + MaxColor: AFC6DA ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: A9C1D7 - RightColor: B0CBE6 + MinColor: A9C1D7 + MaxColor: B0CBE6 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 97ACBB - RightColor: A6BACB + MinColor: 97ACBB + MaxColor: A6BACB ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 93A1A9 - RightColor: ACBECE + MinColor: 93A1A9 + MaxColor: ACBECE ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: BFD5E8 - RightColor: C0D4E5 + MinColor: BFD5E8 + MaxColor: C0D4E5 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 9DAEB9 - RightColor: A4B7C3 + MinColor: 9DAEB9 + MaxColor: A4B7C3 ZOffset: -12 ZRamp: 0 Template@238: @@ -5260,48 +5262,48 @@ Size: 4, 3 Tiles: 1: Clear - LeftColor: C2DBEE - RightColor: C0DAF0 + MinColor: C2DBEE + MaxColor: C0DAF0 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: A5BCCF - RightColor: B3CCE2 + MinColor: A5BCCF + MaxColor: B3CCE2 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: ACC3D9 - RightColor: ACC6E3 + MinColor: ACC3D9 + MaxColor: ACC6E3 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: ADC1D1 - RightColor: B5CEE2 + MinColor: ADC1D1 + MaxColor: B5CEE2 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 9FB1BE - RightColor: 9EB4C5 + MinColor: 9FB1BE + MaxColor: 9EB4C5 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: A0B1BE - RightColor: A6BBCE + MinColor: A0B1BE + MaxColor: A6BBCE ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: ACC2D3 - RightColor: B3C8D9 + MinColor: ACC2D3 + MaxColor: B3C8D9 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 9FB3BF - RightColor: A1B2BE + MinColor: 9FB3BF + MaxColor: A1B2BE ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: BFD9ED - RightColor: B9D2EA + MinColor: BFD9ED + MaxColor: B9D2EA ZOffset: -12 ZRamp: 0 Template@239: @@ -5311,33 +5313,33 @@ Size: 3, 3 Tiles: 1: Clear - LeftColor: AEC5D6 - RightColor: B5CEE4 + MinColor: AEC5D6 + MaxColor: B5CEE4 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: AEC4D6 - RightColor: B4CDE7 + MinColor: AEC4D6 + MaxColor: B4CDE7 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 95A8B5 - RightColor: A3BACB + MinColor: 95A8B5 + MaxColor: A3BACB ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 92A4B0 - RightColor: 9DB2C2 + MinColor: 92A4B0 + MaxColor: 9DB2C2 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: B2C9DF - RightColor: C0D7E9 + MinColor: B2C9DF + MaxColor: C0D7E9 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 9CB1C2 - RightColor: A3BCCF + MinColor: 9CB1C2 + MaxColor: A3BCCF ZOffset: -12 ZRamp: 0 Template@240: @@ -5347,48 +5349,48 @@ Size: 4, 4 Tiles: 2: DirtRoad - LeftColor: AEC4D8 - RightColor: ABBFD1 + MinColor: AEC4D8 + MaxColor: ABBFD1 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9DB0BF - RightColor: 90A0AB + MinColor: 9DB0BF + MaxColor: 90A0AB ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: BCD5E9 - RightColor: B8D0E5 + MinColor: BCD5E9 + MaxColor: B8D0E5 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: ABC2D5 - RightColor: A8BDCD + MinColor: ABC2D5 + MaxColor: A8BDCD ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: ABC2D6 - RightColor: A2B8CA + MinColor: ABC2D6 + MaxColor: A2B8CA ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: BBD4E9 - RightColor: B4CCE1 + MinColor: BBD4E9 + MaxColor: B4CCE1 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: A2B6C7 - RightColor: ABBFCF + MinColor: A2B6C7 + MaxColor: ABBFCF ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: ADC3D4 - RightColor: B4CDE0 + MinColor: ADC3D4 + MaxColor: B4CDE0 ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: B7D1E9 - RightColor: B1C9DC + MinColor: B7D1E9 + MaxColor: B1C9DC ZOffset: -12 ZRamp: 0 Template@241: @@ -5398,48 +5400,48 @@ Size: 3, 4 Tiles: 1: DirtRoad - LeftColor: B3CBE3 - RightColor: AFC5DA + MinColor: B3CBE3 + MaxColor: AFC5DA ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: A4B5C2 - RightColor: 94A1A9 + MinColor: A4B5C2 + MaxColor: 94A1A9 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: BBD5EE - RightColor: BAD2E9 + MinColor: BBD5EE + MaxColor: BAD2E9 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: B1C7DA - RightColor: AFC4D6 + MinColor: B1C7DA + MaxColor: AFC4D6 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B3C9DD - RightColor: AEC3D5 + MinColor: B3C9DD + MaxColor: AEC3D5 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: BDD1E6 - RightColor: B3C8DB + MinColor: BDD1E6 + MaxColor: B3C8DB ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: B8CEE2 - RightColor: BAD0E5 + MinColor: B8CEE2 + MaxColor: BAD0E5 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: C4DDF1 - RightColor: BED6EA + MinColor: C4DDF1 + MaxColor: BED6EA ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: C1DBF0 - RightColor: BCD6ED + MinColor: C1DBF0 + MaxColor: BCD6ED ZOffset: -12 ZRamp: 0 Template@242: @@ -5449,33 +5451,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: B7CCDD - RightColor: B2C7D9 + MinColor: B7CCDD + MaxColor: B2C7D9 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: A1AFBA - RightColor: 859095 + MinColor: A1AFBA + MaxColor: 859095 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: BCD4E9 - RightColor: B8CFE5 + MinColor: BCD4E9 + MaxColor: B8CFE5 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: ADC1D4 - RightColor: 9DADB8 + MinColor: ADC1D4 + MaxColor: 9DADB8 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A2B6C7 - RightColor: A5B8C9 + MinColor: A2B6C7 + MaxColor: A5B8C9 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: B7D1EB - RightColor: B4CBDE + MinColor: B7D1EB + MaxColor: B4CBDE ZOffset: -12 ZRamp: 0 Template@243: @@ -5485,53 +5487,53 @@ Size: 5, 3 Tiles: 1: DirtRoad - LeftColor: AAC6DF - RightColor: B4CFE8 + MinColor: AAC6DF + MaxColor: B4CFE8 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 96ABBB - RightColor: ACC6DB + MinColor: 96ABBB + MaxColor: ACC6DB ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 91A6B2 - RightColor: 8CA1AE + MinColor: 91A6B2 + MaxColor: 8CA1AE ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 85949C - RightColor: 88959D + MinColor: 85949C + MaxColor: 88959D ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 9FB1BF - RightColor: A9C2D4 + MinColor: 9FB1BF + MaxColor: A9C2D4 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 8999A2 - RightColor: 7D8E97 + MinColor: 8999A2 + MaxColor: 7D8E97 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A1B5C4 - RightColor: 8D9FA9 + MinColor: A1B5C4 + MaxColor: 8D9FA9 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: A2BACA - RightColor: 9DAFBB + MinColor: A2BACA + MaxColor: 9DAFBB ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: B6CEE5 - RightColor: A2BACD + MinColor: B6CEE5 + MaxColor: A2BACD ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 9CAFBB - RightColor: 9FAFB9 + MinColor: 9CAFBB + MaxColor: 9FAFB9 ZOffset: -12 ZRamp: 0 Template@244: @@ -5541,53 +5543,53 @@ Size: 3, 5 Tiles: 1: DirtRoad - LeftColor: A8BFD0 - RightColor: A0B6C8 + MinColor: A8BFD0 + MaxColor: A0B6C8 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 8C9BA4 - RightColor: 869298 + MinColor: 8C9BA4 + MaxColor: 869298 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: ADC6DC - RightColor: A7BED1 + MinColor: ADC6DC + MaxColor: A7BED1 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 88979F - RightColor: 8C9BA3 + MinColor: 88979F + MaxColor: 8C9BA3 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A7BCCB - RightColor: 9EB3BF + MinColor: A7BCCB + MaxColor: 9EB3BF ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: B4CBE1 - RightColor: A8B9C7 + MinColor: B4CBE1 + MaxColor: A8B9C7 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A8B7C2 - RightColor: AABCC9 + MinColor: A8B7C2 + MaxColor: AABCC9 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 9AADBA - RightColor: A6B7C4 + MinColor: 9AADBA + MaxColor: A6B7C4 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: B2C3D2 - RightColor: BFD3E7 + MinColor: B2C3D2 + MaxColor: BFD3E7 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: A3B8C6 - RightColor: BCD3E7 + MinColor: A3B8C6 + MaxColor: BCD3E7 ZOffset: -12 ZRamp: 0 Template@245: @@ -5597,33 +5599,33 @@ Size: 2, 4 Tiles: 1: Clear - LeftColor: B9D0E4 - RightColor: BCD5EA + MinColor: B9D0E4 + MaxColor: BCD5EA ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: B8CEE1 - RightColor: B6CCE0 + MinColor: B8CEE1 + MaxColor: B6CCE0 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: ADC4DA - RightColor: B5CDE3 + MinColor: ADC4DA + MaxColor: B5CDE3 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: B5C7D7 - RightColor: ACBECF + MinColor: B5C7D7 + MaxColor: ACBECF ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: B1C7DD - RightColor: B1CBE7 + MinColor: B1C7DD + MaxColor: B1CBE7 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: B8D1E9 - RightColor: BCD3E5 + MinColor: B8D1E9 + MaxColor: BCD3E5 ZOffset: -12 ZRamp: 0 Template@246: @@ -5633,43 +5635,43 @@ Size: 4, 2 Tiles: 0: DirtRoad - LeftColor: 9AACB8 - RightColor: B8CCDE + MinColor: 9AACB8 + MaxColor: B8CCDE ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: BBCFDF - RightColor: BBCFE1 + MinColor: BBCFDF + MaxColor: BBCFE1 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: C1D6E9 - RightColor: B9D3EB + MinColor: C1D6E9 + MaxColor: B9D3EB ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: A1B5C6 - RightColor: A7C0D7 + MinColor: A1B5C6 + MaxColor: A7C0D7 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: A7BED2 - RightColor: 98AAB5 + MinColor: A7BED2 + MaxColor: 98AAB5 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: AEC3D2 - RightColor: 99AAB6 + MinColor: AEC3D2 + MaxColor: 99AAB6 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: A7BCCD - RightColor: 95A5B1 + MinColor: A7BCCD + MaxColor: 95A5B1 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A7BBCC - RightColor: 92A2AD + MinColor: A7BBCC + MaxColor: 92A2AD ZOffset: -12 ZRamp: 0 Template@247: @@ -5679,43 +5681,43 @@ Size: 4, 2 Tiles: 0: DirtRoad - LeftColor: 96A8B5 - RightColor: A9BFCF + MinColor: 96A8B5 + MaxColor: A9BFCF ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 94A5B1 - RightColor: 91A3AF + MinColor: 94A5B1 + MaxColor: 91A3AF ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 92A3AD - RightColor: A0B2C0 + MinColor: 92A3AD + MaxColor: A0B2C0 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 91A3AE - RightColor: A9C1D5 + MinColor: 91A3AE + MaxColor: A9C1D5 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: AEC5D6 - RightColor: 9DAFBA + MinColor: AEC5D6 + MaxColor: 9DAFBA ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B9D2EB - RightColor: A9BECD + MinColor: B9D2EB + MaxColor: A9BECD ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: B7D1EA - RightColor: A8BDCD + MinColor: B7D1EA + MaxColor: A8BDCD ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: B7CFE1 - RightColor: 95A6B0 + MinColor: B7CFE1 + MaxColor: 95A6B0 ZOffset: -12 ZRamp: 0 Template@248: @@ -5725,43 +5727,43 @@ Size: 4, 2 Tiles: 0: DirtRoad - LeftColor: 8FA1AE - RightColor: AEC7DE + MinColor: 8FA1AE + MaxColor: AEC7DE ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9CB2C2 - RightColor: B1C9E0 + MinColor: 9CB2C2 + MaxColor: B1C9E0 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: AFC6DA - RightColor: B4CCE1 + MinColor: AFC6DA + MaxColor: B4CCE1 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 95A7B3 - RightColor: A8BFD2 + MinColor: 95A7B3 + MaxColor: A8BFD2 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: A1B6C6 - RightColor: 92A6B2 + MinColor: A1B6C6 + MaxColor: 92A6B2 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: AFC6D9 - RightColor: 9AAEBB + MinColor: AFC6D9 + MaxColor: 9AAEBB ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: B1C8DA - RightColor: 8EA4B1 + MinColor: B1C8DA + MaxColor: 8EA4B1 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A4BCCE - RightColor: 92A3AE + MinColor: A4BCCE + MaxColor: 92A3AE ZOffset: -12 ZRamp: 0 Template@249: @@ -5771,43 +5773,43 @@ Size: 4, 2 Tiles: 0: DirtRoad - LeftColor: 8E9FA9 - RightColor: A6BBCD + MinColor: 8E9FA9 + MaxColor: A6BBCD ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 92A4AF - RightColor: 9DB3C5 + MinColor: 92A4AF + MaxColor: 9DB3C5 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7C8E97 - RightColor: A7BED1 + MinColor: 7C8E97 + MaxColor: A7BED1 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 95A6B3 - RightColor: A8C0D3 + MinColor: 95A6B3 + MaxColor: A8C0D3 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B0C5D4 - RightColor: 8697A0 + MinColor: B0C5D4 + MaxColor: 8697A0 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A1B7C8 - RightColor: 8699A3 + MinColor: A1B7C8 + MaxColor: 8699A3 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: ABC3DA - RightColor: 899BA6 + MinColor: ABC3DA + MaxColor: 899BA6 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A7BDCF - RightColor: 8F9FA8 + MinColor: A7BDCF + MaxColor: 8F9FA8 ZOffset: -12 ZRamp: 0 Template@250: @@ -5817,33 +5819,33 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: 92A4B0 - RightColor: A3B9CB + MinColor: 92A4B0 + MaxColor: A3B9CB ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 92A5B2 - RightColor: 9DB3C4 + MinColor: 92A5B2 + MaxColor: 9DB3C4 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 93A4B1 - RightColor: A7BED1 + MinColor: 93A4B1 + MaxColor: A7BED1 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: AEC3D2 - RightColor: 92A4B0 + MinColor: AEC3D2 + MaxColor: 92A4B0 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: A6BCCD - RightColor: 98AEBC + MinColor: A6BCCD + MaxColor: 98AEBC ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: ABC2D5 - RightColor: 91A0A9 + MinColor: ABC2D5 + MaxColor: 91A0A9 ZOffset: -12 ZRamp: 0 Template@251: @@ -5853,23 +5855,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: A3B7C5 - RightColor: B8CFE4 + MinColor: A3B7C5 + MaxColor: B8CFE4 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: ABBFCE - RightColor: B1C9DE + MinColor: ABBFCE + MaxColor: B1C9DE ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: B4CCE0 - RightColor: 9EB2C0 + MinColor: B4CCE0 + MaxColor: 9EB2C0 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: ABC3D9 - RightColor: A2B7C8 + MinColor: ABC3D9 + MaxColor: A2B7C8 ZOffset: -12 ZRamp: 0 Template@252: @@ -5879,13 +5881,13 @@ Size: 1, 2 Tiles: 0: DirtRoad - LeftColor: 8D9FAB - RightColor: AAC2D5 + MinColor: 8D9FAB + MaxColor: AAC2D5 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A7BCCF - RightColor: 8FA3B1 + MinColor: A7BCCF + MaxColor: 8FA3B1 ZOffset: -12 ZRamp: 0 Template@253: @@ -5895,13 +5897,13 @@ Size: 1, 2 Tiles: 0: DirtRoad - LeftColor: 96A8B4 - RightColor: ADC4D9 + MinColor: 96A8B4 + MaxColor: ADC4D9 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A7BED1 - RightColor: 98A9B4 + MinColor: A7BED1 + MaxColor: 98A9B4 ZOffset: -12 ZRamp: 0 Template@254: @@ -5911,33 +5913,33 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: 94AABA - RightColor: B9D2EA + MinColor: 94AABA + MaxColor: B9D2EA ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: ABC1D4 - RightColor: BAD1E8 + MinColor: ABC1D4 + MaxColor: BAD1E8 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: B5CCE2 - RightColor: B9D3ED + MinColor: B5CCE2 + MaxColor: B9D3ED ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: B2CBDE - RightColor: 94A9B7 + MinColor: B2CBDE + MaxColor: 94A9B7 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B1C9E2 - RightColor: 9EB3C4 + MinColor: B1C9E2 + MaxColor: 9EB3C4 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: B5CDE2 - RightColor: BDD3E7 + MinColor: B5CDE2 + MaxColor: BDD3E7 ZOffset: -12 ZRamp: 0 Template@255: @@ -5947,23 +5949,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: A2B9CC - RightColor: BBD6EE + MinColor: A2B9CC + MaxColor: BBD6EE ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: BBD1E4 - RightColor: BFD8EE + MinColor: BBD1E4 + MaxColor: BFD8EE ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: AEC6D9 - RightColor: A2B7C6 + MinColor: AEC6D9 + MaxColor: A2B7C6 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: B0CAE1 - RightColor: AFCAE4 + MinColor: B0CAE1 + MaxColor: AFCAE4 ZOffset: -12 ZRamp: 0 Template@256: @@ -5973,38 +5975,38 @@ Size: 3, 3 Tiles: 1: Clear - LeftColor: BBD2E4 - RightColor: B9CBDB + MinColor: BBD2E4 + MaxColor: B9CBDB ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: B7CADA - RightColor: BBD5EB + MinColor: B7CADA + MaxColor: BBD5EB ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 94A7B3 - RightColor: B1C8DD + MinColor: 94A7B3 + MaxColor: B1C8DD ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B2C7D9 - RightColor: B0C8DB + MinColor: B2C7D9 + MaxColor: B0C8DB ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: B9D3ED - RightColor: B9D1E9 + MinColor: B9D3ED + MaxColor: B9D1E9 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: A9BECD - RightColor: 8999A2 + MinColor: A9BECD + MaxColor: 8999A2 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: AAC1D4 - RightColor: B9CDE0 + MinColor: AAC1D4 + MaxColor: B9CDE0 ZOffset: -12 ZRamp: 0 Template@257: @@ -6014,33 +6016,33 @@ Size: 3, 2 Tiles: 0: Clear - LeftColor: B8D3EA - RightColor: B9D3EC + MinColor: B8D3EA + MaxColor: B9D3EC ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A2B8CC - RightColor: B0CAE3 + MinColor: A2B8CC + MaxColor: B0CAE3 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9DB0BE - RightColor: B1C9DD + MinColor: 9DB0BE + MaxColor: B1C9DD ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: C1DCF2 - RightColor: B7D0E6 + MinColor: C1DCF2 + MaxColor: B7D0E6 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: BFD6E9 - RightColor: ADC2D3 + MinColor: BFD6E9 + MaxColor: ADC2D3 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: AFC7DB - RightColor: 95A8B3 + MinColor: AFC7DB + MaxColor: 95A8B3 ZOffset: -12 ZRamp: 0 Template@258: @@ -6050,23 +6052,23 @@ Size: 2, 2 Tiles: 0: Clear - LeftColor: B7D1EB - RightColor: B8D3ED + MinColor: B7D1EB + MaxColor: B8D3ED ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: AFC2D2 - RightColor: B1C6D8 + MinColor: AFC2D2 + MaxColor: B1C6D8 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: B9D3E8 - RightColor: B7D0E5 + MinColor: B9D3E8 + MaxColor: B7D0E5 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: BCD4E8 - RightColor: 9FB2BE + MinColor: BCD4E8 + MaxColor: 9FB2BE ZOffset: -12 ZRamp: 0 Template@259: @@ -6076,23 +6078,23 @@ Size: 2, 2 Tiles: 0: Clear - LeftColor: C3D8EC - RightColor: B2C9E0 + MinColor: C3D8EC + MaxColor: B2C9E0 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 98AFBE - RightColor: AAC2D7 + MinColor: 98AFBE + MaxColor: AAC2D7 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: BFD5E9 - RightColor: BDD0E3 + MinColor: BFD5E9 + MaxColor: BDD0E3 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: BAD1E4 - RightColor: 97ACB8 + MinColor: BAD1E4 + MaxColor: 97ACB8 ZOffset: -12 ZRamp: 0 Template@260: @@ -6102,43 +6104,43 @@ Size: 4, 3 Tiles: 0: DirtRoad - LeftColor: 9FB3C0 - RightColor: B7CEE3 + MinColor: 9FB3C0 + MaxColor: B7CEE3 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: B0C7DB - RightColor: BDD8F1 + MinColor: B0C7DB + MaxColor: BDD8F1 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B4CCE0 - RightColor: 9BB1C0 + MinColor: B4CCE0 + MaxColor: 9BB1C0 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A3B7C7 - RightColor: 8F9EA6 + MinColor: A3B7C7 + MaxColor: 8F9EA6 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 9FB0BD - RightColor: B4CCDF + MinColor: 9FB0BD + MaxColor: B4CCDF ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A4B9C7 - RightColor: B1C9DD + MinColor: A4B9C7 + MaxColor: B1C9DD ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: C2DCF2 - RightColor: B6CEE3 + MinColor: C2DCF2 + MaxColor: B6CEE3 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: B2CBE3 - RightColor: 99AFC0 + MinColor: B2CBE3 + MaxColor: 99AFC0 ZOffset: -12 ZRamp: 0 Template@261: @@ -6148,43 +6150,43 @@ Size: 4, 3 Tiles: 2: Clear - LeftColor: B5CCE0 - RightColor: BAD2E6 + MinColor: B5CCE0 + MaxColor: BAD2E6 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9DB0BC - RightColor: B0C7DC + MinColor: 9DB0BC + MaxColor: B0C7DC ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 94A5B0 - RightColor: ACC1D3 + MinColor: 94A5B0 + MaxColor: ACC1D3 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 94A3AC - RightColor: A9BCCB + MinColor: 94A3AC + MaxColor: A9BCCB ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: ABBECE - RightColor: 9FAEBA + MinColor: ABBECE + MaxColor: 9FAEBA ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: ABC0D0 - RightColor: 99AEBD + MinColor: ABC0D0 + MaxColor: 99AEBD ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: AFC6DA - RightColor: A2B5C4 + MinColor: AFC6DA + MaxColor: A2B5C4 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: B8D2EB - RightColor: B5CEE5 + MinColor: B8D2EB + MaxColor: B5CEE5 ZOffset: -12 ZRamp: 0 Template@262: @@ -6194,43 +6196,43 @@ Size: 4, 2 Tiles: 0: Clear - LeftColor: BDD6EC - RightColor: BBD3E7 + MinColor: BDD6EC + MaxColor: BBD3E7 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: B0C5D9 - RightColor: BBD5EC + MinColor: B0C5D9 + MaxColor: BBD5EC ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: BBD4E7 - RightColor: BDD8F1 + MinColor: BBD4E7 + MaxColor: BDD8F1 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: B9D3EC - RightColor: BBD6EF + MinColor: B9D3EC + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: B9D5F0 - RightColor: B3CEE9 + MinColor: B9D5F0 + MaxColor: B3CEE9 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: C1DAEE - RightColor: AEC3D4 + MinColor: C1DAEE + MaxColor: AEC3D4 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: B4CADC - RightColor: B3C8DA + MinColor: B4CADC + MaxColor: B3C8DA ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: B6CFE8 - RightColor: BBD6F0 + MinColor: B6CFE8 + MaxColor: BBD6F0 ZOffset: -12 ZRamp: 0 Template@263: @@ -6240,48 +6242,48 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: B7D0E3 - RightColor: C1DBF2 + MinColor: B7D0E3 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: BBD6F1 - RightColor: AEC3D5 + MinColor: BBD6F1 + MaxColor: AEC3D5 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 92A0A8 - RightColor: 93A5B1 + MinColor: 92A0A8 + MaxColor: 93A5B1 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: AFC6D9 - RightColor: BFDAF2 + MinColor: AFC6D9 + MaxColor: BFDAF2 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: C0DBF2 - RightColor: A7BCCB + MinColor: C0DBF2 + MaxColor: A7BCCB ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 8B9AA4 - RightColor: 8799A4 + MinColor: 8B9AA4 + MaxColor: 8799A4 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: B0C7D7 - RightColor: C1DBF1 + MinColor: B0C7D7 + MaxColor: C1DBF1 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: BCD6EE - RightColor: A5BBCD + MinColor: BCD6EE + MaxColor: A5BBCD ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: 92A5B1 - RightColor: 96A8B5 + MinColor: 92A5B1 + MaxColor: 96A8B5 ZOffset: -12 ZRamp: 0 Template@264: @@ -6291,48 +6293,48 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: AFC7DC - RightColor: BBD6EF + MinColor: AFC7DC + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: BAD5F0 - RightColor: A6BCCE + MinColor: BAD5F0 + MaxColor: A6BCCE ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 93A3AD - RightColor: 9FB4C6 + MinColor: 93A3AD + MaxColor: 9FB4C6 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: BAD3E8 - RightColor: BDD8F0 + MinColor: BAD3E8 + MaxColor: BDD8F0 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: BCD8F1 - RightColor: ABC0D1 + MinColor: BCD8F1 + MaxColor: ABC0D1 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 9DAFBB - RightColor: A4B9CA + MinColor: 9DAFBB + MaxColor: A4B9CA ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: B2C7D8 - RightColor: C0DAF1 + MinColor: B2C7D8 + MaxColor: C0DAF1 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: BFDBF2 - RightColor: B1C7DA + MinColor: BFDBF2 + MaxColor: B1C7DA ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: 94A6B2 - RightColor: 9AAAB6 + MinColor: 94A6B2 + MaxColor: 9AAAB6 ZOffset: -12 ZRamp: 0 Template@265: @@ -6342,48 +6344,48 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: B1C4D2 - RightColor: C1DBF1 + MinColor: B1C4D2 + MaxColor: C1DBF1 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: C2DCF2 - RightColor: B3C9DB + MinColor: C2DCF2 + MaxColor: B3C9DB ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A6BCCF - RightColor: A6B9C9 + MinColor: A6BCCF + MaxColor: A6B9C9 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: B0C9DE - RightColor: BAD5ED + MinColor: B0C9DE + MaxColor: BAD5ED ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: BCD6EE - RightColor: B3C9DD + MinColor: BCD6EE + MaxColor: B3C9DD ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: A8BDD0 - RightColor: ACBFCF + MinColor: A8BDD0 + MaxColor: ACBFCF ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: B7CFE4 - RightColor: C2DDF3 + MinColor: B7CFE4 + MaxColor: C2DDF3 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: BAD5EF - RightColor: B2CADF + MinColor: BAD5EF + MaxColor: B2CADF ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: A5B8C7 - RightColor: A7BCCD + MinColor: A5B8C7 + MaxColor: A7BCCD ZOffset: -12 ZRamp: 0 Template@266: @@ -6393,48 +6395,48 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: AABFD5 - RightColor: C0DBF2 + MinColor: AABFD5 + MaxColor: C0DBF2 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B9D4ED - RightColor: AFC6D9 + MinColor: B9D4ED + MaxColor: AFC6D9 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A5B9C9 - RightColor: 93A5B1 + MinColor: A5B9C9 + MaxColor: 93A5B1 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: AAC0D0 - RightColor: C1DBF2 + MinColor: AAC0D0 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: C2DCF2 - RightColor: B1C8DA + MinColor: C2DCF2 + MaxColor: B1C8DA ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: ABC0D0 - RightColor: 97A8B4 + MinColor: ABC0D0 + MaxColor: 97A8B4 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: B0C6D9 - RightColor: B7D2EC + MinColor: B0C6D9 + MaxColor: B7D2EC ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: C2DDF2 - RightColor: B8D1E5 + MinColor: C2DDF2 + MaxColor: B8D1E5 ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: 97AAB8 - RightColor: 9EB3C4 + MinColor: 97AAB8 + MaxColor: 9EB3C4 ZOffset: -12 ZRamp: 0 Template@267: @@ -6444,33 +6446,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: ACC0CE - RightColor: C1DBF1 + MinColor: ACC0CE + MaxColor: C1DBF1 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: B8D4EE - RightColor: A4BACC + MinColor: B8D4EE + MaxColor: A4BACC ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8FA1AB - RightColor: 9AAEBB + MinColor: 8FA1AB + MaxColor: 9AAEBB ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A3B8CA - RightColor: BBD5EB + MinColor: A3B8CA + MaxColor: BBD5EB ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: BED9F1 - RightColor: ACC2D5 + MinColor: BED9F1 + MaxColor: ACC2D5 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 92A4B0 - RightColor: 98A9B4 + MinColor: 92A4B0 + MaxColor: 98A9B4 ZOffset: -12 ZRamp: 0 Template@268: @@ -6480,18 +6482,18 @@ Size: 2, 2 Tiles: 1: DirtRoad - LeftColor: B3CADF - RightColor: BBD6EF + MinColor: B3CADF + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: B8D3EF - RightColor: A4BAD2 + MinColor: B8D3EF + MaxColor: A4BAD2 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9CB1C7 - RightColor: A1B7C9 + MinColor: 9CB1C7 + MaxColor: A1B7C9 ZOffset: -12 ZRamp: 0 Template@269: @@ -6501,18 +6503,18 @@ Size: 2, 2 Tiles: 1: DirtRoad - LeftColor: B4CBDE - RightColor: C2DDF3 + MinColor: B4CBDE + MaxColor: C2DDF3 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: C4DDF1 - RightColor: B1C6D8 + MinColor: C4DDF1 + MaxColor: B1C6D8 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9EB1BE - RightColor: 9AADBB + MinColor: 9EB1BE + MaxColor: 9AADBB ZOffset: -12 ZRamp: 0 Template@270: @@ -6522,48 +6524,48 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: ADC2D5 - RightColor: BCD6EE + MinColor: ADC2D5 + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: BFDAF2 - RightColor: B0C6D7 + MinColor: BFDAF2 + MaxColor: B0C6D7 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A6B7C4 - RightColor: ADC0CF + MinColor: A6B7C4 + MaxColor: ADC0CF ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: B5CDE5 - RightColor: B6D1EE + MinColor: B5CDE5 + MaxColor: B6D1EE ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: C0D9EF - RightColor: B8CDE0 + MinColor: C0D9EF + MaxColor: B8CDE0 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: B1C7D9 - RightColor: B3C8DB + MinColor: B1C7D9 + MaxColor: B3C8DB ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: B8D1E8 - RightColor: BBD5EE + MinColor: B8D1E8 + MaxColor: BBD5EE ZOffset: -12 ZRamp: 0 14: Clear - LeftColor: C0DAEF - RightColor: B5CEE5 + MinColor: C0DAEF + MaxColor: B5CEE5 ZOffset: -12 ZRamp: 0 15: Clear - LeftColor: B7D2ED - RightColor: BAD5EE + MinColor: B7D2ED + MaxColor: BAD5EE ZOffset: -12 ZRamp: 0 Template@271: @@ -6573,53 +6575,53 @@ Size: 4, 5 Tiles: 1: DirtRoad - LeftColor: 97ADC0 - RightColor: B4CFE9 + MinColor: 97ADC0 + MaxColor: B4CFE9 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: BFDAF2 - RightColor: ABC3D8 + MinColor: BFDAF2 + MaxColor: ABC3D8 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A5BCD1 - RightColor: A6BFD5 + MinColor: A5BCD1 + MaxColor: A6BFD5 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: B7CEE4 - RightColor: B8D3EC + MinColor: B7CEE4 + MaxColor: B8D3EC ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: BFD8ED - RightColor: B4CBDE + MinColor: BFD8ED + MaxColor: B4CBDE ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: B8CDE1 - RightColor: B5CDE6 + MinColor: B8CDE1 + MaxColor: B5CDE6 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: BBD3E8 - RightColor: BDD8EF + MinColor: BBD3E8 + MaxColor: BDD8EF ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: BBD6EF - RightColor: B9D2EA + MinColor: BBD6EF + MaxColor: B9D2EA ZOffset: -12 ZRamp: 0 14: Clear - LeftColor: BED3E7 - RightColor: BAD3E7 + MinColor: BED3E7 + MaxColor: BAD3E7 ZOffset: -12 ZRamp: 0 18: Clear - LeftColor: BFD9F0 - RightColor: BFD9EF + MinColor: BFD9F0 + MaxColor: BFD9EF ZOffset: -12 ZRamp: 0 Template@272: @@ -6629,33 +6631,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: ACC2D6 - RightColor: B6D1EF + MinColor: ACC2D6 + MaxColor: B6D1EF ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: BAD5EE - RightColor: A1B5C3 + MinColor: BAD5EE + MaxColor: A1B5C3 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 91A2AC - RightColor: 9EB0BD + MinColor: 91A2AC + MaxColor: 9EB0BD ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B5CDE2 - RightColor: BAD4EE + MinColor: B5CDE2 + MaxColor: BAD4EE ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: C2DCF2 - RightColor: AFC4D6 + MinColor: C2DCF2 + MaxColor: AFC4D6 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: BCD3E5 - RightColor: BAD2E5 + MinColor: BCD3E5 + MaxColor: BAD2E5 ZOffset: -12 ZRamp: 0 Template@273: @@ -6665,48 +6667,48 @@ Size: 4, 4 Tiles: 1: Clear - LeftColor: B6D1EA - RightColor: B9D4EF + MinColor: B6D1EA + MaxColor: B9D4EF ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: BED9F1 - RightColor: BED7ED + MinColor: BED9F1 + MaxColor: BED7ED ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: B3CBE6 - RightColor: ADC6DE + MinColor: B3CBE6 + MaxColor: ADC6DE ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: B5CCE0 - RightColor: C5DAED + MinColor: B5CCE0 + MaxColor: C5DAED ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: C4DDF1 - RightColor: B7CEE4 + MinColor: C4DDF1 + MaxColor: B7CEE4 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 9FB2C1 - RightColor: A6BCCF + MinColor: 9FB2C1 + MaxColor: A6BCCF ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: B1C8DB - RightColor: C3DAEE + MinColor: B1C8DB + MaxColor: C3DAEE ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: BCD5EE - RightColor: B2C5D5 + MinColor: BCD5EE + MaxColor: B2C5D5 ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: A1B5C5 - RightColor: 9AABB8 + MinColor: A1B5C5 + MaxColor: 9AABB8 ZOffset: -12 ZRamp: 0 Template@274: @@ -6716,33 +6718,33 @@ Size: 2, 3 Tiles: 0: Clear - LeftColor: C0DAF1 - RightColor: C0DAF0 + MinColor: C0DAF1 + MaxColor: C0DAF0 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: B8D3EE - RightColor: BDD8F1 + MinColor: B8D3EE + MaxColor: BDD8F1 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: BFD9ED - RightColor: B0C7DA + MinColor: BFD9ED + MaxColor: B0C7DA ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: AEC4D5 - RightColor: BBD4EC + MinColor: AEC4D5 + MaxColor: BBD4EC ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: BCD5EE - RightColor: B8D2EA + MinColor: BCD5EE + MaxColor: B8D2EA ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 9CB0BF - RightColor: 9BAFC0 + MinColor: 9CB0BF + MaxColor: 9BAFC0 ZOffset: -12 ZRamp: 0 Template@275: @@ -6752,33 +6754,33 @@ Size: 3, 3 Tiles: 1: Clear - LeftColor: BFD9F0 - RightColor: BFDAF2 + MinColor: BFD9F0 + MaxColor: BFDAF2 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: C5DEF2 - RightColor: B3CDE3 + MinColor: C5DEF2 + MaxColor: B3CDE3 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: B1C9E1 - RightColor: B7D1EA + MinColor: B1C9E1 + MaxColor: B7D1EA ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B3CDE6 - RightColor: BCD7F0 + MinColor: B3CDE6 + MaxColor: BCD7F0 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: BDD5EB - RightColor: BBD1E5 + MinColor: BDD5EB + MaxColor: BBD1E5 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 99AEBC - RightColor: A4BDD4 + MinColor: 99AEBC + MaxColor: A4BDD4 ZOffset: -12 ZRamp: 0 Template@276: @@ -6788,58 +6790,58 @@ Size: 5, 3 Tiles: 1: DirtRoad - LeftColor: 9DB1C0 - RightColor: BCD5EA + MinColor: 9DB1C0 + MaxColor: BCD5EA ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: B4CDE6 - RightColor: B5D0ED + MinColor: B4CDE6 + MaxColor: B5D0ED ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: C4DDF1 - RightColor: A8BDCE + MinColor: C4DDF1 + MaxColor: A8BDCE ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 97ABBA - RightColor: 8B9DA8 + MinColor: 97ABBA + MaxColor: 8B9DA8 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 9BAEBB - RightColor: AAC1D3 + MinColor: 9BAEBB + MaxColor: AAC1D3 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: B1C7DC - RightColor: B2CCE4 + MinColor: B1C7DC + MaxColor: B2CCE4 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: BBD3E8 - RightColor: BCD7EF + MinColor: BBD3E8 + MaxColor: BCD7EF ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: B7D2EC - RightColor: AFCAE8 + MinColor: B7D2EC + MaxColor: AFCAE8 ZOffset: -12 ZRamp: 0 12: DirtRoad - LeftColor: C0DAEF - RightColor: AFC3D4 + MinColor: C0DAEF + MaxColor: AFC3D4 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: AFC6D7 - RightColor: 9AACB9 + MinColor: AFC6D7 + MaxColor: 9AACB9 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 909EA6 - RightColor: A6BACA + MinColor: 909EA6 + MaxColor: A6BACA ZOffset: -12 ZRamp: 0 Template@277: @@ -6849,53 +6851,53 @@ Size: 3, 5 Tiles: 1: DirtRoad - LeftColor: B0C9E3 - RightColor: B4CFEE + MinColor: B0C9E3 + MaxColor: B4CFEE ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: B8D0E7 - RightColor: A0B1BF + MinColor: B8D0E7 + MaxColor: A0B1BF ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 98A7B2 - RightColor: B5CDE4 + MinColor: 98A7B2 + MaxColor: B5CDE4 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: C0D9EE - RightColor: B8CFE6 + MinColor: C0D9EE + MaxColor: B8CFE6 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A1B4C3 - RightColor: 8D9FAB + MinColor: A1B4C3 + MaxColor: 8D9FAB ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: B7D0E7 - RightColor: BCD7F0 + MinColor: B7D0E7 + MaxColor: BCD7F0 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: B5CCE2 - RightColor: 9EB1BF + MinColor: B5CCE2 + MaxColor: 9EB1BF ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 95A7B3 - RightColor: BBD5ED + MinColor: 95A7B3 + MaxColor: BBD5ED ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: B9D4EE - RightColor: B0C8DD + MinColor: B9D4EE + MaxColor: B0C8DD ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: A1B4C4 - RightColor: 95AAB6 + MinColor: A1B4C4 + MaxColor: 95AAB6 ZOffset: -12 ZRamp: 0 Template@278: @@ -6905,48 +6907,48 @@ Size: 4, 4 Tiles: 1: Clear - LeftColor: BFD8ED - RightColor: BED9F1 + MinColor: BFD8ED + MaxColor: BED9F1 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: C0DBF2 - RightColor: BDD8F0 + MinColor: C0DBF2 + MaxColor: BDD8F0 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: ABC2D7 - RightColor: A9C1D6 + MinColor: ABC2D7 + MaxColor: A9C1D6 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: BCD5EA - RightColor: C0D8EE + MinColor: BCD5EA + MaxColor: C0D8EE ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: BAD5F0 - RightColor: B1C9E0 + MinColor: BAD5F0 + MaxColor: B1C9E0 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: B0C6D9 - RightColor: A4B9CC + MinColor: B0C6D9 + MaxColor: A4B9CC ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: B3CBDE - RightColor: C2DDF3 + MinColor: B3CBDE + MaxColor: C2DDF3 ZOffset: -12 ZRamp: 0 14: Clear - LeftColor: BDD7EF - RightColor: C0D2E3 + MinColor: BDD7EF + MaxColor: C0D2E3 ZOffset: -12 ZRamp: 0 15: Clear - LeftColor: C1D5E6 - RightColor: B2C9DC + MinColor: C1D5E6 + MaxColor: B2C9DC ZOffset: -12 ZRamp: 0 Template@279: @@ -6956,43 +6958,43 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: A7BED2 - RightColor: 95A3AD + MinColor: A7BED2 + MaxColor: 95A3AD ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8FA1AE - RightColor: A8BED1 + MinColor: 8FA1AE + MaxColor: A8BED1 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: ADC4D8 - RightColor: 95A6B2 + MinColor: ADC4D8 + MaxColor: 95A6B2 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9DB0BE - RightColor: ABC3D7 + MinColor: 9DB0BE + MaxColor: ABC3D7 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B6CDDF - RightColor: 9EB1BF + MinColor: B6CDDF + MaxColor: 9EB1BF ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 9AB0C0 - RightColor: B0C8DE + MinColor: 9AB0C0 + MaxColor: B0C8DE ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: B1C7D9 - RightColor: 99ABB8 + MinColor: B1C7D9 + MaxColor: 99ABB8 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A0B2BF - RightColor: BAD3E6 + MinColor: A0B2BF + MaxColor: BAD3E6 ZOffset: -12 ZRamp: 0 Template@280: @@ -7002,43 +7004,43 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: A6BDCF - RightColor: 95A7B3 + MinColor: A6BDCF + MaxColor: 95A7B3 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 96A8B3 - RightColor: ABC2D9 + MinColor: 96A8B3 + MaxColor: ABC2D9 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: A9C0D2 - RightColor: 95AAB9 + MinColor: A9C0D2 + MaxColor: 95AAB9 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9DB3C2 - RightColor: B3CDE1 + MinColor: 9DB3C2 + MaxColor: B3CDE1 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: A6BFD3 - RightColor: ABC2D5 + MinColor: A6BFD3 + MaxColor: ABC2D5 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B0C7D7 - RightColor: B2C9DB + MinColor: B0C7D7 + MaxColor: B2C9DB ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: AFC5D9 - RightColor: 8FA2AD + MinColor: AFC5D9 + MaxColor: 8FA2AD ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A6BCCC - RightColor: B9D1E6 + MinColor: A6BCCC + MaxColor: B9D1E6 ZOffset: -12 ZRamp: 0 Template@281: @@ -7048,43 +7050,43 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: B1CADC - RightColor: 91A6B3 + MinColor: B1CADC + MaxColor: 91A6B3 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A0B4C3 - RightColor: AFC7DD + MinColor: A0B4C3 + MaxColor: AFC7DD ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: B0C7DA - RightColor: A1B5C4 + MinColor: B0C7DA + MaxColor: A1B5C4 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: A1B6C7 - RightColor: B4CEE8 + MinColor: A1B6C7 + MaxColor: B4CEE8 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B1CADF - RightColor: A0B4C4 + MinColor: B1CADF + MaxColor: A0B4C4 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: A6BAC8 - RightColor: BCD5E9 + MinColor: A6BAC8 + MaxColor: BCD5E9 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: B1C7D9 - RightColor: 90A5B4 + MinColor: B1C7D9 + MaxColor: 90A5B4 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 9BAEB9 - RightColor: B8D1E4 + MinColor: 9BAEB9 + MaxColor: B8D1E4 ZOffset: -12 ZRamp: 0 Template@282: @@ -7094,43 +7096,43 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: ACC4DA - RightColor: 94A7B4 + MinColor: ACC4DA + MaxColor: 94A7B4 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 98AAB7 - RightColor: B8D0E3 + MinColor: 98AAB7 + MaxColor: B8D0E3 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: AEC6DD - RightColor: 9AAFC1 + MinColor: AEC6DD + MaxColor: 9AAFC1 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9DB0BD - RightColor: A5BACA + MinColor: 9DB0BD + MaxColor: A5BACA ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B3C8D8 - RightColor: A1B5C6 + MinColor: B3C8D8 + MaxColor: A1B5C6 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 8D9EA9 - RightColor: A4B8C9 + MinColor: 8D9EA9 + MaxColor: A4B8C9 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: ACC3D3 - RightColor: 93A6B2 + MinColor: ACC3D3 + MaxColor: 93A6B2 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A3B5C2 - RightColor: B8CFE3 + MinColor: A3B5C2 + MaxColor: B8CFE3 ZOffset: -12 ZRamp: 0 Template@283: @@ -7140,33 +7142,33 @@ Size: 2, 3 Tiles: 0: DirtRoad - LeftColor: ABC3D6 - RightColor: 91A5B3 + MinColor: ABC3D6 + MaxColor: 91A5B3 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9AACB9 - RightColor: B2CADD + MinColor: 9AACB9 + MaxColor: B2CADD ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: ACC3D7 - RightColor: 97ABB9 + MinColor: ACC3D7 + MaxColor: 97ABB9 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9FB3C0 - RightColor: ABC3D6 + MinColor: 9FB3C0 + MaxColor: ABC3D6 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: AFC5D7 - RightColor: 94A8B5 + MinColor: AFC5D7 + MaxColor: 94A8B5 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 9DAFBB - RightColor: B3CBDE + MinColor: 9DAFBB + MaxColor: B3CBDE ZOffset: -12 ZRamp: 0 Template@284: @@ -7176,23 +7178,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: AAC1D6 - RightColor: A4B4C0 + MinColor: AAC1D6 + MaxColor: A4B4C0 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 99ABB7 - RightColor: B3CADD + MinColor: 99ABB7 + MaxColor: B3CADD ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: AFC5D8 - RightColor: 9DB1C0 + MinColor: AFC5D8 + MaxColor: 9DB1C0 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: A8BBC9 - RightColor: BBD1E3 + MinColor: A8BBC9 + MaxColor: BBD1E3 ZOffset: -12 ZRamp: 0 Template@285: @@ -7202,13 +7204,13 @@ Size: 2, 1 Tiles: 0: DirtRoad - LeftColor: AAC1D4 - RightColor: 95A8B5 + MinColor: AAC1D4 + MaxColor: 95A8B5 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9DAEBA - RightColor: B8D0E4 + MinColor: 9DAEBA + MaxColor: B8D0E4 ZOffset: -12 ZRamp: 0 Template@286: @@ -7218,13 +7220,13 @@ Size: 2, 1 Tiles: 0: DirtRoad - LeftColor: ADC4D6 - RightColor: 9AADBB + MinColor: ADC4D6 + MaxColor: 9AADBB ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A1B5C3 - RightColor: AEC5D9 + MinColor: A1B5C3 + MaxColor: AEC5D9 ZOffset: -12 ZRamp: 0 Template@287: @@ -7234,43 +7236,43 @@ Size: 2, 4 Tiles: 0: Clear - LeftColor: B9D3ED - RightColor: BBD0E5 + MinColor: B9D3ED + MaxColor: BBD0E5 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: BBD3E9 - RightColor: BAD5ED + MinColor: BBD3E9 + MaxColor: BAD5ED ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: B9D3EB - RightColor: B9D1E6 + MinColor: B9D3EB + MaxColor: B9D1E6 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: B8D0E5 - RightColor: B7D0E9 + MinColor: B8D0E5 + MaxColor: B7D0E9 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B8CFE2 - RightColor: AFC5D7 + MinColor: B8CFE2 + MaxColor: AFC5D7 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: B5CBDD - RightColor: B7CFE5 + MinColor: B5CBDD + MaxColor: B7CFE5 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: B0C7DA - RightColor: 9DAEBA + MinColor: B0C7DA + MaxColor: 9DAEBA ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: A9BFCF - RightColor: BED7EB + MinColor: A9BFCF + MaxColor: BED7EB ZOffset: -12 ZRamp: 0 Template@288: @@ -7280,38 +7282,38 @@ Size: 3, 3 Tiles: 0: Clear - LeftColor: B4CEE5 - RightColor: B4CEEA + MinColor: B4CEE5 + MaxColor: B4CEEA ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: BBD6EF - RightColor: C0DBF2 + MinColor: BBD6EF + MaxColor: C0DBF2 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: B7CDE0 - RightColor: A7BBCC + MinColor: B7CDE0 + MaxColor: A7BBCC ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: ADC3D7 - RightColor: B9D4EC + MinColor: ADC3D7 + MaxColor: B9D4EC ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: BBD5EA - RightColor: BED8ED + MinColor: BBD5EA + MaxColor: BED8ED ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: B4CBDE - RightColor: A3B8C8 + MinColor: B4CBDE + MaxColor: A3B8C8 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 8FA5B4 - RightColor: A1B9CC + MinColor: 8FA5B4 + MaxColor: A1B9CC ZOffset: -12 ZRamp: 0 Template@289: @@ -7321,28 +7323,28 @@ Size: 2, 3 Tiles: 0: Clear - LeftColor: BFD9ED - RightColor: C1DBF2 + MinColor: BFD9ED + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: B8D3ED - RightColor: AFC9E4 + MinColor: B8D3ED + MaxColor: AFC9E4 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: B2CCE5 - RightColor: BBD5EC + MinColor: B2CCE5 + MaxColor: BBD5EC ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: ADC7E2 - RightColor: ADC4D9 + MinColor: ADC7E2 + MaxColor: ADC4D9 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 9BB0BF - RightColor: ADC6DB + MinColor: 9BB0BF + MaxColor: ADC6DB ZOffset: -12 ZRamp: 0 Template@290: @@ -7352,38 +7354,38 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: B1CADF - RightColor: 97ABBA + MinColor: B1CADF + MaxColor: 97ABBA ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A2B6C5 - RightColor: B7CFE2 + MinColor: A2B6C5 + MaxColor: B7CFE2 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: BAD2E5 - RightColor: ABBFD0 + MinColor: BAD2E5 + MaxColor: ABBFD0 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: B1C6D9 - RightColor: BAD2E8 + MinColor: B1C6D9 + MaxColor: BAD2E8 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: B7D0E6 - RightColor: B1C9DF + MinColor: B7D0E6 + MaxColor: B1C9DF ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: BCD6ED - RightColor: C0DAEF + MinColor: BCD6ED + MaxColor: C0DAEF ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: B8D3ED - RightColor: B2CCE7 + MinColor: B8D3ED + MaxColor: B2CCE7 ZOffset: -12 ZRamp: 0 Template@291: @@ -7393,43 +7395,43 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: B6CFE3 - RightColor: 95AAB8 + MinColor: B6CFE3 + MaxColor: 95AAB8 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9CB2C5 - RightColor: B0CAE5 + MinColor: 9CB2C5 + MaxColor: B0CAE5 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: B6CEE4 - RightColor: A4B8C8 + MinColor: B6CEE4 + MaxColor: A4B8C8 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: A0B4C4 - RightColor: B5CCDF + MinColor: A0B4C4 + MaxColor: B5CCDF ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: ADC5DB - RightColor: 9EB2C2 + MinColor: ADC5DB + MaxColor: 9EB2C2 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: B2C7DA - RightColor: B5CDE1 + MinColor: B2C7DA + MaxColor: B5CDE1 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: B8D3EC - RightColor: A7BCCF + MinColor: B8D3EC + MaxColor: A7BCCF ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: BED8ED - RightColor: BCD7EF + MinColor: BED8ED + MaxColor: BCD7EF ZOffset: -12 ZRamp: 0 Template@292: @@ -7439,23 +7441,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: B7D0E6 - RightColor: A0B4C4 + MinColor: B7D0E6 + MaxColor: A0B4C4 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: B2C5DA - RightColor: B7D0E6 + MinColor: B2C5DA + MaxColor: B7D0E6 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: BBD7F1 - RightColor: B7D0E8 + MinColor: BBD7F1 + MaxColor: B7D0E8 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: C2DAED - RightColor: BED6EB + MinColor: C2DAED + MaxColor: BED6EB ZOffset: -12 ZRamp: 0 Template@293: @@ -7465,43 +7467,43 @@ Size: 3, 4 Tiles: 1: DirtRoad - LeftColor: B8D2EB - RightColor: 9AACBB + MinColor: B8D2EB + MaxColor: 9AACBB ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9BAFBC - RightColor: B0C8DE + MinColor: 9BAFBC + MaxColor: B0C8DE ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: A0B5C7 - RightColor: A4B6C4 + MinColor: A0B5C7 + MaxColor: A4B6C4 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: ADC4D5 - RightColor: B8D1E5 + MinColor: ADC4D5 + MaxColor: B8D1E5 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: B5CFE7 - RightColor: B2CADF + MinColor: B5CFE7 + MaxColor: B2CADF ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 9CAEBB - RightColor: A1B5C5 + MinColor: 9CAEBB + MaxColor: A1B5C5 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: B2CADD - RightColor: A1B5C4 + MinColor: B2CADD + MaxColor: A1B5C4 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: A0B4C5 - RightColor: B9D1E3 + MinColor: A0B4C5 + MaxColor: B9D1E3 ZOffset: -12 ZRamp: 0 Template@294: @@ -7511,43 +7513,43 @@ Size: 3, 4 Tiles: 0: DirtRoad - LeftColor: B8D0E3 - RightColor: 95A7B4 + MinColor: B8D0E3 + MaxColor: 95A7B4 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 96A9B7 - RightColor: B6D0E5 + MinColor: 96A9B7 + MaxColor: B6D0E5 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: BCD5EC - RightColor: BFD2E2 + MinColor: BCD5EC + MaxColor: BFD2E2 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 99ABB7 - RightColor: A4BACF + MinColor: 99ABB7 + MaxColor: A4BACF ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: B3CADD - RightColor: 8FA2AD + MinColor: B3CADD + MaxColor: 8FA2AD ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: B0C8E0 - RightColor: BBD6EF + MinColor: B0C8E0 + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: AEC5D6 - RightColor: 94A7B5 + MinColor: AEC5D6 + MaxColor: 94A7B5 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: A4B7C9 - RightColor: B3CDE9 + MinColor: A4B7C9 + MaxColor: B3CDE9 ZOffset: -12 ZRamp: 0 Template@295: @@ -7557,28 +7559,28 @@ Size: 2, 3 Tiles: 0: Clear - LeftColor: B4CDE5 - RightColor: B1C9DF + MinColor: B4CDE5 + MaxColor: B1C9DF ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: B4CADF - RightColor: C4DDF1 + MinColor: B4CADF + MaxColor: C4DDF1 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: C4DDF1 - RightColor: B8D0E9 + MinColor: C4DDF1 + MaxColor: B8D0E9 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: AFC4D8 - RightColor: B7D0E7 + MinColor: AFC4D8 + MaxColor: B7D0E7 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: B6D1EA - RightColor: AAC4DD + MinColor: B6D1EA + MaxColor: AAC4DD ZOffset: -12 ZRamp: 0 Template@296: @@ -7589,85 +7591,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 81878D - RightColor: 7D8A96 + MinColor: 81878D + MaxColor: 7D8A96 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 716F6C - RightColor: 696B6A + MinColor: 716F6C + MaxColor: 696B6A ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: BFD4E6 - RightColor: C0DAEF + MinColor: BFD4E6 + MaxColor: C0DAEF ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 484D4F - RightColor: 6B7074 + MinColor: 484D4F + MaxColor: 6B7074 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 454546 - RightColor: 6C6F71 + MinColor: 454546 + MaxColor: 6C6F71 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: B7CBDF - RightColor: 94A3AD + MinColor: B7CBDF + MaxColor: 94A3AD ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 3E3E3C - RightColor: 3F3E3A + MinColor: 3E3E3C + MaxColor: 3F3E3A ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 3F3E39 - RightColor: 3F3D38 + MinColor: 3F3E39 + MaxColor: 3F3D38 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C0D1E2 - RightColor: 757A7E + MinColor: C0D1E2 + MaxColor: 757A7E ZOffset: -12 ZRamp: 0 9: Road Height: 4 - LeftColor: 697177 - RightColor: 454748 + MinColor: 697177 + MaxColor: 454748 ZOffset: -12 ZRamp: 0 10: Road Height: 4 - LeftColor: 626363 - RightColor: 454545 + MinColor: 626363 + MaxColor: 454545 ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: BED4E6 - RightColor: 6F7478 + MinColor: BED4E6 + MaxColor: 6F7478 ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 8694A2 - RightColor: 797C7F + MinColor: 8694A2 + MaxColor: 797C7F ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: B0C2D1 - RightColor: 999FA4 + MinColor: B0C2D1 + MaxColor: 999FA4 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: B7CDE1 - RightColor: BCD4EA + MinColor: B7CDE1 + MaxColor: BCD4EA ZOffset: -12 ZRamp: 0 Template@297: @@ -7678,85 +7680,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 81878D - RightColor: 7D8A96 + MinColor: 81878D + MaxColor: 7D8A96 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 716F6C - RightColor: 67696A + MinColor: 716F6C + MaxColor: 67696A ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 62758D - RightColor: 889DC2 + MinColor: 62758D + MaxColor: 889DC2 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 484D4F - RightColor: 6B7074 + MinColor: 484D4F + MaxColor: 6B7074 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 454546 - RightColor: 6C6F71 + MinColor: 454546 + MaxColor: 6C6F71 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 7489A8 - RightColor: 68727F + MinColor: 7489A8 + MaxColor: 68727F ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 3E3E3C - RightColor: 3F3E3A + MinColor: 3E3E3C + MaxColor: 3F3E3A ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 3F3E39 - RightColor: 3F3D38 + MinColor: 3F3E39 + MaxColor: 3F3D38 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 62748D - RightColor: 686C73 + MinColor: 62748D + MaxColor: 686C73 ZOffset: -12 ZRamp: 0 9: Road Height: 4 - LeftColor: 697177 - RightColor: 454748 + MinColor: 697177 + MaxColor: 454748 ZOffset: -12 ZRamp: 0 10: Road Height: 4 - LeftColor: 626363 - RightColor: 454545 + MinColor: 626363 + MaxColor: 454545 ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 5F7189 - RightColor: 61656A + MinColor: 5F7189 + MaxColor: 61656A ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 8593A0 - RightColor: 7A7E81 + MinColor: 8593A0 + MaxColor: 7A7E81 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 9DABBD - RightColor: 989FA4 + MinColor: 9DABBD + MaxColor: 989FA4 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 7A8EB4 - RightColor: 6C7D9A + MinColor: 7A8EB4 + MaxColor: 6C7D9A ZOffset: -12 ZRamp: 0 Template@298: @@ -7766,61 +7768,61 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 81878B - RightColor: 7F8C9A + MinColor: 81878B + MaxColor: 7F8C9A ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 464646 - RightColor: 6D6E6E + MinColor: 464646 + MaxColor: 6D6E6E ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 484C4F - RightColor: 6C7379 + MinColor: 484C4F + MaxColor: 6C7379 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 3E3E3A - RightColor: 3F3F3B + MinColor: 3E3E3A + MaxColor: 3F3F3B ZOffset: -12 ZRamp: 0 5: Road Height: 4 - LeftColor: 3F3E3B - RightColor: 3E3F3E + MinColor: 3F3E3B + MaxColor: 3E3F3E ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 606061 - RightColor: 454545 + MinColor: 606061 + MaxColor: 454545 ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 676C70 - RightColor: 4A5055 + MinColor: 676C70 + MaxColor: 4A5055 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: A9AEB1 - RightColor: 9EA1A0 + MinColor: A9AEB1 + MaxColor: 9EA1A0 ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 7F8A97 - RightColor: 767A7F + MinColor: 7F8A97 + MaxColor: 767A7F ZOffset: -12 ZRamp: 0 Template@299: @@ -7831,85 +7833,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 73808D - RightColor: 71767A + MinColor: 73808D + MaxColor: 71767A ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 747B82 - RightColor: 505355 + MinColor: 747B82 + MaxColor: 505355 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3F3F3B - RightColor: 40413E + MinColor: 3F3F3B + MaxColor: 40413E ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 45484C - RightColor: 6D7379 + MinColor: 45484C + MaxColor: 6D7379 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 6D7074 - RightColor: 808D98 + MinColor: 6D7074 + MaxColor: 808D98 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: B3BCC3 - RightColor: 9D9C97 + MinColor: B3BCC3 + MaxColor: 9D9C97 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 5F6061 - RightColor: 595C5E + MinColor: 5F6061 + MaxColor: 595C5E ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 3F3E3B - RightColor: 40403D + MinColor: 3F3E3B + MaxColor: 40403D ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 464646 - RightColor: 616161 + MinColor: 464646 + MaxColor: 616161 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 9BA8B3 - RightColor: 949DA2 + MinColor: 9BA8B3 + MaxColor: 949DA2 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: C0DAEF - RightColor: C6D9EB + MinColor: C0DAEF + MaxColor: C6D9EB ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: BAD5EE - RightColor: B8C4CF + MinColor: BAD5EE + MaxColor: B8C4CF ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: C4DEF1 - RightColor: A0A4A5 + MinColor: C4DEF1 + MaxColor: A0A4A5 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: BED4E6 - RightColor: A0A5A8 + MinColor: BED4E6 + MaxColor: A0A5A8 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: C0DAEF - RightColor: C6D9EB + MinColor: C0DAEF + MaxColor: C6D9EB ZOffset: -12 ZRamp: 0 Template@300: @@ -7920,85 +7922,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 73808D - RightColor: 71767A + MinColor: 73808D + MaxColor: 71767A ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 747B82 - RightColor: 505355 + MinColor: 747B82 + MaxColor: 505355 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3F3F3B - RightColor: 40413E + MinColor: 3F3F3B + MaxColor: 40413E ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 45484C - RightColor: 6D7379 + MinColor: 45484C + MaxColor: 6D7379 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 6D7074 - RightColor: 808D98 + MinColor: 6D7074 + MaxColor: 808D98 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: A4ABB4 - RightColor: 9D9C97 + MinColor: A4ABB4 + MaxColor: 9D9C97 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 5F6061 - RightColor: 595C5E + MinColor: 5F6061 + MaxColor: 595C5E ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 3F3E3B - RightColor: 40403D + MinColor: 3F3E3B + MaxColor: 40403D ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 464646 - RightColor: 616161 + MinColor: 464646 + MaxColor: 616161 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 909FAD - RightColor: 8D959C + MinColor: 909FAD + MaxColor: 8D959C ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 7C91B8 - RightColor: 677897 + MinColor: 7C91B8 + MaxColor: 677897 ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 7489A9 - RightColor: 9AA6B7 + MinColor: 7489A9 + MaxColor: 9AA6B7 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 7689AE - RightColor: 919599 + MinColor: 7689AE + MaxColor: 919599 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 778AA9 - RightColor: 969BA0 + MinColor: 778AA9 + MaxColor: 969BA0 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 768AB0 - RightColor: 7585A2 + MinColor: 768AB0 + MaxColor: 7585A2 ZOffset: -12 ZRamp: 0 Template@301: @@ -8008,61 +8010,61 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 606161 - RightColor: 565657 + MinColor: 606161 + MaxColor: 565657 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3F3D39 - RightColor: 3F3D39 + MinColor: 3F3D39 + MaxColor: 3F3D39 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 454545 - RightColor: 606061 + MinColor: 454545 + MaxColor: 606061 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 848C93 - RightColor: 7A7D7F + MinColor: 848C93 + MaxColor: 7A7D7F ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 7F8E9C - RightColor: 71777D + MinColor: 7F8E9C + MaxColor: 71777D ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 767A7E - RightColor: 4A4B4C + MinColor: 767A7E + MaxColor: 4A4B4C ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 42413E - RightColor: 42423F + MinColor: 42413E + MaxColor: 42423F ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 4F5050 - RightColor: 777B7E + MinColor: 4F5050 + MaxColor: 777B7E ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 6E7378 - RightColor: 747C85 + MinColor: 6E7378 + MaxColor: 747C85 ZOffset: -12 ZRamp: 0 Template@302: @@ -8072,56 +8074,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 696967 + MinColor: 71706D + MaxColor: 696967 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C3D2E0 - RightColor: C2DBF0 + MinColor: C3D2E0 + MaxColor: C2DBF0 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 454646 - RightColor: 6C6E6E + MinColor: 454646 + MaxColor: 6C6E6E ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: C3D1DF - RightColor: 97A4AC + MinColor: C3D1DF + MaxColor: 97A4AC ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 3F3D39 - RightColor: 403D38 + MinColor: 3F3D39 + MaxColor: 403D38 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: BDD0E1 - RightColor: 717679 + MinColor: BDD0E1 + MaxColor: 717679 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 626262 - RightColor: 464646 + MinColor: 626262 + MaxColor: 464646 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: BFD0E1 - RightColor: 707578 + MinColor: BFD0E1 + MaxColor: 707578 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B1B7BA - RightColor: 989896 + MinColor: B1B7BA + MaxColor: 989896 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BCD2E6 - RightColor: B6D1EE + MinColor: BCD2E6 + MaxColor: B6D1EE ZOffset: -12 ZRamp: 0 Template@303: @@ -8131,56 +8133,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 696967 + MinColor: 71706D + MaxColor: 696967 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C3D2E0 - RightColor: C2DBF0 + MinColor: C3D2E0 + MaxColor: C2DBF0 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3F4141 - RightColor: 656667 + MinColor: 3F4141 + MaxColor: 656667 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: C3D1DF - RightColor: 97A4AC + MinColor: C3D1DF + MaxColor: 97A4AC ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 393936 - RightColor: 3E3C39 + MinColor: 393936 + MaxColor: 3E3C39 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: BDD0E1 - RightColor: 717679 + MinColor: BDD0E1 + MaxColor: 717679 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 4A4A4A - RightColor: 414141 + MinColor: 4A4A4A + MaxColor: 414141 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: BFD0E1 - RightColor: 707578 + MinColor: BFD0E1 + MaxColor: 707578 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: A3A8AB - RightColor: 929290 + MinColor: A3A8AB + MaxColor: 929290 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD0E3 - RightColor: B6D1EE + MinColor: BAD0E3 + MaxColor: B6D1EE ZOffset: -12 ZRamp: 0 Template@304: @@ -8190,56 +8192,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 696967 + MinColor: 71706D + MaxColor: 696967 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C0CEDC - RightColor: C2DBF0 + MinColor: C0CEDC + MaxColor: C2DBF0 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 404040 - RightColor: 646566 + MinColor: 404040 + MaxColor: 646566 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B2C0CD - RightColor: 889299 + MinColor: B2C0CD + MaxColor: 889299 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 3D3C3A - RightColor: 383735 + MinColor: 3D3C3A + MaxColor: 383735 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: AEC1D0 - RightColor: 6F7477 + MinColor: AEC1D0 + MaxColor: 6F7477 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 5B5B5B - RightColor: 404040 + MinColor: 5B5B5B + MaxColor: 404040 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B8C4D0 - RightColor: 6B7073 + MinColor: B8C4D0 + MaxColor: 6B7073 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: AFB4B7 - RightColor: 90918F + MinColor: AFB4B7 + MaxColor: 90918F ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD0E3 - RightColor: A5BDD5 + MinColor: BAD0E3 + MaxColor: A5BDD5 ZOffset: -12 ZRamp: 0 Template@305: @@ -8249,56 +8251,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 686866 + MinColor: 71706D + MaxColor: 686866 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C0CEDC - RightColor: C2DBF0 + MinColor: C0CEDC + MaxColor: C2DBF0 ZOffset: -12 ZRamp: 0 2: Rough Height: 4 - LeftColor: 3C3C3D - RightColor: 5A5B5C + MinColor: 3C3C3D + MaxColor: 5A5B5C ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B2C0CD - RightColor: 889299 + MinColor: B2C0CD + MaxColor: 889299 ZOffset: -12 ZRamp: 0 4: Rough Height: 4 - LeftColor: 393936 - RightColor: 3A3835 + MinColor: 393936 + MaxColor: 3A3835 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: AEC1D0 - RightColor: 6F7477 + MinColor: AEC1D0 + MaxColor: 6F7477 ZOffset: -12 ZRamp: 0 6: Rough Height: 4 - LeftColor: 4B4B4B - RightColor: 3D3D3D + MinColor: 4B4B4B + MaxColor: 3D3D3D ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B8C4D0 - RightColor: 6B7073 + MinColor: B8C4D0 + MaxColor: 6B7073 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: A3A8AB - RightColor: 90918F + MinColor: A3A8AB + MaxColor: 90918F ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD0E3 - RightColor: A5BDD5 + MinColor: BAD0E3 + MaxColor: A5BDD5 ZOffset: -12 ZRamp: 0 Template@306: @@ -8308,53 +8310,53 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 7A7977 - RightColor: 8F9090 + MinColor: 7A7977 + MaxColor: 8F9090 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: BCC7D2 - RightColor: ACBCC8 + MinColor: BCC7D2 + MaxColor: ACBCC8 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 656462 - RightColor: 6C6C6B + MinColor: 656462 + MaxColor: 6C6C6B ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 798187 - RightColor: A3B8C9 + MinColor: 798187 + MaxColor: A3B8C9 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6E6D6B - RightColor: 858481 + MinColor: 6E6D6B + MaxColor: 858481 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 91A0AC - RightColor: 7A868E + MinColor: 91A0AC + MaxColor: 7A868E ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 797875 - RightColor: 979692 + MinColor: 797875 + MaxColor: 979692 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B4BEC7 - RightColor: ADC4DA + MinColor: B4BEC7 + MaxColor: ADC4DA ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: AEB6BB - RightColor: A5ABAE + MinColor: AEB6BB + MaxColor: A5ABAE ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD0E3 - RightColor: A5BBD1 + MinColor: BAD0E3 + MaxColor: A5BBD1 ZOffset: -12 ZRamp: 0 Template@307: @@ -8364,56 +8366,56 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: B8C0C6 - RightColor: 9D9C98 + MinColor: B8C0C6 + MaxColor: 9D9C98 ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 606161 - RightColor: 565657 + MinColor: 606161 + MaxColor: 565657 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3F3D39 - RightColor: 3F3D39 + MinColor: 3F3D39 + MaxColor: 3F3D39 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 454545 - RightColor: 606061 + MinColor: 454545 + MaxColor: 606061 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 8C9296 - RightColor: 878989 + MinColor: 8C9296 + MaxColor: 878989 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C4DEF1 - RightColor: C3D4E4 + MinColor: C4DEF1 + MaxColor: C3D4E4 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: BED4E6 - RightColor: AFBCC7 + MinColor: BED4E6 + MaxColor: AFBCC7 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: C0DAEF - RightColor: A3A6A6 + MinColor: C0DAEF + MaxColor: A3A6A6 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: BAD5EE - RightColor: A1A4A5 + MinColor: BAD5EE + MaxColor: A1A4A5 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD5EE - RightColor: BED5EA + MinColor: BAD5EE + MaxColor: BED5EA ZOffset: -12 ZRamp: 0 Template@308: @@ -8424,50 +8426,50 @@ Tiles: 1: Road Height: 4 - LeftColor: 585858 - RightColor: 4E4E4E + MinColor: 585858 + MaxColor: 4E4E4E ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3C3B37 - RightColor: 3B3A36 + MinColor: 3C3B37 + MaxColor: 3B3A36 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 444444 - RightColor: 535353 + MinColor: 444444 + MaxColor: 535353 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 8C9296 - RightColor: 888989 + MinColor: 8C9296 + MaxColor: 888989 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C4DEF1 - RightColor: B6BDC2 + MinColor: C4DEF1 + MaxColor: B6BDC2 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: BED4E6 - RightColor: A0A4A5 + MinColor: BED4E6 + MaxColor: A0A4A5 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: C0DAEF - RightColor: A3A6A6 + MinColor: C0DAEF + MaxColor: A3A6A6 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: BAD5EE - RightColor: A1A4A5 + MinColor: BAD5EE + MaxColor: A1A4A5 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD5EE - RightColor: BED5EA + MinColor: BAD5EE + MaxColor: BED5EA ZOffset: -12 ZRamp: 0 Template@309: @@ -8477,56 +8479,56 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: 9FA6AA - RightColor: 8E8D89 + MinColor: 9FA6AA + MaxColor: 8E8D89 ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 565656 - RightColor: 515151 + MinColor: 565656 + MaxColor: 515151 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3C3A35 - RightColor: 3E3D39 + MinColor: 3C3A35 + MaxColor: 3E3D39 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 3F3F3F - RightColor: 5F6060 + MinColor: 3F3F3F + MaxColor: 5F6060 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 8C9296 - RightColor: 868888 + MinColor: 8C9296 + MaxColor: 868888 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: C4DEF1 - RightColor: B5C5D3 + MinColor: C4DEF1 + MaxColor: B5C5D3 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: B5C9D8 - RightColor: 9FA9B2 + MinColor: B5C9D8 + MaxColor: 9FA9B2 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: B9CFE0 - RightColor: 949694 + MinColor: B9CFE0 + MaxColor: 949694 ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: B7CDE1 - RightColor: 9B9E9F + MinColor: B7CDE1 + MaxColor: 9B9E9F ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: B9D3ED - RightColor: BED5EA + MinColor: B9D3ED + MaxColor: BED5EA ZOffset: -12 ZRamp: 0 Template@310: @@ -8537,50 +8539,50 @@ Tiles: 1: Rough Height: 4 - LeftColor: 414242 - RightColor: 4B4B4B + MinColor: 414242 + MaxColor: 4B4B4B ZOffset: -12 ZRamp: 0 2: Rough Height: 4 - LeftColor: 363430 - RightColor: 35332F + MinColor: 363430 + MaxColor: 35332F ZOffset: -12 ZRamp: 0 3: Rough Height: 4 - LeftColor: 313131 - RightColor: 4D4D4D + MinColor: 313131 + MaxColor: 4D4D4D ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 84888A - RightColor: 838484 + MinColor: 84888A + MaxColor: 838484 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: BAD1E3 - RightColor: A6ACB0 + MinColor: BAD1E3 + MaxColor: A6ACB0 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: B5C9D8 - RightColor: 8E9192 + MinColor: B5C9D8 + MaxColor: 8E9192 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B6CBDC - RightColor: 929492 + MinColor: B6CBDC + MaxColor: 929492 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B7CDE1 - RightColor: A0A3A3 + MinColor: B7CDE1 + MaxColor: A0A3A3 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: B6D0E9 - RightColor: B0C1D1 + MinColor: B6D0E9 + MaxColor: B0C1D1 ZOffset: -12 ZRamp: 0 Template@311: @@ -8590,53 +8592,53 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: 9EA5AA - RightColor: 898987 + MinColor: 9EA5AA + MaxColor: 898987 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 959898 - RightColor: 969491 + MinColor: 959898 + MaxColor: 969491 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 8F8E87 - RightColor: 888783 + MinColor: 8F8E87 + MaxColor: 888783 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 959490 - RightColor: 787776 + MinColor: 959490 + MaxColor: 787776 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 828688 - RightColor: 8D9499 + MinColor: 828688 + MaxColor: 8D9499 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: BAD1E3 - RightColor: B4C0CA + MinColor: BAD1E3 + MaxColor: B4C0CA ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: AEBECA - RightColor: 9FAEBC + MinColor: AEBECA + MaxColor: 9FAEBC ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: A9B4BD - RightColor: 71767D + MinColor: A9B4BD + MaxColor: 71767D ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B6CCE1 - RightColor: 9EA6AD + MinColor: B6CCE1 + MaxColor: 9EA6AD ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: B2CBE5 - RightColor: AEC0D1 + MinColor: B2CBE5 + MaxColor: AEC0D1 ZOffset: -12 ZRamp: 0 Template@312: @@ -8646,18 +8648,18 @@ Size: 1, 3 Tiles: 0: Road - LeftColor: 606970 - RightColor: 929CA5 + MinColor: 606970 + MaxColor: 929CA5 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 545959 - RightColor: 5A5C5A + MinColor: 545959 + MaxColor: 5A5C5A ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 919AA3 - RightColor: 6C747A + MinColor: 919AA3 + MaxColor: 6C747A ZOffset: -12 ZRamp: 0 Template@313: @@ -8667,18 +8669,18 @@ Size: 3, 1 Tiles: 0: Road - LeftColor: 9DA3A8 - RightColor: 626466 + MinColor: 9DA3A8 + MaxColor: 626466 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 585752 - RightColor: 585854 + MinColor: 585752 + MaxColor: 585854 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 6A6A6B - RightColor: 9FA4A8 + MinColor: 6A6A6B + MaxColor: 9FA4A8 ZOffset: -12 ZRamp: 0 Template@314: @@ -8688,48 +8690,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 5B646C - RightColor: 595D60 + MinColor: 5B646C + MaxColor: 595D60 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 4E5256 - RightColor: 545454 + MinColor: 4E5256 + MaxColor: 545454 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 505151 - RightColor: 6F7780 + MinColor: 505151 + MaxColor: 6F7780 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 545454 - RightColor: 4F5050 + MinColor: 545454 + MaxColor: 4F5050 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 515253 - RightColor: 4D5358 + MinColor: 515253 + MaxColor: 4D5358 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 4E5356 - RightColor: 525659 + MinColor: 4E5356 + MaxColor: 525659 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 757C81 - RightColor: 505050 + MinColor: 757C81 + MaxColor: 505050 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 545454 - RightColor: 4A5356 + MinColor: 545454 + MaxColor: 4A5356 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 666C70 - RightColor: 5E656A + MinColor: 666C70 + MaxColor: 5E656A ZOffset: -12 ZRamp: 0 Template@315: @@ -8739,48 +8741,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 5C636B - RightColor: 5A5D61 + MinColor: 5C636B + MaxColor: 5A5D61 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 55544F - RightColor: 545452 + MinColor: 55544F + MaxColor: 545452 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 565656 - RightColor: 6C757D + MinColor: 565656 + MaxColor: 6C757D ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 545454 - RightColor: 545555 + MinColor: 545454 + MaxColor: 545555 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 545652 - RightColor: 555550 + MinColor: 545652 + MaxColor: 555550 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 555656 - RightColor: 545759 + MinColor: 555656 + MaxColor: 545759 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 73797F - RightColor: 545454 + MinColor: 73797F + MaxColor: 545454 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 585752 - RightColor: 585854 + MinColor: 585752 + MaxColor: 585854 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 686D70 - RightColor: 5F656A + MinColor: 686D70 + MaxColor: 5F656A ZOffset: -12 ZRamp: 0 Template@316: @@ -8790,48 +8792,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 5B636A - RightColor: 595D60 + MinColor: 5B636A + MaxColor: 595D60 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 535456 - RightColor: 545454 + MinColor: 535456 + MaxColor: 545454 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 52575A - RightColor: 6C757E + MinColor: 52575A + MaxColor: 6C757E ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 545959 - RightColor: 5A5C5A + MinColor: 545959 + MaxColor: 5A5C5A ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 535452 - RightColor: 545553 + MinColor: 535452 + MaxColor: 545553 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 535453 - RightColor: 535553 + MinColor: 535453 + MaxColor: 535553 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 747C82 - RightColor: 54585B + MinColor: 747C82 + MaxColor: 54585B ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 545557 - RightColor: 52575A + MinColor: 545557 + MaxColor: 52575A ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 656C70 - RightColor: 61686D + MinColor: 656C70 + MaxColor: 61686D ZOffset: -12 ZRamp: 0 Template@317: @@ -8841,48 +8843,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 606970 - RightColor: 929CA5 + MinColor: 606970 + MaxColor: 929CA5 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 798086 - RightColor: 9CA7AF + MinColor: 798086 + MaxColor: 9CA7AF ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 60696F - RightColor: 919BA3 + MinColor: 60696F + MaxColor: 919BA3 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 545959 - RightColor: 5A5C5A + MinColor: 545959 + MaxColor: 5A5C5A ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 535452 - RightColor: 545553 + MinColor: 535452 + MaxColor: 545553 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 535453 - RightColor: 535553 + MinColor: 535453 + MaxColor: 535553 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 747C82 - RightColor: 54585B + MinColor: 747C82 + MaxColor: 54585B ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 545557 - RightColor: 52575A + MinColor: 545557 + MaxColor: 52575A ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 656C70 - RightColor: 61686D + MinColor: 656C70 + MaxColor: 61686D ZOffset: -12 ZRamp: 0 Template@318: @@ -8892,48 +8894,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 5C636B - RightColor: 5A5D61 + MinColor: 5C636B + MaxColor: 5A5D61 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 55544F - RightColor: 545452 + MinColor: 55544F + MaxColor: 545452 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 656A6F - RightColor: 959FA8 + MinColor: 656A6F + MaxColor: 959FA8 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 545454 - RightColor: 545555 + MinColor: 545454 + MaxColor: 545555 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 545652 - RightColor: 555550 + MinColor: 545652 + MaxColor: 555550 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 646567 - RightColor: A7ABAF + MinColor: 646567 + MaxColor: A7ABAF ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 73797F - RightColor: 545454 + MinColor: 73797F + MaxColor: 545454 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 585752 - RightColor: 585854 + MinColor: 585752 + MaxColor: 585854 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 676869 - RightColor: 9B9FA2 + MinColor: 676869 + MaxColor: 9B9FA2 ZOffset: -12 ZRamp: 0 Template@319: @@ -8943,48 +8945,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 5B636A - RightColor: 595D60 + MinColor: 5B636A + MaxColor: 595D60 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 535456 - RightColor: 545454 + MinColor: 535456 + MaxColor: 545454 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 52575A - RightColor: 6C757E + MinColor: 52575A + MaxColor: 6C757E ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 545959 - RightColor: 5A5C5A + MinColor: 545959 + MaxColor: 5A5C5A ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 535452 - RightColor: 545553 + MinColor: 535452 + MaxColor: 545553 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 535453 - RightColor: 535553 + MinColor: 535453 + MaxColor: 535553 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 919AA3 - RightColor: 6C747A + MinColor: 919AA3 + MaxColor: 6C747A ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 8E98A1 - RightColor: 6B7176 + MinColor: 8E98A1 + MaxColor: 6B7176 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 8D98A1 - RightColor: 626C73 + MinColor: 8D98A1 + MaxColor: 626C73 ZOffset: -12 ZRamp: 0 Template@320: @@ -8994,48 +8996,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 9EA6AB - RightColor: 646768 + MinColor: 9EA6AB + MaxColor: 646768 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 55544F - RightColor: 545452 + MinColor: 55544F + MaxColor: 545452 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 565656 - RightColor: 6C757D + MinColor: 565656 + MaxColor: 6C757D ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 999EA3 - RightColor: 67696B + MinColor: 999EA3 + MaxColor: 67696B ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 545652 - RightColor: 555550 + MinColor: 545652 + MaxColor: 555550 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 555656 - RightColor: 545759 + MinColor: 555656 + MaxColor: 545759 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 9DA3A8 - RightColor: 626466 + MinColor: 9DA3A8 + MaxColor: 626466 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 585752 - RightColor: 585854 + MinColor: 585752 + MaxColor: 585854 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 686D70 - RightColor: 5F656A + MinColor: 686D70 + MaxColor: 5F656A ZOffset: -12 ZRamp: 0 Template@321: @@ -9045,63 +9047,63 @@ Size: 4, 3 Tiles: 0: Clear - LeftColor: C4D7E5 - RightColor: C3D5E4 + MinColor: C4D7E5 + MaxColor: C3D5E4 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: B5C3D0 - RightColor: C6D1DD + MinColor: B5C3D0 + MaxColor: C6D1DD ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: B6C5D2 - RightColor: B6C5D3 + MinColor: B6C5D2 + MaxColor: B6C5D3 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 9FAEBA - RightColor: 93A2AD + MinColor: 9FAEBA + MaxColor: 93A2AD ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: BCD3E7 - RightColor: BECEDD + MinColor: BCD3E7 + MaxColor: BECEDD ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: BBCBD9 - RightColor: BECDDC + MinColor: BBCBD9 + MaxColor: BECDDC ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: B3BBC2 - RightColor: 9DA8AD + MinColor: B3BBC2 + MaxColor: 9DA8AD ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 71797B - RightColor: 777D7D + MinColor: 71797B + MaxColor: 777D7D ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: C2DAEC - RightColor: BBCCDB + MinColor: C2DAEC + MaxColor: BBCCDB ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: C2D6E8 - RightColor: C1CFDA + MinColor: C2D6E8 + MaxColor: C1CFDA ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: B5CADD - RightColor: BBC5D0 + MinColor: B5CADD + MaxColor: BBC5D0 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: B0BCC7 - RightColor: 727E85 + MinColor: B0BCC7 + MaxColor: 727E85 ZOffset: -12 ZRamp: 0 Template@322: @@ -9111,63 +9113,63 @@ Size: 4, 3 Tiles: 0: Road - LeftColor: 727B80 - RightColor: A2AEB6 + MinColor: 727B80 + MaxColor: A2AEB6 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A6ADB3 - RightColor: B6C3CF + MinColor: A6ADB3 + MaxColor: B6C3CF ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: B7C5D1 - RightColor: BFCFDF + MinColor: B7C5D1 + MaxColor: BFCFDF ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: C5D6E5 - RightColor: C7DDEF + MinColor: C5D6E5 + MaxColor: C7DDEF ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 595E5E - RightColor: 73797B + MinColor: 595E5E + MaxColor: 73797B ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 969A9C - RightColor: A6A9AC + MinColor: 969A9C + MaxColor: A6A9AC ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: BCC3C9 - RightColor: C0C7CE + MinColor: BCC3C9 + MaxColor: C0C7CE ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: C7D3E0 - RightColor: C6DAEA + MinColor: C7D3E0 + MaxColor: C6DAEA ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 919AA3 - RightColor: 848D93 + MinColor: 919AA3 + MaxColor: 848D93 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: B4C2CF - RightColor: B2BFC9 + MinColor: B4C2CF + MaxColor: B2BFC9 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: C0CFDD - RightColor: B7C7D6 + MinColor: C0CFDD + MaxColor: B7C7D6 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: BFD4E7 - RightColor: C0D4E6 + MinColor: BFD4E7 + MaxColor: C0D4E6 ZOffset: -12 ZRamp: 0 Template@323: @@ -9177,63 +9179,63 @@ Size: 4, 3 Tiles: 0: DirtRoad - LeftColor: 7A858D - RightColor: BDCBD9 + MinColor: 7A858D + MaxColor: BDCBD9 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 727E87 - RightColor: 717980 + MinColor: 727E87 + MaxColor: 717980 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 535556 - RightColor: 7F858B + MinColor: 535556 + MaxColor: 7F858B ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 73797E - RightColor: 929EA8 + MinColor: 73797E + MaxColor: 929EA8 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 5A5F60 - RightColor: 606361 + MinColor: 5A5F60 + MaxColor: 606361 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 585754 - RightColor: 4F4E4B + MinColor: 585754 + MaxColor: 4F4E4B ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 4B4A46 - RightColor: 4E4C4A + MinColor: 4B4A46 + MaxColor: 4E4C4A ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 575652 - RightColor: 575856 + MinColor: 575652 + MaxColor: 575856 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 939FA8 - RightColor: 96A5B2 + MinColor: 939FA8 + MaxColor: 96A5B2 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: ABBDCC - RightColor: 616364 + MinColor: ABBDCC + MaxColor: 616364 ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: 65696D - RightColor: 5B5C5C + MinColor: 65696D + MaxColor: 5B5C5C ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 8F989F - RightColor: 7B8389 + MinColor: 8F989F + MaxColor: 7B8389 ZOffset: -12 ZRamp: 0 Template@324: @@ -9243,63 +9245,63 @@ Size: 3, 4 Tiles: 0: DirtRoad - LeftColor: B5C0C9 - RightColor: 6B7073 + MinColor: B5C0C9 + MaxColor: 6B7073 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 585853 - RightColor: 565652 + MinColor: 585853 + MaxColor: 565652 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 6C7378 - RightColor: 929DA6 + MinColor: 6C7378 + MaxColor: 929DA6 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: B4C5D3 - RightColor: 848E97 + MinColor: B4C5D3 + MaxColor: 848E97 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 596364 - RightColor: 697478 + MinColor: 596364 + MaxColor: 697478 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: ABB5BD - RightColor: B2BCC2 + MinColor: ABB5BD + MaxColor: B2BCC2 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: ADB9C3 - RightColor: 829099 + MinColor: ADB9C3 + MaxColor: 829099 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 737E81 - RightColor: 717D87 + MinColor: 737E81 + MaxColor: 717D87 ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 82898E - RightColor: A8B6C2 + MinColor: 82898E + MaxColor: A8B6C2 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: C1D5E9 - RightColor: B6C2CE + MinColor: C1D5E9 + MaxColor: B6C2CE ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: BCCCDA - RightColor: 9EAAB1 + MinColor: BCCCDA + MaxColor: 9EAAB1 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: B5C2CE - RightColor: C1CDD8 + MinColor: B5C2CE + MaxColor: C1CDD8 ZOffset: -12 ZRamp: 0 Template@325: @@ -9309,63 +9311,63 @@ Size: 3, 4 Tiles: 0: Clear - LeftColor: B7D1EA - RightColor: B6D1EF + MinColor: B7D1EA + MaxColor: B6D1EF ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: BED4E6 - RightColor: B5CCE2 + MinColor: BED4E6 + MaxColor: B5CCE2 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: ABC1D3 - RightColor: B4CDE3 + MinColor: ABC1D3 + MaxColor: B4CDE3 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: BCCFDE - RightColor: B1C3D3 + MinColor: BCCFDE + MaxColor: B1C3D3 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: B3C3D0 - RightColor: B8C8D7 + MinColor: B3C3D0 + MaxColor: B8C8D7 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: ACBECD - RightColor: BCCEE1 + MinColor: ACBECD + MaxColor: BCCEE1 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: A9B6C1 - RightColor: A7B5C0 + MinColor: A9B6C1 + MaxColor: A7B5C0 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 879093 - RightColor: 99A6AF + MinColor: 879093 + MaxColor: 99A6AF ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 8E9497 - RightColor: B7C9DA + MinColor: 8E9497 + MaxColor: B7C9DA ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 9DA3A8 - RightColor: 747576 + MinColor: 9DA3A8 + MaxColor: 747576 ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 585752 - RightColor: 5D5D59 + MinColor: 585752 + MaxColor: 5D5D59 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 6E6F6F - RightColor: A1A6AA + MinColor: 6E6F6F + MaxColor: A1A6AA ZOffset: -12 ZRamp: 0 Template@326: @@ -9375,63 +9377,63 @@ Size: 3, 4 Tiles: 0: Clear - LeftColor: A8B3BB - RightColor: 727578 + MinColor: A8B3BB + MaxColor: 727578 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 585855 - RightColor: 54524C + MinColor: 585855 + MaxColor: 54524C ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 788288 - RightColor: A5AAAE + MinColor: 788288 + MaxColor: A5AAAE ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: B2BBC5 - RightColor: 6A7073 + MinColor: B2BBC5 + MaxColor: 6A7073 ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: 565956 - RightColor: 4E4F4F + MinColor: 565956 + MaxColor: 4E4F4F ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 7C858A - RightColor: AEBBC4 + MinColor: 7C858A + MaxColor: AEBBC4 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: B8C8D5 - RightColor: 8F989E + MinColor: B8C8D5 + MaxColor: 8F989E ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 72777A - RightColor: 535350 + MinColor: 72777A + MaxColor: 535350 ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 8C9499 - RightColor: ADB8BF + MinColor: 8C9499 + MaxColor: ADB8BF ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 9EADBA - RightColor: 8E979F + MinColor: 9EADBA + MaxColor: 8E979F ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 6D6F6F - RightColor: 747B7E + MinColor: 6D6F6F + MaxColor: 747B7E ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 72787B - RightColor: 9EAEBD + MinColor: 72787B + MaxColor: 9EAEBD ZOffset: -12 ZRamp: 0 Template@327: @@ -9441,83 +9443,83 @@ Size: 4, 5 Tiles: 0: Road - LeftColor: 606970 - RightColor: 929CA5 + MinColor: 606970 + MaxColor: 929CA5 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 7A8287 - RightColor: 9DA8B0 + MinColor: 7A8287 + MaxColor: 9DA8B0 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 60696F - RightColor: 919BA3 + MinColor: 60696F + MaxColor: 919BA3 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 717E86 - RightColor: 92A0AC + MinColor: 717E86 + MaxColor: 92A0AC ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 555959 - RightColor: 5B5E5B + MinColor: 555959 + MaxColor: 5B5E5B ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 5B5B59 - RightColor: 565654 + MinColor: 5B5B59 + MaxColor: 565654 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 535453 - RightColor: 535553 + MinColor: 535453 + MaxColor: 535553 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 565B5C - RightColor: 535858 + MinColor: 565B5C + MaxColor: 535858 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 8F99A0 - RightColor: 737C84 + MinColor: 8F99A0 + MaxColor: 737C84 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 8E9BA3 - RightColor: 7C848A + MinColor: 8E9BA3 + MaxColor: 7C848A ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 909CA5 - RightColor: 6A747B + MinColor: 909CA5 + MaxColor: 6A747B ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 9EABB7 - RightColor: 6A767E + MinColor: 9EABB7 + MaxColor: 6A767E ZOffset: -12 ZRamp: 0 12: DirtRoad - LeftColor: 96A8B5 - RightColor: 9DB4C4 + MinColor: 96A8B5 + MaxColor: 9DB4C4 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 93A5B0 - RightColor: 9EB2C1 + MinColor: 93A5B0 + MaxColor: 9EB2C1 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: B1C9DE - RightColor: BED4E6 + MinColor: B1C9DE + MaxColor: BED4E6 ZOffset: -12 ZRamp: 0 17: DirtRoad - LeftColor: 9CB1C2 - RightColor: A3BCCF + MinColor: 9CB1C2 + MaxColor: A3BCCF ZOffset: -12 ZRamp: 0 Template@328: @@ -9527,73 +9529,73 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: A1B6C6 - RightColor: A6B9C7 + MinColor: A1B6C6 + MaxColor: A6B9C7 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 84959E - RightColor: 89969E + MinColor: 84959E + MaxColor: 89969E ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 626C72 - RightColor: 97A1AB + MinColor: 626C72 + MaxColor: 97A1AB ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 848D92 - RightColor: 9AA7AF + MinColor: 848D92 + MaxColor: 9AA7AF ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 747E83 - RightColor: 929EA5 + MinColor: 747E83 + MaxColor: 929EA5 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 79868D - RightColor: 92A0AC + MinColor: 79868D + MaxColor: 92A0AC ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 545959 - RightColor: 5D605D + MinColor: 545959 + MaxColor: 5D605D ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 696965 - RightColor: 666663 + MinColor: 696965 + MaxColor: 666663 ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 555655 - RightColor: 5F615F + MinColor: 555655 + MaxColor: 5F615F ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 5C6366 - RightColor: 555A5A + MinColor: 5C6366 + MaxColor: 555A5A ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 919AA3 - RightColor: 6C747A + MinColor: 919AA3 + MaxColor: 6C747A ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 8F9AA2 - RightColor: 7A8185 + MinColor: 8F9AA2 + MaxColor: 7A8185 ZOffset: -12 ZRamp: 0 14: Road - LeftColor: 99A2A9 - RightColor: 677077 + MinColor: 99A2A9 + MaxColor: 677077 ZOffset: -12 ZRamp: 0 15: Road - LeftColor: 9AA6B1 - RightColor: 646E76 + MinColor: 9AA6B1 + MaxColor: 646E76 ZOffset: -12 ZRamp: 0 Template@329: @@ -9603,83 +9605,83 @@ Size: 4, 5 Tiles: 1: DirtRoad - LeftColor: AFC7D9 - RightColor: 91A5B2 + MinColor: AFC7D9 + MaxColor: 91A5B2 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9AACBA - RightColor: B6D0E5 + MinColor: 9AACBA + MaxColor: B6D0E5 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 606970 - RightColor: A3ADB8 + MinColor: 606970 + MaxColor: A3ADB8 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 9EA6AD - RightColor: B5BEC8 + MinColor: 9EA6AD + MaxColor: B5BEC8 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 7A848F - RightColor: 949FA8 + MinColor: 7A848F + MaxColor: 949FA8 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 727F87 - RightColor: 92A0AC + MinColor: 727F87 + MaxColor: 92A0AC ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 545959 - RightColor: 5E615F + MinColor: 545959 + MaxColor: 5E615F ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 707375 - RightColor: 808388 + MinColor: 707375 + MaxColor: 808388 ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 777A7F - RightColor: 6A6F71 + MinColor: 777A7F + MaxColor: 6A6F71 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 585E60 - RightColor: 535959 + MinColor: 585E60 + MaxColor: 535959 ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 919AA3 - RightColor: 737B82 + MinColor: 919AA3 + MaxColor: 737B82 ZOffset: -12 ZRamp: 0 13: Road - LeftColor: A2ACB5 - RightColor: 888F94 + MinColor: A2ACB5 + MaxColor: 888F94 ZOffset: -12 ZRamp: 0 14: Road - LeftColor: A9B4BE - RightColor: 818A95 + MinColor: A9B4BE + MaxColor: 818A95 ZOffset: -12 ZRamp: 0 15: Road - LeftColor: A8B4C1 - RightColor: 69757D + MinColor: A8B4C1 + MaxColor: 69757D ZOffset: -12 ZRamp: 0 17: DirtRoad - LeftColor: AEC5D6 - RightColor: 92A6B3 + MinColor: AEC5D6 + MaxColor: 92A6B3 ZOffset: -12 ZRamp: 0 18: DirtRoad - LeftColor: 9CAFBB - RightColor: B7D0E4 + MinColor: 9CAFBB + MaxColor: B7D0E4 ZOffset: -12 ZRamp: 0 Template@330: @@ -9689,83 +9691,83 @@ Size: 5, 4 Tiles: 2: Road - LeftColor: 9FA9B1 - RightColor: 6D7174 + MinColor: 9FA9B1 + MaxColor: 6D7174 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 5B5A56 - RightColor: 565653 + MinColor: 5B5A56 + MaxColor: 565653 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 656A6F - RightColor: 959FA8 + MinColor: 656A6F + MaxColor: 959FA8 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: A4B4C0 - RightColor: A5B9C9 + MinColor: A4B4C0 + MaxColor: A5B9C9 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 9CA3A7 - RightColor: 797B7C + MinColor: 9CA3A7 + MaxColor: 797B7C ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 595853 - RightColor: 555653 + MinColor: 595853 + MaxColor: 555653 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 646667 - RightColor: A7ABAF + MinColor: 646667 + MaxColor: A7ABAF ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: A7B8C4 - RightColor: AABDCC + MinColor: A7B8C4 + MaxColor: AABDCC ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 91A0A9 - RightColor: 869197 + MinColor: 91A0A9 + MaxColor: 869197 ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 94999C - RightColor: 747779 + MinColor: 94999C + MaxColor: 747779 ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 5C5E5A - RightColor: 5A5A56 + MinColor: 5C5E5A + MaxColor: 5A5A56 ZOffset: -12 ZRamp: 0 14: Road - LeftColor: 676969 - RightColor: 9B9FA2 + MinColor: 676969 + MaxColor: 9B9FA2 ZOffset: -12 ZRamp: 0 16: DirtRoad - LeftColor: 9BAEBB - RightColor: A1B4C4 + MinColor: 9BAEBB + MaxColor: A1B4C4 ZOffset: -12 ZRamp: 0 17: Road - LeftColor: 9BA1A5 - RightColor: 727475 + MinColor: 9BA1A5 + MaxColor: 727475 ZOffset: -12 ZRamp: 0 18: Road - LeftColor: 5C5B56 - RightColor: 595955 + MinColor: 5C5B56 + MaxColor: 595955 ZOffset: -12 ZRamp: 0 19: Road - LeftColor: 6A6A6B - RightColor: 9FA4A8 + MinColor: 6A6A6B + MaxColor: 9FA4A8 ZOffset: -12 ZRamp: 0 Template@331: @@ -9775,73 +9777,73 @@ Size: 4, 4 Tiles: 0: Road - LeftColor: 9FA9B1 - RightColor: 6B6F72 + MinColor: 9FA9B1 + MaxColor: 6B6F72 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 5A5955 - RightColor: 575753 + MinColor: 5A5955 + MaxColor: 575753 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 6C7175 - RightColor: 959FA8 + MinColor: 6C7175 + MaxColor: 959FA8 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 9EA6AB - RightColor: 646768 + MinColor: 9EA6AB + MaxColor: 646768 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 575651 - RightColor: 575754 + MinColor: 575651 + MaxColor: 575754 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 737576 - RightColor: 9B9FA1 + MinColor: 737576 + MaxColor: 9B9FA1 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 93A0A7 - RightColor: 838D92 + MinColor: 93A0A7 + MaxColor: 838D92 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 9BA0A4 - RightColor: 696C6D + MinColor: 9BA0A4 + MaxColor: 696C6D ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 575954 - RightColor: 5D5C57 + MinColor: 575954 + MaxColor: 5D5C57 ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 737475 - RightColor: 96999B + MinColor: 737475 + MaxColor: 96999B ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: A0B2C0 - RightColor: A5B8C8 + MinColor: A0B2C0 + MaxColor: A5B8C8 ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 9DA3A8 - RightColor: 656768 + MinColor: 9DA3A8 + MaxColor: 656768 ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 585752 - RightColor: 585854 + MinColor: 585752 + MaxColor: 585854 ZOffset: -12 ZRamp: 0 14: Road - LeftColor: 6C6D6D - RightColor: A0A5A8 + MinColor: 6C6D6D + MaxColor: A0A5A8 ZOffset: -12 ZRamp: 0 Template@332: @@ -9851,83 +9853,83 @@ Size: 5, 4 Tiles: 1: Road - LeftColor: B6C0C8 - RightColor: 7A7E81 + MinColor: B6C0C8 + MaxColor: 7A7E81 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 5D5C58 - RightColor: 5B5B57 + MinColor: 5D5C58 + MaxColor: 5B5B57 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 7A8187 - RightColor: 959FA8 + MinColor: 7A8187 + MaxColor: 959FA8 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 94A6B2 - RightColor: ABC0D2 + MinColor: 94A6B2 + MaxColor: ABC0D2 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 96A0A7 - RightColor: 939799 + MinColor: 96A0A7 + MaxColor: 939799 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 6F6F6D - RightColor: 6B6D70 + MinColor: 6F6F6D + MaxColor: 6B6D70 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 848687 - RightColor: B7BFC5 + MinColor: 848687 + MaxColor: B7BFC5 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 9DB1BD - RightColor: B0C7DD + MinColor: 9DB1BD + MaxColor: B0C7DD ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: A6BDD0 - RightColor: 94A5B0 + MinColor: A6BDD0 + MaxColor: 94A5B0 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 8C9397 - RightColor: 898E91 + MinColor: 8C9397 + MaxColor: 898E91 ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 626564 - RightColor: 6F7172 + MinColor: 626564 + MaxColor: 6F7172 ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 888B8D - RightColor: A0A5A9 + MinColor: 888B8D + MaxColor: A0A5A9 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: A9BECE - RightColor: 99AEBE + MinColor: A9BECE + MaxColor: 99AEBE ZOffset: -12 ZRamp: 0 16: Road - LeftColor: 9DA3A8 - RightColor: 6A6C6E + MinColor: 9DA3A8 + MaxColor: 6A6C6E ZOffset: -12 ZRamp: 0 17: Road - LeftColor: 5B5A55 - RightColor: 5A5A56 + MinColor: 5B5A55 + MaxColor: 5A5A56 ZOffset: -12 ZRamp: 0 18: Road - LeftColor: 737474 - RightColor: B9BEC3 + MinColor: 737474 + MaxColor: B9BEC3 ZOffset: -12 ZRamp: 0 Template@333: @@ -9937,23 +9939,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 293840 - RightColor: 293840 + MinColor: 293840 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 29373F - RightColor: 29373F + MinColor: 29373F + MaxColor: 29373F ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 28373F - RightColor: 293841 + MinColor: 28373F + MaxColor: 293841 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 28373F - RightColor: 29373F + MinColor: 28373F + MaxColor: 29373F ZOffset: -12 ZRamp: 0 Template@334: @@ -9963,23 +9965,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 293740 - RightColor: 293840 + MinColor: 293740 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 2B3A43 - RightColor: 293840 + MinColor: 2B3A43 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 293840 - RightColor: 293840 + MinColor: 293840 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 293840 - RightColor: 293840 + MinColor: 293840 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 Template@335: @@ -9989,23 +9991,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 2B3B43 - RightColor: 293840 + MinColor: 2B3B43 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 28373F - RightColor: 293840 + MinColor: 28373F + MaxColor: 293840 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 293840 - RightColor: 2C3C44 + MinColor: 293840 + MaxColor: 2C3C44 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 2A3A42 - RightColor: 28373F + MinColor: 2A3A42 + MaxColor: 28373F ZOffset: -12 ZRamp: 0 Template@336: @@ -10015,23 +10017,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 293840 - RightColor: 28373F + MinColor: 293840 + MaxColor: 28373F ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 28373F - RightColor: 293840 + MinColor: 28373F + MaxColor: 293840 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 293840 - RightColor: 293840 + MinColor: 293840 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 293840 - RightColor: 293840 + MinColor: 293840 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 Template@337: @@ -10041,23 +10043,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 293840 - RightColor: 293840 + MinColor: 293840 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 293840 - RightColor: 293840 + MinColor: 293840 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 293840 - RightColor: 28373F + MinColor: 293840 + MaxColor: 28373F ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 293740 - RightColor: 293840 + MinColor: 293740 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 Template@338: @@ -10067,23 +10069,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 28373F - RightColor: 29373F + MinColor: 28373F + MaxColor: 29373F ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 28373F - RightColor: 293841 + MinColor: 28373F + MaxColor: 293841 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 29373F - RightColor: 29373F + MinColor: 29373F + MaxColor: 29373F ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 293840 - RightColor: 293840 + MinColor: 293840 + MaxColor: 293840 ZOffset: -12 ZRamp: 0 Template@339: @@ -10093,23 +10095,23 @@ Size: 2, 2 Tiles: 0: Cliff - LeftColor: 4E5E68 - RightColor: 495862 + MinColor: 4E5E68 + MaxColor: 495862 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 3D4D58 - RightColor: 293941 + MinColor: 3D4D58 + MaxColor: 293941 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 29373F - RightColor: 2F3E47 + MinColor: 29373F + MaxColor: 2F3E47 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 2A3941 - RightColor: 2A3941 + MinColor: 2A3941 + MaxColor: 2A3941 ZOffset: -12 ZRamp: 0 Template@340: @@ -10119,23 +10121,23 @@ Size: 2, 2 Tiles: 0: Cliff - LeftColor: 455763 - RightColor: 475660 + MinColor: 455763 + MaxColor: 475660 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 32414C - RightColor: 293941 + MinColor: 32414C + MaxColor: 293941 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 293840 - RightColor: 2D3C46 + MinColor: 293840 + MaxColor: 2D3C46 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 34444F - RightColor: 4A5A67 + MinColor: 34444F + MaxColor: 4A5A67 ZOffset: -12 ZRamp: 0 Template@341: @@ -10145,8 +10147,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 2A3941 - RightColor: 293841 + MinColor: 2A3941 + MaxColor: 293841 ZOffset: -12 ZRamp: 0 Template@342: @@ -10156,8 +10158,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 293841 - RightColor: 293941 + MinColor: 293841 + MaxColor: 293941 ZOffset: -12 ZRamp: 0 Template@343: @@ -10167,8 +10169,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 2B3B44 - RightColor: 2A3A42 + MinColor: 2B3B44 + MaxColor: 2A3A42 ZOffset: -12 ZRamp: 0 Template@344: @@ -10178,8 +10180,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 293840 - RightColor: 28373F + MinColor: 293840 + MaxColor: 28373F ZOffset: -12 ZRamp: 0 Template@345: @@ -10189,8 +10191,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 28373F - RightColor: 293840 + MinColor: 28373F + MaxColor: 293840 ZOffset: -12 ZRamp: 0 Template@346: @@ -10200,8 +10202,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 394954 - RightColor: 3B4C59 + MinColor: 394954 + MaxColor: 3B4C59 ZOffset: -12 ZRamp: 0 Template@387: @@ -10212,14 +10214,14 @@ Tiles: 0: DirtRoad RampType: 1 - LeftColor: AAB8C1 - RightColor: BCCED8 + MinColor: AAB8C1 + MaxColor: BCCED8 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 1 - LeftColor: C5D7E1 - RightColor: C0D2DF + MinColor: C5D7E1 + MaxColor: C0D2DF ZOffset: -12 ZRamp: 0 Template@388: @@ -10230,14 +10232,14 @@ Tiles: 0: DirtRoad RampType: 1 - LeftColor: A5B5BF - RightColor: C1D5E1 + MinColor: A5B5BF + MaxColor: C1D5E1 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 1 - LeftColor: C5D9E6 - RightColor: B8CBD9 + MinColor: C5D9E6 + MaxColor: B8CBD9 ZOffset: -12 ZRamp: 0 Template@389: @@ -10248,14 +10250,14 @@ Tiles: 0: DirtRoad RampType: 2 - LeftColor: 9DB7D3 - RightColor: 8BA3B4 + MinColor: 9DB7D3 + MaxColor: 8BA3B4 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 2 - LeftColor: 9AB2CC - RightColor: 9CB6D4 + MinColor: 9AB2CC + MaxColor: 9CB6D4 ZOffset: -12 ZRamp: 0 Template@390: @@ -10266,14 +10268,14 @@ Tiles: 0: DirtRoad RampType: 2 - LeftColor: 9DB4D5 - RightColor: 90A4B5 + MinColor: 9DB4D5 + MaxColor: 90A4B5 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 2 - LeftColor: 97AFC4 - RightColor: 9CB4D1 + MinColor: 97AFC4 + MaxColor: 9CB4D1 ZOffset: -12 ZRamp: 0 Template@391: @@ -10284,14 +10286,14 @@ Tiles: 0: DirtRoad RampType: 3 - LeftColor: 9AB1C4 - RightColor: A0B5C9 + MinColor: 9AB1C4 + MaxColor: A0B5C9 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 3 - LeftColor: A5BCD5 - RightColor: 93A9BD + MinColor: A5BCD5 + MaxColor: 93A9BD ZOffset: -12 ZRamp: 0 Template@392: @@ -10302,14 +10304,14 @@ Tiles: 0: DirtRoad RampType: 3 - LeftColor: 98ABB9 - RightColor: A3B9CE + MinColor: 98ABB9 + MaxColor: A3B9CE ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 3 - LeftColor: A8C0D6 - RightColor: 93A8B7 + MinColor: A8C0D6 + MaxColor: 93A8B7 ZOffset: -12 ZRamp: 0 Template@393: @@ -10320,14 +10322,14 @@ Tiles: 0: DirtRoad RampType: 4 - LeftColor: C8D8E2 - RightColor: A5B3BC + MinColor: C8D8E2 + MaxColor: A5B3BC ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 4 - LeftColor: ACBDCA - RightColor: C3D5E2 + MinColor: ACBDCA + MaxColor: C3D5E2 ZOffset: -12 ZRamp: 0 Template@394: @@ -10338,14 +10340,14 @@ Tiles: 0: DirtRoad RampType: 4 - LeftColor: CAD9E2 - RightColor: B4C2CC + MinColor: CAD9E2 + MaxColor: B4C2CC ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 4 - LeftColor: B7C9D5 - RightColor: C5D8E6 + MinColor: B7C9D5 + MaxColor: C5D8E6 ZOffset: -12 ZRamp: 0 Template@403: @@ -10357,65 +10359,65 @@ 1: Clear Height: 3 RampType: 11 - LeftColor: B2CAE2 - RightColor: C2D9EC + MinColor: B2CAE2 + MaxColor: C2D9EC ZOffset: -12 ZRamp: 0 2: Clear Height: 3 RampType: 4 - LeftColor: CADBE8 - RightColor: B9CFE2 + MinColor: CADBE8 + MaxColor: B9CFE2 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 8D9FAE - RightColor: 8497A6 + MinColor: 8D9FAE + MaxColor: 8497A6 ZOffset: -12 ZRamp: 0 4: Cliff Height: 3 RampType: 3 - LeftColor: 99B0CF - RightColor: A7BEDD + MinColor: 99B0CF + MaxColor: A7BEDD ZOffset: -12 ZRamp: 0 5: Clear Height: 2 RampType: 4 - LeftColor: C9DDEB - RightColor: CADEEE + MinColor: C9DDEB + MaxColor: CADEEE ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: BCD7F0 - RightColor: ACC1D5 + MinColor: BCD7F0 + MaxColor: ACC1D5 ZOffset: -12 ZRamp: 0 7: Cliff RampType: 1 - LeftColor: D9EAF3 - RightColor: CDDFEB + MinColor: D9EAF3 + MaxColor: CDDFEB ZOffset: -12 ZRamp: 0 8: Clear Height: 1 RampType: 4 - LeftColor: C5D7E2 - RightColor: B8CBDA + MinColor: C5D7E2 + MaxColor: B8CBDA ZOffset: -12 ZRamp: 0 10: Clear RampType: 8 - LeftColor: BED9F1 - RightColor: E0EDF5 + MinColor: BED9F1 + MaxColor: E0EDF5 ZOffset: -12 ZRamp: 0 11: Clear RampType: 4 - LeftColor: CADFEF - RightColor: C7DAE8 + MinColor: CADFEF + MaxColor: C7DAE8 ZOffset: -12 ZRamp: 0 Template@404: @@ -10427,65 +10429,65 @@ 0: Clear Height: 3 RampType: 4 - LeftColor: CBE0EE - RightColor: CCDEEB + MinColor: CBE0EE + MaxColor: CCDEEB ZOffset: -12 ZRamp: 0 1: Clear Height: 3 RampType: 12 - LeftColor: C7DCE9 - RightColor: BFD8EE + MinColor: C7DCE9 + MaxColor: BFD8EE ZOffset: -12 ZRamp: 0 3: Clear Height: 2 RampType: 4 - LeftColor: D1E4EF - RightColor: C1D5E3 + MinColor: D1E4EF + MaxColor: C1D5E3 ZOffset: -12 ZRamp: 0 4: Cliff Height: 3 RampType: 1 - LeftColor: ADC3D4 - RightColor: C6DAE9 + MinColor: ADC3D4 + MaxColor: C6DAE9 ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 8799A9 - RightColor: 869AB1 + MinColor: 8799A9 + MaxColor: 869AB1 ZOffset: -12 ZRamp: 0 6: Clear Height: 1 RampType: 4 - LeftColor: CCDFEB - RightColor: CEE0EC + MinColor: CCDFEB + MaxColor: CEE0EC ZOffset: -12 ZRamp: 0 7: Cliff RampType: 3 - LeftColor: A6BED8 - RightColor: 9FB6CC + MinColor: A6BED8 + MaxColor: 9FB6CC ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B3CCE5 - RightColor: A5BACD + MinColor: B3CCE5 + MaxColor: A5BACD ZOffset: -12 ZRamp: 0 9: Clear RampType: 4 - LeftColor: CDE1EF - RightColor: C5D9E8 + MinColor: CDE1EF + MaxColor: C5D9E8 ZOffset: -12 ZRamp: 0 10: Clear RampType: 7 - LeftColor: C3DBEE - RightColor: BCD2E3 + MinColor: C3DBEE + MaxColor: BCD2E3 ZOffset: -12 ZRamp: 0 Template@405: @@ -10497,65 +10499,65 @@ 0: Clear Height: 3 RampType: 3 - LeftColor: A2BBE0 - RightColor: B1CCE8 + MinColor: A2BBE0 + MaxColor: B1CCE8 ZOffset: -12 ZRamp: 0 1: Clear Height: 2 RampType: 3 - LeftColor: 9BB4CD - RightColor: A6BFD9 + MinColor: 9BB4CD + MaxColor: A6BFD9 ZOffset: -12 ZRamp: 0 2: Clear Height: 1 RampType: 3 - LeftColor: ACC2D9 - RightColor: A9C3E1 + MinColor: ACC2D9 + MaxColor: A9C3E1 ZOffset: -12 ZRamp: 0 3: Clear RampType: 3 - LeftColor: AFCAE6 - RightColor: A9C4E0 + MinColor: AFCAE6 + MaxColor: A9C4E0 ZOffset: -12 ZRamp: 0 4: Clear Height: 3 RampType: 10 - LeftColor: BAD5EE - RightColor: A3BDE0 + MinColor: BAD5EE + MaxColor: A3BDE0 ZOffset: -12 ZRamp: 0 5: Cliff Height: 3 RampType: 2 - LeftColor: 9FB9D4 - RightColor: 9CB6D1 + MinColor: 9FB9D4 + MaxColor: 9CB6D1 ZOffset: -12 ZRamp: 0 6: Cliff RampType: 4 - LeftColor: D0E5F2 - RightColor: A8BFD0 + MinColor: D0E5F2 + MaxColor: A8BFD0 ZOffset: -12 ZRamp: 0 7: Clear RampType: 7 - LeftColor: C6E0F2 - RightColor: BFD8EC + MinColor: C6E0F2 + MaxColor: BFD8EC ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 8DA1B4 - RightColor: 8698A8 + MinColor: 8DA1B4 + MaxColor: 8698A8 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: ADC5DD - RightColor: 8BA7C0 + MinColor: ADC5DD + MaxColor: 8BA7C0 ZOffset: -12 ZRamp: 0 Template@406: @@ -10566,66 +10568,66 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 899EB0 - RightColor: 8696A4 + MinColor: 899EB0 + MaxColor: 8696A4 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 86A2C1 - RightColor: 87A2B8 + MinColor: 86A2C1 + MaxColor: 87A2B8 ZOffset: -12 ZRamp: 0 4: Clear Height: 3 RampType: 11 - LeftColor: B5CEE7 - RightColor: CCE2F2 + MinColor: B5CEE7 + MaxColor: CCE2F2 ZOffset: -12 ZRamp: 0 5: Cliff Height: 3 RampType: 4 - LeftColor: CFE2ED - RightColor: B7CDDC + MinColor: CFE2ED + MaxColor: B7CDDC ZOffset: -12 ZRamp: 0 6: Cliff RampType: 2 - LeftColor: A4BEE1 - RightColor: 9FB9DD + MinColor: A4BEE1 + MaxColor: 9FB9DD ZOffset: -12 ZRamp: 0 7: Clear RampType: 6 - LeftColor: A4BEE0 - RightColor: BDD9F1 + MinColor: A4BEE0 + MaxColor: BDD9F1 ZOffset: -12 ZRamp: 0 8: Clear Height: 3 RampType: 3 - LeftColor: AFCAE7 - RightColor: A2BDDE + MinColor: AFCAE7 + MaxColor: A2BDDE ZOffset: -12 ZRamp: 0 9: Clear Height: 2 RampType: 3 - LeftColor: A7C2E1 - RightColor: B0C8E1 + MinColor: A7C2E1 + MaxColor: B0C8E1 ZOffset: -12 ZRamp: 0 10: Clear Height: 1 RampType: 3 - LeftColor: ADC5DB - RightColor: 94AEC5 + MinColor: ADC5DB + MaxColor: 94AEC5 ZOffset: -12 ZRamp: 0 11: Clear RampType: 3 - LeftColor: A7C2E0 - RightColor: ACC6E5 + MinColor: A7C2E0 + MaxColor: ACC6E5 ZOffset: -12 ZRamp: 0 Template@407: @@ -10636,65 +10638,65 @@ Tiles: 1: Clear RampType: 5 - LeftColor: ABC4DF - RightColor: AAC4E3 + MinColor: ABC4DF + MaxColor: AAC4E3 ZOffset: -12 ZRamp: 0 2: Clear RampType: 2 - LeftColor: 9BB6D6 - RightColor: A4C0E0 + MinColor: 9BB6D6 + MaxColor: A4C0E0 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 9FB7DC - RightColor: A1B7D3 + MinColor: 9FB7DC + MaxColor: A1B7D3 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 9DB8D7 - RightColor: 9FB9D9 + MinColor: 9DB8D7 + MaxColor: 9FB9D9 ZOffset: -12 ZRamp: 0 5: Clear Height: 1 RampType: 2 - LeftColor: A3BEDF - RightColor: A2BCDD + MinColor: A3BEDF + MaxColor: A2BCDD ZOffset: -12 ZRamp: 0 6: Clear Height: 4 - LeftColor: 8393A6 - RightColor: 748295 + MinColor: 8393A6 + MaxColor: 748295 ZOffset: -12 ZRamp: 0 7: Clear Height: 3 RampType: 3 - LeftColor: 98AFC9 - RightColor: A2BAD5 + MinColor: 98AFC9 + MaxColor: A2BAD5 ZOffset: -12 ZRamp: 0 8: Clear Height: 2 RampType: 2 - LeftColor: 9DB8D7 - RightColor: 9DB4D3 + MinColor: 9DB8D7 + MaxColor: 9DB4D3 ZOffset: -12 ZRamp: 0 10: Clear Height: 3 RampType: 10 - LeftColor: BBD5ED - RightColor: 9EB6E0 + MinColor: BBD5ED + MaxColor: 9EB6E0 ZOffset: -12 ZRamp: 0 11: Clear Height: 3 RampType: 2 - LeftColor: A0B9DC - RightColor: 9EB9DC + MinColor: A0B9DC + MaxColor: 9EB9DC ZOffset: -12 ZRamp: 0 Template@408: @@ -10705,46 +10707,46 @@ Tiles: 0: Clear RampType: 2 - LeftColor: 95AFC9 - RightColor: A3BCE0 + MinColor: 95AFC9 + MaxColor: A3BCE0 ZOffset: -12 ZRamp: 0 1: Clear RampType: 6 - LeftColor: A3BDE2 - RightColor: BCD7F0 + MinColor: A3BDE2 + MaxColor: BCD7F0 ZOffset: -12 ZRamp: 0 3: Clear Height: 1 RampType: 2 - LeftColor: 9AB5D4 - RightColor: 95B0CB + MinColor: 9AB5D4 + MaxColor: 95B0CB ZOffset: -12 ZRamp: 0 4: Cliff RampType: 3 - LeftColor: A8C3E6 - RightColor: A7C1E5 + MinColor: A8C3E6 + MaxColor: A7C1E5 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: BBD7F1 - RightColor: C2DDF3 + MinColor: BBD7F1 + MaxColor: C2DDF3 ZOffset: -12 ZRamp: 0 6: Clear Height: 2 RampType: 2 - LeftColor: 9EB7DB - RightColor: 9FB9DA + MinColor: 9EB7DB + MaxColor: 9FB9DA ZOffset: -12 ZRamp: 0 9: Clear Height: 3 RampType: 2 - LeftColor: ABC4E1 - RightColor: A1B9DC + MinColor: ABC4E1 + MaxColor: A1B9DC ZOffset: -12 ZRamp: 0 Template@409: @@ -10756,21 +10758,21 @@ 0: Cliff Height: 3 RampType: 1 - LeftColor: C4DBED - RightColor: B7CBDD + MinColor: C4DBED + MaxColor: B7CBDD ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 8899A8 - RightColor: 8899AA + MinColor: 8899A8 + MaxColor: 8899AA ZOffset: -12 ZRamp: 0 2: Clear Height: 3 RampType: 9 - LeftColor: BED9F0 - RightColor: C3DEF2 + MinColor: BED9F0 + MaxColor: C3DEF2 ZOffset: -12 ZRamp: 0 Template@410: @@ -10780,66 +10782,66 @@ Size: 4, 3 Tiles: 1: Cliff - LeftColor: B2C5D3 - RightColor: C4D7E5 + MinColor: B2C5D3 + MaxColor: C4D7E5 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 8797A5 - RightColor: 8699AC + MinColor: 8797A5 + MaxColor: 8699AC ZOffset: -12 ZRamp: 0 4: Clear RampType: 5 - LeftColor: C9E0EF - RightColor: BED5EA + MinColor: C9E0EF + MaxColor: BED5EA ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: D4E5EF - RightColor: CADEEB + MinColor: D4E5EF + MaxColor: CADEEB ZOffset: -12 ZRamp: 0 6: Cliff Height: 3 RampType: 4 - LeftColor: B6CBDA - RightColor: C7D7E2 + MinColor: B6CBDA + MaxColor: C7D7E2 ZOffset: -12 ZRamp: 0 7: Clear Height: 3 RampType: 12 - LeftColor: C7DAE7 - RightColor: BDD8F0 + MinColor: C7DAE7 + MaxColor: BDD8F0 ZOffset: -12 ZRamp: 0 8: Clear RampType: 1 - LeftColor: D2E5F1 - RightColor: D1E5F1 + MinColor: D2E5F1 + MaxColor: D1E5F1 ZOffset: -12 ZRamp: 0 9: Clear Height: 1 RampType: 1 - LeftColor: D2E5F0 - RightColor: D2E4EE + MinColor: D2E5F0 + MaxColor: D2E4EE ZOffset: -12 ZRamp: 0 10: Clear Height: 2 RampType: 1 - LeftColor: D4E5EF - RightColor: BACDDA + MinColor: D4E5EF + MaxColor: BACDDA ZOffset: -12 ZRamp: 0 11: Clear Height: 3 RampType: 1 - LeftColor: CCE3F1 - RightColor: BED5E5 + MinColor: CCE3F1 + MaxColor: BED5E5 ZOffset: -12 ZRamp: 0 Template@411: @@ -10850,46 +10852,46 @@ Tiles: 0: Clear RampType: 1 - LeftColor: D2E2EC - RightColor: C7D7E2 + MinColor: D2E2EC + MaxColor: C7D7E2 ZOffset: -12 ZRamp: 0 1: Clear Height: 1 RampType: 1 - LeftColor: C4D3DE - RightColor: CEE1ED + MinColor: C4D3DE + MaxColor: CEE1ED ZOffset: -12 ZRamp: 0 2: Clear Height: 2 RampType: 1 - LeftColor: D3E5F0 - RightColor: CEE2EE + MinColor: D3E5F0 + MaxColor: CEE2EE ZOffset: -12 ZRamp: 0 3: Clear Height: 3 RampType: 1 - LeftColor: D1E8F5 - RightColor: CCE3F2 + MinColor: D1E8F5 + MaxColor: CCE3F2 ZOffset: -12 ZRamp: 0 4: Clear RampType: 8 - LeftColor: BFD8ED - RightColor: DBE7EE + MinColor: BFD8ED + MaxColor: DBE7EE ZOffset: -12 ZRamp: 0 5: Cliff RampType: 4 - LeftColor: BED2E7 - RightColor: C9DCEA + MinColor: BED2E7 + MaxColor: C9DCEA ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C4DDF1 - RightColor: C1DBF1 + MinColor: C4DDF1 + MaxColor: C1DBF1 ZOffset: -12 ZRamp: 0 Template@412: @@ -10901,21 +10903,21 @@ 0: Cliff Height: 3 RampType: 2 - LeftColor: B5CCE1 - RightColor: ACC7E7 + MinColor: B5CCE1 + MaxColor: ACC7E7 ZOffset: -12 ZRamp: 0 1: Clear Height: 3 RampType: 9 - LeftColor: B6D2EF - RightColor: B0CCE9 + MinColor: B6D2EF + MaxColor: B0CCE9 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 7C8D9F - RightColor: 8092A1 + MinColor: 7C8D9F + MaxColor: 8092A1 ZOffset: -12 ZRamp: 0 Template@423: @@ -10925,131 +10927,131 @@ Size: 5, 8 Tiles: 0: Cliff - LeftColor: A1B2C2 - RightColor: 778189 + MinColor: A1B2C2 + MaxColor: 778189 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 565C60 - RightColor: B0C6DA + MinColor: 565C60 + MaxColor: B0C6DA ZOffset: -12 ZRamp: 0 2: Water RampType: 4 - LeftColor: A6B8C8 - RightColor: B8CDE0 + MinColor: A6B8C8 + MaxColor: B8CDE0 ZOffset: -12 ZRamp: 0 3: Water RampType: 12 - LeftColor: 777E85 - RightColor: 9BABB7 + MinColor: 777E85 + MaxColor: 9BABB7 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 3E4E58 - RightColor: 79858D + MinColor: 3E4E58 + MaxColor: 79858D ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 52575A - RightColor: 545556 + MinColor: 52575A + MaxColor: 545556 ZOffset: -12 ZRamp: 0 7: Water - LeftColor: 717D8A - RightColor: 70818F + MinColor: 717D8A + MaxColor: 70818F ZOffset: -12 ZRamp: 0 8: Water RampType: 8 - LeftColor: 4F5A63 - RightColor: 8E9EAA + MinColor: 4F5A63 + MaxColor: 8E9EAA ZOffset: -12 ZRamp: 0 10: Water - LeftColor: 293840 - RightColor: 314149 + MinColor: 293840 + MaxColor: 314149 ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 3B4950 - RightColor: 525657 + MinColor: 3B4950 + MaxColor: 525657 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 454D51 - RightColor: 63737E + MinColor: 454D51 + MaxColor: 63737E ZOffset: -12 ZRamp: 0 13: Water - LeftColor: 37454C - RightColor: 35434C + MinColor: 37454C + MaxColor: 35434C ZOffset: -12 ZRamp: 0 16: Water - LeftColor: 293840 - RightColor: 2C3A42 + MinColor: 293840 + MaxColor: 2C3A42 ZOffset: -12 ZRamp: 0 17: Cliff - LeftColor: 354249 - RightColor: 3B4951 + MinColor: 354249 + MaxColor: 3B4951 ZOffset: -12 ZRamp: 0 18: Water - LeftColor: 303D44 - RightColor: 2A3840 + MinColor: 303D44 + MaxColor: 2A3840 ZOffset: -12 ZRamp: 0 22: Cliff - LeftColor: 303C43 - RightColor: 3A444C + MinColor: 303C43 + MaxColor: 3A444C ZOffset: -12 ZRamp: 0 23: Cliff - LeftColor: 40484E - RightColor: 3B4951 + MinColor: 40484E + MaxColor: 3B4951 ZOffset: -12 ZRamp: 0 27: Cliff - LeftColor: 37454D - RightColor: 323E44 + MinColor: 37454D + MaxColor: 323E44 ZOffset: -12 ZRamp: 0 28: Cliff - LeftColor: 4B4C4D - RightColor: 434649 + MinColor: 4B4C4D + MaxColor: 434649 ZOffset: -12 ZRamp: 0 29: Water - LeftColor: 2A373E - RightColor: 28373F + MinColor: 2A373E + MaxColor: 28373F ZOffset: -12 ZRamp: 0 32: Cliff - LeftColor: 293840 - RightColor: 4C5A64 + MinColor: 293840 + MaxColor: 4C5A64 ZOffset: -12 ZRamp: 0 33: Cliff - LeftColor: 454D53 - RightColor: 515152 + MinColor: 454D53 + MaxColor: 515152 ZOffset: -12 ZRamp: 0 34: Cliff - LeftColor: 34373A - RightColor: 27333B + MinColor: 34373A + MaxColor: 27333B ZOffset: -12 ZRamp: 0 38: Cliff - LeftColor: 293840 - RightColor: 464D50 + MinColor: 293840 + MaxColor: 464D50 ZOffset: -12 ZRamp: 0 39: Cliff - LeftColor: 313538 - RightColor: 32363A + MinColor: 313538 + MaxColor: 32363A ZOffset: -12 ZRamp: 0 Template@424: @@ -11059,38 +11061,38 @@ Size: 3, 3 Tiles: 1: Cliff - LeftColor: 747677 - RightColor: 6C7680 + MinColor: 747677 + MaxColor: 6C7680 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 788691 - RightColor: 8392A0 + MinColor: 788691 + MaxColor: 8392A0 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 707A82 - RightColor: 666F77 + MinColor: 707A82 + MaxColor: 666F77 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 75818D - RightColor: 828F9A + MinColor: 75818D + MaxColor: 828F9A ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: B1BDC8 - RightColor: 878788 + MinColor: B1BDC8 + MaxColor: 878788 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B6C1C7 - RightColor: B7BBBD + MinColor: B6C1C7 + MaxColor: B7BBBD ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C0CCD8 - RightColor: 828D97 + MinColor: C0CCD8 + MaxColor: 828D97 ZOffset: -12 ZRamp: 0 Template@435: @@ -11101,46 +11103,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8593A0 - RightColor: 77838C + MinColor: 8593A0 + MaxColor: 77838C ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 4E5860 - RightColor: 3C4751 + MinColor: 4E5860 + MaxColor: 3C4751 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 7A8B9C - RightColor: 7B8A9A + MinColor: 7A8B9C + MaxColor: 7B8A9A ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 687B90 - RightColor: 4E5C65 + MinColor: 687B90 + MaxColor: 4E5C65 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: A9BFD3 - RightColor: A1B5C7 + MinColor: A9BFD3 + MaxColor: A1B5C7 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 455662 - RightColor: 70879B + MinColor: 455662 + MaxColor: 70879B ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: B3CADD - RightColor: 99A7B4 + MinColor: B3CADD + MaxColor: 99A7B4 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 667580 - RightColor: 38454E + MinColor: 667580 + MaxColor: 38454E ZOffset: -12 ZRamp: 0 Template@436: @@ -11151,24 +11153,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 2C373D - RightColor: 263138 + MinColor: 2C373D + MaxColor: 263138 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 656D72 - RightColor: 576065 + MinColor: 656D72 + MaxColor: 576065 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: A9B8C2 - RightColor: ABB8C2 + MinColor: A9B8C2 + MaxColor: ABB8C2 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 485862 - RightColor: 738690 + MinColor: 485862 + MaxColor: 738690 ZOffset: -12 ZRamp: 0 Template@437: @@ -11179,46 +11181,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 333F46 - RightColor: 28343A + MinColor: 333F46 + MaxColor: 28343A ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 424E55 - RightColor: 253036 + MinColor: 424E55 + MaxColor: 253036 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 80868D - RightColor: 485258 + MinColor: 80868D + MaxColor: 485258 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 70797E - RightColor: 505C63 + MinColor: 70797E + MaxColor: 505C63 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: A0B1BC - RightColor: CED7DF + MinColor: A0B1BC + MaxColor: CED7DF ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C1CCD5 - RightColor: B6C3D0 + MinColor: C1CCD5 + MaxColor: B6C3D0 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 445560 - RightColor: 728691 + MinColor: 445560 + MaxColor: 728691 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 62737E - RightColor: 798B96 + MinColor: 62737E + MaxColor: 798B96 ZOffset: -12 ZRamp: 0 Template@438: @@ -11229,46 +11231,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 2B3339 - RightColor: 444D52 + MinColor: 2B3339 + MaxColor: 444D52 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 838E9A - RightColor: 8494A4 + MinColor: 838E9A + MaxColor: 8494A4 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 6C7378 - RightColor: 38434A + MinColor: 6C7378 + MaxColor: 38434A ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 79838B - RightColor: 94A2AF + MinColor: 79838B + MaxColor: 94A2AF ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: B7C1C8 - RightColor: A8B7C2 + MinColor: B7C1C8 + MaxColor: A8B7C2 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: B4C9DE - RightColor: 859BAC + MinColor: B4C9DE + MaxColor: 859BAC ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 475863 - RightColor: 798A95 + MinColor: 475863 + MaxColor: 798A95 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: A1AFBB - RightColor: B0C2D3 + MinColor: A1AFBB + MaxColor: B0C2D3 ZOffset: -12 ZRamp: 0 Template@439: @@ -11278,8 +11280,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AFCBED - RightColor: B0CCED + MinColor: AFCBED + MaxColor: B0CCED ZOffset: -12 ZRamp: 0 Template@440: @@ -11289,8 +11291,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AAC4EA - RightColor: ABC6EB + MinColor: AAC4EA + MaxColor: ABC6EB ZOffset: -12 ZRamp: 0 Template@441: @@ -11300,8 +11302,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AECAEC - RightColor: A5BEE7 + MinColor: AECAEC + MaxColor: A5BEE7 ZOffset: -12 ZRamp: 0 Template@442: @@ -11311,8 +11313,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ADC8EC - RightColor: A7C1E8 + MinColor: ADC8EC + MaxColor: A7C1E8 ZOffset: -12 ZRamp: 0 Template@443: @@ -11322,8 +11324,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ABC6EB - RightColor: 9EB5E3 + MinColor: ABC6EB + MaxColor: 9EB5E3 ZOffset: -12 ZRamp: 0 Template@444: @@ -11333,8 +11335,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A2BBE6 - RightColor: ACC7EB + MinColor: A2BBE6 + MaxColor: ACC7EB ZOffset: -12 ZRamp: 0 Template@445: @@ -11344,8 +11346,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A5BFE8 - RightColor: A5BFE8 + MinColor: A5BFE8 + MaxColor: A5BFE8 ZOffset: -12 ZRamp: 0 Template@446: @@ -11355,8 +11357,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A2BBE6 - RightColor: A6BFE7 + MinColor: A2BBE6 + MaxColor: A6BFE7 ZOffset: -12 ZRamp: 0 Template@447: @@ -11366,8 +11368,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A8C3EA - RightColor: 9EB5E3 + MinColor: A8C3EA + MaxColor: 9EB5E3 ZOffset: -12 ZRamp: 0 Template@448: @@ -11377,8 +11379,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A4BEE8 - RightColor: ADC9EC + MinColor: A4BEE8 + MaxColor: ADC9EC ZOffset: -12 ZRamp: 0 Template@449: @@ -11388,8 +11390,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A4BEE8 - RightColor: A6C0E9 + MinColor: A4BEE8 + MaxColor: A6C0E9 ZOffset: -12 ZRamp: 0 Template@450: @@ -11399,8 +11401,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A3BDE7 - RightColor: A6C0E8 + MinColor: A3BDE7 + MaxColor: A6C0E8 ZOffset: -12 ZRamp: 0 Template@451: @@ -11410,8 +11412,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A6C0E9 - RightColor: 9DB4E3 + MinColor: A6C0E9 + MaxColor: 9DB4E3 ZOffset: -12 ZRamp: 0 Template@452: @@ -11421,8 +11423,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9DB5E4 - RightColor: AEC9EC + MinColor: 9DB5E4 + MaxColor: AEC9EC ZOffset: -12 ZRamp: 0 Template@453: @@ -11432,8 +11434,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9EB6E4 - RightColor: A5BEE8 + MinColor: 9EB6E4 + MaxColor: A5BEE8 ZOffset: -12 ZRamp: 0 Template@454: @@ -11443,8 +11445,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9DB4E3 - RightColor: A6BFE7 + MinColor: 9DB4E3 + MaxColor: A6BFE7 ZOffset: -12 ZRamp: 0 Template@455: @@ -11454,8 +11456,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9AB0E1 - RightColor: 98AEE0 + MinColor: 9AB0E1 + MaxColor: 98AEE0 ZOffset: -12 ZRamp: 0 Template@456: @@ -11465,8 +11467,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 415160 - RightColor: 677895 + MinColor: 415160 + MaxColor: 677895 ZOffset: -12 ZRamp: 0 Template@457: @@ -11476,8 +11478,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 3E4F5F - RightColor: 637693 + MinColor: 3E4F5F + MaxColor: 637693 ZOffset: -12 ZRamp: 0 Template@458: @@ -11487,8 +11489,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 475769 - RightColor: 8195BB + MinColor: 475769 + MaxColor: 8195BB ZOffset: -12 ZRamp: 0 Template@459: @@ -11498,8 +11500,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6B7D9F - RightColor: 3F505F + MinColor: 6B7D9F + MaxColor: 3F505F ZOffset: -12 ZRamp: 0 Template@460: @@ -11509,8 +11511,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7386A9 - RightColor: 7384A6 + MinColor: 7386A9 + MaxColor: 7384A6 ZOffset: -12 ZRamp: 0 Template@461: @@ -11520,8 +11522,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6B7D9F - RightColor: 677A99 + MinColor: 6B7D9F + MaxColor: 677A99 ZOffset: -12 ZRamp: 0 Template@462: @@ -11531,8 +11533,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7385A8 - RightColor: 8598C1 + MinColor: 7385A8 + MaxColor: 8598C1 ZOffset: -12 ZRamp: 0 Template@463: @@ -11542,8 +11544,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 596A80 - RightColor: 3A4B57 + MinColor: 596A80 + MaxColor: 3A4B57 ZOffset: -12 ZRamp: 0 Template@464: @@ -11553,8 +11555,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 596B82 - RightColor: 677895 + MinColor: 596B82 + MaxColor: 677895 ZOffset: -12 ZRamp: 0 Template@465: @@ -11564,8 +11566,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5F7189 - RightColor: 6A7E9C + MinColor: 5F7189 + MaxColor: 6A7E9C ZOffset: -12 ZRamp: 0 Template@466: @@ -11575,8 +11577,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 60728B - RightColor: 8195BB + MinColor: 60728B + MaxColor: 8195BB ZOffset: -12 ZRamp: 0 Template@467: @@ -11586,8 +11588,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7E91B9 - RightColor: 465768 + MinColor: 7E91B9 + MaxColor: 465768 ZOffset: -12 ZRamp: 0 Template@468: @@ -11597,8 +11599,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7F93BB - RightColor: 7284A6 + MinColor: 7F93BB + MaxColor: 7284A6 ZOffset: -12 ZRamp: 0 Template@469: @@ -11608,8 +11610,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7E91B9 - RightColor: 6E82A2 + MinColor: 7E91B9 + MaxColor: 6E82A2 ZOffset: -12 ZRamp: 0 Template@470: @@ -11619,8 +11621,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7F92BA - RightColor: 8397BF + MinColor: 7F92BA + MaxColor: 8397BF ZOffset: -12 ZRamp: 0 Template@471: @@ -11630,8 +11632,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 475769 - RightColor: 7183A5 + MinColor: 475769 + MaxColor: 7183A5 ZOffset: -12 ZRamp: 0 Template@472: @@ -11641,8 +11643,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 475869 - RightColor: 637693 + MinColor: 475869 + MaxColor: 637693 ZOffset: -12 ZRamp: 0 Template@473: @@ -11652,8 +11654,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 506073 - RightColor: 8195BB + MinColor: 506073 + MaxColor: 8195BB ZOffset: -12 ZRamp: 0 Template@474: @@ -11663,8 +11665,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7083A5 - RightColor: 465667 + MinColor: 7083A5 + MaxColor: 465667 ZOffset: -12 ZRamp: 0 Template@475: @@ -11674,8 +11676,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7183A6 - RightColor: 6E81A1 + MinColor: 7183A6 + MaxColor: 6E81A1 ZOffset: -12 ZRamp: 0 Template@476: @@ -11685,8 +11687,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 596A80 - RightColor: 4F6074 + MinColor: 596A80 + MaxColor: 4F6074 ZOffset: -12 ZRamp: 0 Template@477: @@ -11696,8 +11698,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5F718B - RightColor: 7182A5 + MinColor: 5F718B + MaxColor: 7182A5 ZOffset: -12 ZRamp: 0 Template@478: @@ -11707,8 +11709,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7E91B9 - RightColor: 5B6C85 + MinColor: 7E91B9 + MaxColor: 5B6C85 ZOffset: -12 ZRamp: 0 Template@479: @@ -11718,8 +11720,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 495A6A - RightColor: 677895 + MinColor: 495A6A + MaxColor: 677895 ZOffset: -12 ZRamp: 0 Template@480: @@ -11729,8 +11731,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 445566 - RightColor: 6A7D9B + MinColor: 445566 + MaxColor: 6A7D9B ZOffset: -12 ZRamp: 0 Template@481: @@ -11740,8 +11742,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6B7D9F - RightColor: 54657C + MinColor: 6B7D9F + MaxColor: 54657C ZOffset: -12 ZRamp: 0 Template@482: @@ -11751,8 +11753,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5F7189 - RightColor: 455666 + MinColor: 5F7189 + MaxColor: 455666 ZOffset: -12 ZRamp: 0 Template@483: @@ -11762,8 +11764,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 506073 - RightColor: 7183A5 + MinColor: 506073 + MaxColor: 7183A5 ZOffset: -12 ZRamp: 0 Template@484: @@ -11773,8 +11775,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4D5D70 - RightColor: 6A7D9B + MinColor: 4D5D70 + MaxColor: 6A7D9B ZOffset: -12 ZRamp: 0 Template@485: @@ -11784,8 +11786,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7083A5 - RightColor: 5A6B84 + MinColor: 7083A5 + MaxColor: 5A6B84 ZOffset: -12 ZRamp: 0 Template@486: @@ -11795,8 +11797,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5F7189 - RightColor: 596B83 + MinColor: 5F7189 + MaxColor: 596B83 ZOffset: -12 ZRamp: 0 Template@487: @@ -11806,8 +11808,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 3E4E5D - RightColor: 3A4A56 + MinColor: 3E4E5D + MaxColor: 3A4A56 ZOffset: -12 ZRamp: 0 Template@488: @@ -11817,8 +11819,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 384856 - RightColor: 48586B + MinColor: 384856 + MaxColor: 48586B ZOffset: -12 ZRamp: 0 Template@489: @@ -11828,8 +11830,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 3E4F5F - RightColor: 3E4E5E + MinColor: 3E4F5F + MaxColor: 3E4E5E ZOffset: -12 ZRamp: 0 Template@490: @@ -11839,8 +11841,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 415160 - RightColor: 33444E + MinColor: 415160 + MaxColor: 33444E ZOffset: -12 ZRamp: 0 Template@491: @@ -11850,8 +11852,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 3E4E5D - RightColor: 4E5F73 + MinColor: 3E4E5D + MaxColor: 4E5F73 ZOffset: -12 ZRamp: 0 Template@492: @@ -11861,8 +11863,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 3E4F5F - RightColor: 52637B + MinColor: 3E4F5F + MaxColor: 52637B ZOffset: -12 ZRamp: 0 Template@493: @@ -11872,8 +11874,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 475869 - RightColor: 3E4E5E + MinColor: 475869 + MaxColor: 3E4E5E ZOffset: -12 ZRamp: 0 Template@494: @@ -11883,8 +11885,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 475767 - RightColor: 3A4A56 + MinColor: 475767 + MaxColor: 3A4A56 ZOffset: -12 ZRamp: 0 Template@495: @@ -11894,8 +11896,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 445566 - RightColor: 596A82 + MinColor: 445566 + MaxColor: 596A82 ZOffset: -12 ZRamp: 0 Template@496: @@ -11905,8 +11907,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 475869 - RightColor: 52637B + MinColor: 475869 + MaxColor: 52637B ZOffset: -12 ZRamp: 0 Template@497: @@ -11916,8 +11918,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4D5D70 - RightColor: 445565 + MinColor: 4D5D70 + MaxColor: 445565 ZOffset: -12 ZRamp: 0 Template@498: @@ -11927,8 +11929,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 475767 - RightColor: 4E5F73 + MinColor: 475767 + MaxColor: 4E5F73 ZOffset: -12 ZRamp: 0 Template@499: @@ -11938,8 +11940,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 445566 - RightColor: 445565 + MinColor: 445566 + MaxColor: 445565 ZOffset: -12 ZRamp: 0 Template@500: @@ -11949,8 +11951,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 415160 - RightColor: 48586B + MinColor: 415160 + MaxColor: 48586B ZOffset: -12 ZRamp: 0 Template@501: @@ -11960,8 +11962,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4D5D70 - RightColor: 596A82 + MinColor: 4D5D70 + MaxColor: 596A82 ZOffset: -12 ZRamp: 0 Template@502: @@ -11971,8 +11973,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 2B3B43 - RightColor: 2A3A42 + MinColor: 2B3B43 + MaxColor: 2A3A42 ZOffset: -12 ZRamp: 0 Template@503: @@ -11982,8 +11984,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B2CEEE - RightColor: B5D0EE + MinColor: B2CEEE + MaxColor: B5D0EE ZOffset: -12 ZRamp: 0 Template@504: @@ -11993,8 +11995,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ADC8EB - RightColor: ADC7EB + MinColor: ADC8EB + MaxColor: ADC7EB ZOffset: -12 ZRamp: 0 Template@505: @@ -12004,8 +12006,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AFCAEC - RightColor: A7C0E8 + MinColor: AFCAEC + MaxColor: A7C0E8 ZOffset: -12 ZRamp: 0 Template@506: @@ -12015,8 +12017,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B0CBED - RightColor: A5BFE8 + MinColor: B0CBED + MaxColor: A5BFE8 ZOffset: -12 ZRamp: 0 Template@507: @@ -12026,8 +12028,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ADC8EC - RightColor: 9EB6E5 + MinColor: ADC8EC + MaxColor: 9EB6E5 ZOffset: -12 ZRamp: 0 Template@508: @@ -12037,8 +12039,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A5BEE8 - RightColor: B0CBED + MinColor: A5BEE8 + MaxColor: B0CBED ZOffset: -12 ZRamp: 0 Template@509: @@ -12048,8 +12050,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A6C0E9 - RightColor: A9C3EA + MinColor: A6C0E9 + MaxColor: A9C3EA ZOffset: -12 ZRamp: 0 Template@510: @@ -12059,8 +12061,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A5BEE8 - RightColor: A5BFE8 + MinColor: A5BEE8 + MaxColor: A5BFE8 ZOffset: -12 ZRamp: 0 Template@511: @@ -12070,8 +12072,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A5BEE7 - RightColor: 9CB4E3 + MinColor: A5BEE7 + MaxColor: 9CB4E3 ZOffset: -12 ZRamp: 0 Template@512: @@ -12081,8 +12083,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A4BDE7 - RightColor: B0CBED + MinColor: A4BDE7 + MaxColor: B0CBED ZOffset: -12 ZRamp: 0 Template@513: @@ -12092,8 +12094,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A4BDE7 - RightColor: A7C0E8 + MinColor: A4BDE7 + MaxColor: A7C0E8 ZOffset: -12 ZRamp: 0 Template@514: @@ -12103,8 +12105,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A6C0E8 - RightColor: A6C0E9 + MinColor: A6C0E8 + MaxColor: A6C0E9 ZOffset: -12 ZRamp: 0 Template@515: @@ -12114,8 +12116,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A6C0E8 - RightColor: A0B8E5 + MinColor: A6C0E8 + MaxColor: A0B8E5 ZOffset: -12 ZRamp: 0 Template@516: @@ -12125,8 +12127,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9EB6E4 - RightColor: ADC8EB + MinColor: 9EB6E4 + MaxColor: ADC8EB ZOffset: -12 ZRamp: 0 Template@517: @@ -12136,8 +12138,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9FB7E5 - RightColor: A9C3EA + MinColor: 9FB7E5 + MaxColor: A9C3EA ZOffset: -12 ZRamp: 0 Template@518: @@ -12147,8 +12149,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9FB7E5 - RightColor: A6C0E9 + MinColor: 9FB7E5 + MaxColor: A6C0E9 ZOffset: -12 ZRamp: 0 Template@519: @@ -12158,8 +12160,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 99B0E0 - RightColor: 99B0E0 + MinColor: 99B0E0 + MaxColor: 99B0E0 ZOffset: -12 ZRamp: 0 Template@520: @@ -12169,8 +12171,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 404F61 - RightColor: 697B9E + MinColor: 404F61 + MaxColor: 697B9E ZOffset: -12 ZRamp: 0 Template@521: @@ -12180,8 +12182,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 3B4C58 - RightColor: 647896 + MinColor: 3B4C58 + MaxColor: 647896 ZOffset: -12 ZRamp: 0 Template@522: @@ -12191,8 +12193,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4E5F74 - RightColor: 8A9FCD + MinColor: 4E5F74 + MaxColor: 8A9FCD ZOffset: -12 ZRamp: 0 Template@523: @@ -12202,8 +12204,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 697C9D - RightColor: 344450 + MinColor: 697C9D + MaxColor: 344450 ZOffset: -12 ZRamp: 0 Template@524: @@ -12213,8 +12215,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 798DB5 - RightColor: 7386AD + MinColor: 798DB5 + MaxColor: 7386AD ZOffset: -12 ZRamp: 0 Template@525: @@ -12224,8 +12226,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6A7E9E - RightColor: 647795 + MinColor: 6A7E9E + MaxColor: 647795 ZOffset: -12 ZRamp: 0 Template@526: @@ -12235,8 +12237,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7B8FB7 - RightColor: 8A9FCD + MinColor: 7B8FB7 + MaxColor: 8A9FCD ZOffset: -12 ZRamp: 0 Template@527: @@ -12246,8 +12248,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 516379 - RightColor: 2B3B44 + MinColor: 516379 + MaxColor: 2B3B44 ZOffset: -12 ZRamp: 0 Template@528: @@ -12257,8 +12259,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 54677E - RightColor: 697B9E + MinColor: 54677E + MaxColor: 697B9E ZOffset: -12 ZRamp: 0 Template@529: @@ -12268,8 +12270,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5D7089 - RightColor: 667998 + MinColor: 5D7089 + MaxColor: 667998 ZOffset: -12 ZRamp: 0 Template@530: @@ -12279,8 +12281,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5F738D - RightColor: 8A9FCD + MinColor: 5F738D + MaxColor: 8A9FCD ZOffset: -12 ZRamp: 0 Template@531: @@ -12290,8 +12292,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7D92B8 - RightColor: 364754 + MinColor: 7D92B8 + MaxColor: 364754 ZOffset: -12 ZRamp: 0 Template@532: @@ -12301,8 +12303,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7E93BB - RightColor: 7386AD + MinColor: 7E93BB + MaxColor: 7386AD ZOffset: -12 ZRamp: 0 Template@533: @@ -12312,8 +12314,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7D92B9 - RightColor: 667998 + MinColor: 7D92B9 + MaxColor: 667998 ZOffset: -12 ZRamp: 0 Template@534: @@ -12323,8 +12325,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7F94BC - RightColor: 8A9FCD + MinColor: 7F94BC + MaxColor: 8A9FCD ZOffset: -12 ZRamp: 0 Template@535: @@ -12334,8 +12336,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4A5A6E - RightColor: 7487AE + MinColor: 4A5A6E + MaxColor: 7487AE ZOffset: -12 ZRamp: 0 Template@536: @@ -12345,8 +12347,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 425463 - RightColor: 647896 + MinColor: 425463 + MaxColor: 647896 ZOffset: -12 ZRamp: 0 Template@537: @@ -12356,8 +12358,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 566780 - RightColor: 8A9FCD + MinColor: 566780 + MaxColor: 8A9FCD ZOffset: -12 ZRamp: 0 Template@538: @@ -12367,8 +12369,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7589AE - RightColor: 364754 + MinColor: 7589AE + MaxColor: 364754 ZOffset: -12 ZRamp: 0 Template@539: @@ -12378,8 +12380,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 768AB0 - RightColor: 667A99 + MinColor: 768AB0 + MaxColor: 667A99 ZOffset: -12 ZRamp: 0 Template@540: @@ -12389,8 +12391,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 516379 - RightColor: 3A4B5A + MinColor: 516379 + MaxColor: 3A4B5A ZOffset: -12 ZRamp: 0 Template@541: @@ -12400,8 +12402,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5E718B - RightColor: 7487AE + MinColor: 5E718B + MaxColor: 7487AE ZOffset: -12 ZRamp: 0 Template@542: @@ -12411,8 +12413,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7D92B8 - RightColor: 45566A + MinColor: 7D92B8 + MaxColor: 45566A ZOffset: -12 ZRamp: 0 Template@543: @@ -12422,8 +12424,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4A5B70 - RightColor: 697B9E + MinColor: 4A5B70 + MaxColor: 697B9E ZOffset: -12 ZRamp: 0 Template@544: @@ -12433,8 +12435,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 47596B - RightColor: 667A99 + MinColor: 47596B + MaxColor: 667A99 ZOffset: -12 ZRamp: 0 Template@545: @@ -12444,8 +12446,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 697C9D - RightColor: 435467 + MinColor: 697C9D + MaxColor: 435467 ZOffset: -12 ZRamp: 0 Template@546: @@ -12455,8 +12457,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5B6F87 - RightColor: 374855 + MinColor: 5B6F87 + MaxColor: 374855 ZOffset: -12 ZRamp: 0 Template@547: @@ -12466,8 +12468,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 54657D - RightColor: 7487AE + MinColor: 54657D + MaxColor: 7487AE ZOffset: -12 ZRamp: 0 Template@548: @@ -12477,8 +12479,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4F6176 - RightColor: 667A99 + MinColor: 4F6176 + MaxColor: 667A99 ZOffset: -12 ZRamp: 0 Template@549: @@ -12488,8 +12490,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7589AE - RightColor: 45576A + MinColor: 7589AE + MaxColor: 45576A ZOffset: -12 ZRamp: 0 Template@550: @@ -12499,8 +12501,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5B6F87 - RightColor: 46586B + MinColor: 5B6F87 + MaxColor: 46586B ZOffset: -12 ZRamp: 0 Template@551: @@ -12510,8 +12512,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 354653 - RightColor: 2B3B44 + MinColor: 354653 + MaxColor: 2B3B44 ZOffset: -12 ZRamp: 0 Template@552: @@ -12521,8 +12523,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 293941 - RightColor: 384856 + MinColor: 293941 + MaxColor: 384856 ZOffset: -12 ZRamp: 0 Template@553: @@ -12532,8 +12534,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 33444F - RightColor: 354552 + MinColor: 33444F + MaxColor: 354552 ZOffset: -12 ZRamp: 0 Template@554: @@ -12543,8 +12545,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 364753 - RightColor: 283840 + MinColor: 364753 + MaxColor: 283840 ZOffset: -12 ZRamp: 0 Template@555: @@ -12554,8 +12556,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 354653 - RightColor: 3A4B5A + MinColor: 354653 + MaxColor: 3A4B5A ZOffset: -12 ZRamp: 0 Template@556: @@ -12565,8 +12567,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 33444F - RightColor: 445568 + MinColor: 33444F + MaxColor: 445568 ZOffset: -12 ZRamp: 0 Template@557: @@ -12576,8 +12578,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 405261 - RightColor: 354552 + MinColor: 405261 + MaxColor: 354552 ZOffset: -12 ZRamp: 0 Template@558: @@ -12587,8 +12589,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 425365 - RightColor: 2B3B44 + MinColor: 425365 + MaxColor: 2B3B44 ZOffset: -12 ZRamp: 0 Template@559: @@ -12598,8 +12600,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 405161 - RightColor: 46586B + MinColor: 405161 + MaxColor: 46586B ZOffset: -12 ZRamp: 0 Template@560: @@ -12609,8 +12611,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 405261 - RightColor: 445568 + MinColor: 405261 + MaxColor: 445568 ZOffset: -12 ZRamp: 0 Template@561: @@ -12620,8 +12622,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4D5F73 - RightColor: 374855 + MinColor: 4D5F73 + MaxColor: 374855 ZOffset: -12 ZRamp: 0 Template@562: @@ -12631,8 +12633,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 425365 - RightColor: 3A4B5A + MinColor: 425365 + MaxColor: 3A4B5A ZOffset: -12 ZRamp: 0 Template@563: @@ -12642,8 +12644,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 405161 - RightColor: 374855 + MinColor: 405161 + MaxColor: 374855 ZOffset: -12 ZRamp: 0 Template@564: @@ -12653,8 +12655,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 364653 - RightColor: 384856 + MinColor: 364653 + MaxColor: 384856 ZOffset: -12 ZRamp: 0 Template@565: @@ -12664,8 +12666,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4D5F73 - RightColor: 46586B + MinColor: 4D5F73 + MaxColor: 46586B ZOffset: -12 ZRamp: 0 Template@566: @@ -12675,8 +12677,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 293941 - RightColor: 283840 + MinColor: 293941 + MaxColor: 283840 ZOffset: -12 ZRamp: 0 Template@567: @@ -12686,8 +12688,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B0CCED - RightColor: AECAEC + MinColor: B0CCED + MaxColor: AECAEC ZOffset: -12 ZRamp: 0 Template@568: @@ -12697,8 +12699,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ABC5EA - RightColor: AAC5EA + MinColor: ABC5EA + MaxColor: AAC5EA ZOffset: -12 ZRamp: 0 Template@569: @@ -12708,8 +12710,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ACC6EB - RightColor: A2BAE6 + MinColor: ACC6EB + MaxColor: A2BAE6 ZOffset: -12 ZRamp: 0 Template@570: @@ -12719,8 +12721,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AEC9EC - RightColor: A1BAE5 + MinColor: AEC9EC + MaxColor: A1BAE5 ZOffset: -12 ZRamp: 0 Template@571: @@ -12730,8 +12732,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ABC6EB - RightColor: 9BB1E2 + MinColor: ABC6EB + MaxColor: 9BB1E2 ZOffset: -12 ZRamp: 0 Template@572: @@ -12741,8 +12743,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A5BEE8 - RightColor: ACC7EB + MinColor: A5BEE8 + MaxColor: ACC7EB ZOffset: -12 ZRamp: 0 Template@573: @@ -12752,8 +12754,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A5BFE8 - RightColor: A3BBE7 + MinColor: A5BFE8 + MaxColor: A3BBE7 ZOffset: -12 ZRamp: 0 Template@574: @@ -12763,8 +12765,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A5BEE8 - RightColor: A1BAE5 + MinColor: A5BEE8 + MaxColor: A1BAE5 ZOffset: -12 ZRamp: 0 Template@575: @@ -12774,8 +12776,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A5BFE8 - RightColor: 9BB1E2 + MinColor: A5BFE8 + MaxColor: 9BB1E2 ZOffset: -12 ZRamp: 0 Template@576: @@ -12785,8 +12787,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A3BCE7 - RightColor: AAC4EB + MinColor: A3BCE7 + MaxColor: AAC4EB ZOffset: -12 ZRamp: 0 Template@577: @@ -12796,8 +12798,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A3BCE7 - RightColor: A2BAE6 + MinColor: A3BCE7 + MaxColor: A2BAE6 ZOffset: -12 ZRamp: 0 Template@578: @@ -12807,8 +12809,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A4BDE7 - RightColor: A2BAE6 + MinColor: A4BDE7 + MaxColor: A2BAE6 ZOffset: -12 ZRamp: 0 Template@579: @@ -12818,8 +12820,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A4BDE7 - RightColor: 9BB1E2 + MinColor: A4BDE7 + MaxColor: 9BB1E2 ZOffset: -12 ZRamp: 0 Template@580: @@ -12829,8 +12831,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9FB7E4 - RightColor: A8C2EA + MinColor: 9FB7E4 + MaxColor: A8C2EA ZOffset: -12 ZRamp: 0 Template@581: @@ -12840,8 +12842,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9FB7E4 - RightColor: A1B9E6 + MinColor: 9FB7E4 + MaxColor: A1B9E6 ZOffset: -12 ZRamp: 0 Template@582: @@ -12851,8 +12853,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9FB7E4 - RightColor: A0B8E5 + MinColor: 9FB7E4 + MaxColor: A0B8E5 ZOffset: -12 ZRamp: 0 Template@583: @@ -12862,8 +12864,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9AB0DF - RightColor: 9AAFE0 + MinColor: 9AB0DF + MaxColor: 9AAFE0 ZOffset: -12 ZRamp: 0 Template@584: @@ -12873,8 +12875,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 405261 - RightColor: 7084A1 + MinColor: 405261 + MaxColor: 7084A1 ZOffset: -12 ZRamp: 0 Template@585: @@ -12884,8 +12886,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 415262 - RightColor: 61738D + MinColor: 415262 + MaxColor: 61738D ZOffset: -12 ZRamp: 0 Template@586: @@ -12895,8 +12897,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 516378 - RightColor: 889DC2 + MinColor: 516378 + MaxColor: 889DC2 ZOffset: -12 ZRamp: 0 Template@587: @@ -12906,8 +12908,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 677B96 - RightColor: 3F505F + MinColor: 677B96 + MaxColor: 3F505F ZOffset: -12 ZRamp: 0 Template@588: @@ -12917,8 +12919,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7589A9 - RightColor: 7E94B6 + MinColor: 7589A9 + MaxColor: 7E94B6 ZOffset: -12 ZRamp: 0 Template@589: @@ -12928,8 +12930,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 677B96 - RightColor: 60738C + MinColor: 677B96 + MaxColor: 60738C ZOffset: -12 ZRamp: 0 Template@590: @@ -12939,8 +12941,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7589A9 - RightColor: 889DC2 + MinColor: 7589A9 + MaxColor: 889DC2 ZOffset: -12 ZRamp: 0 Template@591: @@ -12950,8 +12952,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 657A94 - RightColor: 31414B + MinColor: 657A94 + MaxColor: 31414B ZOffset: -12 ZRamp: 0 Template@592: @@ -12961,8 +12963,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 657A94 - RightColor: 7084A1 + MinColor: 657A94 + MaxColor: 7084A1 ZOffset: -12 ZRamp: 0 Template@593: @@ -12972,8 +12974,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 768BAB - RightColor: 647792 + MinColor: 768BAB + MaxColor: 647792 ZOffset: -12 ZRamp: 0 Template@594: @@ -12983,8 +12985,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 768BAB - RightColor: 889DC2 + MinColor: 768BAB + MaxColor: 889DC2 ZOffset: -12 ZRamp: 0 Template@595: @@ -12994,8 +12996,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 859BBF - RightColor: 435464 + MinColor: 859BBF + MaxColor: 435464 ZOffset: -12 ZRamp: 0 Template@596: @@ -13005,8 +13007,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 859BBF - RightColor: 7E94B6 + MinColor: 859BBF + MaxColor: 7E94B6 ZOffset: -12 ZRamp: 0 Template@597: @@ -13016,8 +13018,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 859BBF - RightColor: 647792 + MinColor: 859BBF + MaxColor: 647792 ZOffset: -12 ZRamp: 0 Template@598: @@ -13027,8 +13029,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 859BBF - RightColor: 889DC2 + MinColor: 859BBF + MaxColor: 889DC2 ZOffset: -12 ZRamp: 0 Template@599: @@ -13038,8 +13040,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4C5F71 - RightColor: 7A8FB0 + MinColor: 4C5F71 + MaxColor: 7A8FB0 ZOffset: -12 ZRamp: 0 Template@600: @@ -13049,8 +13051,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4D6072 - RightColor: 61738D + MinColor: 4D6072 + MaxColor: 61738D ZOffset: -12 ZRamp: 0 Template@601: @@ -13060,8 +13062,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5D7188 - RightColor: 889DC2 + MinColor: 5D7188 + MaxColor: 889DC2 ZOffset: -12 ZRamp: 0 Template@602: @@ -13071,8 +13073,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6D829F - RightColor: 425362 + MinColor: 6D829F + MaxColor: 425362 ZOffset: -12 ZRamp: 0 Template@603: @@ -13082,8 +13084,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6D829F - RightColor: 62758F + MinColor: 6D829F + MaxColor: 62758F ZOffset: -12 ZRamp: 0 Template@604: @@ -13093,8 +13095,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 657A94 - RightColor: 415363 + MinColor: 657A94 + MaxColor: 415363 ZOffset: -12 ZRamp: 0 Template@605: @@ -13104,8 +13106,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7288A5 - RightColor: 7A8FB0 + MinColor: 7288A5 + MaxColor: 7A8FB0 ZOffset: -12 ZRamp: 0 Template@606: @@ -13115,8 +13117,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 859BBF - RightColor: 54677C + MinColor: 859BBF + MaxColor: 54677C ZOffset: -12 ZRamp: 0 Template@607: @@ -13126,8 +13128,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4C5F72 - RightColor: 7084A1 + MinColor: 4C5F72 + MaxColor: 7084A1 ZOffset: -12 ZRamp: 0 Template@608: @@ -13137,8 +13139,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 47596B - RightColor: 637690 + MinColor: 47596B + MaxColor: 637690 ZOffset: -12 ZRamp: 0 Template@609: @@ -13148,8 +13150,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 677B96 - RightColor: 506277 + MinColor: 677B96 + MaxColor: 506277 ZOffset: -12 ZRamp: 0 Template@610: @@ -13159,8 +13161,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7187A3 - RightColor: 3D4F5C + MinColor: 7187A3 + MaxColor: 3D4F5C ZOffset: -12 ZRamp: 0 Template@611: @@ -13170,8 +13172,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 586D82 - RightColor: 7A8FB0 + MinColor: 586D82 + MaxColor: 7A8FB0 ZOffset: -12 ZRamp: 0 Template@612: @@ -13181,8 +13183,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 53677B - RightColor: 637690 + MinColor: 53677B + MaxColor: 637690 ZOffset: -12 ZRamp: 0 Template@613: @@ -13192,8 +13194,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6D829F - RightColor: 52657A + MinColor: 6D829F + MaxColor: 52657A ZOffset: -12 ZRamp: 0 Template@614: @@ -13203,8 +13205,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7187A3 - RightColor: 4E6174 + MinColor: 7187A3 + MaxColor: 4E6174 ZOffset: -12 ZRamp: 0 Template@615: @@ -13214,8 +13216,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 344550 - RightColor: 2F3F48 + MinColor: 344550 + MaxColor: 2F3F48 ZOffset: -12 ZRamp: 0 Template@616: @@ -13225,8 +13227,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 2E3E47 - RightColor: 3D4E5C + MinColor: 2E3E47 + MaxColor: 3D4E5C ZOffset: -12 ZRamp: 0 Template@617: @@ -13236,8 +13238,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 3C4D5A - RightColor: 394A57 + MinColor: 3C4D5A + MaxColor: 394A57 ZOffset: -12 ZRamp: 0 Template@618: @@ -13247,8 +13249,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 3A4B58 - RightColor: 2C3C45 + MinColor: 3A4B58 + MaxColor: 2C3C45 ZOffset: -12 ZRamp: 0 Template@619: @@ -13258,8 +13260,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 344550 - RightColor: 405160 + MinColor: 344550 + MaxColor: 405160 ZOffset: -12 ZRamp: 0 Template@620: @@ -13269,8 +13271,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 3C4D5A - RightColor: 4A5D6F + MinColor: 3C4D5A + MaxColor: 4A5D6F ZOffset: -12 ZRamp: 0 Template@621: @@ -13280,8 +13282,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 475B6B - RightColor: 394A57 + MinColor: 475B6B + MaxColor: 394A57 ZOffset: -12 ZRamp: 0 Template@622: @@ -13291,8 +13293,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 405361 - RightColor: 2F3F48 + MinColor: 405361 + MaxColor: 2F3F48 ZOffset: -12 ZRamp: 0 Template@623: @@ -13302,8 +13304,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 425563 - RightColor: 4D6072 + MinColor: 425563 + MaxColor: 4D6072 ZOffset: -12 ZRamp: 0 Template@624: @@ -13313,8 +13315,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 475B6B - RightColor: 4A5D6F + MinColor: 475B6B + MaxColor: 4A5D6F ZOffset: -12 ZRamp: 0 Template@625: @@ -13324,8 +13326,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4E6274 - RightColor: 3C4D5A + MinColor: 4E6274 + MaxColor: 3C4D5A ZOffset: -12 ZRamp: 0 Template@626: @@ -13335,8 +13337,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 405361 - RightColor: 405160 + MinColor: 405361 + MaxColor: 405160 ZOffset: -12 ZRamp: 0 Template@627: @@ -13346,8 +13348,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 425563 - RightColor: 3C4D5A + MinColor: 425563 + MaxColor: 3C4D5A ZOffset: -12 ZRamp: 0 Template@628: @@ -13357,8 +13359,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 3A4B58 - RightColor: 3D4E5C + MinColor: 3A4B58 + MaxColor: 3D4E5C ZOffset: -12 ZRamp: 0 Template@629: @@ -13368,8 +13370,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4E6274 - RightColor: 4D6072 + MinColor: 4E6274 + MaxColor: 4D6072 ZOffset: -12 ZRamp: 0 Template@630: @@ -13379,8 +13381,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 2B3B43 - RightColor: 2B3A42 + MinColor: 2B3B43 + MaxColor: 2B3A42 ZOffset: -12 ZRamp: 0 Template@631: @@ -13390,8 +13392,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 Template@632: @@ -13401,8 +13403,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ACBFD3 - RightColor: A5B4C9 + MinColor: ACBFD3 + MaxColor: A5B4C9 ZOffset: -12 ZRamp: 0 Template@633: @@ -13412,8 +13414,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B8D0E8 - RightColor: 98A9BE + MinColor: B8D0E8 + MaxColor: 98A9BE ZOffset: -12 ZRamp: 0 Template@634: @@ -13423,8 +13425,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AFC0D0 - RightColor: 99ABC6 + MinColor: AFC0D0 + MaxColor: 99ABC6 ZOffset: -12 ZRamp: 0 Template@635: @@ -13434,8 +13436,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9BAEC4 - RightColor: B5C9DC + MinColor: 9BAEC4 + MaxColor: B5C9DC ZOffset: -12 ZRamp: 0 Template@636: @@ -13445,8 +13447,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 97A7C0 - RightColor: A9BBD3 + MinColor: 97A7C0 + MaxColor: A9BBD3 ZOffset: -12 ZRamp: 0 Template@637: @@ -13456,8 +13458,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9AACC1 - RightColor: 97A9C1 + MinColor: 9AACC1 + MaxColor: 97A9C1 ZOffset: -12 ZRamp: 0 Template@638: @@ -13467,8 +13469,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 96A6BE - RightColor: 99ACC7 + MinColor: 96A6BE + MaxColor: 99ACC7 ZOffset: -12 ZRamp: 0 Template@639: @@ -13478,8 +13480,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9CABC3 - RightColor: 98A6B4 + MinColor: 9CABC3 + MaxColor: 98A6B4 ZOffset: -12 ZRamp: 0 Template@640: @@ -13489,8 +13491,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9CADC5 - RightColor: ACBFD9 + MinColor: 9CADC5 + MaxColor: ACBFD9 ZOffset: -12 ZRamp: 0 Template@641: @@ -13500,8 +13502,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9EB1C7 - RightColor: 98ADC4 + MinColor: 9EB1C7 + MaxColor: 98ADC4 ZOffset: -12 ZRamp: 0 Template@642: @@ -13511,8 +13513,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9BACC3 - RightColor: 99ABC6 + MinColor: 9BACC3 + MaxColor: 99ABC6 ZOffset: -12 ZRamp: 0 Template@643: @@ -13522,8 +13524,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 8F9EB7 - RightColor: A9BCCF + MinColor: 8F9EB7 + MaxColor: A9BCCF ZOffset: -12 ZRamp: 0 Template@644: @@ -13533,8 +13535,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 93A2BD - RightColor: A8BAD4 + MinColor: 93A2BD + MaxColor: A8BAD4 ZOffset: -12 ZRamp: 0 Template@645: @@ -13544,8 +13546,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 8C9CB4 - RightColor: 99AABE + MinColor: 8C9CB4 + MaxColor: 99AABE ZOffset: -12 ZRamp: 0 Template@646: @@ -13555,8 +13557,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 93A4C0 - RightColor: 99AECC + MinColor: 93A4C0 + MaxColor: 99AECC ZOffset: -12 ZRamp: 0 Template@647: @@ -13566,8 +13568,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B3C6D8 - RightColor: A2B2C8 + MinColor: B3C6D8 + MaxColor: A2B2C8 ZOffset: -12 ZRamp: 0 Template@648: @@ -13577,8 +13579,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: BAC8D5 - RightColor: 98A9BD + MinColor: BAC8D5 + MaxColor: 98A9BD ZOffset: -12 ZRamp: 0 Template@649: @@ -13588,8 +13590,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A8B5C1 - RightColor: 99ABC6 + MinColor: A8B5C1 + MaxColor: 99ABC6 ZOffset: -12 ZRamp: 0 Template@650: @@ -13599,8 +13601,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 99AABF - RightColor: ABBCCC + MinColor: 99AABF + MaxColor: ABBCCC ZOffset: -12 ZRamp: 0 Template@651: @@ -13610,8 +13612,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 97A8BD - RightColor: 92A2B7 + MinColor: 97A8BD + MaxColor: 92A2B7 ZOffset: -12 ZRamp: 0 Template@652: @@ -13621,8 +13623,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 97A6BB - RightColor: 9DABB6 + MinColor: 97A6BB + MaxColor: 9DABB6 ZOffset: -12 ZRamp: 0 Template@653: @@ -13632,8 +13634,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 98A6BB - RightColor: A9BAD2 + MinColor: 98A6BB + MaxColor: A9BAD2 ZOffset: -12 ZRamp: 0 Template@654: @@ -13643,8 +13645,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 8F9EB7 - RightColor: 9EABB7 + MinColor: 8F9EB7 + MaxColor: 9EABB7 ZOffset: -12 ZRamp: 0 Template@655: @@ -13654,8 +13656,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A6B1BC - RightColor: A5B3C9 + MinColor: A6B1BC + MaxColor: A5B3C9 ZOffset: -12 ZRamp: 0 Template@656: @@ -13665,8 +13667,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B2C8DE - RightColor: 919FB1 + MinColor: B2C8DE + MaxColor: 919FB1 ZOffset: -12 ZRamp: 0 Template@657: @@ -13676,8 +13678,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 9BAEC4 - RightColor: ADBECD + MinColor: 9BAEC4 + MaxColor: ADBECD ZOffset: -12 ZRamp: 0 Template@658: @@ -13687,8 +13689,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 99A6BA - RightColor: B1C3D3 + MinColor: 99A6BA + MaxColor: B1C3D3 ZOffset: -12 ZRamp: 0 Template@659: @@ -13698,8 +13700,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A7B5C3 - RightColor: ADBCD0 + MinColor: A7B5C3 + MaxColor: ADBCD0 ZOffset: -12 ZRamp: 0 Template@660: @@ -13709,8 +13711,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ACBBCA - RightColor: 92A2B5 + MinColor: ACBBCA + MaxColor: 92A2B5 ZOffset: -12 ZRamp: 0 Template@661: @@ -13720,8 +13722,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 95A6BA - RightColor: A4B3BF + MinColor: 95A6BA + MaxColor: A4B3BF ZOffset: -12 ZRamp: 0 Template@662: @@ -13731,8 +13733,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: A0AAB8 - RightColor: 9DA8B0 + MinColor: A0AAB8 + MaxColor: 9DA8B0 ZOffset: -12 ZRamp: 0 Template@663: @@ -13742,8 +13744,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AEC4DB - RightColor: AABED4 + MinColor: AEC4DB + MaxColor: AABED4 ZOffset: -12 ZRamp: 0 Template@664: @@ -13753,8 +13755,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: BCD5ED - RightColor: A6B3BE + MinColor: BCD5ED + MaxColor: A6B3BE ZOffset: -12 ZRamp: 0 Template@665: @@ -13764,8 +13766,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B9C8D6 - RightColor: BFD4E6 + MinColor: B9C8D6 + MaxColor: BFD4E6 ZOffset: -12 ZRamp: 0 Template@666: @@ -13775,8 +13777,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ADB9C5 - RightColor: BDD8F0 + MinColor: ADB9C5 + MaxColor: BDD8F0 ZOffset: -12 ZRamp: 0 Template@667: @@ -13786,8 +13788,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B5CDE5 - RightColor: AEBFCC + MinColor: B5CDE5 + MaxColor: AEBFCC ZOffset: -12 ZRamp: 0 Template@668: @@ -13797,8 +13799,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B8C7D5 - RightColor: A2ADB5 + MinColor: B8C7D5 + MaxColor: A2ADB5 ZOffset: -12 ZRamp: 0 Template@669: @@ -13808,8 +13810,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ACBDCC - RightColor: BFD4E5 + MinColor: ACBDCC + MaxColor: BFD4E5 ZOffset: -12 ZRamp: 0 Template@670: @@ -13819,8 +13821,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AEBDCA - RightColor: AEC6DE + MinColor: AEBDCA + MaxColor: AEC6DE ZOffset: -12 ZRamp: 0 Template@671: @@ -13830,8 +13832,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: B0C1D0 - RightColor: A8B6C1 + MinColor: B0C1D0 + MaxColor: A8B6C1 ZOffset: -12 ZRamp: 0 Template@672: @@ -13841,8 +13843,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: ADBBC9 - RightColor: A2ADB5 + MinColor: ADBBC9 + MaxColor: A2ADB5 ZOffset: -12 ZRamp: 0 Template@673: @@ -13852,8 +13854,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AAB6C2 - RightColor: B5C8D9 + MinColor: AAB6C2 + MaxColor: B5C8D9 ZOffset: -12 ZRamp: 0 Template@674: @@ -13863,8 +13865,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AEBDCA - RightColor: AEBFCC + MinColor: AEBDCA + MaxColor: AEBFCC ZOffset: -12 ZRamp: 0 Template@675: @@ -13874,8 +13876,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AFBFCE - RightColor: AEC3D8 + MinColor: AFBFCE + MaxColor: AEC3D8 ZOffset: -12 ZRamp: 0 Template@676: @@ -13885,8 +13887,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AEC2D5 - RightColor: ADBECE + MinColor: AEC2D5 + MaxColor: ADBECE ZOffset: -12 ZRamp: 0 Template@677: @@ -13896,8 +13898,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: AAB6C2 - RightColor: A8B6C1 + MinColor: AAB6C2 + MaxColor: A8B6C1 ZOffset: -12 ZRamp: 0 Template@678: @@ -13907,8 +13909,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 Template@679: @@ -13919,46 +13921,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 525D63 - RightColor: 353F47 + MinColor: 525D63 + MaxColor: 353F47 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 394853 - RightColor: 53646D + MinColor: 394853 + MaxColor: 53646D ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 7F94A2 - RightColor: 7D909D + MinColor: 7F94A2 + MaxColor: 7D909D ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 8695A1 - RightColor: 647681 + MinColor: 8695A1 + MaxColor: 647681 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 8B9AA7 - RightColor: 7A848D + MinColor: 8B9AA7 + MaxColor: 7A848D ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 8296AA - RightColor: 647587 + MinColor: 8296AA + MaxColor: 647587 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: A0B6CC - RightColor: 7D96AC + MinColor: A0B6CC + MaxColor: 7D96AC ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: A6B3BF - RightColor: AAB9C4 + MinColor: A6B3BF + MaxColor: AAB9C4 ZOffset: -12 ZRamp: 0 Template@680: @@ -13969,24 +13971,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 2B3840 - RightColor: 3E4950 + MinColor: 2B3840 + MaxColor: 3E4950 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 414B54 - RightColor: 68757D + MinColor: 414B54 + MaxColor: 68757D ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: BECBD8 - RightColor: B1C1CE + MinColor: BECBD8 + MaxColor: B1C1CE ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 778992 - RightColor: 50626C + MinColor: 778992 + MaxColor: 50626C ZOffset: -12 ZRamp: 0 Template@681: @@ -13997,46 +13999,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 243038 - RightColor: 28353E + MinColor: 243038 + MaxColor: 28353E ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 39454F - RightColor: 5F6A72 + MinColor: 39454F + MaxColor: 5F6A72 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 9FB2C0 - RightColor: 9DAFBD + MinColor: 9FB2C0 + MaxColor: 9DAFBD ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 667680 - RightColor: 566269 + MinColor: 667680 + MaxColor: 566269 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 26333B - RightColor: 2C3842 + MinColor: 26333B + MaxColor: 2C3842 ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 3F4B53 - RightColor: 5F6A72 + MinColor: 3F4B53 + MaxColor: 5F6A72 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: BDCAD7 - RightColor: AABAC8 + MinColor: BDCAD7 + MaxColor: AABAC8 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 8C979E - RightColor: 52626B + MinColor: 8C979E + MaxColor: 52626B ZOffset: -12 ZRamp: 0 Template@682: @@ -14047,46 +14049,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 555E65 - RightColor: 81909E + MinColor: 555E65 + MaxColor: 81909E ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 7D8FA2 - RightColor: 758697 + MinColor: 7D8FA2 + MaxColor: 758697 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: AAC3DC - RightColor: 7F9CB5 + MinColor: AAC3DC + MaxColor: 7F9CB5 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 788EA5 - RightColor: B4C9DC + MinColor: 788EA5 + MaxColor: B4C9DC ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 28343C - RightColor: 2D3843 + MinColor: 28343C + MaxColor: 2D3843 ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 424F58 - RightColor: 53667A + MinColor: 424F58 + MaxColor: 53667A ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 99ACB9 - RightColor: 748EA1 + MinColor: 99ACB9 + MaxColor: 748EA1 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 6D7F8B - RightColor: 435764 + MinColor: 6D7F8B + MaxColor: 435764 ZOffset: -12 ZRamp: 0 Template@683: @@ -14097,20 +14099,20 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8798A8 - RightColor: 6B7C8C + MinColor: 8798A8 + MaxColor: 6B7C8C ZOffset: -12 ZRamp: 0 2: Rough Height: 4 - LeftColor: 8897A7 - RightColor: 78848E + MinColor: 8897A7 + MaxColor: 78848E ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 414C55 - RightColor: 495763 + MinColor: 414C55 + MaxColor: 495763 ZOffset: -12 ZRamp: 0 Template@684: @@ -14121,8 +14123,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 212D34 - RightColor: 34414A + MinColor: 212D34 + MaxColor: 34414A ZOffset: -12 ZRamp: 0 Template@685: @@ -14133,14 +14135,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 243037 - RightColor: 404F59 + MinColor: 243037 + MaxColor: 404F59 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 2A383F - RightColor: 313F47 + MinColor: 2A383F + MaxColor: 313F47 ZOffset: -12 ZRamp: 0 Template@686: @@ -14151,20 +14153,20 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 7C8C9C - RightColor: 728191 + MinColor: 7C8C9C + MaxColor: 728191 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 253037 - RightColor: 3C474F + MinColor: 253037 + MaxColor: 3C474F ZOffset: -12 ZRamp: 0 3: Rough Height: 4 - LeftColor: 7B8692 - RightColor: 82919E + MinColor: 7B8692 + MaxColor: 82919E ZOffset: -12 ZRamp: 0 Template@687: @@ -14175,20 +14177,20 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 67757E - RightColor: 515F69 + MinColor: 67757E + MaxColor: 515F69 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 8E9DAB - RightColor: 8C9DAB + MinColor: 8E9DAB + MaxColor: 8C9DAB ZOffset: -12 ZRamp: 0 3: Rough Height: 4 - LeftColor: 8C9BA9 - RightColor: 7B868F + MinColor: 8C9BA9 + MaxColor: 7B868F ZOffset: -12 ZRamp: 0 Template@688: @@ -14199,8 +14201,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 32414B - RightColor: 222E35 + MinColor: 32414B + MaxColor: 222E35 ZOffset: -12 ZRamp: 0 Template@689: @@ -14211,14 +14213,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 2E3C45 - RightColor: 2E3B44 + MinColor: 2E3C45 + MaxColor: 2E3B44 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 34424C - RightColor: 26333A + MinColor: 34424C + MaxColor: 26333A ZOffset: -12 ZRamp: 0 Template@690: @@ -14229,20 +14231,20 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8191A3 - RightColor: 8192A4 + MinColor: 8191A3 + MaxColor: 8192A4 ZOffset: -12 ZRamp: 0 1: Rough Height: 4 - LeftColor: 5A646B - RightColor: 81919F + MinColor: 5A646B + MaxColor: 81919F ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 415160 - RightColor: 2F3C48 + MinColor: 415160 + MaxColor: 2F3C48 ZOffset: -12 ZRamp: 0 Template@691: @@ -14252,18 +14254,18 @@ Size: 1, 3 Tiles: 0: Rough - LeftColor: 5E666C - RightColor: 88949F + MinColor: 5E666C + MaxColor: 88949F ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 56595B - RightColor: 666E72 + MinColor: 56595B + MaxColor: 666E72 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 8E9BA6 - RightColor: 859098 + MinColor: 8E9BA6 + MaxColor: 859098 ZOffset: -12 ZRamp: 0 Template@692: @@ -14273,18 +14275,18 @@ Size: 3, 1 Tiles: 0: Rough - LeftColor: A4ADB4 - RightColor: 656C70 + MinColor: A4ADB4 + MaxColor: 656C70 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 595B58 - RightColor: 5D6265 + MinColor: 595B58 + MaxColor: 5D6265 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 636769 - RightColor: 919BA4 + MinColor: 636769 + MaxColor: 919BA4 ZOffset: -12 ZRamp: 0 Template@693: @@ -14294,18 +14296,18 @@ Size: 1, 3 Tiles: 0: Rough - LeftColor: 707579 - RightColor: 8A9298 + MinColor: 707579 + MaxColor: 8A9298 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 595C5D - RightColor: 545755 + MinColor: 595C5D + MaxColor: 545755 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 94A1AD - RightColor: 52575B + MinColor: 94A1AD + MaxColor: 52575B ZOffset: -12 ZRamp: 0 Template@694: @@ -14315,18 +14317,18 @@ Size: 3, 1 Tiles: 0: Rough - LeftColor: A7BBCC - RightColor: 767C81 + MinColor: A7BBCC + MaxColor: 767C81 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 717B81 - RightColor: 565652 + MinColor: 717B81 + MaxColor: 565652 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 7B868F - RightColor: 98A4AC + MinColor: 7B868F + MaxColor: 98A4AC ZOffset: -12 ZRamp: 0 Template@695: @@ -14337,85 +14339,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 81878D - RightColor: 7D8A96 + MinColor: 81878D + MaxColor: 7D8A96 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 716F6C - RightColor: 696B6A + MinColor: 716F6C + MaxColor: 696B6A ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: BFD4E6 - RightColor: C0DAEF + MinColor: BFD4E6 + MaxColor: C0DAEF ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 484D4F - RightColor: 6B7074 + MinColor: 484D4F + MaxColor: 6B7074 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 454546 - RightColor: 6C6F71 + MinColor: 454546 + MaxColor: 6C6F71 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: B7CBDF - RightColor: 94A3AD + MinColor: B7CBDF + MaxColor: 94A3AD ZOffset: -12 ZRamp: 0 6: Rail Height: 4 - LeftColor: 393C3F - RightColor: 3D3F41 + MinColor: 393C3F + MaxColor: 3D3F41 ZOffset: -12 ZRamp: 0 7: Rail Height: 4 - LeftColor: 3A3B3D - RightColor: 3D3E40 + MinColor: 3A3B3D + MaxColor: 3D3E40 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C0D1E2 - RightColor: 757A7E + MinColor: C0D1E2 + MaxColor: 757A7E ZOffset: -12 ZRamp: 0 9: Road Height: 4 - LeftColor: 697177 - RightColor: 454748 + MinColor: 697177 + MaxColor: 454748 ZOffset: -12 ZRamp: 0 10: Road Height: 4 - LeftColor: 626363 - RightColor: 454545 + MinColor: 626363 + MaxColor: 454545 ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: BED4E6 - RightColor: 6F7478 + MinColor: BED4E6 + MaxColor: 6F7478 ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 8694A2 - RightColor: 797C7F + MinColor: 8694A2 + MaxColor: 797C7F ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: B0C2D1 - RightColor: 999FA4 + MinColor: B0C2D1 + MaxColor: 999FA4 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: B7CDE1 - RightColor: BCD4EA + MinColor: B7CDE1 + MaxColor: BCD4EA ZOffset: -12 ZRamp: 0 Template@696: @@ -14426,85 +14428,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 81878D - RightColor: 7D8A96 + MinColor: 81878D + MaxColor: 7D8A96 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 716F6C - RightColor: 67696A + MinColor: 716F6C + MaxColor: 67696A ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 62758D - RightColor: 889DC2 + MinColor: 62758D + MaxColor: 889DC2 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 484D4F - RightColor: 6B7074 + MinColor: 484D4F + MaxColor: 6B7074 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 454546 - RightColor: 6C6F71 + MinColor: 454546 + MaxColor: 6C6F71 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 7489A8 - RightColor: 68727F + MinColor: 7489A8 + MaxColor: 68727F ZOffset: -12 ZRamp: 0 6: Rail Height: 4 - LeftColor: 393C3F - RightColor: 3D3F41 + MinColor: 393C3F + MaxColor: 3D3F41 ZOffset: -12 ZRamp: 0 7: Rail Height: 4 - LeftColor: 3A3B3D - RightColor: 3D3E40 + MinColor: 3A3B3D + MaxColor: 3D3E40 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 62748D - RightColor: 686C73 + MinColor: 62748D + MaxColor: 686C73 ZOffset: -12 ZRamp: 0 9: Road Height: 4 - LeftColor: 697177 - RightColor: 454748 + MinColor: 697177 + MaxColor: 454748 ZOffset: -12 ZRamp: 0 10: Road Height: 4 - LeftColor: 626363 - RightColor: 454545 + MinColor: 626363 + MaxColor: 454545 ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 5F7189 - RightColor: 61656A + MinColor: 5F7189 + MaxColor: 61656A ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 8593A0 - RightColor: 7A7E81 + MinColor: 8593A0 + MaxColor: 7A7E81 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 9DABBD - RightColor: 989FA4 + MinColor: 9DABBD + MaxColor: 989FA4 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 7A8EB4 - RightColor: 6C7D9A + MinColor: 7A8EB4 + MaxColor: 6C7D9A ZOffset: -12 ZRamp: 0 Template@697: @@ -14514,61 +14516,61 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 81878B - RightColor: 7F8C9A + MinColor: 81878B + MaxColor: 7F8C9A ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 464646 - RightColor: 6D6E6E + MinColor: 464646 + MaxColor: 6D6E6E ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 484C4F - RightColor: 6C7379 + MinColor: 484C4F + MaxColor: 6C7379 ZOffset: -12 ZRamp: 0 4: Rail Height: 4 - LeftColor: 3A3B3D - RightColor: 3D3F41 + MinColor: 3A3B3D + MaxColor: 3D3F41 ZOffset: -12 ZRamp: 0 5: Rail Height: 4 - LeftColor: 3A3C3E - RightColor: 3C3F42 + MinColor: 3A3C3E + MaxColor: 3C3F42 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 606061 - RightColor: 454545 + MinColor: 606061 + MaxColor: 454545 ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 676C70 - RightColor: 4A5055 + MinColor: 676C70 + MaxColor: 4A5055 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: A9AEB1 - RightColor: 9EA1A0 + MinColor: A9AEB1 + MaxColor: 9EA1A0 ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 7F8A97 - RightColor: 767A7F + MinColor: 7F8A97 + MaxColor: 767A7F ZOffset: -12 ZRamp: 0 Template@698: @@ -14579,85 +14581,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 73808D - RightColor: 71767A + MinColor: 73808D + MaxColor: 71767A ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 747B82 - RightColor: 505355 + MinColor: 747B82 + MaxColor: 505355 ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 3B3C3E - RightColor: 393C3F + MinColor: 3B3C3E + MaxColor: 393C3F ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 45484C - RightColor: 6D7379 + MinColor: 45484C + MaxColor: 6D7379 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 6D7074 - RightColor: 808D98 + MinColor: 6D7074 + MaxColor: 808D98 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: B3BCC3 - RightColor: 9D9C97 + MinColor: B3BCC3 + MaxColor: 9D9C97 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 5F6061 - RightColor: 595C5E + MinColor: 5F6061 + MaxColor: 595C5E ZOffset: -12 ZRamp: 0 7: Rail Height: 4 - LeftColor: 3A3C3F - RightColor: 393B3E + MinColor: 3A3C3F + MaxColor: 393B3E ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 464646 - RightColor: 616161 + MinColor: 464646 + MaxColor: 616161 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 9BA8B3 - RightColor: 949DA2 + MinColor: 9BA8B3 + MaxColor: 949DA2 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: C0DAEF - RightColor: C6D9EB + MinColor: C0DAEF + MaxColor: C6D9EB ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: BAD5EE - RightColor: B8C4CF + MinColor: BAD5EE + MaxColor: B8C4CF ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: C4DEF1 - RightColor: A0A4A5 + MinColor: C4DEF1 + MaxColor: A0A4A5 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: BED4E6 - RightColor: A0A5A8 + MinColor: BED4E6 + MaxColor: A0A5A8 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: C0DAEF - RightColor: C6D9EB + MinColor: C0DAEF + MaxColor: C6D9EB ZOffset: -12 ZRamp: 0 Template@699: @@ -14668,85 +14670,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 73808D - RightColor: 71767A + MinColor: 73808D + MaxColor: 71767A ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 747B82 - RightColor: 505355 + MinColor: 747B82 + MaxColor: 505355 ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 3B3C3E - RightColor: 393C3F + MinColor: 3B3C3E + MaxColor: 393C3F ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 45484C - RightColor: 6D7379 + MinColor: 45484C + MaxColor: 6D7379 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 6D7074 - RightColor: 808D98 + MinColor: 6D7074 + MaxColor: 808D98 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: A4ABB4 - RightColor: 9D9C97 + MinColor: A4ABB4 + MaxColor: 9D9C97 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 5F6061 - RightColor: 595C5E + MinColor: 5F6061 + MaxColor: 595C5E ZOffset: -12 ZRamp: 0 7: Rail Height: 4 - LeftColor: 3A3C3F - RightColor: 393B3E + MinColor: 3A3C3F + MaxColor: 393B3E ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 464646 - RightColor: 616161 + MinColor: 464646 + MaxColor: 616161 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 909FAD - RightColor: 8D959C + MinColor: 909FAD + MaxColor: 8D959C ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 7C91B8 - RightColor: 677897 + MinColor: 7C91B8 + MaxColor: 677897 ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 7489A9 - RightColor: 9AA6B7 + MinColor: 7489A9 + MaxColor: 9AA6B7 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 7689AE - RightColor: 919599 + MinColor: 7689AE + MaxColor: 919599 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 778AA9 - RightColor: 969BA0 + MinColor: 778AA9 + MaxColor: 969BA0 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 768AB0 - RightColor: 7585A2 + MinColor: 768AB0 + MaxColor: 7585A2 ZOffset: -12 ZRamp: 0 Template@700: @@ -14756,61 +14758,61 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 606161 - RightColor: 565657 + MinColor: 606161 + MaxColor: 565657 ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 3A3C3D - RightColor: 393B3D + MinColor: 3A3C3D + MaxColor: 393B3D ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 454545 - RightColor: 606061 + MinColor: 454545 + MaxColor: 606061 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 848C93 - RightColor: 7A7D7F + MinColor: 848C93 + MaxColor: 7A7D7F ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 7F8E9C - RightColor: 71777D + MinColor: 7F8E9C + MaxColor: 71777D ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 767A7E - RightColor: 4A4B4C + MinColor: 767A7E + MaxColor: 4A4B4C ZOffset: -12 ZRamp: 0 7: Rail Height: 4 - LeftColor: 3B3D3F - RightColor: 3A3C3E + MinColor: 3B3D3F + MaxColor: 3A3C3E ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 4F5050 - RightColor: 777B7E + MinColor: 4F5050 + MaxColor: 777B7E ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 6E7378 - RightColor: 747C85 + MinColor: 6E7378 + MaxColor: 747C85 ZOffset: -12 ZRamp: 0 Template@701: @@ -14820,56 +14822,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 696967 + MinColor: 71706D + MaxColor: 696967 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C3D2E0 - RightColor: C2DBF0 + MinColor: C3D2E0 + MaxColor: C2DBF0 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 454646 - RightColor: 6C6E6E + MinColor: 454646 + MaxColor: 6C6E6E ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: C3D1DF - RightColor: 97A4AC + MinColor: C3D1DF + MaxColor: 97A4AC ZOffset: -12 ZRamp: 0 4: Rail Height: 4 - LeftColor: 373633 - RightColor: 373632 + MinColor: 373633 + MaxColor: 373632 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: BDD0E1 - RightColor: 717679 + MinColor: BDD0E1 + MaxColor: 717679 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 626262 - RightColor: 464646 + MinColor: 626262 + MaxColor: 464646 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: BFD0E1 - RightColor: 707578 + MinColor: BFD0E1 + MaxColor: 707578 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B1B7BA - RightColor: 989896 + MinColor: B1B7BA + MaxColor: 989896 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BCD2E6 - RightColor: B6D1EE + MinColor: BCD2E6 + MaxColor: B6D1EE ZOffset: -12 ZRamp: 0 Template@702: @@ -14879,56 +14881,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 696967 + MinColor: 71706D + MaxColor: 696967 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C3D2E0 - RightColor: C2DBF0 + MinColor: C3D2E0 + MaxColor: C2DBF0 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3F4141 - RightColor: 656667 + MinColor: 3F4141 + MaxColor: 656667 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: C3D1DF - RightColor: 97A4AC + MinColor: C3D1DF + MaxColor: 97A4AC ZOffset: -12 ZRamp: 0 4: Rail Height: 4 - LeftColor: 343331 - RightColor: 383734 + MinColor: 343331 + MaxColor: 383734 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: BDD0E1 - RightColor: 717679 + MinColor: BDD0E1 + MaxColor: 717679 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 4A4A4A - RightColor: 414141 + MinColor: 4A4A4A + MaxColor: 414141 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: BFD0E1 - RightColor: 707578 + MinColor: BFD0E1 + MaxColor: 707578 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: A3A8AB - RightColor: 929290 + MinColor: A3A8AB + MaxColor: 929290 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD0E3 - RightColor: B6D1EE + MinColor: BAD0E3 + MaxColor: B6D1EE ZOffset: -12 ZRamp: 0 Template@703: @@ -14938,56 +14940,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 696967 + MinColor: 71706D + MaxColor: 696967 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C0CEDC - RightColor: C2DBF0 + MinColor: C0CEDC + MaxColor: C2DBF0 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 404040 - RightColor: 646566 + MinColor: 404040 + MaxColor: 646566 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B2C0CD - RightColor: 889299 + MinColor: B2C0CD + MaxColor: 889299 ZOffset: -12 ZRamp: 0 4: Rail Height: 4 - LeftColor: 363533 - RightColor: 31312F + MinColor: 363533 + MaxColor: 31312F ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: AEC1D0 - RightColor: 6F7477 + MinColor: AEC1D0 + MaxColor: 6F7477 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 5B5B5B - RightColor: 404040 + MinColor: 5B5B5B + MaxColor: 404040 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B8C4D0 - RightColor: 6B7073 + MinColor: B8C4D0 + MaxColor: 6B7073 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: AFB4B7 - RightColor: 90918F + MinColor: AFB4B7 + MaxColor: 90918F ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD0E3 - RightColor: A5BDD5 + MinColor: BAD0E3 + MaxColor: A5BDD5 ZOffset: -12 ZRamp: 0 Template@704: @@ -14997,56 +14999,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 686866 + MinColor: 71706D + MaxColor: 686866 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C0CEDC - RightColor: C2DBF0 + MinColor: C0CEDC + MaxColor: C2DBF0 ZOffset: -12 ZRamp: 0 2: Rough Height: 4 - LeftColor: 3C3C3D - RightColor: 5A5B5C + MinColor: 3C3C3D + MaxColor: 5A5B5C ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B2C0CD - RightColor: 889299 + MinColor: B2C0CD + MaxColor: 889299 ZOffset: -12 ZRamp: 0 4: Rough Height: 4 - LeftColor: 353533 - RightColor: 343330 + MinColor: 353533 + MaxColor: 343330 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: AEC1D0 - RightColor: 6F7477 + MinColor: AEC1D0 + MaxColor: 6F7477 ZOffset: -12 ZRamp: 0 6: Rough Height: 4 - LeftColor: 4B4B4B - RightColor: 3D3D3D + MinColor: 4B4B4B + MaxColor: 3D3D3D ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B8C4D0 - RightColor: 6B7073 + MinColor: B8C4D0 + MaxColor: 6B7073 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: A3A8AB - RightColor: 90918F + MinColor: A3A8AB + MaxColor: 90918F ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD0E3 - RightColor: A5BDD5 + MinColor: BAD0E3 + MaxColor: A5BDD5 ZOffset: -12 ZRamp: 0 Template@705: @@ -15056,53 +15058,53 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 7A7977 - RightColor: 8F9090 + MinColor: 7A7977 + MaxColor: 8F9090 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: BCC7D2 - RightColor: ACBCC8 + MinColor: BCC7D2 + MaxColor: ACBCC8 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 636260 - RightColor: 6C6C6B + MinColor: 636260 + MaxColor: 6C6C6B ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 777F85 - RightColor: A3B8C9 + MinColor: 777F85 + MaxColor: A3B8C9 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6E6D6B - RightColor: 838380 + MinColor: 6E6D6B + MaxColor: 838380 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 8F9EAA - RightColor: 76828B + MinColor: 8F9EAA + MaxColor: 76828B ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 797875 - RightColor: 979692 + MinColor: 797875 + MaxColor: 979692 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B4BEC7 - RightColor: ADC4DA + MinColor: B4BEC7 + MaxColor: ADC4DA ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: AEB6BB - RightColor: A5ABAE + MinColor: AEB6BB + MaxColor: A5ABAE ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD0E3 - RightColor: A5BBD1 + MinColor: BAD0E3 + MaxColor: A5BBD1 ZOffset: -12 ZRamp: 0 Template@706: @@ -15112,56 +15114,56 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: B8C0C6 - RightColor: 9D9C98 + MinColor: B8C0C6 + MaxColor: 9D9C98 ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 606161 - RightColor: 565657 + MinColor: 606161 + MaxColor: 565657 ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 363531 - RightColor: 373632 + MinColor: 363531 + MaxColor: 373632 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 454545 - RightColor: 606061 + MinColor: 454545 + MaxColor: 606061 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 8C9296 - RightColor: 878989 + MinColor: 8C9296 + MaxColor: 878989 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C4DEF1 - RightColor: C3D4E4 + MinColor: C4DEF1 + MaxColor: C3D4E4 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: BED4E6 - RightColor: AFBCC7 + MinColor: BED4E6 + MaxColor: AFBCC7 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: C0DAEF - RightColor: A3A6A6 + MinColor: C0DAEF + MaxColor: A3A6A6 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: BAD5EE - RightColor: A1A4A5 + MinColor: BAD5EE + MaxColor: A1A4A5 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD5EE - RightColor: BED5EA + MinColor: BAD5EE + MaxColor: BED5EA ZOffset: -12 ZRamp: 0 Template@707: @@ -15172,50 +15174,50 @@ Tiles: 1: Road Height: 4 - LeftColor: 585858 - RightColor: 4E4E4E + MinColor: 585858 + MaxColor: 4E4E4E ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 33322F - RightColor: 343330 + MinColor: 33322F + MaxColor: 343330 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 444444 - RightColor: 535353 + MinColor: 444444 + MaxColor: 535353 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 8C9296 - RightColor: 888989 + MinColor: 8C9296 + MaxColor: 888989 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C4DEF1 - RightColor: B6BDC2 + MinColor: C4DEF1 + MaxColor: B6BDC2 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: BED4E6 - RightColor: A0A4A5 + MinColor: BED4E6 + MaxColor: A0A4A5 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: C0DAEF - RightColor: A3A6A6 + MinColor: C0DAEF + MaxColor: A3A6A6 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: BAD5EE - RightColor: A1A4A5 + MinColor: BAD5EE + MaxColor: A1A4A5 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BAD5EE - RightColor: BED5EA + MinColor: BAD5EE + MaxColor: BED5EA ZOffset: -12 ZRamp: 0 Template@708: @@ -15225,56 +15227,56 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: 9FA6AA - RightColor: 8E8D89 + MinColor: 9FA6AA + MaxColor: 8E8D89 ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 565656 - RightColor: 515151 + MinColor: 565656 + MaxColor: 515151 ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 33322E - RightColor: 373633 + MinColor: 33322E + MaxColor: 373633 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 3F3F3F - RightColor: 5F6060 + MinColor: 3F3F3F + MaxColor: 5F6060 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 8C9296 - RightColor: 868888 + MinColor: 8C9296 + MaxColor: 868888 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C4DEF1 - RightColor: B5C5D3 + MinColor: C4DEF1 + MaxColor: B5C5D3 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: B5C9D8 - RightColor: 9FA9B2 + MinColor: B5C9D8 + MaxColor: 9FA9B2 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B9CFE0 - RightColor: 949594 + MinColor: B9CFE0 + MaxColor: 949594 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B7CDE1 - RightColor: 9B9E9F + MinColor: B7CDE1 + MaxColor: 9B9E9F ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: B9D3ED - RightColor: BED5EA + MinColor: B9D3ED + MaxColor: BED5EA ZOffset: -12 ZRamp: 0 Template@709: @@ -15285,50 +15287,50 @@ Tiles: 1: Rough Height: 4 - LeftColor: 414242 - RightColor: 4B4B4B + MinColor: 414242 + MaxColor: 4B4B4B ZOffset: -12 ZRamp: 0 2: Rough Height: 4 - LeftColor: 2E2D2B - RightColor: 2D2B28 + MinColor: 2E2D2B + MaxColor: 2D2B28 ZOffset: -12 ZRamp: 0 3: Rough Height: 4 - LeftColor: 313131 - RightColor: 4D4D4D + MinColor: 313131 + MaxColor: 4D4D4D ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 84888A - RightColor: 838484 + MinColor: 84888A + MaxColor: 838484 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: BAD1E3 - RightColor: A6ACB0 + MinColor: BAD1E3 + MaxColor: A6ACB0 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: B5C9D8 - RightColor: 8E9192 + MinColor: B5C9D8 + MaxColor: 8E9192 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B6CBDC - RightColor: 929492 + MinColor: B6CBDC + MaxColor: 929492 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B7CDE1 - RightColor: A0A3A3 + MinColor: B7CDE1 + MaxColor: A0A3A3 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: B6D0E9 - RightColor: B0C1D1 + MinColor: B6D0E9 + MaxColor: B0C1D1 ZOffset: -12 ZRamp: 0 Template@710: @@ -15338,53 +15340,53 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: 9EA5AA - RightColor: 898987 + MinColor: 9EA5AA + MaxColor: 898987 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 959898 - RightColor: 969491 + MinColor: 959898 + MaxColor: 969491 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 898883 - RightColor: 888783 + MinColor: 898883 + MaxColor: 888783 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 949390 - RightColor: 787776 + MinColor: 949390 + MaxColor: 787776 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 828688 - RightColor: 8D9499 + MinColor: 828688 + MaxColor: 8D9499 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: BAD1E3 - RightColor: B4C0CA + MinColor: BAD1E3 + MaxColor: B4C0CA ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: AEBECA - RightColor: 9FAEBC + MinColor: AEBECA + MaxColor: 9FAEBC ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: A9B4BD - RightColor: 6D737A + MinColor: A9B4BD + MaxColor: 6D737A ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B6CCE1 - RightColor: 9EA6AD + MinColor: B6CCE1 + MaxColor: 9EA6AD ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: B2CBE5 - RightColor: AEC0D1 + MinColor: B2CBE5 + MaxColor: AEC0D1 ZOffset: -12 ZRamp: 0 Template@711: @@ -15394,183 +15396,183 @@ Size: 9, 7 Tiles: 2: Rough - LeftColor: 7F858C - RightColor: 9DADBC + MinColor: 7F858C + MaxColor: 9DADBC ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 848B92 - RightColor: A8BCCC + MinColor: 848B92 + MaxColor: A8BCCC ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: 929CA7 - RightColor: 8B959E + MinColor: 929CA7 + MaxColor: 8B959E ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: ADBFCD - RightColor: 98A8B5 + MinColor: ADBFCD + MaxColor: 98A8B5 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 9CAAB6 - RightColor: A8B7C8 + MinColor: 9CAAB6 + MaxColor: A8B7C8 ZOffset: -12 ZRamp: 0 18: Rough - LeftColor: BCD2E5 - RightColor: B6CBDC + MinColor: BCD2E5 + MaxColor: B6CBDC ZOffset: -12 ZRamp: 0 19: Rough - LeftColor: 72787F - RightColor: 9AA8B5 + MinColor: 72787F + MaxColor: 9AA8B5 ZOffset: -12 ZRamp: 0 20: Rough - LeftColor: AABAC8 - RightColor: 929AA3 + MinColor: AABAC8 + MaxColor: 929AA3 ZOffset: -12 ZRamp: 0 21: Rough - LeftColor: 9FAEBD - RightColor: 818B96 + MinColor: 9FAEBD + MaxColor: 818B96 ZOffset: -12 ZRamp: 0 22: Rough - LeftColor: 9FACBA - RightColor: ABBCCC + MinColor: 9FACBA + MaxColor: ABBCCC ZOffset: -12 ZRamp: 0 23: Rough - LeftColor: A6B9C9 - RightColor: B6CBDD + MinColor: A6B9C9 + MaxColor: B6CBDD ZOffset: -12 ZRamp: 0 24: Rough - LeftColor: 858F98 - RightColor: B0C3D4 + MinColor: 858F98 + MaxColor: B0C3D4 ZOffset: -12 ZRamp: 0 25: Rough - LeftColor: 909CA6 - RightColor: B4CEEA + MinColor: 909CA6 + MaxColor: B4CEEA ZOffset: -12 ZRamp: 0 26: Rough - LeftColor: A0AEBD - RightColor: B7CDE2 + MinColor: A0AEBD + MaxColor: B7CDE2 ZOffset: -12 ZRamp: 0 28: Rough - LeftColor: B5C9DD - RightColor: 8D97A1 + MinColor: B5C9DD + MaxColor: 8D97A1 ZOffset: -12 ZRamp: 0 29: Rough - LeftColor: ABBCCB - RightColor: A2B0C0 + MinColor: ABBCCB + MaxColor: A2B0C0 ZOffset: -12 ZRamp: 0 30: Rough - LeftColor: 80878E - RightColor: 929BA3 + MinColor: 80878E + MaxColor: 929BA3 ZOffset: -12 ZRamp: 0 31: Rough - LeftColor: A7B6C2 - RightColor: A8B9C7 + MinColor: A7B6C2 + MaxColor: A8B9C7 ZOffset: -12 ZRamp: 0 32: Rough - LeftColor: B1C4D3 - RightColor: A9BACA + MinColor: B1C4D3 + MaxColor: A9BACA ZOffset: -12 ZRamp: 0 33: Rough - LeftColor: 9AA6B1 - RightColor: 9EA9B4 + MinColor: 9AA6B1 + MaxColor: 9EA9B4 ZOffset: -12 ZRamp: 0 34: Rough - LeftColor: A1B0BE - RightColor: 919BA6 + MinColor: A1B0BE + MaxColor: 919BA6 ZOffset: -12 ZRamp: 0 35: Rough - LeftColor: 98A2AE - RightColor: B0C3D4 + MinColor: 98A2AE + MaxColor: B0C3D4 ZOffset: -12 ZRamp: 0 38: Rough - LeftColor: 94A0AD - RightColor: 9FACB8 + MinColor: 94A0AD + MaxColor: 9FACB8 ZOffset: -12 ZRamp: 0 39: Rough - LeftColor: 9EADBD - RightColor: 98A3AE + MinColor: 9EADBD + MaxColor: 98A3AE ZOffset: -12 ZRamp: 0 40: Rough - LeftColor: 9BA6B2 - RightColor: A6B6C3 + MinColor: 9BA6B2 + MaxColor: A6B6C3 ZOffset: -12 ZRamp: 0 41: Rough - LeftColor: 9CAAB6 - RightColor: B5C6D4 + MinColor: 9CAAB6 + MaxColor: B5C6D4 ZOffset: -12 ZRamp: 0 42: Rough - LeftColor: B5CBDE - RightColor: BDD7EE + MinColor: B5CBDE + MaxColor: BDD7EE ZOffset: -12 ZRamp: 0 43: Rough - LeftColor: BBD3E9 - RightColor: B2C8DE + MinColor: BBD3E9 + MaxColor: B2C8DE ZOffset: -12 ZRamp: 0 44: Rough - LeftColor: 9FAEC0 - RightColor: AEC0D0 + MinColor: 9FAEC0 + MaxColor: AEC0D0 ZOffset: -12 ZRamp: 0 49: Rough - LeftColor: A9BACA - RightColor: A3B5C7 + MinColor: A9BACA + MaxColor: A3B5C7 ZOffset: -12 ZRamp: 0 50: Rough - LeftColor: B1C2D1 - RightColor: A2ADB8 + MinColor: B1C2D1 + MaxColor: A2ADB8 ZOffset: -12 ZRamp: 0 51: Rough - LeftColor: 98A3AF - RightColor: 9FADB8 + MinColor: 98A3AF + MaxColor: 9FADB8 ZOffset: -12 ZRamp: 0 52: Rough - LeftColor: A0ACB5 - RightColor: A4B2BE + MinColor: A0ACB5 + MaxColor: A4B2BE ZOffset: -12 ZRamp: 0 53: Rough - LeftColor: AABCCD - RightColor: 97A3AD + MinColor: AABCCD + MaxColor: 97A3AD ZOffset: -12 ZRamp: 0 60: Rough - LeftColor: B6CBDF - RightColor: 9BA7B2 + MinColor: B6CBDF + MaxColor: 9BA7B2 ZOffset: -12 ZRamp: 0 61: Rough - LeftColor: 9CACBE - RightColor: A1B0C0 + MinColor: 9CACBE + MaxColor: A1B0C0 ZOffset: -12 ZRamp: 0 Template@712: @@ -15580,53 +15582,53 @@ Size: 4, 4 Tiles: 1: Rough - LeftColor: 9AAABA - RightColor: A5B8C9 + MinColor: 9AAABA + MaxColor: A5B8C9 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 848C94 - RightColor: A5B8C9 + MinColor: 848C94 + MaxColor: A5B8C9 ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: 94A0AC - RightColor: 949FAA + MinColor: 94A0AC + MaxColor: 949FAA ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 858B93 - RightColor: 8E9AA5 + MinColor: 858B93 + MaxColor: 8E9AA5 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 8D959E - RightColor: 8C939C + MinColor: 8D959E + MaxColor: 8C939C ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 99A9B8 - RightColor: AFC5DC + MinColor: 99A9B8 + MaxColor: AFC5DC ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: 9DAEBD - RightColor: 9EABB8 + MinColor: 9DAEBD + MaxColor: 9EABB8 ZOffset: -12 ZRamp: 0 9: Rough - LeftColor: 828B94 - RightColor: 99A5AF + MinColor: 828B94 + MaxColor: 99A5AF ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: A7B8C8 - RightColor: 9BACBC + MinColor: A7B8C8 + MaxColor: 9BACBC ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: B1C5D8 - RightColor: ABBAC8 + MinColor: B1C5D8 + MaxColor: ABBAC8 ZOffset: -12 ZRamp: 0 Template@713: @@ -15636,58 +15638,58 @@ Size: 5, 3 Tiles: 0: Rough - LeftColor: B4CCE2 - RightColor: 9CA8B5 + MinColor: B4CCE2 + MaxColor: 9CA8B5 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 95A1B0 - RightColor: 8C97A2 + MinColor: 95A1B0 + MaxColor: 8C97A2 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: B0C2D2 - RightColor: B7CEE2 + MinColor: B0C2D2 + MaxColor: B7CEE2 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 929DA8 - RightColor: ADC2D4 + MinColor: 929DA8 + MaxColor: ADC2D4 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: BDD3E5 - RightColor: B3C7D8 + MinColor: BDD3E5 + MaxColor: B3C7D8 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 909BA6 - RightColor: 9CA4AA + MinColor: 909BA6 + MaxColor: 9CA4AA ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: A8B8C6 - RightColor: 929AA3 + MinColor: A8B8C6 + MaxColor: 929AA3 ZOffset: -12 ZRamp: 0 9: Rough - LeftColor: A0B0BE - RightColor: 99A8B6 + MinColor: A0B0BE + MaxColor: 99A8B6 ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: B9CDDE - RightColor: 8D97A0 + MinColor: B9CDDE + MaxColor: 8D97A0 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: B2C6D9 - RightColor: B0C3D6 + MinColor: B2C6D9 + MaxColor: B0C3D6 ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: 8A949D - RightColor: 94A0A9 + MinColor: 8A949D + MaxColor: 94A0A9 ZOffset: -12 ZRamp: 0 Template@714: @@ -15697,43 +15699,43 @@ Size: 4, 3 Tiles: 0: Rough - LeftColor: A1B0BD - RightColor: 9BA8B4 + MinColor: A1B0BD + MaxColor: 9BA8B4 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: A6B7C8 - RightColor: 919DA9 + MinColor: A6B7C8 + MaxColor: 919DA9 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 929DA9 - RightColor: A8BBCC + MinColor: 929DA9 + MaxColor: A8BBCC ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: B5C9DB - RightColor: C2D6E4 + MinColor: B5C9DB + MaxColor: C2D6E4 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 8F9BA7 - RightColor: A7B7C5 + MinColor: 8F9BA7 + MaxColor: A7B7C5 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 929DA6 - RightColor: B4CADB + MinColor: 929DA6 + MaxColor: B4CADB ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: A4B5C3 - RightColor: 9EA9B4 + MinColor: A4B5C3 + MaxColor: 9EA9B4 ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: A5B6C7 - RightColor: 97A3B0 + MinColor: A5B6C7 + MaxColor: 97A3B0 ZOffset: -12 ZRamp: 0 Template@715: @@ -15743,63 +15745,63 @@ Size: 3, 5 Tiles: 1: Rough - LeftColor: 939BA2 - RightColor: A4B4C2 + MinColor: 939BA2 + MaxColor: A4B4C2 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 8F99A2 - RightColor: 8D959E + MinColor: 8F99A2 + MaxColor: 8D959E ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: 7D8289 - RightColor: 899097 + MinColor: 7D8289 + MaxColor: 899097 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 86919D - RightColor: B1C5D8 + MinColor: 86919D + MaxColor: B1C5D8 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 99A8B8 - RightColor: 94A1AC + MinColor: 99A8B8 + MaxColor: 94A1AC ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: BBD1E3 - RightColor: 8F9BA9 + MinColor: BBD1E3 + MaxColor: 8F9BA9 ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: 939FA9 - RightColor: ADC0D1 + MinColor: 939FA9 + MaxColor: ADC0D1 ZOffset: -12 ZRamp: 0 9: Rough - LeftColor: B7CCDE - RightColor: 97A6B5 + MinColor: B7CCDE + MaxColor: 97A6B5 ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: A2ADB7 - RightColor: A6B1BA + MinColor: A2ADB7 + MaxColor: A6B1BA ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: A7B5C3 - RightColor: 94A0AC + MinColor: A7B5C3 + MaxColor: 94A0AC ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: A1B1C0 - RightColor: AABBCC + MinColor: A1B1C0 + MaxColor: AABBCC ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: ADBDCC - RightColor: BBCEDC + MinColor: ADBDCC + MaxColor: BBCEDC ZOffset: -12 ZRamp: 0 Template@716: @@ -15809,68 +15811,68 @@ Size: 4, 4 Tiles: 1: Clear - LeftColor: B3CADF - RightColor: A9BED3 + MinColor: B3CADF + MaxColor: A9BED3 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: BACFE0 - RightColor: B8CFE5 + MinColor: BACFE0 + MaxColor: B8CFE5 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: B8CFE1 - RightColor: AEC3D4 + MinColor: B8CFE1 + MaxColor: AEC3D4 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 838D96 - RightColor: 8F9BA7 + MinColor: 838D96 + MaxColor: 8F9BA7 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: A5B3C1 - RightColor: B3C7DB + MinColor: A5B3C1 + MaxColor: B3C7DB ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 9DAAB5 - RightColor: A5B9CB + MinColor: 9DAAB5 + MaxColor: A5B9CB ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: B9D3EC - RightColor: A3B3C4 + MinColor: B9D3EC + MaxColor: A3B3C4 ZOffset: -12 ZRamp: 0 9: Rough - LeftColor: 99A4AF - RightColor: 9CAAB6 + MinColor: 99A4AF + MaxColor: 9CAAB6 ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: A2AEB9 - RightColor: A4B0BA + MinColor: A2AEB9 + MaxColor: A4B0BA ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: 7E858C - RightColor: 88949E + MinColor: 7E858C + MaxColor: 88949E ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: A0AEBD - RightColor: 7D868E + MinColor: A0AEBD + MaxColor: 7D868E ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: ADBCCB - RightColor: A1AEB8 + MinColor: ADBCCB + MaxColor: A1AEB8 ZOffset: -12 ZRamp: 0 15: Rough - LeftColor: A9B8C7 - RightColor: A5B7C8 + MinColor: A9B8C7 + MaxColor: A5B7C8 ZOffset: -12 ZRamp: 0 Template@717: @@ -15880,43 +15882,43 @@ Size: 3, 3 Tiles: 0: Rough - LeftColor: A0B0C1 - RightColor: A4B4C3 + MinColor: A0B0C1 + MaxColor: A4B4C3 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: ACBFD2 - RightColor: A7B8C8 + MinColor: ACBFD2 + MaxColor: A7B8C8 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: A6B5C2 - RightColor: ADC1D1 + MinColor: A6B5C2 + MaxColor: ADC1D1 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 9EACB9 - RightColor: A5B4C3 + MinColor: 9EACB9 + MaxColor: A5B4C3 ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: AEBECD - RightColor: ABBAC7 + MinColor: AEBECD + MaxColor: ABBAC7 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: BAC9D5 - RightColor: A6B5C5 + MinColor: BAC9D5 + MaxColor: A6B5C5 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: B5C9DC - RightColor: A5B3BF + MinColor: B5C9DC + MaxColor: A5B3BF ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: B7CCDE - RightColor: A3B3C1 + MinColor: B7CCDE + MaxColor: A3B3C1 ZOffset: -12 ZRamp: 0 Template@718: @@ -15926,113 +15928,113 @@ Size: 6, 10 Tiles: 1: Rough - LeftColor: AABECF - RightColor: ACC1D4 + MinColor: AABECF + MaxColor: ACC1D4 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 99A6B4 - RightColor: 95A1AD + MinColor: 99A6B4 + MaxColor: 95A1AD ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 848B92 - RightColor: 919DAA + MinColor: 848B92 + MaxColor: 919DAA ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: ABBECF - RightColor: 99A8B6 + MinColor: ABBECF + MaxColor: 99A8B6 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 8F99A3 - RightColor: 939DA5 + MinColor: 8F99A3 + MaxColor: 939DA5 ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: 858C94 - RightColor: 94A4B1 + MinColor: 858C94 + MaxColor: 94A4B1 ZOffset: -12 ZRamp: 0 15: Rough - LeftColor: A1B2C1 - RightColor: B3C7D8 + MinColor: A1B2C1 + MaxColor: B3C7D8 ZOffset: -12 ZRamp: 0 20: Rough - LeftColor: 9FAEBD - RightColor: 959FAC + MinColor: 9FAEBD + MaxColor: 959FAC ZOffset: -12 ZRamp: 0 21: Rough - LeftColor: A4B4C4 - RightColor: 7D838A + MinColor: A4B4C4 + MaxColor: 7D838A ZOffset: -12 ZRamp: 0 22: Rough - LeftColor: 939EAA - RightColor: A9BCCD + MinColor: 939EAA + MaxColor: A9BCCD ZOffset: -12 ZRamp: 0 26: Rough - LeftColor: B2C6D9 - RightColor: A6B7C7 + MinColor: B2C6D9 + MaxColor: A6B7C7 ZOffset: -12 ZRamp: 0 27: Rough - LeftColor: 9EADBA - RightColor: C2D7E4 + MinColor: 9EADBA + MaxColor: C2D7E4 ZOffset: -12 ZRamp: 0 28: Rough - LeftColor: 99A6B1 - RightColor: B0C3D2 + MinColor: 99A6B1 + MaxColor: B0C3D2 ZOffset: -12 ZRamp: 0 33: Rough - LeftColor: B7CCDC - RightColor: A9BACA + MinColor: B7CCDC + MaxColor: A9BACA ZOffset: -12 ZRamp: 0 34: Rough - LeftColor: 98A4AF - RightColor: 9EA9B4 + MinColor: 98A4AF + MaxColor: 9EA9B4 ZOffset: -12 ZRamp: 0 35: Rough - LeftColor: A6B7C6 - RightColor: B4C9DB + MinColor: A6B7C6 + MaxColor: B4C9DB ZOffset: -12 ZRamp: 0 40: Rough - LeftColor: ABBCCA - RightColor: C1DBEE + MinColor: ABBCCA + MaxColor: C1DBEE ZOffset: -12 ZRamp: 0 45: Rough - LeftColor: AEBFCF - RightColor: A8B6C2 + MinColor: AEBFCF + MaxColor: A8B6C2 ZOffset: -12 ZRamp: 0 46: Rough - LeftColor: A0AEBC - RightColor: AEC0D0 + MinColor: A0AEBC + MaxColor: AEC0D0 ZOffset: -12 ZRamp: 0 51: Rough - LeftColor: BBD0E2 - RightColor: B8C9D6 + MinColor: BBD0E2 + MaxColor: B8C9D6 ZOffset: -12 ZRamp: 0 52: Rough - LeftColor: A8B8C5 - RightColor: A9B9CA + MinColor: A8B8C5 + MaxColor: A9B9CA ZOffset: -12 ZRamp: 0 57: Rough - LeftColor: B0C2D3 - RightColor: ADBECE + MinColor: B0C2D3 + MaxColor: ADBECE ZOffset: -12 ZRamp: 0 Template@719: @@ -16042,83 +16044,83 @@ Size: 8, 3 Tiles: 0: Clear - LeftColor: C5DBED - RightColor: CAE2F4 + MinColor: C5DBED + MaxColor: CAE2F4 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: B2C1CA - RightColor: A1B0BD + MinColor: B2C1CA + MaxColor: A1B0BD ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 7F878D - RightColor: 8A959F + MinColor: 7F878D + MaxColor: 8A959F ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 939EA6 - RightColor: 9AA9B5 + MinColor: 939EA6 + MaxColor: 9AA9B5 ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: A5B5C3 - RightColor: 8E99A3 + MinColor: A5B5C3 + MaxColor: 8E99A3 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: B6CADA - RightColor: BBD7F1 + MinColor: B6CADA + MaxColor: BBD7F1 ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: B3C9DD - RightColor: 96A0AA + MinColor: B3C9DD + MaxColor: 96A0AA ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: AFC2D4 - RightColor: 98A3AD + MinColor: AFC2D4 + MaxColor: 98A3AD ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: BED6EA - RightColor: AFC0D2 + MinColor: BED6EA + MaxColor: AFC0D2 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: AFC1D4 - RightColor: 8E99A5 + MinColor: AFC1D4 + MaxColor: 8E99A5 ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: 97A5B5 - RightColor: A4B2BC + MinColor: 97A5B5 + MaxColor: A4B2BC ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 939CA6 - RightColor: 9AA7B2 + MinColor: 939CA6 + MaxColor: 9AA7B2 ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: 9CAAB5 - RightColor: B3C6D4 + MinColor: 9CAAB5 + MaxColor: B3C6D4 ZOffset: -12 ZRamp: 0 15: Rough - LeftColor: A8BCCE - RightColor: AABED0 + MinColor: A8BCCE + MaxColor: AABED0 ZOffset: -12 ZRamp: 0 21: Clear - LeftColor: C1DCF3 - RightColor: B6CBDD + MinColor: C1DCF3 + MaxColor: B6CBDD ZOffset: -12 ZRamp: 0 22: Clear - LeftColor: B1C5D6 - RightColor: BDD4E7 + MinColor: B1C5D6 + MaxColor: BDD4E7 ZOffset: -12 ZRamp: 0 Template@720: @@ -16128,43 +16130,43 @@ Size: 3, 4 Tiles: 0: Rough - LeftColor: A8BBCC - RightColor: 99A9B8 + MinColor: A8BBCC + MaxColor: 99A9B8 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 9FAEBB - RightColor: B5CDE4 + MinColor: 9FAEBB + MaxColor: B5CDE4 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 9CACB9 - RightColor: 98A4AE + MinColor: 9CACB9 + MaxColor: 98A4AE ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: A7B5C2 - RightColor: A8B9C6 + MinColor: A7B5C2 + MaxColor: A8B9C6 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: ADBECC - RightColor: B0C6D9 + MinColor: ADBECC + MaxColor: B0C6D9 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: A3B2C1 - RightColor: A7B7C4 + MinColor: A3B2C1 + MaxColor: A7B7C4 ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: A9BBCA - RightColor: BBCFDF + MinColor: A9BBCA + MaxColor: BBCFDF ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: A4B4C3 - RightColor: B2C7DA + MinColor: A4B4C3 + MaxColor: B2C7DA ZOffset: -12 ZRamp: 0 Template@721: @@ -16175,8 +16177,8 @@ Tiles: 0: Clear RampType: 1 - LeftColor: D0E4F0 - RightColor: CEE2EE + MinColor: D0E4F0 + MaxColor: CEE2EE ZOffset: -12 ZRamp: 0 Template@722: @@ -16187,8 +16189,8 @@ Tiles: 0: Clear RampType: 1 - LeftColor: D2E5F0 - RightColor: CDE0EE + MinColor: D2E5F0 + MaxColor: CDE0EE ZOffset: -12 ZRamp: 0 Template@723: @@ -16199,8 +16201,8 @@ Tiles: 0: Clear RampType: 1 - LeftColor: D0E4F0 - RightColor: CCE0EE + MinColor: D0E4F0 + MaxColor: CCE0EE ZOffset: -12 ZRamp: 0 Template@724: @@ -16211,8 +16213,8 @@ Tiles: 0: Clear RampType: 2 - LeftColor: A0B9DD - RightColor: A1BCDE + MinColor: A0B9DD + MaxColor: A1BCDE ZOffset: -12 ZRamp: 0 Template@725: @@ -16223,8 +16225,8 @@ Tiles: 0: Clear RampType: 2 - LeftColor: A6BFE2 - RightColor: 9EB9DC + MinColor: A6BFE2 + MaxColor: 9EB9DC ZOffset: -12 ZRamp: 0 Template@726: @@ -16235,8 +16237,8 @@ Tiles: 0: Clear RampType: 2 - LeftColor: A6C0E2 - RightColor: A1BCDE + MinColor: A6C0E2 + MaxColor: A1BCDE ZOffset: -12 ZRamp: 0 Template@727: @@ -16247,8 +16249,8 @@ Tiles: 0: Clear RampType: 3 - LeftColor: AAC5E3 - RightColor: A7C3E1 + MinColor: AAC5E3 + MaxColor: A7C3E1 ZOffset: -12 ZRamp: 0 Template@728: @@ -16259,8 +16261,8 @@ Tiles: 0: Clear RampType: 3 - LeftColor: AFCAE6 - RightColor: A2BDDD + MinColor: AFCAE6 + MaxColor: A2BDDD ZOffset: -12 ZRamp: 0 Template@729: @@ -16271,8 +16273,8 @@ Tiles: 0: Clear RampType: 3 - LeftColor: AFCAE6 - RightColor: A7C3E1 + MinColor: AFCAE6 + MaxColor: A7C3E1 ZOffset: -12 ZRamp: 0 Template@730: @@ -16283,8 +16285,8 @@ Tiles: 0: Clear RampType: 4 - LeftColor: D2E5F2 - RightColor: D1E3EF + MinColor: D2E5F2 + MaxColor: D1E3EF ZOffset: -12 ZRamp: 0 Template@731: @@ -16295,8 +16297,8 @@ Tiles: 0: Clear RampType: 4 - LeftColor: D6E8F2 - RightColor: CBDFED + MinColor: D6E8F2 + MaxColor: CBDFED ZOffset: -12 ZRamp: 0 Template@732: @@ -16307,8 +16309,8 @@ Tiles: 0: Clear RampType: 4 - LeftColor: D2E5F2 - RightColor: CBDFED + MinColor: D2E5F2 + MaxColor: CBDFED ZOffset: -12 ZRamp: 0 Template@745: @@ -16319,26 +16321,26 @@ Tiles: 0: Cliff RampType: 1 - LeftColor: 738691 - RightColor: CCE1F0 + MinColor: 738691 + MaxColor: CCE1F0 ZOffset: -12 ZRamp: 0 1: Cliff RampType: 1 - LeftColor: 465865 - RightColor: 495C6B + MinColor: 465865 + MaxColor: 495C6B ZOffset: -12 ZRamp: 0 2: Cliff RampType: 1 - LeftColor: 7D8F9A - RightColor: 5A6F7D + MinColor: 7D8F9A + MaxColor: 5A6F7D ZOffset: -12 ZRamp: 0 3: Cliff RampType: 1 - LeftColor: C9DAE4 - RightColor: C7D9E6 + MinColor: C9DAE4 + MaxColor: C7D9E6 ZOffset: -12 ZRamp: 0 Template@746: @@ -16349,26 +16351,26 @@ Tiles: 0: Cliff RampType: 2 - LeftColor: A0B8DC - RightColor: 879EB3 + MinColor: A0B8DC + MaxColor: 879EB3 ZOffset: -12 ZRamp: 0 1: Cliff RampType: 2 - LeftColor: 596E7A - RightColor: 465966 + MinColor: 596E7A + MaxColor: 465966 ZOffset: -12 ZRamp: 0 2: Cliff RampType: 2 - LeftColor: 3B4D5B - RightColor: 728699 + MinColor: 3B4D5B + MaxColor: 728699 ZOffset: -12 ZRamp: 0 3: Cliff RampType: 2 - LeftColor: 93AEC8 - RightColor: 93ADCC + MinColor: 93AEC8 + MaxColor: 93ADCC ZOffset: -12 ZRamp: 0 Template@747: @@ -16379,26 +16381,26 @@ Tiles: 0: Cliff RampType: 3 - LeftColor: 8DA2B5 - RightColor: A4BCD4 + MinColor: 8DA2B5 + MaxColor: A4BCD4 ZOffset: -12 ZRamp: 0 1: Cliff RampType: 3 - LeftColor: 4B5E6E - RightColor: 51636F + MinColor: 4B5E6E + MaxColor: 51636F ZOffset: -12 ZRamp: 0 2: Cliff RampType: 3 - LeftColor: 657887 - RightColor: 516270 + MinColor: 657887 + MaxColor: 516270 ZOffset: -12 ZRamp: 0 3: Cliff RampType: 3 - LeftColor: B9D2E7 - RightColor: A7BBCE + MinColor: B9D2E7 + MaxColor: A7BBCE ZOffset: -12 ZRamp: 0 Template@748: @@ -16409,26 +16411,26 @@ Tiles: 0: Cliff RampType: 4 - LeftColor: D4E5EF - RightColor: 91A1AA + MinColor: D4E5EF + MaxColor: 91A1AA ZOffset: -12 ZRamp: 0 1: Cliff RampType: 4 - LeftColor: 5E6E79 - RightColor: 67767F + MinColor: 5E6E79 + MaxColor: 67767F ZOffset: -12 ZRamp: 0 2: Cliff RampType: 4 - LeftColor: 6B7D88 - RightColor: 75868F + MinColor: 6B7D88 + MaxColor: 75868F ZOffset: -12 ZRamp: 0 3: Cliff RampType: 4 - LeftColor: C5D8E5 - RightColor: C5D7E3 + MinColor: C5D8E5 + MaxColor: C5D7E3 ZOffset: -12 ZRamp: 0 Template@749: @@ -16439,20 +16441,20 @@ Tiles: 0: Road RampType: 1 - LeftColor: 6A7279 - RightColor: A2AEB6 + MinColor: 6A7279 + MaxColor: A2AEB6 ZOffset: -12 ZRamp: 0 1: Road RampType: 1 - LeftColor: 616161 - RightColor: 686558 + MinColor: 616161 + MaxColor: 686558 ZOffset: -12 ZRamp: 0 2: Road RampType: 1 - LeftColor: 9AA7B0 - RightColor: 7A838B + MinColor: 9AA7B0 + MaxColor: 7A838B ZOffset: -12 ZRamp: 0 Template@750: @@ -16463,20 +16465,20 @@ Tiles: 0: Road RampType: 2 - LeftColor: 8494AA - RightColor: 596069 + MinColor: 8494AA + MaxColor: 596069 ZOffset: -12 ZRamp: 0 1: Road RampType: 2 - LeftColor: 535146 - RightColor: 4E4F4F + MinColor: 535146 + MaxColor: 4E4F4F ZOffset: -12 ZRamp: 0 2: Road RampType: 2 - LeftColor: 697682 - RightColor: 7F92A7 + MinColor: 697682 + MaxColor: 7F92A7 ZOffset: -12 ZRamp: 0 Template@751: @@ -16487,20 +16489,20 @@ Tiles: 0: Road RampType: 3 - LeftColor: 4D4E4F - RightColor: 7E868E + MinColor: 4D4E4F + MaxColor: 7E868E ZOffset: -12 ZRamp: 0 1: Road RampType: 3 - LeftColor: 4D4E4F - RightColor: 4F4F4E + MinColor: 4D4E4F + MaxColor: 4F4F4E ZOffset: -12 ZRamp: 0 2: Road RampType: 3 - LeftColor: 7F8991 - RightColor: 5B6165 + MinColor: 7F8991 + MaxColor: 5B6165 ZOffset: -12 ZRamp: 0 Template@752: @@ -16511,20 +16513,20 @@ Tiles: 0: DirtRoad RampType: 4 - LeftColor: A2A9AE - RightColor: 5F6265 + MinColor: A2A9AE + MaxColor: 5F6265 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 4 - LeftColor: 575855 - RightColor: 575858 + MinColor: 575855 + MaxColor: 575858 ZOffset: -12 ZRamp: 0 2: DirtRoad RampType: 4 - LeftColor: 64696D - RightColor: 8B949A + MinColor: 64696D + MaxColor: 8B949A ZOffset: -12 ZRamp: 0 Template@753: @@ -16535,8 +16537,8 @@ Tiles: 0: Rail RampType: 1 - LeftColor: 4C4D4C - RightColor: 4D4C46 + MinColor: 4C4D4C + MaxColor: 4D4C46 ZOffset: -12 ZRamp: 0 Template@754: @@ -16547,8 +16549,8 @@ Tiles: 0: Rail RampType: 2 - LeftColor: 3E434A - RightColor: 454645 + MinColor: 3E434A + MaxColor: 454645 ZOffset: -12 ZRamp: 0 Template@755: @@ -16559,8 +16561,8 @@ Tiles: 0: Rail RampType: 3 - LeftColor: 4A4942 - RightColor: 474847 + MinColor: 4A4942 + MaxColor: 474847 ZOffset: -12 ZRamp: 0 Template@756: @@ -16571,8 +16573,8 @@ Tiles: 0: Rail RampType: 4 - LeftColor: 373A3B - RightColor: 4B483F + MinColor: 373A3B + MaxColor: 4B483F ZOffset: -12 ZRamp: 0 Template@772: @@ -16582,78 +16584,78 @@ Size: 3, 5 Tiles: 0: Cliff - LeftColor: BAD5F0 - RightColor: B6D1EF + MinColor: BAD5F0 + MaxColor: B6D1EF ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: BBD7F1 - RightColor: BDD8F1 + MinColor: BBD7F1 + MaxColor: BDD8F1 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 89A1AC - RightColor: 8AA2AD + MinColor: 89A1AC + MaxColor: 8AA2AD ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 606970 - RightColor: 929CA5 + MinColor: 606970 + MaxColor: 929CA5 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 798086 - RightColor: 9CA7AF + MinColor: 798086 + MaxColor: 9CA7AF ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 4A5157 - RightColor: 697479 + MinColor: 4A5157 + MaxColor: 697479 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 545959 - RightColor: 5A5C5A + MinColor: 545959 + MaxColor: 5A5C5A ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 535452 - RightColor: 545553 + MinColor: 535452 + MaxColor: 545553 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 424342 - RightColor: 424442 + MinColor: 424342 + MaxColor: 424442 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 919AA3 - RightColor: 6C747A + MinColor: 919AA3 + MaxColor: 6C747A ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 8E98A1 - RightColor: 6B7176 + MinColor: 8E98A1 + MaxColor: 6B7176 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 667279 - RightColor: 4B5459 + MinColor: 667279 + MaxColor: 4B5459 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 89A1AD - RightColor: 879FAC + MinColor: 89A1AD + MaxColor: 879FAC ZOffset: -12 ZRamp: 0 Template@773: @@ -16663,78 +16665,78 @@ Size: 5, 3 Tiles: 0: Cliff - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 9FA9B1 - RightColor: 6B6F72 + MinColor: 9FA9B1 + MaxColor: 6B6F72 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 585753 - RightColor: 565652 + MinColor: 585753 + MaxColor: 565652 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 656A6F - RightColor: 959FA8 + MinColor: 656A6F + MaxColor: 959FA8 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: C2DCF2 - RightColor: BFDAF2 + MinColor: C2DCF2 + MaxColor: BFDAF2 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 9EA6AB - RightColor: 646768 + MinColor: 9EA6AB + MaxColor: 646768 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 55544F - RightColor: 545452 + MinColor: 55544F + MaxColor: 545452 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 646567 - RightColor: A7ABAF + MinColor: 646567 + MaxColor: A7ABAF ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C4DDF1 - RightColor: C1DBF1 + MinColor: C4DDF1 + MaxColor: C1DBF1 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 8BA1AD - RightColor: 89A0AC + MinColor: 8BA1AD + MaxColor: 89A0AC ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 71777A - RightColor: 525556 + MinColor: 71777A + MaxColor: 525556 ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 454747 - RightColor: 464746 + MinColor: 454747 + MaxColor: 464746 ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 525454 - RightColor: 747779 + MinColor: 525454 + MaxColor: 747779 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 859DA9 - RightColor: 819BA8 + MinColor: 859DA9 + MaxColor: 819BA8 ZOffset: -12 ZRamp: 0 Template@774: @@ -16744,63 +16746,63 @@ Size: 3, 4 Tiles: 0: Cliff - LeftColor: 0F1011 - RightColor: 48525C + MinColor: 0F1011 + MaxColor: 48525C ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5F6467 - RightColor: 686E77 + MinColor: 5F6467 + MaxColor: 686E77 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 9BAEC1 - RightColor: BBD6EF + MinColor: 9BAEC1 + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 26292A - RightColor: 101213 + MinColor: 26292A + MaxColor: 101213 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 475055 - RightColor: 75828C + MinColor: 475055 + MaxColor: 75828C ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 798085 - RightColor: 9CA7AF + MinColor: 798085 + MaxColor: 9CA7AF ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 1B1C1B - RightColor: 080909 + MinColor: 1B1C1B + MaxColor: 080909 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 3B3D3C - RightColor: 434644 + MinColor: 3B3D3C + MaxColor: 434644 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 535451 - RightColor: 545553 + MinColor: 535451 + MaxColor: 545553 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 0B0C0C - RightColor: 353B3E + MinColor: 0B0C0C + MaxColor: 353B3E ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 68747B - RightColor: 515B60 + MinColor: 68747B + MaxColor: 515B60 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 8D98A0 - RightColor: 6B7176 + MinColor: 8D98A0 + MaxColor: 6B7176 ZOffset: -12 ZRamp: 0 Template@775: @@ -16810,63 +16812,63 @@ Size: 4, 3 Tiles: 0: Cliff - LeftColor: 232526 - RightColor: 525B63 + MinColor: 232526 + MaxColor: 525B63 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 495155 - RightColor: 0A0A0B + MinColor: 495155 + MaxColor: 0A0A0B ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 2A2D2D - RightColor: 050505 + MinColor: 2A2D2D + MaxColor: 050505 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 353B3E - RightColor: 0B0C0C + MinColor: 353B3E + MaxColor: 0B0C0C ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 606B77 - RightColor: 606870 + MinColor: 606B77 + MaxColor: 606870 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 75828C - RightColor: 475055 + MinColor: 75828C + MaxColor: 475055 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 434644 - RightColor: 3B3D3C + MinColor: 434644 + MaxColor: 3B3D3C ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 515B60 - RightColor: 68747B + MinColor: 515B60 + MaxColor: 68747B ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C2DDF2 - RightColor: 9DB0C3 + MinColor: C2DDF2 + MaxColor: 9DB0C3 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 9CA7B0 - RightColor: 798085 + MinColor: 9CA7B0 + MaxColor: 798085 ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 545553 - RightColor: 535451 + MinColor: 545553 + MaxColor: 535451 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 6B7176 - RightColor: 8D98A0 + MinColor: 6B7176 + MaxColor: 8D98A0 ZOffset: -12 ZRamp: 0 Template@776: @@ -16877,18 +16879,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 8395A7 - RightColor: 798895 + MinColor: 8395A7 + MaxColor: 798895 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 95AFCA - RightColor: 959DA2 + MinColor: 95AFCA + MaxColor: 959DA2 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: C0D8EB - RightColor: 99A0A4 + MinColor: C0D8EB + MaxColor: 99A0A4 ZOffset: -12 ZRamp: 0 Template@777: @@ -16898,18 +16900,18 @@ Size: 1, 3 Tiles: 0: Cliff - LeftColor: 85A0B5 - RightColor: 8EA2B5 + MinColor: 85A0B5 + MaxColor: 8EA2B5 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 8E99A5 - RightColor: 6E7780 + MinColor: 8E99A5 + MaxColor: 6E7780 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 9EA9B2 - RightColor: B6C8D9 + MinColor: 9EA9B2 + MaxColor: B6C8D9 ZOffset: -12 ZRamp: 0 Template@778: @@ -16919,78 +16921,78 @@ Size: 3, 5 Tiles: 0: Cliff - LeftColor: BAD5F0 - RightColor: B6D1EF + MinColor: BAD5F0 + MaxColor: B6D1EF ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: BBD7F1 - RightColor: BDD8F1 + MinColor: BBD7F1 + MaxColor: BDD8F1 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 89A1AC - RightColor: 8AA2AD + MinColor: 89A1AC + MaxColor: 8AA2AD ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 606970 - RightColor: 929CA5 + MinColor: 606970 + MaxColor: 929CA5 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 798086 - RightColor: 9CA7AF + MinColor: 798086 + MaxColor: 9CA7AF ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 4A5157 - RightColor: 697479 + MinColor: 4A5157 + MaxColor: 697479 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 4D5155 - RightColor: 525558 + MinColor: 4D5155 + MaxColor: 525558 ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 4D4F52 - RightColor: 515356 + MinColor: 4D4F52 + MaxColor: 515356 ZOffset: -12 ZRamp: 0 8: Rail - LeftColor: 494C50 - RightColor: 4D5154 + MinColor: 494C50 + MaxColor: 4D5154 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 919AA3 - RightColor: 6C747A + MinColor: 919AA3 + MaxColor: 6C747A ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 8E98A1 - RightColor: 6B7176 + MinColor: 8E98A1 + MaxColor: 6B7176 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 667279 - RightColor: 4B5459 + MinColor: 667279 + MaxColor: 4B5459 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 89A1AD - RightColor: 879FAC + MinColor: 89A1AD + MaxColor: 879FAC ZOffset: -12 ZRamp: 0 Template@779: @@ -17000,78 +17002,78 @@ Size: 5, 3 Tiles: 0: Cliff - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 9FA9B1 - RightColor: 6B6F72 + MinColor: 9FA9B1 + MaxColor: 6B6F72 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 4F5154 - RightColor: 4D4F53 + MinColor: 4F5154 + MaxColor: 4D4F53 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 656A6F - RightColor: 959FA8 + MinColor: 656A6F + MaxColor: 959FA8 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: C2DCF2 - RightColor: BFDAF2 + MinColor: C2DCF2 + MaxColor: BFDAF2 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 9EA6AB - RightColor: 646768 + MinColor: 9EA6AB + MaxColor: 646768 ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 4F5154 - RightColor: 4D4F52 + MinColor: 4F5154 + MaxColor: 4D4F52 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 646567 - RightColor: A7ABAF + MinColor: 646567 + MaxColor: A7ABAF ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C4DDF1 - RightColor: C1DBF1 + MinColor: C4DDF1 + MaxColor: C1DBF1 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 8BA1AD - RightColor: 89A0AC + MinColor: 8BA1AD + MaxColor: 89A0AC ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 71777A - RightColor: 525556 + MinColor: 71777A + MaxColor: 525556 ZOffset: -12 ZRamp: 0 12: Rail - LeftColor: 4C4E50 - RightColor: 494C50 + MinColor: 4C4E50 + MaxColor: 494C50 ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 525454 - RightColor: 747779 + MinColor: 525454 + MaxColor: 747779 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 859DA9 - RightColor: 819BA8 + MinColor: 859DA9 + MaxColor: 819BA8 ZOffset: -12 ZRamp: 0 Template@780: @@ -17081,63 +17083,63 @@ Size: 3, 4 Tiles: 0: Cliff - LeftColor: 0F1011 - RightColor: 48525C + MinColor: 0F1011 + MaxColor: 48525C ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5F6467 - RightColor: 686E77 + MinColor: 5F6467 + MaxColor: 686E77 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 9BAEC1 - RightColor: BBD6EF + MinColor: 9BAEC1 + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 26292A - RightColor: 101213 + MinColor: 26292A + MaxColor: 101213 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 475055 - RightColor: 75828C + MinColor: 475055 + MaxColor: 75828C ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 798085 - RightColor: 9CA7AF + MinColor: 798085 + MaxColor: 9CA7AF ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 232425 - RightColor: 090A0A + MinColor: 232425 + MaxColor: 090A0A ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 3C4043 - RightColor: 484C50 + MinColor: 3C4043 + MaxColor: 484C50 ZOffset: -12 ZRamp: 0 8: Rail - LeftColor: 4D4F52 - RightColor: 515356 + MinColor: 4D4F52 + MaxColor: 515356 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 0B0C0C - RightColor: 353B3E + MinColor: 0B0C0C + MaxColor: 353B3E ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 68747B - RightColor: 515B60 + MinColor: 68747B + MaxColor: 515B60 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 8D98A0 - RightColor: 6B7176 + MinColor: 8D98A0 + MaxColor: 6B7176 ZOffset: -12 ZRamp: 0 Template@781: @@ -17147,63 +17149,63 @@ Size: 4, 3 Tiles: 0: Cliff - LeftColor: 232526 - RightColor: 525B63 + MinColor: 232526 + MaxColor: 525B63 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 495155 - RightColor: 0A0A0B + MinColor: 495155 + MaxColor: 0A0A0B ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 292C2D - RightColor: 060606 + MinColor: 292C2D + MaxColor: 060606 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 353B3E - RightColor: 0B0C0C + MinColor: 353B3E + MaxColor: 0B0C0C ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 606B77 - RightColor: 606870 + MinColor: 606B77 + MaxColor: 606870 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 75828C - RightColor: 475055 + MinColor: 75828C + MaxColor: 475055 ZOffset: -12 ZRamp: 0 6: Rail - LeftColor: 44494C - RightColor: 383C3F + MinColor: 44494C + MaxColor: 383C3F ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 515B60 - RightColor: 68747B + MinColor: 515B60 + MaxColor: 68747B ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C2DDF2 - RightColor: 9DB0C3 + MinColor: C2DDF2 + MaxColor: 9DB0C3 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 9CA7B0 - RightColor: 798085 + MinColor: 9CA7B0 + MaxColor: 798085 ZOffset: -12 ZRamp: 0 10: Rail - LeftColor: 4E5053 - RightColor: 4C4F52 + MinColor: 4E5053 + MaxColor: 4C4F52 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 6B7176 - RightColor: 8D98A0 + MinColor: 6B7176 + MaxColor: 8D98A0 ZOffset: -12 ZRamp: 0 Template@987: @@ -17214,112 +17216,112 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 889CAE - RightColor: 8FA2B1 + MinColor: 889CAE + MaxColor: 8FA2B1 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 9DA9B1 - RightColor: 8A9AA8 + MinColor: 9DA9B1 + MaxColor: 8A9AA8 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 9CA8B2 - RightColor: 99A7B3 + MinColor: 9CA8B2 + MaxColor: 99A7B3 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 9FABB4 - RightColor: 93A6B4 + MinColor: 9FABB4 + MaxColor: 93A6B4 ZOffset: -12 ZRamp: 0 6: Cliff Height: 4 - LeftColor: 8C9DAE - RightColor: 7E90A0 + MinColor: 8C9DAE + MaxColor: 7E90A0 ZOffset: -12 ZRamp: 0 7: Cliff Height: 4 - LeftColor: 7C8DA2 - RightColor: 879CB1 + MinColor: 7C8DA2 + MaxColor: 879CB1 ZOffset: -12 ZRamp: 0 8: Cliff Height: 4 - LeftColor: 84919F - RightColor: 8E9CAA + MinColor: 84919F + MaxColor: 8E9CAA ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 6D8092 - RightColor: 8697A8 + MinColor: 6D8092 + MaxColor: 8697A8 ZOffset: -12 ZRamp: 0 10: Cliff Height: 4 - LeftColor: 8194A5 - RightColor: 8F9FAD + MinColor: 8194A5 + MaxColor: 8F9FAD ZOffset: -12 ZRamp: 0 11: Cliff Height: 4 - LeftColor: 8597A9 - RightColor: 869AB1 + MinColor: 8597A9 + MaxColor: 869AB1 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: BCD7F0 - RightColor: ACC1D5 + MinColor: BCD7F0 + MaxColor: ACC1D5 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: D9E9F4 - RightColor: B1C3D3 + MinColor: D9E9F4 + MaxColor: B1C3D3 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: C6D8E5 - RightColor: AABED1 + MinColor: C6D8E5 + MaxColor: AABED1 ZOffset: -12 ZRamp: 0 15: Cliff - LeftColor: BED1E1 - RightColor: 9CB3C8 + MinColor: BED1E1 + MaxColor: 9CB3C8 ZOffset: -12 ZRamp: 0 16: Cliff - LeftColor: B7CDE1 - RightColor: 94AABD + MinColor: B7CDE1 + MaxColor: 94AABD ZOffset: -12 ZRamp: 0 17: Cliff - LeftColor: B3CDE7 - RightColor: A6BCCF + MinColor: B3CDE7 + MaxColor: A6BCCF ZOffset: -12 ZRamp: 0 19: Cliff - LeftColor: BCD8F1 - RightColor: C5DDF2 + MinColor: BCD8F1 + MaxColor: C5DDF2 ZOffset: -12 ZRamp: 0 20: Cliff - LeftColor: C8E1F3 - RightColor: C6DDEF + MinColor: C8E1F3 + MaxColor: C6DDEF ZOffset: -12 ZRamp: 0 21: Cliff - LeftColor: BAD5EF - RightColor: C2DBEF + MinColor: BAD5EF + MaxColor: C2DBEF ZOffset: -12 ZRamp: 0 22: Cliff - LeftColor: BDD7EE - RightColor: C2DBEF + MinColor: BDD7EE + MaxColor: C2DBEF ZOffset: -12 ZRamp: 0 Template@988: @@ -17330,112 +17332,112 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 899EB0 - RightColor: 8696A4 + MinColor: 899EB0 + MaxColor: 8696A4 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 87A3C2 - RightColor: 87A2B8 + MinColor: 87A3C2 + MaxColor: 87A2B8 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 96A7B5 - RightColor: 98A9B6 + MinColor: 96A7B5 + MaxColor: 98A9B6 ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 899EB0 - RightColor: 7F909F + MinColor: 899EB0 + MaxColor: 7F909F ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: A1BBDB - RightColor: 7E9BB4 + MinColor: A1BBDB + MaxColor: 7E9BB4 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: BBD5ED - RightColor: C2DCF2 + MinColor: BBD5ED + MaxColor: C2DCF2 ZOffset: -12 ZRamp: 0 8: Cliff Height: 4 - LeftColor: 8A9EB1 - RightColor: 8B9EB0 + MinColor: 8A9EB1 + MaxColor: 8B9EB0 ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 7F92A4 - RightColor: 7D8FA0 + MinColor: 7F92A4 + MaxColor: 7D8FA0 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 9BB5D0 - RightColor: 839EB8 + MinColor: 9BB5D0 + MaxColor: 839EB8 ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: ADC8E6 - RightColor: BCD6EF + MinColor: ADC8E6 + MaxColor: BCD6EF ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 94A7B6 - RightColor: 8DA0B0 + MinColor: 94A7B6 + MaxColor: 8DA0B0 ZOffset: -12 ZRamp: 0 13: Cliff Height: 4 - LeftColor: 879CB0 - RightColor: 738799 + MinColor: 879CB0 + MaxColor: 738799 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: B7D1E5 - RightColor: 94ADC7 + MinColor: B7D1E5 + MaxColor: 94ADC7 ZOffset: -12 ZRamp: 0 15: Cliff - LeftColor: ADC8E7 - RightColor: B8D3EE + MinColor: ADC8E7 + MaxColor: B8D3EE ZOffset: -12 ZRamp: 0 16: Cliff Height: 4 - LeftColor: 8CA0B2 - RightColor: 8295AC + MinColor: 8CA0B2 + MaxColor: 8295AC ZOffset: -12 ZRamp: 0 17: Cliff Height: 4 - LeftColor: 778998 - RightColor: 738493 + MinColor: 778998 + MaxColor: 738493 ZOffset: -12 ZRamp: 0 18: Cliff - LeftColor: CAE0EE - RightColor: 88A3B6 + MinColor: CAE0EE + MaxColor: 88A3B6 ZOffset: -12 ZRamp: 0 19: Cliff - LeftColor: C3DCF0 - RightColor: BFDAF0 + MinColor: C3DCF0 + MaxColor: BFDAF0 ZOffset: -12 ZRamp: 0 21: Cliff Height: 4 - LeftColor: 8DA1B4 - RightColor: 8698A8 + MinColor: 8DA1B4 + MaxColor: 8698A8 ZOffset: -12 ZRamp: 0 22: Cliff - LeftColor: ADC5DD - RightColor: 8AA7BF + MinColor: ADC5DD + MaxColor: 8AA7BF ZOffset: -12 ZRamp: 0 Template@989: @@ -17445,8 +17447,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 54564F - RightColor: 565750 + MinColor: 54564F + MaxColor: 565750 ZOffset: -12 ZRamp: 0 Template@990: @@ -17456,8 +17458,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 6B7576 - RightColor: 646F70 + MinColor: 6B7576 + MaxColor: 646F70 ZOffset: -12 ZRamp: 0 Template@991: @@ -17467,8 +17469,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 747F84 - RightColor: 7E8D96 + MinColor: 747F84 + MaxColor: 7E8D96 ZOffset: -12 ZRamp: 0 Template@992: @@ -17478,8 +17480,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 5D605A - RightColor: 85939A + MinColor: 5D605A + MaxColor: 85939A ZOffset: -12 ZRamp: 0 Template@993: @@ -17489,8 +17491,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 687071 - RightColor: A2B6C9 + MinColor: 687071 + MaxColor: A2B6C9 ZOffset: -12 ZRamp: 0 Template@994: @@ -17500,8 +17502,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 7B8B95 - RightColor: 595B55 + MinColor: 7B8B95 + MaxColor: 595B55 ZOffset: -12 ZRamp: 0 Template@995: @@ -17511,8 +17513,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 9AAAB8 - RightColor: 919FAA + MinColor: 9AAAB8 + MaxColor: 919FAA ZOffset: -12 ZRamp: 0 Template@996: @@ -17522,8 +17524,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 85929A - RightColor: 8B98A0 + MinColor: 85929A + MaxColor: 8B98A0 ZOffset: -12 ZRamp: 0 Template@997: @@ -17533,8 +17535,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 919FAB - RightColor: AEC5DB + MinColor: 919FAB + MaxColor: AEC5DB ZOffset: -12 ZRamp: 0 Template@998: @@ -17544,8 +17546,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 7B8487 - RightColor: 5C5E58 + MinColor: 7B8487 + MaxColor: 5C5E58 ZOffset: -12 ZRamp: 0 Template@999: @@ -17555,8 +17557,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 93A4AF - RightColor: 8C98A1 + MinColor: 93A4AF + MaxColor: 8C98A1 ZOffset: -12 ZRamp: 0 Template@1000: @@ -17566,8 +17568,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 8597A4 - RightColor: 7F8E98 + MinColor: 8597A4 + MaxColor: 7F8E98 ZOffset: -12 ZRamp: 0 Template@1001: @@ -17577,8 +17579,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: A4B3C0 - RightColor: BDD6EB + MinColor: A4B3C0 + MaxColor: BDD6EB ZOffset: -12 ZRamp: 0 Template@1002: @@ -17588,8 +17590,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: A3B5C4 - RightColor: 616460 + MinColor: A3B5C4 + MaxColor: 616460 ZOffset: -12 ZRamp: 0 Template@1003: @@ -17599,8 +17601,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: B1C7D9 - RightColor: 8E9DAA + MinColor: B1C7D9 + MaxColor: 8E9DAA ZOffset: -12 ZRamp: 0 Template@1004: @@ -17610,8 +17612,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: BCD5EE - RightColor: A3B6C6 + MinColor: BCD5EE + MaxColor: A3B6C6 ZOffset: -12 ZRamp: 0 Template@1005: @@ -17621,8 +17623,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 8F9DA7 - RightColor: 90A3B3 + MinColor: 8F9DA7 + MaxColor: 90A3B3 ZOffset: -12 ZRamp: 0 Template@1006: @@ -17632,8 +17634,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 757D81 - RightColor: A0A4A7 + MinColor: 757D81 + MaxColor: A0A4A7 ZOffset: -12 ZRamp: 0 Template@1007: @@ -17643,8 +17645,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: B9CDDE - RightColor: B6C9DB + MinColor: B9CDDE + MaxColor: B6C9DB ZOffset: -12 ZRamp: 0 Template@1008: @@ -17654,8 +17656,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 929EA5 - RightColor: A7BACB + MinColor: 929EA5 + MaxColor: A7BACB ZOffset: -12 ZRamp: 0 Template@1009: @@ -17665,8 +17667,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: A3A9AE - RightColor: B9C7D6 + MinColor: A3A9AE + MaxColor: B9C7D6 ZOffset: -12 ZRamp: 0 Template@1010: @@ -17676,8 +17678,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: A6A9AB - RightColor: BFD0E0 + MinColor: A6A9AB + MaxColor: BFD0E0 ZOffset: -12 ZRamp: 0 Template@1011: @@ -17687,8 +17689,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: B2C0CE - RightColor: A7A9AB + MinColor: B2C0CE + MaxColor: A7A9AB ZOffset: -12 ZRamp: 0 Template@1012: @@ -17698,8 +17700,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: A6B7C5 - RightColor: A0B2C0 + MinColor: A6B7C5 + MaxColor: A0B2C0 ZOffset: -12 ZRamp: 0 Template@1013: @@ -17709,8 +17711,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: B6C6D4 - RightColor: A1B1BE + MinColor: B6C6D4 + MaxColor: A1B1BE ZOffset: -12 ZRamp: 0 Template@1014: @@ -17720,8 +17722,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: AEB9C2 - RightColor: B4CBDE + MinColor: AEB9C2 + MaxColor: B4CBDE ZOffset: -12 ZRamp: 0 Template@1015: @@ -17731,8 +17733,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: A4B8C8 - RightColor: 8F999F + MinColor: A4B8C8 + MaxColor: 8F999F ZOffset: -12 ZRamp: 0 Template@1016: @@ -17742,8 +17744,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 93A4B0 - RightColor: AAB9C6 + MinColor: 93A4B0 + MaxColor: AAB9C6 ZOffset: -12 ZRamp: 0 Template@1017: @@ -17753,8 +17755,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: A7B3BD - RightColor: A8B3BC + MinColor: A7B3BD + MaxColor: A8B3BC ZOffset: -12 ZRamp: 0 Template@1018: @@ -17764,8 +17766,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: ADBBC6 - RightColor: C0D9EF + MinColor: ADBBC6 + MaxColor: C0D9EF ZOffset: -12 ZRamp: 0 Template@1019: @@ -17775,8 +17777,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: B3C7D9 - RightColor: 95989A + MinColor: B3C7D9 + MaxColor: 95989A ZOffset: -12 ZRamp: 0 Template@1020: @@ -17786,8 +17788,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: BED5E7 - RightColor: A2AFBA + MinColor: BED5E7 + MaxColor: A2AFBA ZOffset: -12 ZRamp: 0 Template@1021: @@ -17797,8 +17799,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: BFD8EB - RightColor: ACB9C4 + MinColor: BFD8EB + MaxColor: ACB9C4 ZOffset: -12 ZRamp: 0 Template@1022: @@ -17808,8 +17810,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: B1C0CD - RightColor: B2C0CC + MinColor: B1C0CD + MaxColor: B2C0CC ZOffset: -12 ZRamp: 0 Template@1023: @@ -17819,78 +17821,78 @@ Size: 3, 5 Tiles: 0: Cliff - LeftColor: BAD5F0 - RightColor: B6D1EF + MinColor: BAD5F0 + MaxColor: B6D1EF ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: BBD7F1 - RightColor: BDD8F1 + MinColor: BBD7F1 + MaxColor: BDD8F1 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 89A1AC - RightColor: 8AA2AD + MinColor: 89A1AC + MaxColor: 8AA2AD ZOffset: -12 ZRamp: 0 3: Road - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 89A1AD - RightColor: 879FAC + MinColor: 89A1AD + MaxColor: 879FAC ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 68717A - RightColor: 687078 + MinColor: 68717A + MaxColor: 687078 ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 69727A - RightColor: 687078 + MinColor: 69727A + MaxColor: 687078 ZOffset: -12 ZRamp: 0 8: Rail - LeftColor: 5B6369 - RightColor: 5D6469 + MinColor: 5B6369 + MaxColor: 5D6469 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 89A1AD - RightColor: 879FAC + MinColor: 89A1AD + MaxColor: 879FAC ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 89A1AD - RightColor: 879FAC + MinColor: 89A1AD + MaxColor: 879FAC ZOffset: -12 ZRamp: 0 Template@1024: @@ -17900,78 +17902,78 @@ Size: 5, 3 Tiles: 0: Cliff - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 1: Road - LeftColor: BBD6EF - RightColor: BCD6EE + MinColor: BBD6EF + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 656D75 - RightColor: 677079 + MinColor: 656D75 + MaxColor: 677079 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: BBD6EF - RightColor: BCD6EE + MinColor: BBD6EF + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: C2DCF2 - RightColor: BFDAF2 + MinColor: C2DCF2 + MaxColor: BFDAF2 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: C1DBF2 - RightColor: C2DDF2 + MinColor: C1DBF2 + MaxColor: C2DDF2 ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 656D75 - RightColor: 68717A + MinColor: 656D75 + MaxColor: 68717A ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: C1DBF2 - RightColor: C2DDF2 + MinColor: C1DBF2 + MaxColor: C2DDF2 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C4DDF1 - RightColor: C1DBF1 + MinColor: C4DDF1 + MaxColor: C1DBF1 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 8BA1AD - RightColor: 89A0AC + MinColor: 8BA1AD + MaxColor: 89A0AC ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 879FAC - RightColor: 89A1AD + MinColor: 879FAC + MaxColor: 89A1AD ZOffset: -12 ZRamp: 0 12: Rail - LeftColor: 5A6166 - RightColor: 5A6268 + MinColor: 5A6166 + MaxColor: 5A6268 ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 879FAC - RightColor: 89A1AD + MinColor: 879FAC + MaxColor: 89A1AD ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 859DA9 - RightColor: 819BA8 + MinColor: 859DA9 + MaxColor: 819BA8 ZOffset: -12 ZRamp: 0 Template@1025: @@ -17981,63 +17983,63 @@ Size: 3, 4 Tiles: 0: Cliff - LeftColor: 0F1011 - RightColor: 48525C + MinColor: 0F1011 + MaxColor: 48525C ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5F6467 - RightColor: 686E77 + MinColor: 5F6467 + MaxColor: 686E77 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 9BAEC1 - RightColor: BBD6EF + MinColor: 9BAEC1 + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 879FAC - RightColor: 1D2225 + MinColor: 879FAC + MaxColor: 1D2225 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: C1DBF2 - RightColor: C2DDF2 + MinColor: C1DBF2 + MaxColor: C2DDF2 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: BBD6EF - RightColor: BCD6EE + MinColor: BBD6EF + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 5A6268 - RightColor: 121415 + MinColor: 5A6268 + MaxColor: 121415 ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 68717A - RightColor: 697178 + MinColor: 68717A + MaxColor: 697178 ZOffset: -12 ZRamp: 0 8: Rail - LeftColor: 677079 - RightColor: 687078 + MinColor: 677079 + MaxColor: 687078 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 1B1F22 - RightColor: 89A1AD + MinColor: 1B1F22 + MaxColor: 89A1AD ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: C1DBF2 - RightColor: C2DDF2 + MinColor: C1DBF2 + MaxColor: C2DDF2 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: BBD6EF - RightColor: BCD6EE + MinColor: BBD6EF + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 Template@1026: @@ -18047,63 +18049,63 @@ Size: 4, 3 Tiles: 0: Cliff - LeftColor: 232526 - RightColor: 525B63 + MinColor: 232526 + MaxColor: 525B63 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 89A1AD - RightColor: 1D2224 + MinColor: 89A1AD + MaxColor: 1D2224 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 5A6166 - RightColor: 111314 + MinColor: 5A6166 + MaxColor: 111314 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 89A1AD - RightColor: 1B1F22 + MinColor: 89A1AD + MaxColor: 1B1F22 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 606B77 - RightColor: 606870 + MinColor: 606B77 + MaxColor: 606870 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 6: Rail - LeftColor: 666E75 - RightColor: 677079 + MinColor: 666E75 + MaxColor: 677079 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C2DDF2 - RightColor: 9DB0C3 + MinColor: C2DDF2 + MaxColor: 9DB0C3 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 10: Rail - LeftColor: 656D75 - RightColor: 667079 + MinColor: 656D75 + MaxColor: 667079 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 Template@1027: @@ -18113,78 +18115,78 @@ Size: 3, 5 Tiles: 0: Cliff - LeftColor: BAD5F0 - RightColor: B6D1EF + MinColor: BAD5F0 + MaxColor: B6D1EF ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: BBD7F1 - RightColor: BDD8F1 + MinColor: BBD7F1 + MaxColor: BDD8F1 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 89A1AC - RightColor: 8AA2AD + MinColor: 89A1AC + MaxColor: 8AA2AD ZOffset: -12 ZRamp: 0 3: Road - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 89A1AD - RightColor: 879FAC + MinColor: 89A1AD + MaxColor: 879FAC ZOffset: -12 ZRamp: 0 6: Road - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 89A1AD - RightColor: 879FAC + MinColor: 89A1AD + MaxColor: 879FAC ZOffset: -12 ZRamp: 0 9: Road - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 89A1AD - RightColor: 879FAC + MinColor: 89A1AD + MaxColor: 879FAC ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 89A1AD - RightColor: 879FAC + MinColor: 89A1AD + MaxColor: 879FAC ZOffset: -12 ZRamp: 0 Template@1028: @@ -18194,78 +18196,78 @@ Size: 5, 3 Tiles: 0: Cliff - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 1: Road - LeftColor: BBD6EF - RightColor: BCD6EE + MinColor: BBD6EF + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 2: Road - LeftColor: BBD6EF - RightColor: BCD6EE + MinColor: BBD6EF + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 3: Road - LeftColor: BBD6EF - RightColor: BCD6EE + MinColor: BBD6EF + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: C2DCF2 - RightColor: BFDAF2 + MinColor: C2DCF2 + MaxColor: BFDAF2 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: C1DBF2 - RightColor: C2DDF2 + MinColor: C1DBF2 + MaxColor: C2DDF2 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: C1DBF2 - RightColor: C2DDF2 + MinColor: C1DBF2 + MaxColor: C2DDF2 ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: C1DBF2 - RightColor: C2DDF2 + MinColor: C1DBF2 + MaxColor: C2DDF2 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C4DDF1 - RightColor: C1DBF1 + MinColor: C4DDF1 + MaxColor: C1DBF1 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 8BA1AD - RightColor: 89A0AC + MinColor: 8BA1AD + MaxColor: 89A0AC ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 879FAC - RightColor: 89A1AD + MinColor: 879FAC + MaxColor: 89A1AD ZOffset: -12 ZRamp: 0 12: Clear - LeftColor: 879FAC - RightColor: 89A1AD + MinColor: 879FAC + MaxColor: 89A1AD ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 879FAC - RightColor: 89A1AD + MinColor: 879FAC + MaxColor: 89A1AD ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 859DA9 - RightColor: 819BA8 + MinColor: 859DA9 + MaxColor: 819BA8 ZOffset: -12 ZRamp: 0 Template@1029: @@ -18275,63 +18277,63 @@ Size: 3, 4 Tiles: 0: Cliff - LeftColor: 0F1011 - RightColor: 48525C + MinColor: 0F1011 + MaxColor: 48525C ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5F6467 - RightColor: 686E77 + MinColor: 5F6467 + MaxColor: 686E77 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 9BAEC1 - RightColor: BBD6EF + MinColor: 9BAEC1 + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 879FAC - RightColor: 1D2225 + MinColor: 879FAC + MaxColor: 1D2225 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: C1DBF2 - RightColor: C2DDF2 + MinColor: C1DBF2 + MaxColor: C2DDF2 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: BBD6EF - RightColor: BCD6EE + MinColor: BBD6EF + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 879FAC - RightColor: 1B2022 + MinColor: 879FAC + MaxColor: 1B2022 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: C1DBF2 - RightColor: C2DDF2 + MinColor: C1DBF2 + MaxColor: C2DDF2 ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: BBD6EF - RightColor: BCD6EE + MinColor: BBD6EF + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 1B1F22 - RightColor: 89A1AD + MinColor: 1B1F22 + MaxColor: 89A1AD ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: C1DBF2 - RightColor: C2DDF2 + MinColor: C1DBF2 + MaxColor: C2DDF2 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: BBD6EF - RightColor: BCD6EE + MinColor: BBD6EF + MaxColor: BCD6EE ZOffset: -12 ZRamp: 0 Template@1030: @@ -18341,63 +18343,63 @@ Size: 4, 3 Tiles: 0: Cliff - LeftColor: 232526 - RightColor: 525B63 + MinColor: 232526 + MaxColor: 525B63 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 89A1AD - RightColor: 1D2224 + MinColor: 89A1AD + MaxColor: 1D2224 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 89A1AD - RightColor: 1B1F22 + MinColor: 89A1AD + MaxColor: 1B1F22 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 89A1AD - RightColor: 1B1F22 + MinColor: 89A1AD + MaxColor: 1B1F22 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 606B77 - RightColor: 606870 + MinColor: 606B77 + MaxColor: 606870 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: C2DDF2 - RightColor: C1DBF2 + MinColor: C2DDF2 + MaxColor: C1DBF2 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C2DDF2 - RightColor: 9DB0C3 + MinColor: C2DDF2 + MaxColor: 9DB0C3 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: BCD6EE - RightColor: BBD6EF + MinColor: BCD6EE + MaxColor: BBD6EF ZOffset: -12 ZRamp: 0 Template@1031: @@ -18407,8 +18409,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 6C7275 - RightColor: 6E6F70 + MinColor: 6C7275 + MaxColor: 6E6F70 ZOffset: -12 ZRamp: 0 Template@1032: @@ -18418,8 +18420,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 686A6E - RightColor: 656768 + MinColor: 686A6E + MaxColor: 656768 ZOffset: -12 ZRamp: 0 Template@1033: @@ -18429,8 +18431,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 6A6C6F - RightColor: 65676A + MinColor: 6A6C6F + MaxColor: 65676A ZOffset: -12 ZRamp: 0 Template@1034: @@ -18440,8 +18442,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 666A6A - RightColor: 646564 + MinColor: 666A6A + MaxColor: 646564 ZOffset: -12 ZRamp: 0 Template@1035: @@ -18451,8 +18453,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 626668 - RightColor: 5F6062 + MinColor: 626668 + MaxColor: 5F6062 ZOffset: -12 ZRamp: 0 Template@1036: @@ -18462,23 +18464,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 666865 - RightColor: 666867 + MinColor: 666865 + MaxColor: 666867 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 666764 - RightColor: 666868 + MinColor: 666764 + MaxColor: 666868 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 646666 - RightColor: 646765 + MinColor: 646666 + MaxColor: 646765 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 656768 - RightColor: 686A68 + MinColor: 656768 + MaxColor: 686A68 ZOffset: -12 ZRamp: 0 Template@1037: @@ -18488,23 +18490,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 676968 - RightColor: 656664 + MinColor: 676968 + MaxColor: 656664 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 656564 - RightColor: 646565 + MinColor: 656564 + MaxColor: 646565 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 676969 - RightColor: 646666 + MinColor: 676969 + MaxColor: 646666 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 676A6A - RightColor: 696A6A + MinColor: 676A6A + MaxColor: 696A6A ZOffset: -12 ZRamp: 0 Template@1038: @@ -18514,23 +18516,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 646665 - RightColor: 606060 + MinColor: 646665 + MaxColor: 606060 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 656869 - RightColor: 686C6D + MinColor: 656869 + MaxColor: 686C6D ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 686C6E - RightColor: 67696B + MinColor: 686C6E + MaxColor: 67696B ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 616366 - RightColor: 636567 + MinColor: 616366 + MaxColor: 636567 ZOffset: -12 ZRamp: 0 Template@1039: @@ -18540,23 +18542,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 6B6C6C - RightColor: 676868 + MinColor: 6B6C6C + MaxColor: 676868 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 6C6D6C - RightColor: 6C6D6D + MinColor: 6C6D6C + MaxColor: 6C6D6D ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 686969 - RightColor: 686969 + MinColor: 686969 + MaxColor: 686969 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 6A6C6E - RightColor: 6C6D6D + MinColor: 6A6C6E + MaxColor: 6C6D6D ZOffset: -12 ZRamp: 0 Template@1040: @@ -18566,23 +18568,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 6D7275 - RightColor: 6B6E6E + MinColor: 6D7275 + MaxColor: 6B6E6E ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 6D6F6F - RightColor: 6B6E6E + MinColor: 6D6F6F + MaxColor: 6B6E6E ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 656768 - RightColor: 676A6C + MinColor: 656768 + MaxColor: 676A6C ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 666969 - RightColor: 6B6F74 + MinColor: 666969 + MaxColor: 6B6F74 ZOffset: -12 ZRamp: 0 Template@1041: @@ -18592,23 +18594,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 686B6E - RightColor: 656668 + MinColor: 686B6E + MaxColor: 656668 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 686968 - RightColor: 676A6B + MinColor: 686968 + MaxColor: 676A6B ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 676A6D - RightColor: 67696B + MinColor: 676A6D + MaxColor: 67696B ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 676B6D - RightColor: 66676A + MinColor: 676B6D + MaxColor: 66676A ZOffset: -12 ZRamp: 0 Template@1042: @@ -18618,23 +18620,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 656764 - RightColor: 6A6B66 + MinColor: 656764 + MaxColor: 6A6B66 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 6C6F6A - RightColor: 696C6C + MinColor: 6C6F6A + MaxColor: 696C6C ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 656765 - RightColor: 686A65 + MinColor: 656765 + MaxColor: 686A65 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 6A6E6D - RightColor: 6B6D6C + MinColor: 6A6E6D + MaxColor: 6B6D6C ZOffset: -12 ZRamp: 0 Template@1043: @@ -18644,23 +18646,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 676A68 - RightColor: 6B6E69 + MinColor: 676A68 + MaxColor: 6B6E69 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 6D6F6A - RightColor: 686D6C + MinColor: 6D6F6A + MaxColor: 686D6C ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 686C6B - RightColor: 6F6F68 + MinColor: 686C6B + MaxColor: 6F6F68 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 6A6A64 - RightColor: 666867 + MinColor: 6A6A64 + MaxColor: 666867 ZOffset: -12 ZRamp: 0 Template@1044: @@ -18670,23 +18672,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 656868 - RightColor: 676864 + MinColor: 656868 + MaxColor: 676864 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 6A6A66 - RightColor: 666A69 + MinColor: 6A6A66 + MaxColor: 666A69 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 676967 - RightColor: 696861 + MinColor: 676967 + MaxColor: 696861 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 6A6B65 - RightColor: 666765 + MinColor: 6A6B65 + MaxColor: 666765 ZOffset: -12 ZRamp: 0 Template@1045: @@ -18696,23 +18698,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 656868 - RightColor: 676864 + MinColor: 656868 + MaxColor: 676864 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 6A6A66 - RightColor: 666A69 + MinColor: 6A6A66 + MaxColor: 666A69 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 676967 - RightColor: 696861 + MinColor: 676967 + MaxColor: 696861 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 6A6B65 - RightColor: 666765 + MinColor: 6A6B65 + MaxColor: 666765 ZOffset: -12 ZRamp: 0 Template@1046: @@ -18722,8 +18724,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 88959F - RightColor: 909DA8 + MinColor: 88959F + MaxColor: 909DA8 ZOffset: -12 ZRamp: 0 Template@1047: @@ -18733,8 +18735,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 7C858B - RightColor: 93A3AF + MinColor: 7C858B + MaxColor: 93A3AF ZOffset: -12 ZRamp: 0 Template@1048: @@ -18744,8 +18746,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 727C81 - RightColor: 97A8B2 + MinColor: 727C81 + MaxColor: 97A8B2 ZOffset: -12 ZRamp: 0 Template@1049: @@ -18755,8 +18757,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 828E96 - RightColor: AFCAE3 + MinColor: 828E96 + MaxColor: AFCAE3 ZOffset: -12 ZRamp: 0 Template@1050: @@ -18766,8 +18768,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 95A6B1 - RightColor: 7A8288 + MinColor: 95A6B1 + MaxColor: 7A8288 ZOffset: -12 ZRamp: 0 Template@1051: @@ -18777,8 +18779,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 9CAEBC - RightColor: 9EAFBD + MinColor: 9CAEBC + MaxColor: 9EAFBD ZOffset: -12 ZRamp: 0 Template@1052: @@ -18788,8 +18790,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: A2B3C0 - RightColor: A2B6C4 + MinColor: A2B3C0 + MaxColor: A2B6C4 ZOffset: -12 ZRamp: 0 Template@1053: @@ -18799,8 +18801,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 848F96 - RightColor: A0B4C4 + MinColor: 848F96 + MaxColor: A0B4C4 ZOffset: -12 ZRamp: 0 Template@1054: @@ -18810,8 +18812,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 8E9FAA - RightColor: 7F868B + MinColor: 8E9FAA + MaxColor: 7F868B ZOffset: -12 ZRamp: 0 Template@1055: @@ -18821,8 +18823,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 93A4B3 - RightColor: 92A0AB + MinColor: 93A4B3 + MaxColor: 92A0AB ZOffset: -12 ZRamp: 0 Template@1056: @@ -18832,8 +18834,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 94A4B0 - RightColor: 96A6B0 + MinColor: 94A4B0 + MaxColor: 96A6B0 ZOffset: -12 ZRamp: 0 Template@1057: @@ -18843,8 +18845,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 8E9CA6 - RightColor: A7C0D6 + MinColor: 8E9CA6 + MaxColor: A7C0D6 ZOffset: -12 ZRamp: 0 Template@1058: @@ -18854,8 +18856,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: B1C9DB - RightColor: 798187 + MinColor: B1C9DB + MaxColor: 798187 ZOffset: -12 ZRamp: 0 Template@1059: @@ -18865,8 +18867,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: B3CADD - RightColor: 91A0AC + MinColor: B3CADD + MaxColor: 91A0AC ZOffset: -12 ZRamp: 0 Template@1060: @@ -18876,8 +18878,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: A6BCCB - RightColor: 88969F + MinColor: A6BCCB + MaxColor: 88969F ZOffset: -12 ZRamp: 0 Template@1061: @@ -18887,7 +18889,7 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 97A8B7 - RightColor: 99AAB8 + MinColor: 97A8B7 + MaxColor: 99AAB8 ZOffset: -12 ZRamp: 0 diff -Nru openra-20200503/mods/ts/tilesets/temperate.yaml openra-20210321/mods/ts/tilesets/temperate.yaml --- openra-20200503/mods/ts/tilesets/temperate.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/tilesets/temperate.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -5,6 +5,8 @@ EditorTemplateOrder: Misc Buildings, Clear, Cliff Pieces, Ice Flow, House, Blank, Ice Ramps, Cliff Set, Civilian Buildings, Shore Pieces, Rough LAT tile, Clear/Rough LAT, Cliff/Water pieces, Bendy Dirt Roads, Dirt Road Junctions, Straight Dirt Roads, Bridges, Paved Roads, Water, Dirt Road Slopes, Slope Set Pieces, Dead Oil Tanker, Ruins, Waterfalls, Ground 01, Ground 02, Sand, Sand/Clear LAT, Rough ground, Paved Road Ends, TrainBridges, Pavement, Pavement/Clear LAT, Paved road bits, Green, Green/Clear LAT, Ramp edge fixup, Water slopes, Pavement (Use for LAT), Paved Road Slopes, Monorail Slopes, Waterfalls-B, Waterfalls-C, Waterfalls-D, Tunnel Floor, Tunnel Side, TrackTunnel Floor, Destroyable Cliffs, Water Caves, Scrin Wreckage, DirtTrackTunnel Floor, DirtTunnel Floor, Crystal LAT tile, Clear Crystal LAT, Swampy, Swampy LAT, Blue Mold, Blue Mold LAT, Crystal Cliff, Kodiak Crash SheetSize: 2048 EnableDepth: true + MinHeightColorBrightness: 1.0 + MaxHeightColorBrightness: 1.6 Terrain: TerrainType@Clear: @@ -86,8 +88,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6D573D - RightColor: 6F593E + MinColor: 6D573D + MaxColor: 6F593E ZOffset: -12 ZRamp: 0 Template@1: @@ -97,8 +99,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 7A7E8B - RightColor: 61666D + MinColor: 7A7E8B + MaxColor: 61666D ZOffset: -12 ZRamp: 0 Template@2: @@ -108,23 +110,23 @@ Size: 2, 2 Tiles: 0: Rough - LeftColor: 808285 - RightColor: 7A7E86 + MinColor: 808285 + MaxColor: 7A7E86 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 6E7176 - RightColor: 83879A + MinColor: 6E7176 + MaxColor: 83879A ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 9C9EB1 - RightColor: 73777E + MinColor: 9C9EB1 + MaxColor: 73777E ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 9297AD - RightColor: 9195AC + MinColor: 9297AD + MaxColor: 9195AC ZOffset: -12 ZRamp: 0 Template@3: @@ -134,48 +136,48 @@ Size: 3, 3 Tiles: 0: Cliff - LeftColor: 676E76 - RightColor: 70767C + MinColor: 676E76 + MaxColor: 70767C ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 505458 - RightColor: 5F636D + MinColor: 505458 + MaxColor: 5F636D ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: BEC0EC - RightColor: CECFF6 + MinColor: BEC0EC + MaxColor: CECFF6 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 787B82 - RightColor: 797E84 + MinColor: 787B82 + MaxColor: 797E84 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6D7075 - RightColor: 575A66 + MinColor: 6D7075 + MaxColor: 575A66 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: C7C8F6 - RightColor: C6C8F8 + MinColor: C7C8F6 + MaxColor: C6C8F8 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: CBCCF7 - RightColor: C4C6E6 + MinColor: CBCCF7 + MaxColor: C4C6E6 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: C2C4E6 - RightColor: ADB0CE + MinColor: C2C4E6 + MaxColor: ADB0CE ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: C4C6F0 - RightColor: C2C4F6 + MinColor: C4C6F0 + MaxColor: C2C4F6 ZOffset: -12 ZRamp: 0 Template@4: @@ -185,8 +187,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: C7C9FA - RightColor: C3C5FA + MinColor: C7C9FA + MaxColor: C3C5FA ZOffset: -12 ZRamp: 0 Template@5: @@ -196,8 +198,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: CBCCF7 - RightColor: CFD0F5 + MinColor: CBCCF7 + MaxColor: CFD0F5 ZOffset: -12 ZRamp: 0 Template@6: @@ -207,8 +209,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: C8CAF9 - RightColor: CBCCF7 + MinColor: C8CAF9 + MaxColor: CBCCF7 ZOffset: -12 ZRamp: 0 Template@7: @@ -218,8 +220,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: CFD0F6 - RightColor: D1D2F5 + MinColor: CFD0F6 + MaxColor: D1D2F5 ZOffset: -12 ZRamp: 0 Template@8: @@ -229,8 +231,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: CFD0F6 - RightColor: D1D2F5 + MinColor: CFD0F6 + MaxColor: D1D2F5 ZOffset: -12 ZRamp: 0 Template@9: @@ -240,8 +242,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: CFD0F6 - RightColor: D1D2F5 + MinColor: CFD0F6 + MaxColor: D1D2F5 ZOffset: -12 ZRamp: 0 Template@10: @@ -251,183 +253,183 @@ Size: 9, 7 Tiles: 2: Rough - LeftColor: 81828D - RightColor: A5A6BE + MinColor: 81828D + MaxColor: A5A6BE ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 878893 - RightColor: B3B4CD + MinColor: 878893 + MaxColor: B3B4CD ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: 9798AA - RightColor: 8F919E + MinColor: 9798AA + MaxColor: 8F919E ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: B8B9CB - RightColor: A0A1B6 + MinColor: B8B9CB + MaxColor: A0A1B6 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: A4A4B8 - RightColor: AFB0CE + MinColor: A4A4B8 + MaxColor: AFB0CE ZOffset: -12 ZRamp: 0 18: Rough - LeftColor: C9CAE7 - RightColor: C3C4DD + MinColor: C9CAE7 + MaxColor: C3C4DD ZOffset: -12 ZRamp: 0 19: Rough - LeftColor: 737582 - RightColor: A3A4BB + MinColor: 737582 + MaxColor: A3A4BB ZOffset: -12 ZRamp: 0 20: Rough - LeftColor: B3B4CA - RightColor: 9596A5 + MinColor: B3B4CA + MaxColor: 9596A5 ZOffset: -12 ZRamp: 0 21: Rough - LeftColor: A7A8C0 - RightColor: 858699 + MinColor: A7A8C0 + MaxColor: 858699 ZOffset: -12 ZRamp: 0 22: Rough - LeftColor: A6A7BD - RightColor: B4B5CF + MinColor: A6A7BD + MaxColor: B4B5CF ZOffset: -12 ZRamp: 0 23: Rough - LeftColor: B0B1CB - RightColor: C4C5E4 + MinColor: B0B1CB + MaxColor: C4C5E4 ZOffset: -12 ZRamp: 0 24: Rough - LeftColor: 999AAA - RightColor: BFC0DD + MinColor: 999AAA + MaxColor: BFC0DD ZOffset: -12 ZRamp: 0 25: Rough - LeftColor: 9697A8 - RightColor: C1C3F3 + MinColor: 9697A8 + MaxColor: C1C3F3 ZOffset: -12 ZRamp: 0 26: Rough - LeftColor: A7A8C1 - RightColor: C3C4E6 + MinColor: A7A8C1 + MaxColor: C3C4E6 ZOffset: -12 ZRamp: 0 28: Rough - LeftColor: BFC1E3 - RightColor: 9192A4 + MinColor: BFC1E3 + MaxColor: 9192A4 ZOffset: -12 ZRamp: 0 29: Rough - LeftColor: B4B5CE - RightColor: AAAAC4 + MinColor: B4B5CE + MaxColor: AAAAC4 ZOffset: -12 ZRamp: 0 30: Rough - LeftColor: 82838F - RightColor: 9697A2 + MinColor: 82838F + MaxColor: 9697A2 ZOffset: -12 ZRamp: 0 31: Rough - LeftColor: AFB0C3 - RightColor: B2B2C8 + MinColor: AFB0C3 + MaxColor: B2B2C8 ZOffset: -12 ZRamp: 0 32: Rough - LeftColor: BDBDD2 - RightColor: B3B3CD + MinColor: BDBDD2 + MaxColor: B3B3CD ZOffset: -12 ZRamp: 0 33: Rough - LeftColor: A0A1B2 - RightColor: A4A4B6 + MinColor: A0A1B2 + MaxColor: A4A4B6 ZOffset: -12 ZRamp: 0 34: Rough - LeftColor: A9AAC1 - RightColor: 9696A9 + MinColor: A9AAC1 + MaxColor: 9696A9 ZOffset: -12 ZRamp: 0 35: Rough - LeftColor: 9D9EB0 - RightColor: BBBCD6 + MinColor: 9D9EB0 + MaxColor: BBBCD6 ZOffset: -12 ZRamp: 0 38: Rough - LeftColor: 9A9BB0 - RightColor: A6A6B9 + MinColor: 9A9BB0 + MaxColor: A6A6B9 ZOffset: -12 ZRamp: 0 39: Rough - LeftColor: A6A7C2 - RightColor: 9D9EB1 + MinColor: A6A7C2 + MaxColor: 9D9EB1 ZOffset: -12 ZRamp: 0 40: Rough - LeftColor: A1A1B5 - RightColor: AFAFC5 + MinColor: A1A1B5 + MaxColor: AFAFC5 ZOffset: -12 ZRamp: 0 41: Rough - LeftColor: A3A4B6 - RightColor: BFC0D3 + MinColor: A3A4B6 + MaxColor: BFC0D3 ZOffset: -12 ZRamp: 0 42: Rough - LeftColor: C0C1E2 - RightColor: CBCCF3 + MinColor: C0C1E2 + MaxColor: CBCCF3 ZOffset: -12 ZRamp: 0 43: Rough - LeftColor: C9CAEA - RightColor: BEBFE5 + MinColor: C9CAEA + MaxColor: BEBFE5 ZOffset: -12 ZRamp: 0 44: Rough - LeftColor: A6A8C6 - RightColor: B8B9D0 + MinColor: A6A8C6 + MaxColor: B8B9D0 ZOffset: -12 ZRamp: 0 49: Rough - LeftColor: B1B3CE - RightColor: ADAECB + MinColor: B1B3CE + MaxColor: ADAECB ZOffset: -12 ZRamp: 0 50: Rough - LeftColor: BBBBD3 - RightColor: A8A9BA + MinColor: BBBBD3 + MaxColor: A8A9BA ZOffset: -12 ZRamp: 0 51: Rough - LeftColor: 9D9EB1 - RightColor: A6A7B7 + MinColor: 9D9EB1 + MaxColor: A6A7B7 ZOffset: -12 ZRamp: 0 52: Rough - LeftColor: A7A7B5 - RightColor: ACADBD + MinColor: A7A7B5 + MaxColor: ACADBD ZOffset: -12 ZRamp: 0 53: Rough - LeftColor: B3B4D1 - RightColor: 9D9EAE + MinColor: B3B4D1 + MaxColor: 9D9EAE ZOffset: -12 ZRamp: 0 60: Rough - LeftColor: C1C2E4 - RightColor: A1A2B5 + MinColor: C1C2E4 + MaxColor: A1A2B5 ZOffset: -12 ZRamp: 0 61: Rough - LeftColor: A3A5C4 - RightColor: A9AAC4 + MinColor: A3A5C4 + MaxColor: A9AAC4 ZOffset: -12 ZRamp: 0 Template@11: @@ -437,23 +439,23 @@ Size: 2, 2 Tiles: 0: Cliff - LeftColor: 8D806A - RightColor: 736C61 + MinColor: 8D806A + MaxColor: 736C61 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 9FA0A5 - RightColor: 7E7A7B + MinColor: 9FA0A5 + MaxColor: 7E7A7B ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: B9B6B8 - RightColor: 968C7B + MinColor: B9B6B8 + MaxColor: 968C7B ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: BCB8B6 - RightColor: 9F9FA4 + MinColor: BCB8B6 + MaxColor: 9F9FA4 ZOffset: -12 ZRamp: 0 Template@12: @@ -463,8 +465,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 282828 - RightColor: 282828 + MinColor: 282828 + MaxColor: 282828 ZOffset: -12 ZRamp: 0 Template@40: @@ -475,8 +477,8 @@ Tiles: 0: Clear RampType: 1 - LeftColor: 746046 - RightColor: 6F5D44 + MinColor: 746046 + MaxColor: 6F5D44 ZOffset: -12 ZRamp: 0 Template@41: @@ -487,8 +489,8 @@ Tiles: 0: Clear RampType: 2 - LeftColor: 4B4439 - RightColor: 443F34 + MinColor: 4B4439 + MaxColor: 443F34 ZOffset: -12 ZRamp: 0 Template@42: @@ -499,8 +501,8 @@ Tiles: 0: Clear RampType: 3 - LeftColor: 584D3E - RightColor: 584D3E + MinColor: 584D3E + MaxColor: 584D3E ZOffset: -12 ZRamp: 0 Template@43: @@ -511,8 +513,8 @@ Tiles: 0: Clear RampType: 4 - LeftColor: 60523F - RightColor: 5D4E3A + MinColor: 60523F + MaxColor: 5D4E3A ZOffset: -12 ZRamp: 0 Template@44: @@ -523,8 +525,8 @@ Tiles: 0: Clear RampType: 5 - LeftColor: 715D44 - RightColor: 473F33 + MinColor: 715D44 + MaxColor: 473F33 ZOffset: -12 ZRamp: 0 Template@45: @@ -535,8 +537,8 @@ Tiles: 0: Clear RampType: 6 - LeftColor: 433D33 - RightColor: 5B4D3B + MinColor: 433D33 + MaxColor: 5B4D3B ZOffset: -12 ZRamp: 0 Template@46: @@ -547,8 +549,8 @@ Tiles: 0: Clear RampType: 7 - LeftColor: 655643 - RightColor: 5B4E3D + MinColor: 655643 + MaxColor: 5B4E3D ZOffset: -12 ZRamp: 0 Template@47: @@ -559,8 +561,8 @@ Tiles: 0: Clear RampType: 8 - LeftColor: 695740 - RightColor: 6C5942 + MinColor: 695740 + MaxColor: 6C5942 ZOffset: -12 ZRamp: 0 Template@48: @@ -571,8 +573,8 @@ Tiles: 0: Clear RampType: 9 - LeftColor: 655641 - RightColor: 655745 + MinColor: 655641 + MaxColor: 655745 ZOffset: -12 ZRamp: 0 Template@49: @@ -583,8 +585,8 @@ Tiles: 0: Clear RampType: 10 - LeftColor: 63533F - RightColor: 423C32 + MinColor: 63533F + MaxColor: 423C32 ZOffset: -12 ZRamp: 0 Template@50: @@ -595,8 +597,8 @@ Tiles: 0: Clear RampType: 11 - LeftColor: 5D4F3C - RightColor: 5F503C + MinColor: 5D4F3C + MaxColor: 5F503C ZOffset: -12 ZRamp: 0 Template@51: @@ -607,8 +609,8 @@ Tiles: 0: Clear RampType: 12 - LeftColor: 756147 - RightColor: 705C43 + MinColor: 756147 + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 Template@52: @@ -619,8 +621,8 @@ Tiles: 0: Clear RampType: 13 - LeftColor: 584838 - RightColor: 584838 + MinColor: 584838 + MaxColor: 584838 ZOffset: -12 ZRamp: 0 Template@53: @@ -631,8 +633,8 @@ Tiles: 0: Clear RampType: 14 - LeftColor: 443D31 - RightColor: 463E32 + MinColor: 443D31 + MaxColor: 463E32 ZOffset: -12 ZRamp: 0 Template@54: @@ -643,8 +645,8 @@ Tiles: 0: Clear RampType: 15 - LeftColor: 645540 - RightColor: 594B37 + MinColor: 645540 + MaxColor: 594B37 ZOffset: -12 ZRamp: 0 Template@55: @@ -655,8 +657,8 @@ Tiles: 0: Clear RampType: 16 - LeftColor: 7C6344 - RightColor: 7E6548 + MinColor: 7C6344 + MaxColor: 7E6548 ZOffset: -12 ZRamp: 0 Template@56: @@ -667,8 +669,8 @@ Tiles: 0: Rough RampType: 17 - LeftColor: 463E32 - RightColor: 796145 + MinColor: 463E32 + MaxColor: 796145 ZOffset: -12 ZRamp: 0 Template@57: @@ -679,8 +681,8 @@ Tiles: 0: Rough RampType: 18 - LeftColor: 755F42 - RightColor: 443D32 + MinColor: 755F42 + MaxColor: 443D32 ZOffset: -12 ZRamp: 0 Template@58: @@ -691,8 +693,8 @@ Tiles: 0: Rough RampType: 19 - LeftColor: 777758 - RightColor: 804F52 + MinColor: 777758 + MaxColor: 804F52 ZOffset: -12 ZRamp: 0 Template@59: @@ -703,8 +705,8 @@ Tiles: 0: Rough RampType: 20 - LeftColor: 9B6876 - RightColor: 6B5643 + MinColor: 9B6876 + MaxColor: 6B5643 ZOffset: -12 ZRamp: 0 Template@60: @@ -715,24 +717,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 3F3B34 - RightColor: 504537 + MinColor: 3F3B34 + MaxColor: 504537 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 514638 - RightColor: 413D36 + MinColor: 514638 + MaxColor: 413D36 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 2D2B27 - RightColor: 413C35 + MinColor: 2D2B27 + MaxColor: 413C35 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 67533B - RightColor: 483E30 + MinColor: 67533B + MaxColor: 483E30 ZOffset: -12 ZRamp: 0 Template@61: @@ -743,13 +745,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 3C3831 - RightColor: 494134 + MinColor: 3C3831 + MaxColor: 494134 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 615B51 - RightColor: 47423B + MinColor: 615B51 + MaxColor: 47423B ZOffset: -12 ZRamp: 0 Template@62: @@ -760,24 +762,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 433D34 - RightColor: 483E32 + MinColor: 433D34 + MaxColor: 483E32 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 5F513E - RightColor: 3F3B34 + MinColor: 5F513E + MaxColor: 3F3B34 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 2D2C28 - RightColor: 37322B + MinColor: 2D2C28 + MaxColor: 37322B ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 685945 - RightColor: 4A4134 + MinColor: 685945 + MaxColor: 4A4134 ZOffset: -12 ZRamp: 0 Template@63: @@ -788,24 +790,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 524637 - RightColor: 594B38 + MinColor: 524637 + MaxColor: 594B38 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 5B503F - RightColor: 4F4A41 + MinColor: 5B503F + MaxColor: 4F4A41 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 49463F - RightColor: 494338 + MinColor: 49463F + MaxColor: 494338 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 695A45 - RightColor: 574D3F + MinColor: 695A45 + MaxColor: 574D3F ZOffset: -12 ZRamp: 0 Template@64: @@ -816,24 +818,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4D463A - RightColor: 4C4234 + MinColor: 4D463A + MaxColor: 4C4234 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 4A4235 - RightColor: 4F4436 + MinColor: 4A4235 + MaxColor: 4F4436 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 695B49 - RightColor: 484339 + MinColor: 695B49 + MaxColor: 484339 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 5B4F3E - RightColor: 534C40 + MinColor: 5B4F3E + MaxColor: 534C40 ZOffset: -12 ZRamp: 0 Template@65: @@ -844,24 +846,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 2B2824 - RightColor: 4E4437 + MinColor: 2B2824 + MaxColor: 4E4437 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 353028 - RightColor: 473F34 + MinColor: 353028 + MaxColor: 473F34 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 6D5B43 - RightColor: 51483C + MinColor: 6D5B43 + MaxColor: 51483C ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 544737 - RightColor: 4A4034 + MinColor: 544737 + MaxColor: 4A4034 ZOffset: -12 ZRamp: 0 Template@66: @@ -872,24 +874,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4A4338 - RightColor: 4F4436 + MinColor: 4A4338 + MaxColor: 4F4436 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 484136 - RightColor: 4D4233 + MinColor: 484136 + MaxColor: 4D4233 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 615443 - RightColor: 47443D + MinColor: 615443 + MaxColor: 47443D ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 5A4D3C - RightColor: 4E473D + MinColor: 5A4D3C + MaxColor: 4E473D ZOffset: -12 ZRamp: 0 Template@67: @@ -900,13 +902,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 39352E - RightColor: 453B2D + MinColor: 39352E + MaxColor: 453B2D ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5A5346 - RightColor: 47433C + MinColor: 5A5346 + MaxColor: 47433C ZOffset: -12 ZRamp: 0 Template@68: @@ -917,18 +919,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 494034 - RightColor: 4E4436 + MinColor: 494034 + MaxColor: 4E4436 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5A4F3F - RightColor: 524C42 + MinColor: 5A4F3F + MaxColor: 524C42 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 544C3F - RightColor: 4E473C + MinColor: 544C3F + MaxColor: 4E473C ZOffset: -12 ZRamp: 0 Template@69: @@ -939,18 +941,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4E4437 - RightColor: 514434 + MinColor: 4E4437 + MaxColor: 514434 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 4F4639 - RightColor: 51493D + MinColor: 4F4639 + MaxColor: 51493D ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 464035 - RightColor: 554E42 + MinColor: 464035 + MaxColor: 554E42 ZOffset: -12 ZRamp: 0 Template@70: @@ -961,18 +963,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4F4334 - RightColor: 494135 + MinColor: 4F4334 + MaxColor: 494135 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 564D3F - RightColor: 48443B + MinColor: 564D3F + MaxColor: 48443B ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 555046 - RightColor: 5E564A + MinColor: 555046 + MaxColor: 5E564A ZOffset: -12 ZRamp: 0 Template@71: @@ -982,8 +984,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 524D43 - RightColor: 534D42 + MinColor: 524D43 + MaxColor: 534D42 ZOffset: -12 ZRamp: 0 Template@72: @@ -993,8 +995,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 443F37 - RightColor: 524B3F + MinColor: 443F37 + MaxColor: 524B3F ZOffset: -12 ZRamp: 0 Template@73: @@ -1004,8 +1006,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 544E43 - RightColor: 3D3830 + MinColor: 544E43 + MaxColor: 3D3830 ZOffset: -12 ZRamp: 0 Template@74: @@ -1016,24 +1018,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 453C30 - RightColor: 42392D + MinColor: 453C30 + MaxColor: 42392D ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 4B4135 - RightColor: 3E3931 + MinColor: 4B4135 + MaxColor: 3E3931 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 4D4334 - RightColor: 403A31 + MinColor: 4D4334 + MaxColor: 403A31 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 5C4F3F - RightColor: 3D3931 + MinColor: 5C4F3F + MaxColor: 3D3931 ZOffset: -12 ZRamp: 0 Template@75: @@ -1044,24 +1046,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4B4032 - RightColor: 413A31 + MinColor: 4B4032 + MaxColor: 413A31 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 453C31 - RightColor: 39342D + MinColor: 453C31 + MaxColor: 39342D ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 453B2F - RightColor: 443D34 + MinColor: 453B2F + MaxColor: 443D34 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 584C3C - RightColor: 454038 + MinColor: 584C3C + MaxColor: 454038 ZOffset: -12 ZRamp: 0 Template@76: @@ -1072,24 +1074,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 443C30 - RightColor: 453C30 + MinColor: 443C30 + MaxColor: 453C30 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 36322C - RightColor: 3A3731 + MinColor: 36322C + MaxColor: 3A3731 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 4F4231 - RightColor: 443D34 + MinColor: 4F4231 + MaxColor: 443D34 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 4B4338 - RightColor: 3F3C37 + MinColor: 4B4338 + MaxColor: 3F3C37 ZOffset: -12 ZRamp: 0 Template@77: @@ -1100,13 +1102,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4A3F2F - RightColor: 4A4338 + MinColor: 4A3F2F + MaxColor: 4A4338 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 484137 - RightColor: 3E3A34 + MinColor: 484137 + MaxColor: 3E3A34 ZOffset: -12 ZRamp: 0 Template@78: @@ -1117,24 +1119,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4B4031 - RightColor: 403C33 + MinColor: 4B4031 + MaxColor: 403C33 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 323230 - RightColor: 46413A + MinColor: 323230 + MaxColor: 46413A ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 4A4236 - RightColor: 2B2A27 + MinColor: 4A4236 + MaxColor: 2B2A27 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 5E5446 - RightColor: 4E4538 + MinColor: 5E5446 + MaxColor: 4E4538 ZOffset: -12 ZRamp: 0 Template@79: @@ -1145,24 +1147,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 514637 - RightColor: 4A4134 + MinColor: 514637 + MaxColor: 4A4134 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2D2C29 - RightColor: 423E36 + MinColor: 2D2C29 + MaxColor: 423E36 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 4D4132 - RightColor: 302E2B + MinColor: 4D4132 + MaxColor: 302E2B ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 5A4F41 - RightColor: 483F33 + MinColor: 5A4F41 + MaxColor: 483F33 ZOffset: -12 ZRamp: 0 Template@80: @@ -1173,24 +1175,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 42392C - RightColor: 3B362E + MinColor: 42392C + MaxColor: 3B362E ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2A2826 - RightColor: 37342E + MinColor: 2A2826 + MaxColor: 37342E ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 484034 - RightColor: 2A2926 + MinColor: 484034 + MaxColor: 2A2926 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 574E41 - RightColor: 4A4237 + MinColor: 574E41 + MaxColor: 4A4237 ZOffset: -12 ZRamp: 0 Template@81: @@ -1201,13 +1203,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 3F382E - RightColor: 433C33 + MinColor: 3F382E + MaxColor: 433C33 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 42392C - RightColor: 383530 + MinColor: 42392C + MaxColor: 383530 ZOffset: -12 ZRamp: 0 Template@82: @@ -1218,14 +1220,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 504332 - RightColor: 494033 + MinColor: 504332 + MaxColor: 494033 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 4A3F31 - RightColor: 3D3830 + MinColor: 4A3F31 + MaxColor: 3D3830 ZOffset: -12 ZRamp: 0 Template@83: @@ -1236,14 +1238,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4F4334 - RightColor: 413B31 + MinColor: 4F4334 + MaxColor: 413B31 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 504434 - RightColor: 423A2F + MinColor: 504434 + MaxColor: 423A2F ZOffset: -12 ZRamp: 0 Template@84: @@ -1254,14 +1256,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4D4234 - RightColor: 423D35 + MinColor: 4D4234 + MaxColor: 423D35 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 433C32 - RightColor: 4A443B + MinColor: 433C32 + MaxColor: 4A443B ZOffset: -12 ZRamp: 0 Template@85: @@ -1272,8 +1274,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4E4233 - RightColor: 3A3329 + MinColor: 4E4233 + MaxColor: 3A3329 ZOffset: -12 ZRamp: 0 Template@86: @@ -1284,20 +1286,20 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4F473B - RightColor: 443F36 + MinColor: 4F473B + MaxColor: 443F36 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 4E4232 - RightColor: 463F35 + MinColor: 4E4232 + MaxColor: 463F35 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 403B33 - RightColor: 50473A + MinColor: 403B33 + MaxColor: 50473A ZOffset: -12 ZRamp: 0 Template@87: @@ -1308,20 +1310,20 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 3D372E - RightColor: 3B362D + MinColor: 3D372E + MaxColor: 3B362D ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 433D33 - RightColor: 3C372F + MinColor: 433D33 + MaxColor: 3C372F ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 50483B - RightColor: 443A2D + MinColor: 50483B + MaxColor: 443A2D ZOffset: -12 ZRamp: 0 Template@88: @@ -1332,8 +1334,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 413B32 - RightColor: 474136 + MinColor: 413B32 + MaxColor: 474136 ZOffset: -12 ZRamp: 0 Template@89: @@ -1344,8 +1346,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 474036 - RightColor: 3C3730 + MinColor: 474036 + MaxColor: 3C3730 ZOffset: -12 ZRamp: 0 Template@90: @@ -1356,20 +1358,20 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 31302B - RightColor: 39352F + MinColor: 31302B + MaxColor: 39352F ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 4D453A - RightColor: 4C4337 + MinColor: 4D453A + MaxColor: 4C4337 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 4C4235 - RightColor: 473F32 + MinColor: 4C4235 + MaxColor: 473F32 ZOffset: -12 ZRamp: 0 Template@91: @@ -1380,20 +1382,20 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 454038 - RightColor: 3F3931 + MinColor: 454038 + MaxColor: 3F3931 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 4E4334 - RightColor: 3C3730 + MinColor: 4E4334 + MaxColor: 3C3730 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 544A3C - RightColor: 4E4335 + MinColor: 544A3C + MaxColor: 4E4335 ZOffset: -12 ZRamp: 0 Template@92: @@ -1404,8 +1406,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4C4234 - RightColor: 453E33 + MinColor: 4C4234 + MaxColor: 453E33 ZOffset: -12 ZRamp: 0 Template@93: @@ -1416,8 +1418,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4A4032 - RightColor: 4F4231 + MinColor: 4A4032 + MaxColor: 4F4231 ZOffset: -12 ZRamp: 0 Template@94: @@ -1428,14 +1430,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4B453A - RightColor: 473F34 + MinColor: 4B453A + MaxColor: 473F34 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 444039 - RightColor: 52483B + MinColor: 444039 + MaxColor: 52483B ZOffset: -12 ZRamp: 0 Template@95: @@ -1446,14 +1448,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 49443B - RightColor: 4B4032 + MinColor: 49443B + MaxColor: 4B4032 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 46413A - RightColor: 504638 + MinColor: 46413A + MaxColor: 504638 ZOffset: -12 ZRamp: 0 Template@96: @@ -1464,14 +1466,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 474138 - RightColor: 474036 + MinColor: 474138 + MaxColor: 474036 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 484239 - RightColor: 595042 + MinColor: 484239 + MaxColor: 595042 ZOffset: -12 ZRamp: 0 Template@97: @@ -1482,8 +1484,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 35322C - RightColor: 39332B + MinColor: 35322C + MaxColor: 39332B ZOffset: -12 ZRamp: 0 Template@98: @@ -1494,8 +1496,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4B4337 - RightColor: 4B4030 + MinColor: 4B4337 + MaxColor: 4B4030 ZOffset: -12 ZRamp: 0 Template@99: @@ -1506,8 +1508,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4D4233 - RightColor: 453E34 + MinColor: 4D4233 + MaxColor: 453E34 ZOffset: -12 ZRamp: 0 Template@100: @@ -1517,48 +1519,48 @@ Size: 3, 3 Tiles: 0: Impassable - LeftColor: 666D76 - RightColor: 71777D + MinColor: 666D76 + MaxColor: 71777D ZOffset: -12 ZRamp: 0 1: Impassable - LeftColor: 505457 - RightColor: 61656F + MinColor: 505457 + MaxColor: 61656F ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: BFC0ED - RightColor: CECFF6 + MinColor: BFC0ED + MaxColor: CECFF6 ZOffset: -12 ZRamp: 0 3: Impassable - LeftColor: 797B82 - RightColor: 7B7F86 + MinColor: 797B82 + MaxColor: 7B7F86 ZOffset: -12 ZRamp: 0 4: Impassable - LeftColor: 6D6F74 - RightColor: 585A66 + MinColor: 6D6F74 + MaxColor: 585A66 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: C7C8F6 - RightColor: C6C8F8 + MinColor: C7C8F6 + MaxColor: C6C8F8 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: CBCCF7 - RightColor: C5C6E6 + MinColor: CBCCF7 + MaxColor: C5C6E6 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: C2C4E6 - RightColor: ADB0CE + MinColor: C2C4E6 + MaxColor: ADB0CE ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: C4C6F0 - RightColor: C2C4F6 + MinColor: C4C6F0 + MaxColor: C2C4F6 ZOffset: -12 ZRamp: 0 Template@101: @@ -1568,13 +1570,13 @@ Size: 1, 2 Tiles: 0: Impassable - LeftColor: B1B1E7 - RightColor: B3B5D9 + MinColor: B1B1E7 + MaxColor: B3B5D9 ZOffset: -12 ZRamp: 0 1: Impassable - LeftColor: B4B5D2 - RightColor: BEBFF7 + MinColor: B4B5D2 + MaxColor: BEBFF7 ZOffset: -12 ZRamp: 0 Template@102: @@ -1584,8 +1586,8 @@ Size: 1, 1 Tiles: 0: Impassable - LeftColor: 9D9EA0 - RightColor: 898B8F + MinColor: 9D9EA0 + MaxColor: 898B8F ZOffset: -12 ZRamp: 0 Template@103: @@ -1595,13 +1597,13 @@ Size: 1, 2 Tiles: 0: Impassable - LeftColor: B7B8E6 - RightColor: B4B6D6 + MinColor: B7B8E6 + MaxColor: B4B6D6 ZOffset: -12 ZRamp: 0 1: Impassable - LeftColor: BABBE1 - RightColor: CACBF6 + MinColor: BABBE1 + MaxColor: CACBF6 ZOffset: -12 ZRamp: 0 Template@104: @@ -1611,18 +1613,18 @@ Size: 2, 2 Tiles: 1: Impassable - LeftColor: 7C818A - RightColor: 676B72 + MinColor: 7C818A + MaxColor: 676B72 ZOffset: -12 ZRamp: 0 2: Impassable - LeftColor: 7B7F83 - RightColor: 7A7E82 + MinColor: 7B7F83 + MaxColor: 7A7E82 ZOffset: -12 ZRamp: 0 3: Impassable - LeftColor: 72757C - RightColor: 6A6D73 + MinColor: 72757C + MaxColor: 6A6D73 ZOffset: -12 ZRamp: 0 Template@105: @@ -1632,33 +1634,33 @@ Size: 3, 3 Tiles: 1: Impassable - LeftColor: 73757B - RightColor: 7D7F88 + MinColor: 73757B + MaxColor: 7D7F88 ZOffset: -12 ZRamp: 0 3: Impassable - LeftColor: 9294A2 - RightColor: 777A80 + MinColor: 9294A2 + MaxColor: 777A80 ZOffset: -12 ZRamp: 0 4: Impassable - LeftColor: 979BAC - RightColor: 9DA0B2 + MinColor: 979BAC + MaxColor: 9DA0B2 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: B3B3BD - RightColor: BDBDD7 + MinColor: B3B3BD + MaxColor: BDBDD7 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: BCBEDB - RightColor: AEADAF + MinColor: BCBEDB + MaxColor: AEADAF ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: BDBFD8 - RightColor: B0B2CA + MinColor: BDBFD8 + MaxColor: B0B2CA ZOffset: -12 ZRamp: 0 Template@106: @@ -1668,8 +1670,8 @@ Size: 1, 1 Tiles: 0: Impassable - LeftColor: 72757D - RightColor: 5C6169 + MinColor: 72757D + MaxColor: 5C6169 ZOffset: -12 ZRamp: 0 Template@107: @@ -1679,13 +1681,13 @@ Size: 1, 2 Tiles: 0: Impassable - LeftColor: 686B6E - RightColor: 727681 + MinColor: 686B6E + MaxColor: 727681 ZOffset: -12 ZRamp: 0 1: Impassable - LeftColor: 797F8D - RightColor: 5E6678 + MinColor: 797F8D + MaxColor: 5E6678 ZOffset: -12 ZRamp: 0 Template@108: @@ -1695,23 +1697,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 3D4148 - RightColor: 504C48 + MinColor: 3D4148 + MaxColor: 504C48 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 484948 - RightColor: 5D5040 + MinColor: 484948 + MaxColor: 5D5040 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 1A2D47 - RightColor: 2E3B4F + MinColor: 1A2D47 + MaxColor: 2E3B4F ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 1C2F4A - RightColor: 2C394A + MinColor: 1C2F4A + MaxColor: 2C394A ZOffset: -12 ZRamp: 0 Template@109: @@ -1721,23 +1723,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 414447 - RightColor: 534D46 + MinColor: 414447 + MaxColor: 534D46 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 3E4347 - RightColor: 5E5347 + MinColor: 3E4347 + MaxColor: 5E5347 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 18283A - RightColor: 232F3C + MinColor: 18283A + MaxColor: 232F3C ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 172B48 - RightColor: 253854 + MinColor: 172B48 + MaxColor: 253854 ZOffset: -12 ZRamp: 0 Template@110: @@ -1747,23 +1749,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 424448 - RightColor: 584D40 + MinColor: 424448 + MaxColor: 584D40 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 2F3947 - RightColor: 5C4F40 + MinColor: 2F3947 + MaxColor: 5C4F40 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 172A43 - RightColor: 24344B + MinColor: 172A43 + MaxColor: 24344B ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 18283D - RightColor: 1E314E + MinColor: 18283D + MaxColor: 1E314E ZOffset: -12 ZRamp: 0 Template@111: @@ -1773,13 +1775,13 @@ Size: 1, 2 Tiles: 0: Water - LeftColor: 504A43 - RightColor: 5D4F3F + MinColor: 504A43 + MaxColor: 5D4F3F ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 162943 - RightColor: 2F3844 + MinColor: 162943 + MaxColor: 2F3844 ZOffset: -12 ZRamp: 0 Template@112: @@ -1789,33 +1791,33 @@ Size: 2, 3 Tiles: 0: Water - LeftColor: 4F4942 - RightColor: 5E5243 + MinColor: 4F4942 + MaxColor: 5E5243 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 4A4B49 - RightColor: 6A563E + MinColor: 4A4B49 + MaxColor: 6A563E ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 263444 - RightColor: 293541 + MinColor: 263444 + MaxColor: 293541 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 283B55 - RightColor: 4C4E50 + MinColor: 283B55 + MaxColor: 4C4E50 ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 142842 - RightColor: 27374D + MinColor: 142842 + MaxColor: 27374D ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 273447 - RightColor: 243246 + MinColor: 273447 + MaxColor: 243246 ZOffset: -12 ZRamp: 0 Template@113: @@ -1825,33 +1827,33 @@ Size: 2, 3 Tiles: 0: Water - LeftColor: 44484C - RightColor: 564F46 + MinColor: 44484C + MaxColor: 564F46 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 545757 - RightColor: 645440 + MinColor: 545757 + MaxColor: 645440 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 42464F - RightColor: 383F49 + MinColor: 42464F + MaxColor: 383F49 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 26354C - RightColor: 38424F + MinColor: 26354C + MaxColor: 38424F ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 162944 - RightColor: 182C48 + MinColor: 162944 + MaxColor: 182C48 ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 102238 - RightColor: 172A45 + MinColor: 102238 + MaxColor: 172A45 ZOffset: -12 ZRamp: 0 Template@114: @@ -1861,23 +1863,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 3C434F - RightColor: 464747 + MinColor: 3C434F + MaxColor: 464747 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 25364E - RightColor: 182A43 + MinColor: 25364E + MaxColor: 182A43 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 162943 - RightColor: 203452 + MinColor: 162943 + MaxColor: 203452 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 12253F - RightColor: 1A2E4B + MinColor: 12253F + MaxColor: 1A2E4B ZOffset: -12 ZRamp: 0 Template@115: @@ -1887,23 +1889,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 4F5051 - RightColor: 4F4F4D + MinColor: 4F5051 + MaxColor: 4F4F4D ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 26374E - RightColor: 14253B + MinColor: 26374E + MaxColor: 14253B ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 1C2F47 - RightColor: 243957 + MinColor: 1C2F47 + MaxColor: 243957 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 102237 - RightColor: 152842 + MinColor: 102237 + MaxColor: 152842 ZOffset: -12 ZRamp: 0 Template@116: @@ -1913,23 +1915,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 544E48 - RightColor: 514D48 + MinColor: 544E48 + MaxColor: 514D48 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 354153 - RightColor: 1F2F46 + MinColor: 354153 + MaxColor: 1F2F46 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 5D4E3B - RightColor: 2F3B4D + MinColor: 5D4E3B + MaxColor: 2F3B4D ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 223551 - RightColor: 1A2D4A + MinColor: 223551 + MaxColor: 1A2D4A ZOffset: -12 ZRamp: 0 Template@117: @@ -1939,23 +1941,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 4C4F54 - RightColor: 544D44 + MinColor: 4C4F54 + MaxColor: 544D44 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 273B5B - RightColor: 16283D + MinColor: 273B5B + MaxColor: 16283D ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 574E44 - RightColor: 364558 + MinColor: 574E44 + MaxColor: 364558 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 1C2E49 - RightColor: 182D4A + MinColor: 1C2E49 + MaxColor: 182D4A ZOffset: -12 ZRamp: 0 Template@118: @@ -1965,23 +1967,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 434850 - RightColor: 5A544D + MinColor: 434850 + MaxColor: 5A544D ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 283C59 - RightColor: 162A41 + MinColor: 283C59 + MaxColor: 162A41 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 625241 - RightColor: 504F4E + MinColor: 625241 + MaxColor: 504F4E ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 1F324D - RightColor: 1D304F + MinColor: 1F324D + MaxColor: 1D304F ZOffset: -12 ZRamp: 0 Template@119: @@ -1991,13 +1993,13 @@ Size: 2, 1 Tiles: 0: Water - LeftColor: 605445 - RightColor: 42464D + MinColor: 605445 + MaxColor: 42464D ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 203046 - RightColor: 16283F + MinColor: 203046 + MaxColor: 16283F ZOffset: -12 ZRamp: 0 Template@120: @@ -2007,33 +2009,33 @@ Size: 3, 2 Tiles: 0: Clear - LeftColor: 605549 - RightColor: 645645 + MinColor: 605549 + MaxColor: 645645 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 3F4958 - RightColor: 4B4A4A + MinColor: 3F4958 + MaxColor: 4B4A4A ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 283850 - RightColor: 14273D + MinColor: 283850 + MaxColor: 14273D ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 52504D - RightColor: 3B4759 + MinColor: 52504D + MaxColor: 3B4759 ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 273548 - RightColor: 1D2D46 + MinColor: 273548 + MaxColor: 1D2D46 ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 1A2F4D - RightColor: 162A45 + MinColor: 1A2F4D + MaxColor: 162A45 ZOffset: -12 ZRamp: 0 Template@121: @@ -2043,33 +2045,33 @@ Size: 3, 2 Tiles: 0: Water - LeftColor: 554D43 - RightColor: 554F48 + MinColor: 554D43 + MaxColor: 554F48 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 334155 - RightColor: 1A2B40 + MinColor: 334155 + MaxColor: 1A2B40 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 23354D - RightColor: 26364D + MinColor: 23354D + MaxColor: 26364D ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 6B563D - RightColor: 494C51 + MinColor: 6B563D + MaxColor: 494C51 ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 4C4A47 - RightColor: 374150 + MinColor: 4C4A47 + MaxColor: 374150 ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 182C49 - RightColor: 182B46 + MinColor: 182C49 + MaxColor: 182B46 ZOffset: -12 ZRamp: 0 Template@122: @@ -2079,23 +2081,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 203148 - RightColor: 152943 + MinColor: 203148 + MaxColor: 152943 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 162A46 - RightColor: 0E2136 + MinColor: 162A46 + MaxColor: 0E2136 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 635545 - RightColor: 434749 + MinColor: 635545 + MaxColor: 434749 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 233449 - RightColor: 192C47 + MinColor: 233449 + MaxColor: 192C47 ZOffset: -12 ZRamp: 0 Template@123: @@ -2105,23 +2107,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 1B2F4D - RightColor: 142841 + MinColor: 1B2F4D + MaxColor: 142841 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 1C3051 - RightColor: 10243B + MinColor: 1C3051 + MaxColor: 10243B ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 55504A - RightColor: 354254 + MinColor: 55504A + MaxColor: 354254 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 24364F - RightColor: 192D4A + MinColor: 24364F + MaxColor: 192D4A ZOffset: -12 ZRamp: 0 Template@124: @@ -2131,23 +2133,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 26354B - RightColor: 203145 + MinColor: 26354B + MaxColor: 203145 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 2C3B50 - RightColor: 10243B + MinColor: 2C3B50 + MaxColor: 10243B ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 5A5247 - RightColor: 3D454E + MinColor: 5A5247 + MaxColor: 3D454E ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 45484D - RightColor: 494A4A + MinColor: 45484D + MaxColor: 494A4A ZOffset: -12 ZRamp: 0 Template@125: @@ -2157,23 +2159,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 172A44 - RightColor: 1C2E47 + MinColor: 172A44 + MaxColor: 1C2E47 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 1C2F4B - RightColor: 13273F + MinColor: 1C2F4B + MaxColor: 13273F ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 55514D - RightColor: 2F3E52 + MinColor: 55514D + MaxColor: 2F3E52 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 514F4D - RightColor: 484746 + MinColor: 514F4D + MaxColor: 484746 ZOffset: -12 ZRamp: 0 Template@126: @@ -2183,23 +2185,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 24354B - RightColor: 1E2F46 + MinColor: 24354B + MaxColor: 1E2F46 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 1B2F4C - RightColor: 142842 + MinColor: 1B2F4C + MaxColor: 142842 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 615241 - RightColor: 414751 + MinColor: 615241 + MaxColor: 414751 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 4E4E4E - RightColor: 3C4451 + MinColor: 4E4E4E + MaxColor: 3C4451 ZOffset: -12 ZRamp: 0 Template@127: @@ -2209,13 +2211,13 @@ Size: 1, 2 Tiles: 0: Water - LeftColor: 1F3149 - RightColor: 162A46 + MinColor: 1F3149 + MaxColor: 162A46 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 5D5142 - RightColor: 534C45 + MinColor: 5D5142 + MaxColor: 534C45 ZOffset: -12 ZRamp: 0 Template@128: @@ -2225,33 +2227,33 @@ Size: 2, 3 Tiles: 0: Water - LeftColor: 152841 - RightColor: 152840 + MinColor: 152841 + MaxColor: 152840 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 253348 - RightColor: 11253D + MinColor: 253348 + MaxColor: 11253D ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 243245 - RightColor: 353C44 + MinColor: 243245 + MaxColor: 353C44 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 3A3F46 - RightColor: 4E4B48 + MinColor: 3A3F46 + MaxColor: 4E4B48 ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 605242 - RightColor: 484847 + MinColor: 605242 + MaxColor: 484847 ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 5B5144 - RightColor: 524E4B + MinColor: 5B5144 + MaxColor: 524E4B ZOffset: -12 ZRamp: 0 Template@129: @@ -2261,33 +2263,33 @@ Size: 2, 3 Tiles: 0: Water - LeftColor: 323A43 - RightColor: 1B2D46 + MinColor: 323A43 + MaxColor: 1B2D46 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 283340 - RightColor: 112339 + MinColor: 283340 + MaxColor: 112339 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 4C4E52 - RightColor: 303A47 + MinColor: 4C4E52 + MaxColor: 303A47 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 283446 - RightColor: 20324E + MinColor: 283446 + MaxColor: 20324E ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 64533E - RightColor: 4E4E4C + MinColor: 64533E + MaxColor: 4E4E4C ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 5A5145 - RightColor: 564D42 + MinColor: 5A5145 + MaxColor: 564D42 ZOffset: -12 ZRamp: 0 Template@130: @@ -2297,23 +2299,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 182D49 - RightColor: 182B47 + MinColor: 182D49 + MaxColor: 182B47 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 283648 - RightColor: 182B44 + MinColor: 283648 + MaxColor: 182B44 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 1D2E43 - RightColor: 223654 + MinColor: 1D2E43 + MaxColor: 223654 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 3B4149 - RightColor: 454648 + MinColor: 3B4149 + MaxColor: 454648 ZOffset: -12 ZRamp: 0 Template@131: @@ -2323,23 +2325,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 253346 - RightColor: 1E2D41 + MinColor: 253346 + MaxColor: 1E2D41 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 303A45 - RightColor: 1E314D + MinColor: 303A45 + MaxColor: 1E314D ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 263241 - RightColor: 3D434A + MinColor: 263241 + MaxColor: 3D434A ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 5B5043 - RightColor: 524E4B + MinColor: 5B5043 + MaxColor: 524E4B ZOffset: -12 ZRamp: 0 Template@132: @@ -2349,23 +2351,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 1F314A - RightColor: 2A3545 + MinColor: 1F314A + MaxColor: 2A3545 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 4B4A49 - RightColor: 5D5244 + MinColor: 4B4A49 + MaxColor: 5D5244 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 213145 - RightColor: 283749 + MinColor: 213145 + MaxColor: 283749 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 50504D - RightColor: 55524C + MinColor: 50504D + MaxColor: 55524C ZOffset: -12 ZRamp: 0 Template@133: @@ -2375,23 +2377,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 1D3046 - RightColor: 353F48 + MinColor: 1D3046 + MaxColor: 353F48 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 4A4B49 - RightColor: 615546 + MinColor: 4A4B49 + MaxColor: 615546 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 1E2E41 - RightColor: 373E47 + MinColor: 1E2E41 + MaxColor: 373E47 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 524C45 - RightColor: 5D5141 + MinColor: 524C45 + MaxColor: 5D5141 ZOffset: -12 ZRamp: 0 Template@134: @@ -2401,23 +2403,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 2A394C - RightColor: 39424E + MinColor: 2A394C + MaxColor: 39424E ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 47494B - RightColor: 5C5248 + MinColor: 47494B + MaxColor: 5C5248 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 212F40 - RightColor: 263750 + MinColor: 212F40 + MaxColor: 263750 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 534D44 - RightColor: 595044 + MinColor: 534D44 + MaxColor: 595044 ZOffset: -12 ZRamp: 0 Template@135: @@ -2427,13 +2429,13 @@ Size: 2, 1 Tiles: 0: Water - LeftColor: 243246 - RightColor: 363E47 + MinColor: 243246 + MaxColor: 363E47 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 544E47 - RightColor: 5F5547 + MinColor: 544E47 + MaxColor: 5F5547 ZOffset: -12 ZRamp: 0 Template@136: @@ -2443,33 +2445,33 @@ Size: 3, 2 Tiles: 0: Water - LeftColor: 15273E - RightColor: 40444B + MinColor: 15273E + MaxColor: 40444B ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 494C50 - RightColor: 4E4C4B + MinColor: 494C50 + MaxColor: 4E4C4B ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 4E463B - RightColor: 66543E + MinColor: 4E463B + MaxColor: 66543E ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 0E2036 - RightColor: 11233A + MinColor: 0E2036 + MaxColor: 11233A ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 213042 - RightColor: 3B444E + MinColor: 213042 + MaxColor: 3B444E ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 524E46 - RightColor: 585043 + MinColor: 524E46 + MaxColor: 585043 ZOffset: -12 ZRamp: 0 Template@137: @@ -2479,33 +2481,33 @@ Size: 3, 2 Tiles: 0: Water - LeftColor: 13253D - RightColor: 162B46 + MinColor: 13253D + MaxColor: 162B46 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 2E405A - RightColor: 353F4A + MinColor: 2E405A + MaxColor: 353F4A ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 565148 - RightColor: 61503B + MinColor: 565148 + MaxColor: 61503B ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 1D2A3B - RightColor: 2E3845 + MinColor: 1D2A3B + MaxColor: 2E3845 ZOffset: -12 ZRamp: 0 4: Water - LeftColor: 60513D - RightColor: 3B434C + MinColor: 60513D + MaxColor: 3B434C ZOffset: -12 ZRamp: 0 5: Water - LeftColor: 5B5041 - RightColor: 5C5143 + MinColor: 5B5041 + MaxColor: 5C5143 ZOffset: -12 ZRamp: 0 Template@138: @@ -2515,23 +2517,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 1F3047 - RightColor: 393C40 + MinColor: 1F3047 + MaxColor: 393C40 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 4A4743 - RightColor: 62523E + MinColor: 4A4743 + MaxColor: 62523E ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 0F2137 - RightColor: 152842 + MinColor: 0F2137 + MaxColor: 152842 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 172B45 - RightColor: 223045 + MinColor: 172B45 + MaxColor: 223045 ZOffset: -12 ZRamp: 0 Template@139: @@ -2541,23 +2543,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 162943 - RightColor: 353C46 + MinColor: 162943 + MaxColor: 353C46 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 57524C - RightColor: 67553F + MinColor: 57524C + MaxColor: 67553F ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 12253D - RightColor: 182D49 + MinColor: 12253D + MaxColor: 182D49 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 172B46 - RightColor: 313D4B + MinColor: 172B46 + MaxColor: 313D4B ZOffset: -12 ZRamp: 0 Template@140: @@ -2567,23 +2569,23 @@ Size: 2, 2 Tiles: 0: Clear - LeftColor: 635645 - RightColor: 5E5446 + MinColor: 635645 + MaxColor: 5E5446 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 434B53 - RightColor: 5E5243 + MinColor: 434B53 + MaxColor: 5E5243 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 655541 - RightColor: 374250 + MinColor: 655541 + MaxColor: 374250 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 1A2D46 - RightColor: 273A56 + MinColor: 1A2D46 + MaxColor: 273A56 ZOffset: -12 ZRamp: 0 Template@141: @@ -2593,23 +2595,23 @@ Size: 2, 2 Tiles: 0: Clear - LeftColor: 5E5040 - RightColor: 645442 + MinColor: 5E5040 + MaxColor: 645442 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 4A4948 - RightColor: 5B5041 + MinColor: 4A4948 + MaxColor: 5B5041 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 605343 - RightColor: 484A4C + MinColor: 605343 + MaxColor: 484A4C ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 343E4C - RightColor: 343E4A + MinColor: 343E4C + MaxColor: 343E4A ZOffset: -12 ZRamp: 0 Template@142: @@ -2619,23 +2621,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 564D43 - RightColor: 564E43 + MinColor: 564D43 + MaxColor: 564E43 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 22354F - RightColor: 13273D + MinColor: 22354F + MaxColor: 13273D ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 6E583E - RightColor: 58534E + MinColor: 6E583E + MaxColor: 58534E ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 4A4949 - RightColor: 4C4B49 + MinColor: 4A4949 + MaxColor: 4C4B49 ZOffset: -12 ZRamp: 0 Template@143: @@ -2645,23 +2647,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 514E49 - RightColor: 534E4A + MinColor: 514E49 + MaxColor: 534E4A ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 28384D - RightColor: 152941 + MinColor: 28384D + MaxColor: 152941 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 705A3E - RightColor: 5B5041 + MinColor: 705A3E + MaxColor: 5B5041 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 524F4B - RightColor: 474949 + MinColor: 524F4B + MaxColor: 474949 ZOffset: -12 ZRamp: 0 Template@144: @@ -2671,23 +2673,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 1D304A - RightColor: 303C4D + MinColor: 1D304A + MaxColor: 303C4D ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 4D4F52 - RightColor: 6D583E + MinColor: 4D4F52 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 554F47 - RightColor: 464B4F + MinColor: 554F47 + MaxColor: 464B4F ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 5F5447 - RightColor: 665541 + MinColor: 5F5447 + MaxColor: 665541 ZOffset: -12 ZRamp: 0 Template@145: @@ -2697,23 +2699,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 22344D - RightColor: 303A47 + MinColor: 22344D + MaxColor: 303A47 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 494D53 - RightColor: 655440 + MinColor: 494D53 + MaxColor: 655440 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 5E5244 - RightColor: 44474B + MinColor: 5E5244 + MaxColor: 44474B ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 5D5245 - RightColor: 5D5143 + MinColor: 5D5245 + MaxColor: 5D5143 ZOffset: -12 ZRamp: 0 Template@146: @@ -2723,23 +2725,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 534F49 - RightColor: 5B5248 + MinColor: 534F49 + MaxColor: 5B5248 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 625442 - RightColor: 6B573E + MinColor: 625442 + MaxColor: 6B573E ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 25313F - RightColor: 37424F + MinColor: 25313F + MaxColor: 37424F ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 585248 - RightColor: 524F4B + MinColor: 585248 + MaxColor: 524F4B ZOffset: -12 ZRamp: 0 Template@147: @@ -2749,23 +2751,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 494B4E - RightColor: 5C544A + MinColor: 494B4E + MaxColor: 5C544A ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 4C4B4A - RightColor: 625240 + MinColor: 4C4B4A + MaxColor: 625240 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 283649 - RightColor: 253855 + MinColor: 283649 + MaxColor: 253855 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 4E4C4A - RightColor: 544F4A + MinColor: 4E4C4A + MaxColor: 544F4A ZOffset: -12 ZRamp: 0 Template@148: @@ -2775,108 +2777,108 @@ Size: 6, 4 Tiles: 1: Clear - LeftColor: 63523D - RightColor: 60513D + MinColor: 63523D + MaxColor: 60513D ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 5D503F - RightColor: 63523E + MinColor: 5D503F + MaxColor: 63523E ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 625340 - RightColor: 66543F + MinColor: 625340 + MaxColor: 66543F ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 645440 - RightColor: 60513D + MinColor: 645440 + MaxColor: 60513D ZOffset: -12 ZRamp: 0 7: Water - LeftColor: 48443F - RightColor: 55493B + MinColor: 48443F + MaxColor: 55493B ZOffset: -12 ZRamp: 0 8: Water - LeftColor: 43413D - RightColor: 45423C + MinColor: 43413D + MaxColor: 45423C ZOffset: -12 ZRamp: 0 9: Water - LeftColor: 44403B - RightColor: 514739 + MinColor: 44403B + MaxColor: 514739 ZOffset: -12 ZRamp: 0 10: Water - LeftColor: 393D40 - RightColor: 534A3F + MinColor: 393D40 + MaxColor: 534A3F ZOffset: -12 ZRamp: 0 11: Water - LeftColor: 272E38 - RightColor: 1B2839 + MinColor: 272E38 + MaxColor: 1B2839 ZOffset: -12 ZRamp: 0 12: Water - LeftColor: 554D42 - RightColor: 4D463C + MinColor: 554D42 + MaxColor: 4D463C ZOffset: -12 ZRamp: 0 13: Water - LeftColor: 45484A - RightColor: 343E4A + MinColor: 45484A + MaxColor: 343E4A ZOffset: -12 ZRamp: 0 14: Water - LeftColor: 3A4045 - RightColor: 3D4041 + MinColor: 3A4045 + MaxColor: 3D4041 ZOffset: -12 ZRamp: 0 15: Water - LeftColor: 232F3D - RightColor: 2B343D + MinColor: 232F3D + MaxColor: 2B343D ZOffset: -12 ZRamp: 0 16: Water - LeftColor: 1F3048 - RightColor: 1E3048 + MinColor: 1F3048 + MaxColor: 1E3048 ZOffset: -12 ZRamp: 0 17: Water - LeftColor: 1E3456 - RightColor: 152842 + MinColor: 1E3456 + MaxColor: 152842 ZOffset: -12 ZRamp: 0 18: Water - LeftColor: 584C3E - RightColor: 44423E + MinColor: 584C3E + MaxColor: 44423E ZOffset: -12 ZRamp: 0 19: Water - LeftColor: 1F304A - RightColor: 223552 + MinColor: 1F304A + MaxColor: 223552 ZOffset: -12 ZRamp: 0 20: Water - LeftColor: 162A46 - RightColor: 1B2D45 + MinColor: 162A46 + MaxColor: 1B2D45 ZOffset: -12 ZRamp: 0 21: Water - LeftColor: 102238 - RightColor: 192E4B + MinColor: 102238 + MaxColor: 192E4B ZOffset: -12 ZRamp: 0 22: Water - LeftColor: 182C49 - RightColor: 1F3557 + MinColor: 182C49 + MaxColor: 1F3557 ZOffset: -12 ZRamp: 0 23: Water - LeftColor: 11243C - RightColor: 12253E + MinColor: 11243C + MaxColor: 12253E ZOffset: -12 ZRamp: 0 Template@149: @@ -2886,153 +2888,153 @@ Size: 9, 5 Tiles: 2: Water - LeftColor: 584E3F - RightColor: 5F513D + MinColor: 584E3F + MaxColor: 5F513D ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 524A3E - RightColor: 645541 + MinColor: 524A3E + MaxColor: 645541 ZOffset: -12 ZRamp: 0 11: Water - LeftColor: 4F4A43 - RightColor: 3B4046 + MinColor: 4F4A43 + MaxColor: 3B4046 ZOffset: -12 ZRamp: 0 12: Water - LeftColor: 383F47 - RightColor: 4E4D49 + MinColor: 383F47 + MaxColor: 4E4D49 ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 65543F - RightColor: 6E5C44 + MinColor: 65543F + MaxColor: 6E5C44 ZOffset: -12 ZRamp: 0 18: Clear - LeftColor: 6C5A42 - RightColor: 665641 + MinColor: 6C5A42 + MaxColor: 665641 ZOffset: -12 ZRamp: 0 19: Water - LeftColor: 574A3A - RightColor: 5B4D3C + MinColor: 574A3A + MaxColor: 5B4D3C ZOffset: -12 ZRamp: 0 20: Water - LeftColor: 383C3E - RightColor: 30373F + MinColor: 383C3E + MaxColor: 30373F ZOffset: -12 ZRamp: 0 21: Water - LeftColor: 28364E - RightColor: 273340 + MinColor: 28364E + MaxColor: 273340 ZOffset: -12 ZRamp: 0 22: Water - LeftColor: 25313F - RightColor: 4C4840 + MinColor: 25313F + MaxColor: 4C4840 ZOffset: -12 ZRamp: 0 23: Water - LeftColor: 333738 - RightColor: 574F44 + MinColor: 333738 + MaxColor: 574F44 ZOffset: -12 ZRamp: 0 24: Water - LeftColor: 28323C - RightColor: 4F473C + MinColor: 28323C + MaxColor: 4F473C ZOffset: -12 ZRamp: 0 25: Water - LeftColor: 404140 - RightColor: 4C4842 + MinColor: 404140 + MaxColor: 4C4842 ZOffset: -12 ZRamp: 0 26: Water - LeftColor: 21324D - RightColor: 16283D + MinColor: 21324D + MaxColor: 16283D ZOffset: -12 ZRamp: 0 28: Water - LeftColor: 5D503E - RightColor: 615444 + MinColor: 5D503E + MaxColor: 615444 ZOffset: -12 ZRamp: 0 29: Water - LeftColor: 5A5246 - RightColor: 363737 + MinColor: 5A5246 + MaxColor: 363737 ZOffset: -12 ZRamp: 0 30: Water - LeftColor: 1E3252 - RightColor: 1A2B41 + MinColor: 1E3252 + MaxColor: 1A2B41 ZOffset: -12 ZRamp: 0 31: Water - LeftColor: 1B3050 - RightColor: 192D4B + MinColor: 1B3050 + MaxColor: 192D4B ZOffset: -12 ZRamp: 0 32: Water - LeftColor: 1C3151 - RightColor: 1B3151 + MinColor: 1C3151 + MaxColor: 1B3151 ZOffset: -12 ZRamp: 0 33: Water - LeftColor: 152944 - RightColor: 172B45 + MinColor: 152944 + MaxColor: 172B45 ZOffset: -12 ZRamp: 0 34: Water - LeftColor: 14273F - RightColor: 192E4B + MinColor: 14273F + MaxColor: 192E4B ZOffset: -12 ZRamp: 0 35: Water - LeftColor: 152842 - RightColor: 132640 + MinColor: 152842 + MaxColor: 132640 ZOffset: -12 ZRamp: 0 37: Water - LeftColor: 695741 - RightColor: 5D4E3B + MinColor: 695741 + MaxColor: 5D4E3B ZOffset: -12 ZRamp: 0 38: Water - LeftColor: 373938 - RightColor: 3D3F3F + MinColor: 373938 + MaxColor: 3D3F3F ZOffset: -12 ZRamp: 0 39: Water - LeftColor: 162944 - RightColor: 162A47 + MinColor: 162944 + MaxColor: 162A47 ZOffset: -12 ZRamp: 0 40: Water - LeftColor: 11233B - RightColor: 182C49 + MinColor: 11233B + MaxColor: 182C49 ZOffset: -12 ZRamp: 0 41: Water - LeftColor: 12253D - RightColor: 11253D + MinColor: 12253D + MaxColor: 11253D ZOffset: -12 ZRamp: 0 42: Water - LeftColor: 0F2136 - RightColor: 10233C + MinColor: 0F2136 + MaxColor: 10233C ZOffset: -12 ZRamp: 0 43: Water - LeftColor: 0E2036 - RightColor: 12253F + MinColor: 0E2036 + MaxColor: 12253F ZOffset: -12 ZRamp: 0 44: Water - LeftColor: 152843 - RightColor: 142842 + MinColor: 152843 + MaxColor: 142842 ZOffset: -12 ZRamp: 0 Template@150: @@ -3042,8 +3044,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 464036 - RightColor: 474137 + MinColor: 464036 + MaxColor: 474137 ZOffset: -12 ZRamp: 0 Template@151: @@ -3053,8 +3055,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 534839 - RightColor: 544939 + MinColor: 534839 + MaxColor: 544939 ZOffset: -12 ZRamp: 0 Template@152: @@ -3064,8 +3066,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 4A4439 - RightColor: 584A38 + MinColor: 4A4439 + MaxColor: 584A38 ZOffset: -12 ZRamp: 0 Template@153: @@ -3075,8 +3077,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 464036 - RightColor: 574A39 + MinColor: 464036 + MaxColor: 574A39 ZOffset: -12 ZRamp: 0 Template@154: @@ -3086,8 +3088,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 4C463B - RightColor: 5E4F3C + MinColor: 4C463B + MaxColor: 5E4F3C ZOffset: -12 ZRamp: 0 Template@155: @@ -3097,8 +3099,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 554939 - RightColor: 494338 + MinColor: 554939 + MaxColor: 494338 ZOffset: -12 ZRamp: 0 Template@156: @@ -3108,8 +3110,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 554938 - RightColor: 574A3A + MinColor: 554938 + MaxColor: 574A3A ZOffset: -12 ZRamp: 0 Template@157: @@ -3119,8 +3121,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 584C3C - RightColor: 584A39 + MinColor: 584C3C + MaxColor: 584A39 ZOffset: -12 ZRamp: 0 Template@158: @@ -3130,8 +3132,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 564B3B - RightColor: 61523F + MinColor: 564B3B + MaxColor: 61523F ZOffset: -12 ZRamp: 0 Template@159: @@ -3141,8 +3143,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 564939 - RightColor: 494338 + MinColor: 564939 + MaxColor: 494338 ZOffset: -12 ZRamp: 0 Template@160: @@ -3152,8 +3154,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 544939 - RightColor: 564937 + MinColor: 544939 + MaxColor: 564937 ZOffset: -12 ZRamp: 0 Template@161: @@ -3163,8 +3165,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 5A4E3D - RightColor: 5B4C39 + MinColor: 5A4E3D + MaxColor: 5B4C39 ZOffset: -12 ZRamp: 0 Template@162: @@ -3174,8 +3176,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 574C3C - RightColor: 60503D + MinColor: 574C3C + MaxColor: 60503D ZOffset: -12 ZRamp: 0 Template@163: @@ -3185,8 +3187,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 64533D - RightColor: 4A4438 + MinColor: 64533D + MaxColor: 4A4438 ZOffset: -12 ZRamp: 0 Template@164: @@ -3196,8 +3198,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 67533B - RightColor: 584B3A + MinColor: 67533B + MaxColor: 584B3A ZOffset: -12 ZRamp: 0 Template@165: @@ -3207,8 +3209,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 635440 - RightColor: 554939 + MinColor: 635440 + MaxColor: 554939 ZOffset: -12 ZRamp: 0 Template@166: @@ -3218,8 +3220,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 5B4D3A - RightColor: 5D4F3D + MinColor: 5B4D3A + MaxColor: 5D4F3D ZOffset: -12 ZRamp: 0 Template@167: @@ -3230,24 +3232,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 3D3325 - RightColor: 52432F + MinColor: 3D3325 + MaxColor: 52432F ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 423B33 - RightColor: 493F30 + MinColor: 423B33 + MaxColor: 493F30 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 31281B - RightColor: 463827 + MinColor: 31281B + MaxColor: 463827 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 2B333B - RightColor: 3C372D + MinColor: 2B333B + MaxColor: 3C372D ZOffset: -12 ZRamp: 0 Template@168: @@ -3258,13 +3260,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 463F33 - RightColor: 524738 + MinColor: 463F33 + MaxColor: 524738 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 464138 - RightColor: 3E382E + MinColor: 464138 + MaxColor: 3E382E ZOffset: -12 ZRamp: 0 Template@169: @@ -3275,24 +3277,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 3E372C - RightColor: 4C402F + MinColor: 3E372C + MaxColor: 4C402F ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 313842 - RightColor: 3F3930 + MinColor: 313842 + MaxColor: 3F3930 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 353027 - RightColor: 3A342A + MinColor: 353027 + MaxColor: 3A342A ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 242D3A - RightColor: 302E2A + MinColor: 242D3A + MaxColor: 302E2A ZOffset: -12 ZRamp: 0 Template@170: @@ -3303,24 +3305,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 504637 - RightColor: 514433 + MinColor: 504637 + MaxColor: 514433 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 26313F - RightColor: 4D4436 + MinColor: 26313F + MaxColor: 4D4436 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 403A2D - RightColor: 4C4234 + MinColor: 403A2D + MaxColor: 4C4234 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 2D353F - RightColor: 453F33 + MinColor: 2D353F + MaxColor: 453F33 ZOffset: -12 ZRamp: 0 Template@171: @@ -3331,24 +3333,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 3E362A - RightColor: 463C2E + MinColor: 3E362A + MaxColor: 463C2E ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 3F3A32 - RightColor: 504434 + MinColor: 3F3A32 + MaxColor: 504434 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 2A3137 - RightColor: 423C32 + MinColor: 2A3137 + MaxColor: 423C32 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 2E3640 - RightColor: 4D463B + MinColor: 2E3640 + MaxColor: 4D463B ZOffset: -12 ZRamp: 0 Template@172: @@ -3359,24 +3361,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 41392D - RightColor: 4D4334 + MinColor: 41392D + MaxColor: 4D4334 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 3A3429 - RightColor: 4A3E2E + MinColor: 3A3429 + MaxColor: 4A3E2E ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 363737 - RightColor: 4D4538 + MinColor: 363737 + MaxColor: 4D4538 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 323436 - RightColor: 4D4436 + MinColor: 323436 + MaxColor: 4D4436 ZOffset: -12 ZRamp: 0 Template@173: @@ -3387,24 +3389,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 483E30 - RightColor: 504332 + MinColor: 483E30 + MaxColor: 504332 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 483F33 - RightColor: 4E4130 + MinColor: 483F33 + MaxColor: 4E4130 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 2B323B - RightColor: 3E3931 + MinColor: 2B323B + MaxColor: 3E3931 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 353B42 - RightColor: 484238 + MinColor: 353B42 + MaxColor: 484238 ZOffset: -12 ZRamp: 0 Template@174: @@ -3415,13 +3417,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 3E362C - RightColor: 4D4233 + MinColor: 3E362C + MaxColor: 4D4233 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 484744 - RightColor: 444038 + MinColor: 484744 + MaxColor: 444038 ZOffset: -12 ZRamp: 0 Template@175: @@ -3432,18 +3434,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 473E32 - RightColor: 524535 + MinColor: 473E32 + MaxColor: 524535 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 34373A - RightColor: 4E473C + MinColor: 34373A + MaxColor: 4E473C ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 4A453B - RightColor: 454139 + MinColor: 4A453B + MaxColor: 454139 ZOffset: -12 ZRamp: 0 Template@176: @@ -3454,23 +3456,23 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 494032 - RightColor: 4C4032 + MinColor: 494032 + MaxColor: 4C4032 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 212932 - RightColor: 494339 + MinColor: 212932 + MaxColor: 494339 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 3E3B35 - RightColor: 484237 + MinColor: 3E3B35 + MaxColor: 484237 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 313740 - RightColor: 1E2B3C + MinColor: 313740 + MaxColor: 1E2B3C ZOffset: -12 ZRamp: 0 Template@177: @@ -3481,18 +3483,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 483D2F - RightColor: 3F3629 + MinColor: 483D2F + MaxColor: 3F3629 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2C333A - RightColor: 3C382F + MinColor: 2C333A + MaxColor: 3C382F ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 46433D - RightColor: 48443E + MinColor: 46433D + MaxColor: 48443E ZOffset: -12 ZRamp: 0 Template@178: @@ -3502,8 +3504,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 47433C - RightColor: 3E3C37 + MinColor: 47433C + MaxColor: 3E3C37 ZOffset: -12 ZRamp: 0 Template@179: @@ -3513,8 +3515,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 423F39 - RightColor: 4E473D + MinColor: 423F39 + MaxColor: 4E473D ZOffset: -12 ZRamp: 0 Template@180: @@ -3524,8 +3526,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 4A453C - RightColor: 3B372F + MinColor: 4A453C + MaxColor: 3B372F ZOffset: -12 ZRamp: 0 Template@181: @@ -3536,24 +3538,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4E4233 - RightColor: 42382C + MinColor: 4E4233 + MaxColor: 42382C ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2E2E2D - RightColor: 32302C + MinColor: 2E2E2D + MaxColor: 32302C ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 483D30 - RightColor: 3D3830 + MinColor: 483D30 + MaxColor: 3D3830 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 30353C - RightColor: 2F3030 + MinColor: 30353C + MaxColor: 2F3030 ZOffset: -12 ZRamp: 0 Template@182: @@ -3564,24 +3566,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 443E34 - RightColor: 423B30 + MinColor: 443E34 + MaxColor: 423B30 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 363531 - RightColor: 27292A + MinColor: 363531 + MaxColor: 27292A ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 473F33 - RightColor: 302E29 + MinColor: 473F33 + MaxColor: 302E29 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 383837 - RightColor: 373632 + MinColor: 383837 + MaxColor: 373632 ZOffset: -12 ZRamp: 0 Template@183: @@ -3592,24 +3594,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 453B2D - RightColor: 463E32 + MinColor: 453B2D + MaxColor: 463E32 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 302B22 - RightColor: 2F2E2B + MinColor: 302B22 + MaxColor: 2F2E2B ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 504434 - RightColor: 463F34 + MinColor: 504434 + MaxColor: 463F34 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 282C30 - RightColor: 3A3732 + MinColor: 282C30 + MaxColor: 3A3732 ZOffset: -12 ZRamp: 0 Template@184: @@ -3620,13 +3622,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4F412F - RightColor: 4A4033 + MinColor: 4F412F + MaxColor: 4A4033 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2C2E2D - RightColor: 363531 + MinColor: 2C2E2D + MaxColor: 363531 ZOffset: -12 ZRamp: 0 Template@185: @@ -3637,24 +3639,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 514434 - RightColor: 3D372F + MinColor: 514434 + MaxColor: 3D372F ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2C2A25 - RightColor: 2B2E31 + MinColor: 2C2A25 + MaxColor: 2B2E31 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 443B2D - RightColor: 242320 + MinColor: 443B2D + MaxColor: 242320 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 303942 - RightColor: 2F3336 + MinColor: 303942 + MaxColor: 2F3336 ZOffset: -12 ZRamp: 0 Template@186: @@ -3665,24 +3667,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4E4232 - RightColor: 453E32 + MinColor: 4E4232 + MaxColor: 453E32 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2D2C2A - RightColor: 23272D + MinColor: 2D2C2A + MaxColor: 23272D ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 514231 - RightColor: 2B2925 + MinColor: 514231 + MaxColor: 2B2925 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 29313A - RightColor: 252C34 + MinColor: 29313A + MaxColor: 252C34 ZOffset: -12 ZRamp: 0 Template@187: @@ -3693,24 +3695,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 463D30 - RightColor: 302F2B + MinColor: 463D30 + MaxColor: 302F2B ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2B2C2B - RightColor: 343431 + MinColor: 2B2C2B + MaxColor: 343431 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 504434 - RightColor: 24221F + MinColor: 504434 + MaxColor: 24221F ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 3C3E40 - RightColor: 2E343B + MinColor: 3C3E40 + MaxColor: 2E343B ZOffset: -12 ZRamp: 0 Template@188: @@ -3721,13 +3723,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4A3E2F - RightColor: 444038 + MinColor: 4A3E2F + MaxColor: 444038 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2B2D2F - RightColor: 30302E + MinColor: 2B2D2F + MaxColor: 30302E ZOffset: -12 ZRamp: 0 Template@189: @@ -3738,29 +3740,29 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 463E32 - RightColor: 4D4031 + MinColor: 463E32 + MaxColor: 4D4031 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 4A463C - RightColor: 3E3C36 + MinColor: 4A463C + MaxColor: 3E3C36 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 2B2824 - RightColor: 37322A + MinColor: 2B2824 + MaxColor: 37322A ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 202D40 - RightColor: 3B3B3B + MinColor: 202D40 + MaxColor: 3B3B3B ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 25303F - RightColor: 373634 + MinColor: 25303F + MaxColor: 373634 ZOffset: -12 ZRamp: 0 Template@190: @@ -3770,13 +3772,13 @@ Size: 1, 2 Tiles: 0: Cliff - LeftColor: 474239 - RightColor: 3F3B35 + MinColor: 474239 + MaxColor: 3F3B35 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 202C3B - RightColor: 373C41 + MinColor: 202C3B + MaxColor: 373C41 ZOffset: -12 ZRamp: 0 Template@191: @@ -3786,13 +3788,13 @@ Size: 2, 1 Tiles: 0: Cliff - LeftColor: 48433B - RightColor: 4C463C + MinColor: 48433B + MaxColor: 4C463C ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 383C41 - RightColor: 202D3D + MinColor: 383C41 + MaxColor: 202D3D ZOffset: -12 ZRamp: 0 Template@192: @@ -3802,13 +3804,13 @@ Size: 2, 1 Tiles: 0: Cliff - LeftColor: 403C33 - RightColor: 4E473B + MinColor: 403C33 + MaxColor: 4E473B ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2D3540 - RightColor: 443F3B + MinColor: 2D3540 + MaxColor: 443F3B ZOffset: -12 ZRamp: 0 Template@193: @@ -3818,13 +3820,13 @@ Size: 1, 2 Tiles: 0: Cliff - LeftColor: 544B3D - RightColor: 423F38 + MinColor: 544B3D + MaxColor: 423F38 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 383D47 - RightColor: 2F3947 + MinColor: 383D47 + MaxColor: 2F3947 ZOffset: -12 ZRamp: 0 Template@194: @@ -3835,29 +3837,29 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4B3F2E - RightColor: 423B31 + MinColor: 4B3F2E + MaxColor: 423B31 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 312F2B - RightColor: 35332E + MinColor: 312F2B + MaxColor: 35332E ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 42413F - RightColor: 16283E + MinColor: 42413F + MaxColor: 16283E ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 4E4132 - RightColor: 282724 + MinColor: 4E4132 + MaxColor: 282724 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 31373E - RightColor: 303439 + MinColor: 31373E + MaxColor: 303439 ZOffset: -12 ZRamp: 0 Template@195: @@ -3867,28 +3869,28 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: 70593E - RightColor: 886946 + MinColor: 70593E + MaxColor: 886946 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 906F49 - RightColor: 8E6E49 + MinColor: 906F49 + MaxColor: 8E6E49 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 92704A - RightColor: 9A754A + MinColor: 92704A + MaxColor: 9A754A ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 70593E - RightColor: 856745 + MinColor: 70593E + MaxColor: 856745 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7F6444 - RightColor: 8B6D48 + MinColor: 7F6444 + MaxColor: 8B6D48 ZOffset: -12 ZRamp: 0 Template@196: @@ -3898,23 +3900,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 7C6243 - RightColor: 8D6C46 + MinColor: 7C6243 + MaxColor: 8D6C46 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 916E47 - RightColor: 8F6E48 + MinColor: 916E47 + MaxColor: 8F6E48 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 6F583D - RightColor: 7A6143 + MinColor: 6F583D + MaxColor: 7A6143 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 7A6143 - RightColor: 927048 + MinColor: 7A6143 + MaxColor: 927048 ZOffset: -12 ZRamp: 0 Template@197: @@ -3924,23 +3926,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 7C6345 - RightColor: 927049 + MinColor: 7C6345 + MaxColor: 927049 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 97744B - RightColor: 806545 + MinColor: 97744B + MaxColor: 806545 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 6F583D - RightColor: 816646 + MinColor: 6F583D + MaxColor: 816646 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8B6C48 - RightColor: 8A6C49 + MinColor: 8B6C48 + MaxColor: 8A6C49 ZOffset: -12 ZRamp: 0 Template@198: @@ -3950,18 +3952,18 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 896A47 - RightColor: 8E6D47 + MinColor: 896A47 + MaxColor: 8E6D47 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8A6943 - RightColor: 7F6443 + MinColor: 8A6943 + MaxColor: 7F6443 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 816544 - RightColor: 7E6342 + MinColor: 816544 + MaxColor: 7E6342 ZOffset: -12 ZRamp: 0 Template@199: @@ -3971,23 +3973,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 8F6E47 - RightColor: 8A6A45 + MinColor: 8F6E47 + MaxColor: 8A6A45 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8B6A45 - RightColor: 7D6344 + MinColor: 8B6A45 + MaxColor: 7D6344 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 826543 - RightColor: 866743 + MinColor: 826543 + MaxColor: 866743 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 765E42 - RightColor: 765E40 + MinColor: 765E42 + MaxColor: 765E40 ZOffset: -12 ZRamp: 0 Template@200: @@ -3997,28 +3999,28 @@ Size: 3, 2 Tiles: 1: DirtRoad - LeftColor: 95734B - RightColor: 957249 + MinColor: 95734B + MaxColor: 957249 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 937048 - RightColor: 7C6141 + MinColor: 937048 + MaxColor: 7C6141 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 6D583E - RightColor: 7C6242 + MinColor: 6D583E + MaxColor: 7C6242 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 7E6343 - RightColor: 947149 + MinColor: 7E6343 + MaxColor: 947149 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 896A46 - RightColor: 846744 + MinColor: 896A46 + MaxColor: 846744 ZOffset: -12 ZRamp: 0 Template@201: @@ -4028,28 +4030,28 @@ Size: 2, 3 Tiles: 0: DirtRoad - LeftColor: 7B6243 - RightColor: 7D6344 + MinColor: 7B6243 + MaxColor: 7D6344 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8F6D46 - RightColor: 99744A + MinColor: 8F6D46 + MaxColor: 99744A ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 6D563C - RightColor: 7C6142 + MinColor: 6D563C + MaxColor: 7C6142 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9C774D - RightColor: 916E46 + MinColor: 9C774D + MaxColor: 916E46 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 71593E - RightColor: 8A6B46 + MinColor: 71593E + MaxColor: 8A6B46 ZOffset: -12 ZRamp: 0 Template@202: @@ -4059,23 +4061,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 755D41 - RightColor: 7F6444 + MinColor: 755D41 + MaxColor: 7F6444 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 957249 - RightColor: 9D774C + MinColor: 957249 + MaxColor: 9D774C ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 725D42 - RightColor: 7E6445 + MinColor: 725D42 + MaxColor: 7E6445 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 906E49 - RightColor: 8F6E49 + MinColor: 906E49 + MaxColor: 8F6E49 ZOffset: -12 ZRamp: 0 Template@203: @@ -4085,23 +4087,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 765F43 - RightColor: 7D6344 + MinColor: 765F43 + MaxColor: 7D6344 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9B764B - RightColor: 9D784D + MinColor: 9B764B + MaxColor: 9D784D ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7F6444 - RightColor: 886A46 + MinColor: 7F6444 + MaxColor: 886A46 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F6E48 - RightColor: 876946 + MinColor: 8F6E48 + MaxColor: 876946 ZOffset: -12 ZRamp: 0 Template@204: @@ -4111,23 +4113,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 99754B - RightColor: 846745 + MinColor: 99754B + MaxColor: 846745 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A07A4D - RightColor: 9E784D + MinColor: A07A4D + MaxColor: 9E784D ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 846744 - RightColor: 927049 + MinColor: 846744 + MaxColor: 927049 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 7A6244 - RightColor: 886A46 + MinColor: 7A6244 + MaxColor: 886A46 ZOffset: -12 ZRamp: 0 Template@205: @@ -4137,28 +4139,28 @@ Size: 3, 2 Tiles: 1: DirtRoad - LeftColor: 8E6D47 - RightColor: 836542 + MinColor: 8E6D47 + MaxColor: 836542 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9F784C - RightColor: 9E784D + MinColor: 9F784C + MaxColor: 9E784D ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 765F43 - RightColor: 836440 + MinColor: 765F43 + MaxColor: 836440 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 7B5F3F - RightColor: 916E46 + MinColor: 7B5F3F + MaxColor: 916E46 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 836644 - RightColor: 886944 + MinColor: 836644 + MaxColor: 886944 ZOffset: -12 ZRamp: 0 Template@206: @@ -4168,28 +4170,28 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: 715A3E - RightColor: 896B48 + MinColor: 715A3E + MaxColor: 896B48 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8D6D49 - RightColor: 9E784D + MinColor: 8D6D49 + MaxColor: 9E784D ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9E794E - RightColor: 9D774C + MinColor: 9E794E + MaxColor: 9D774C ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 70593F - RightColor: 866A48 + MinColor: 70593F + MaxColor: 866A48 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7E6345 - RightColor: 7F6547 + MinColor: 7E6345 + MaxColor: 7F6547 ZOffset: -12 ZRamp: 0 Template@207: @@ -4199,33 +4201,33 @@ Size: 2, 3 Tiles: 0: DirtRoad - LeftColor: 7E6445 - RightColor: 775E41 + MinColor: 7E6445 + MaxColor: 775E41 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8F6E48 - RightColor: 816443 + MinColor: 8F6E48 + MaxColor: 816443 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7C6142 - RightColor: 8E6D47 + MinColor: 7C6142 + MaxColor: 8E6D47 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8E6F4B - RightColor: 98754B + MinColor: 8E6F4B + MaxColor: 98754B ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 705A40 - RightColor: 7E6343 + MinColor: 705A40 + MaxColor: 7E6343 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 95734B - RightColor: 8E6E49 + MinColor: 95734B + MaxColor: 8E6E49 ZOffset: -12 ZRamp: 0 Template@208: @@ -4235,23 +4237,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 7D6343 - RightColor: 785F40 + MinColor: 7D6343 + MaxColor: 785F40 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8C6C47 - RightColor: 816443 + MinColor: 8C6C47 + MaxColor: 816443 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 826644 - RightColor: 8B6B45 + MinColor: 826644 + MaxColor: 8B6B45 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 926F48 - RightColor: 95724A + MinColor: 926F48 + MaxColor: 95724A ZOffset: -12 ZRamp: 0 Template@209: @@ -4261,18 +4263,18 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 896A47 - RightColor: 7A5F40 + MinColor: 896A47 + MaxColor: 7A5F40 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 937048 - RightColor: 816543 + MinColor: 937048 + MaxColor: 816543 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F6E48 - RightColor: 937049 + MinColor: 8F6E48 + MaxColor: 937049 ZOffset: -12 ZRamp: 0 Template@210: @@ -4282,18 +4284,18 @@ Size: 2, 2 Tiles: 1: DirtRoad - LeftColor: 906F4A - RightColor: 806443 + MinColor: 906F4A + MaxColor: 806443 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 70593E - RightColor: 7D6344 + MinColor: 70593E + MaxColor: 7D6344 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 7C6243 - RightColor: 94714A + MinColor: 7C6243 + MaxColor: 94714A ZOffset: -12 ZRamp: 0 Template@211: @@ -4303,33 +4305,33 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: 7E6344 - RightColor: 7D6344 + MinColor: 7E6344 + MaxColor: 7D6344 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 896A46 - RightColor: 785E40 + MinColor: 896A46 + MaxColor: 785E40 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 765D40 - RightColor: 6E5A40 + MinColor: 765D40 + MaxColor: 6E5A40 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 7D6142 - RightColor: 8B6B46 + MinColor: 7D6142 + MaxColor: 8B6B46 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8C6D49 - RightColor: 906F49 + MinColor: 8C6D49 + MaxColor: 906F49 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 93704A - RightColor: 896A46 + MinColor: 93704A + MaxColor: 896A46 ZOffset: -12 ZRamp: 0 Template@212: @@ -4339,18 +4341,18 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 8C6C48 - RightColor: 7F6444 + MinColor: 8C6C48 + MaxColor: 7F6444 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 866846 - RightColor: 745D40 + MinColor: 866846 + MaxColor: 745D40 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 94724C - RightColor: 8A6A45 + MinColor: 94724C + MaxColor: 8A6A45 ZOffset: -12 ZRamp: 0 Template@213: @@ -4360,23 +4362,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 886A46 - RightColor: 7A6042 + MinColor: 886A46 + MaxColor: 7A6042 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 775D3E - RightColor: 735B3E + MinColor: 775D3E + MaxColor: 735B3E ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 836644 - RightColor: 8D6C46 + MinColor: 836644 + MaxColor: 8D6C46 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8E6D46 - RightColor: 8B6B46 + MinColor: 8E6D46 + MaxColor: 8B6B46 ZOffset: -12 ZRamp: 0 Template@214: @@ -4386,28 +4388,28 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: 8C6C48 - RightColor: 7E6343 + MinColor: 8C6C48 + MaxColor: 7E6343 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8A6D4A - RightColor: 7A6144 + MinColor: 8A6D4A + MaxColor: 7A6144 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7A6042 - RightColor: 735C3F + MinColor: 7A6042 + MaxColor: 735C3F ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 916F48 - RightColor: 96724A + MinColor: 916F48 + MaxColor: 96724A ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 8C6D49 - RightColor: 775F42 + MinColor: 8C6D49 + MaxColor: 775F42 ZOffset: -12 ZRamp: 0 Template@215: @@ -4417,23 +4419,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 8B6C48 - RightColor: 7A6142 + MinColor: 8B6C48 + MaxColor: 7A6142 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 806444 - RightColor: 715A3E + MinColor: 806444 + MaxColor: 715A3E ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 93714A - RightColor: 96744C + MinColor: 93714A + MaxColor: 96744C ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 947149 - RightColor: 816544 + MinColor: 947149 + MaxColor: 816544 ZOffset: -12 ZRamp: 0 Template@216: @@ -4443,18 +4445,18 @@ Size: 2, 2 Tiles: 1: DirtRoad - LeftColor: 8D6E4A - RightColor: 705B41 + MinColor: 8D6E4A + MaxColor: 705B41 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7D6343 - RightColor: 8E6D47 + MinColor: 7D6343 + MaxColor: 8E6D47 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F6F49 - RightColor: 876A47 + MinColor: 8F6F49 + MaxColor: 876A47 ZOffset: -12 ZRamp: 0 Template@217: @@ -4464,23 +4466,23 @@ Size: 2, 3 Tiles: 1: DirtRoad - LeftColor: 856847 - RightColor: 705A3F + MinColor: 856847 + MaxColor: 705A3F ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 8A6C47 - RightColor: 8D6D47 + MinColor: 8A6C47 + MaxColor: 8D6D47 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8B6A44 - RightColor: 816442 + MinColor: 8B6A44 + MaxColor: 816442 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 816544 - RightColor: 7C6242 + MinColor: 816544 + MaxColor: 7C6242 ZOffset: -12 ZRamp: 0 Template@218: @@ -4490,28 +4492,28 @@ Size: 2, 3 Tiles: 1: DirtRoad - LeftColor: 7D6343 - RightColor: 6E5A40 + MinColor: 7D6343 + MaxColor: 6E5A40 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 98744B - RightColor: 9E784D + MinColor: 98744B + MaxColor: 9E784D ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 95734A - RightColor: 826644 + MinColor: 95734A + MaxColor: 826644 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 846644 - RightColor: 93724B + MinColor: 846644 + MaxColor: 93724B ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7B6243 - RightColor: 826644 + MinColor: 7B6243 + MaxColor: 826644 ZOffset: -12 ZRamp: 0 Template@219: @@ -4521,23 +4523,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 7C6142 - RightColor: 8E6D47 + MinColor: 7C6142 + MaxColor: 8E6D47 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9A764D - RightColor: 8F6F4B + MinColor: 9A764D + MaxColor: 8F6F4B ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7E6444 - RightColor: 886A47 + MinColor: 7E6444 + MaxColor: 886A47 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 91714B - RightColor: 99754C + MinColor: 91714B + MaxColor: 99754C ZOffset: -12 ZRamp: 0 Template@220: @@ -4547,23 +4549,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 8F6E48 - RightColor: 806444 + MinColor: 8F6E48 + MaxColor: 806444 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8F6E49 - RightColor: 816443 + MinColor: 8F6E49 + MaxColor: 816443 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 947149 - RightColor: 916F48 + MinColor: 947149 + MaxColor: 916F48 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 927049 - RightColor: 9A754C + MinColor: 927049 + MaxColor: 9A754C ZOffset: -12 ZRamp: 0 Template@221: @@ -4573,23 +4575,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 96734B - RightColor: 99764D + MinColor: 96734B + MaxColor: 99764D ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 96734A - RightColor: 7F6545 + MinColor: 96734A + MaxColor: 7F6545 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 937048 - RightColor: 957148 + MinColor: 937048 + MaxColor: 957148 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 906F47 - RightColor: 7B6041 + MinColor: 906F47 + MaxColor: 7B6041 ZOffset: -12 ZRamp: 0 Template@222: @@ -4599,23 +4601,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 8E6E49 - RightColor: 896B48 + MinColor: 8E6E49 + MaxColor: 896B48 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9C774D - RightColor: 90704B + MinColor: 9C774D + MaxColor: 90704B ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 866845 - RightColor: 8D6D48 + MinColor: 866845 + MaxColor: 8D6D48 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8A6B47 - RightColor: 9A764C + MinColor: 8A6B47 + MaxColor: 9A764C ZOffset: -12 ZRamp: 0 Template@223: @@ -4625,23 +4627,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 8B6C48 - RightColor: 96744C + MinColor: 8B6C48 + MaxColor: 96744C ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9B784E - RightColor: 91714B + MinColor: 9B784E + MaxColor: 91714B ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 8C6C47 - RightColor: 8C6C48 + MinColor: 8C6C47 + MaxColor: 8C6C48 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F704A - RightColor: 96734B + MinColor: 8F704A + MaxColor: 96734B ZOffset: -12 ZRamp: 0 Template@224: @@ -4651,38 +4653,38 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 8A6E4C - RightColor: 836746 + MinColor: 8A6E4C + MaxColor: 836746 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9F794D - RightColor: 9E784C + MinColor: 9F794D + MaxColor: 9E784C ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F6E49 - RightColor: 886946 + MinColor: 8F6E49 + MaxColor: 886946 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 96744D - RightColor: A47E52 + MinColor: 96744D + MaxColor: A47E52 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 91704A - RightColor: 8C6D47 + MinColor: 91704A + MaxColor: 8C6D47 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 856745 - RightColor: 91704B + MinColor: 856745 + MaxColor: 91704B ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 97744C - RightColor: 8E6E49 + MinColor: 97744C + MaxColor: 8E6E49 ZOffset: -12 ZRamp: 0 Template@225: @@ -4692,33 +4694,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 775E41 - RightColor: 6E5940 + MinColor: 775E41 + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8E6E48 - RightColor: 8B6B46 + MinColor: 8E6E48 + MaxColor: 8B6B46 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 9B754B - RightColor: 866743 + MinColor: 9B754B + MaxColor: 866743 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 806342 - RightColor: 70593E + MinColor: 806342 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 876845 - RightColor: 937049 + MinColor: 876845 + MaxColor: 937049 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 97744C - RightColor: 8F6F49 + MinColor: 97744C + MaxColor: 8F6F49 ZOffset: -12 ZRamp: 0 Template@226: @@ -4728,33 +4730,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 91704A - RightColor: 7F6343 + MinColor: 91704A + MaxColor: 7F6343 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 99744A - RightColor: 9D784C + MinColor: 99744A + MaxColor: 9D784C ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8D6D48 - RightColor: 96734A + MinColor: 8D6D48 + MaxColor: 96734A ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8D6D47 - RightColor: 95724A + MinColor: 8D6D47 + MaxColor: 95724A ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 816646 - RightColor: 846745 + MinColor: 816646 + MaxColor: 846745 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 846745 - RightColor: 816545 + MinColor: 846745 + MaxColor: 816545 ZOffset: -12 ZRamp: 0 Template@227: @@ -4764,38 +4766,38 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 8C6B47 - RightColor: 856745 + MinColor: 8C6B47 + MaxColor: 856745 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9F794D - RightColor: 9E784D + MinColor: 9F794D + MaxColor: 9E784D ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 715B40 - RightColor: 876946 + MinColor: 715B40 + MaxColor: 876946 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 906E47 - RightColor: 9D784D + MinColor: 906E47 + MaxColor: 9D784D ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 967249 - RightColor: 896A46 + MinColor: 967249 + MaxColor: 896A46 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 6E573D - RightColor: 826644 + MinColor: 6E573D + MaxColor: 826644 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 95734B - RightColor: 8F6F49 + MinColor: 95734B + MaxColor: 8F6F49 ZOffset: -12 ZRamp: 0 Template@228: @@ -4805,38 +4807,38 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 8A6C4A - RightColor: 856745 + MinColor: 8A6C4A + MaxColor: 856745 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: A07A4E - RightColor: 9E794D + MinColor: A07A4E + MaxColor: 9E794D ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8D6D48 - RightColor: 947149 + MinColor: 8D6D48 + MaxColor: 947149 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 916E47 - RightColor: 99754B + MinColor: 916E47 + MaxColor: 99754B ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 937148 - RightColor: 896A46 + MinColor: 937148 + MaxColor: 896A46 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 846745 - RightColor: 8F6D47 + MinColor: 846745 + MaxColor: 8F6D47 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 98744B - RightColor: 906F49 + MinColor: 98744B + MaxColor: 906F49 ZOffset: -12 ZRamp: 0 Template@229: @@ -4846,68 +4848,68 @@ Size: 4, 4 Tiles: 2: DirtRoad - LeftColor: 876C4B - RightColor: 896A46 + MinColor: 876C4B + MaxColor: 896A46 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9C774B - RightColor: 9F784C + MinColor: 9C774B + MaxColor: 9F784C ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7F6446 - RightColor: 7B6143 + MinColor: 7F6446 + MaxColor: 7B6143 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 9C784E - RightColor: 9D794F + MinColor: 9C784E + MaxColor: 9D794F ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 856644 - RightColor: 806443 + MinColor: 856644 + MaxColor: 806443 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 98744B - RightColor: 7F6444 + MinColor: 98744B + MaxColor: 7F6444 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 92714B - RightColor: 9E794F + MinColor: 92714B + MaxColor: 9E794F ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 987853 - RightColor: 977751 + MinColor: 987853 + MaxColor: 977751 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 96754E - RightColor: 876946 + MinColor: 96754E + MaxColor: 876946 ZOffset: -12 ZRamp: 0 12: DirtRoad - LeftColor: 896A46 - RightColor: 99754C + MinColor: 896A46 + MaxColor: 99754C ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 846949 - RightColor: 96744D + MinColor: 846949 + MaxColor: 96744D ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 8A6B48 - RightColor: 91724F + MinColor: 8A6B48 + MaxColor: 91724F ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: 866845 - RightColor: 95734C + MinColor: 866845 + MaxColor: 95734C ZOffset: -12 ZRamp: 0 Template@230: @@ -4917,48 +4919,48 @@ Size: 4, 4 Tiles: 2: DirtRoad - LeftColor: 876B4B - RightColor: 816544 + MinColor: 876B4B + MaxColor: 816544 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: A07A4D - RightColor: 9E784D + MinColor: A07A4D + MaxColor: 9E784D ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7E6548 - RightColor: 7B6143 + MinColor: 7E6548 + MaxColor: 7B6143 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: A17B4E - RightColor: 9F7A4E + MinColor: A17B4E + MaxColor: 9F7A4E ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 846745 - RightColor: 886A46 + MinColor: 846745 + MaxColor: 886A46 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 8D6D48 - RightColor: 866744 + MinColor: 8D6D48 + MaxColor: 866744 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 876845 - RightColor: 93714A + MinColor: 876845 + MaxColor: 93714A ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 806545 - RightColor: 866743 + MinColor: 806545 + MaxColor: 866743 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 846745 - RightColor: 816544 + MinColor: 846745 + MaxColor: 816544 ZOffset: -12 ZRamp: 0 Template@231: @@ -4968,48 +4970,48 @@ Size: 4, 4 Tiles: 2: DirtRoad - LeftColor: 856A4A - RightColor: 876845 + MinColor: 856A4A + MaxColor: 876845 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9B764B - RightColor: 9F784C + MinColor: 9B764B + MaxColor: 9F784C ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7E6446 - RightColor: 7A6042 + MinColor: 7E6446 + MaxColor: 7A6042 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 9B784F - RightColor: 99764E + MinColor: 9B784F + MaxColor: 99764E ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 795F40 - RightColor: 7F6443 + MinColor: 795F40 + MaxColor: 7F6443 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 866948 - RightColor: 7F6546 + MinColor: 866948 + MaxColor: 7F6546 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 947048 - RightColor: 99764C + MinColor: 947048 + MaxColor: 99764C ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 876B4A - RightColor: 856A4B + MinColor: 876B4A + MaxColor: 856A4B ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 8A6A45 - RightColor: 896B47 + MinColor: 8A6A45 + MaxColor: 896B47 ZOffset: -12 ZRamp: 0 Template@232: @@ -5019,48 +5021,48 @@ Size: 4, 4 Tiles: 2: DirtRoad - LeftColor: 816443 - RightColor: 826441 + MinColor: 816443 + MaxColor: 826441 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F6D47 - RightColor: 967248 + MinColor: 8F6D47 + MaxColor: 967248 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 795E3F - RightColor: 725B3F + MinColor: 795E3F + MaxColor: 725B3F ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 7C6346 - RightColor: 856845 + MinColor: 7C6346 + MaxColor: 856845 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 836542 - RightColor: 795E3F + MinColor: 836542 + MaxColor: 795E3F ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 876947 - RightColor: 876946 + MinColor: 876947 + MaxColor: 876946 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 947148 - RightColor: 896741 + MinColor: 947148 + MaxColor: 896741 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 7C6141 - RightColor: 7A6142 + MinColor: 7C6141 + MaxColor: 7A6142 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 8B6B46 - RightColor: 866846 + MinColor: 8B6B46 + MaxColor: 866846 ZOffset: -12 ZRamp: 0 Template@233: @@ -5070,63 +5072,63 @@ Size: 4, 4 Tiles: 0: Clear - LeftColor: 775E40 - RightColor: 755C3F + MinColor: 775E40 + MaxColor: 755C3F ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 8E6D47 - RightColor: 7D6243 + MinColor: 8E6D47 + MaxColor: 7D6243 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9C774C - RightColor: 93714A + MinColor: 9C774C + MaxColor: 93714A ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 9C764A - RightColor: 9D764A + MinColor: 9C764A + MaxColor: 9D764A ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 7C6344 - RightColor: 886945 + MinColor: 7C6344 + MaxColor: 886945 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 9E784D - RightColor: A27C4F + MinColor: 9E784D + MaxColor: A27C4F ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 856643 - RightColor: 8C6B44 + MinColor: 856643 + MaxColor: 8C6B44 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 765D41 - RightColor: 7A5F3F + MinColor: 765D41 + MaxColor: 7A5F3F ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 8E6E4A - RightColor: 916F48 + MinColor: 8E6E4A + MaxColor: 916F48 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 9D774B - RightColor: 916F48 + MinColor: 9D774B + MaxColor: 916F48 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 755D40 - RightColor: 6F593D + MinColor: 755D40 + MaxColor: 6F593D ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 8A6B46 - RightColor: 886A46 + MinColor: 8A6B46 + MaxColor: 886A46 ZOffset: -12 ZRamp: 0 Template@234: @@ -5136,33 +5138,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 8C6B45 - RightColor: 8D6B45 + MinColor: 8C6B45 + MaxColor: 8D6B45 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 9E784D - RightColor: 9B764B + MinColor: 9E784D + MaxColor: 9B764B ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 896C48 - RightColor: 886945 + MinColor: 896C48 + MaxColor: 886945 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: A27B4E - RightColor: 9B764B + MinColor: A27B4E + MaxColor: 9B764B ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7D6141 - RightColor: 806240 + MinColor: 7D6141 + MaxColor: 806240 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 866946 - RightColor: 866946 + MinColor: 866946 + MaxColor: 866946 ZOffset: -12 ZRamp: 0 Template@235: @@ -5172,18 +5174,18 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 876B4B - RightColor: 907049 + MinColor: 876B4B + MaxColor: 907049 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: A07A4E - RightColor: 9F794D + MinColor: A07A4E + MaxColor: 9F794D ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F6C44 - RightColor: 8B6B46 + MinColor: 8F6C44 + MaxColor: 8B6B46 ZOffset: -12 ZRamp: 0 Template@236: @@ -5193,18 +5195,18 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 8F6D47 - RightColor: 886844 + MinColor: 8F6D47 + MaxColor: 886844 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 9D774B - RightColor: 9D774B + MinColor: 9D774B + MaxColor: 9D774B ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 876845 - RightColor: 836543 + MinColor: 876845 + MaxColor: 836543 ZOffset: -12 ZRamp: 0 Template@237: @@ -5214,43 +5216,43 @@ Size: 4, 4 Tiles: 2: Clear - LeftColor: 715A3F - RightColor: 6E583D + MinColor: 715A3F + MaxColor: 6E583D ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7C6143 - RightColor: 755E41 + MinColor: 7C6143 + MaxColor: 755E41 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 796144 - RightColor: 745D43 + MinColor: 796144 + MaxColor: 745D43 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 775E42 - RightColor: 735B3F + MinColor: 775E42 + MaxColor: 735B3F ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 896C49 - RightColor: 775D3F + MinColor: 896C49 + MaxColor: 775D3F ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 926E46 - RightColor: 876742 + MinColor: 926E46 + MaxColor: 876742 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 765D40 - RightColor: 765E41 + MinColor: 765D40 + MaxColor: 765E41 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 836644 - RightColor: 856846 + MinColor: 836644 + MaxColor: 856846 ZOffset: -12 ZRamp: 0 Template@238: @@ -5260,48 +5262,48 @@ Size: 4, 3 Tiles: 1: Clear - LeftColor: 745D42 - RightColor: 725B41 + MinColor: 745D42 + MaxColor: 725B41 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 7B6345 - RightColor: 796144 + MinColor: 7B6345 + MaxColor: 796144 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 735B40 - RightColor: 70593F + MinColor: 735B40 + MaxColor: 70593F ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 886B49 - RightColor: 836949 + MinColor: 886B49 + MaxColor: 836949 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 9A7851 - RightColor: 896D4E + MinColor: 9A7851 + MaxColor: 896D4E ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 856C4E - RightColor: 7E6548 + MinColor: 856C4E + MaxColor: 7E6548 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 755D42 - RightColor: 715A3F + MinColor: 755D42 + MaxColor: 715A3F ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 8B6C47 - RightColor: 92714C + MinColor: 8B6C47 + MaxColor: 92714C ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 766046 - RightColor: 765F44 + MinColor: 766046 + MaxColor: 765F44 ZOffset: -12 ZRamp: 0 Template@239: @@ -5311,33 +5313,33 @@ Size: 3, 3 Tiles: 1: Clear - LeftColor: 7B6244 - RightColor: 775F43 + MinColor: 7B6244 + MaxColor: 775F43 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 816647 - RightColor: 725B3F + MinColor: 816647 + MaxColor: 725B3F ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 876947 - RightColor: 876947 + MinColor: 876947 + MaxColor: 876947 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 906E47 - RightColor: 866846 + MinColor: 906E47 + MaxColor: 866846 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 755D41 - RightColor: 775E40 + MinColor: 755D41 + MaxColor: 775E40 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 8A6A45 - RightColor: 846745 + MinColor: 8A6A45 + MaxColor: 846745 ZOffset: -12 ZRamp: 0 Template@240: @@ -5347,48 +5349,48 @@ Size: 4, 4 Tiles: 2: DirtRoad - LeftColor: 806341 - RightColor: 846643 + MinColor: 806341 + MaxColor: 846643 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8E6D47 - RightColor: 916F47 + MinColor: 8E6D47 + MaxColor: 916F47 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 735B3E - RightColor: 745B3E + MinColor: 735B3E + MaxColor: 745B3E ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 7B6142 - RightColor: 8A6943 + MinColor: 7B6142 + MaxColor: 8A6943 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 846541 - RightColor: 836542 + MinColor: 846541 + MaxColor: 836542 ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 71593D - RightColor: 765B3D + MinColor: 71593D + MaxColor: 765B3D ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 7E6140 - RightColor: 82633F + MinColor: 7E6140 + MaxColor: 82633F ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 7A5E3E - RightColor: 775D3E + MinColor: 7A5E3E + MaxColor: 775D3E ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 735B40 - RightColor: 775D3F + MinColor: 735B40 + MaxColor: 775D3F ZOffset: -12 ZRamp: 0 Template@241: @@ -5398,48 +5400,48 @@ Size: 3, 4 Tiles: 1: DirtRoad - LeftColor: 795F3F - RightColor: 856643 + MinColor: 795F3F + MaxColor: 856643 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7E6141 - RightColor: 957249 + MinColor: 7E6141 + MaxColor: 957249 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 705A3F - RightColor: 826443 + MinColor: 705A3F + MaxColor: 826443 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 937048 - RightColor: 8C6A43 + MinColor: 937048 + MaxColor: 8C6A43 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 775D40 - RightColor: 7E6240 + MinColor: 775D40 + MaxColor: 7E6240 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 796044 - RightColor: 846849 + MinColor: 796044 + MaxColor: 846849 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 866743 - RightColor: 836543 + MinColor: 866743 + MaxColor: 836543 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 725D43 - RightColor: 786043 + MinColor: 725D43 + MaxColor: 786043 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 735C41 - RightColor: 7A6041 + MinColor: 735C41 + MaxColor: 7A6041 ZOffset: -12 ZRamp: 0 Template@242: @@ -5449,33 +5451,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 796144 - RightColor: 7D6344 + MinColor: 796144 + MaxColor: 7D6344 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 896A46 - RightColor: 9C774C + MinColor: 896A46 + MaxColor: 9C774C ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 766045 - RightColor: 745D41 + MinColor: 766045 + MaxColor: 745D41 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 816545 - RightColor: 896B47 + MinColor: 816545 + MaxColor: 896B47 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 816443 - RightColor: 7F6443 + MinColor: 816443 + MaxColor: 7F6443 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 6F593F - RightColor: 7C6345 + MinColor: 6F593F + MaxColor: 7C6345 ZOffset: -12 ZRamp: 0 Template@243: @@ -5485,53 +5487,53 @@ Size: 5, 3 Tiles: 1: DirtRoad - LeftColor: 7D6242 - RightColor: 7A6142 + MinColor: 7D6242 + MaxColor: 7A6142 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 977349 - RightColor: 856541 + MinColor: 977349 + MaxColor: 856541 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: A0794D - RightColor: 96724A + MinColor: A0794D + MaxColor: 96724A ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: A17B4F - RightColor: A37C4F + MinColor: A17B4F + MaxColor: A37C4F ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 856845 - RightColor: 836643 + MinColor: 856845 + MaxColor: 836643 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 9D774B - RightColor: 997449 + MinColor: 9D774B + MaxColor: 997449 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 8A6B46 - RightColor: 977349 + MinColor: 8A6B46 + MaxColor: 977349 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 846644 - RightColor: 8D6D47 + MinColor: 846644 + MaxColor: 8D6D47 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 755D40 - RightColor: 7D6343 + MinColor: 755D40 + MaxColor: 7D6343 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 8A6B47 - RightColor: 866744 + MinColor: 8A6B47 + MaxColor: 866744 ZOffset: -12 ZRamp: 0 Template@244: @@ -5541,53 +5543,53 @@ Size: 3, 5 Tiles: 1: DirtRoad - LeftColor: 795F40 - RightColor: 7B6041 + MinColor: 795F40 + MaxColor: 7B6041 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 906F48 - RightColor: 9F7B50 + MinColor: 906F48 + MaxColor: 9F7B50 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 796143 - RightColor: 775F42 + MinColor: 796143 + MaxColor: 775F42 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8C6C47 - RightColor: 8F6F49 + MinColor: 8C6C47 + MaxColor: 8F6F49 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7F6546 - RightColor: 866946 + MinColor: 7F6546 + MaxColor: 866946 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 795F41 - RightColor: 8C6C48 + MinColor: 795F41 + MaxColor: 8C6C48 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 7E6343 - RightColor: 7A6041 + MinColor: 7E6343 + MaxColor: 7A6041 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 8E6F4A - RightColor: 846745 + MinColor: 8E6F4A + MaxColor: 846745 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 826442 - RightColor: 7B6142 + MinColor: 826442 + MaxColor: 7B6142 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 856845 - RightColor: 796143 + MinColor: 856845 + MaxColor: 796143 ZOffset: -12 ZRamp: 0 Template@245: @@ -5597,33 +5599,33 @@ Size: 2, 4 Tiles: 1: Clear - LeftColor: 7B6143 - RightColor: 765E41 + MinColor: 7B6143 + MaxColor: 765E41 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 786144 - RightColor: 7A6243 + MinColor: 786144 + MaxColor: 7A6243 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 7D6447 - RightColor: 796245 + MinColor: 7D6447 + MaxColor: 796245 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 826747 - RightColor: 846847 + MinColor: 826747 + MaxColor: 846847 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 755D41 - RightColor: 725B3F + MinColor: 755D41 + MaxColor: 725B3F ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 71593E - RightColor: 775F42 + MinColor: 71593E + MaxColor: 775F42 ZOffset: -12 ZRamp: 0 Template@246: @@ -5633,43 +5635,43 @@ Size: 4, 2 Tiles: 0: DirtRoad - LeftColor: 896B47 - RightColor: 7A6041 + MinColor: 896B47 + MaxColor: 7A6041 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 7B6243 - RightColor: 796043 + MinColor: 7B6243 + MaxColor: 796043 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 775E40 - RightColor: 755D3F + MinColor: 775E40 + MaxColor: 755D3F ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8A6B47 - RightColor: 816443 + MinColor: 8A6B47 + MaxColor: 816443 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 846745 - RightColor: 8B6C47 + MinColor: 846745 + MaxColor: 8B6C47 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7E6344 - RightColor: 8F6E48 + MinColor: 7E6344 + MaxColor: 8F6E48 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 846643 - RightColor: 906F48 + MinColor: 846643 + MaxColor: 906F48 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 836644 - RightColor: 98744B + MinColor: 836644 + MaxColor: 98744B ZOffset: -12 ZRamp: 0 Template@247: @@ -5679,43 +5681,43 @@ Size: 4, 2 Tiles: 0: DirtRoad - LeftColor: 8F6E48 - RightColor: 7E6242 + MinColor: 8F6E48 + MaxColor: 7E6242 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 92704A - RightColor: 8E6E49 + MinColor: 92704A + MaxColor: 8E6E49 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 917049 - RightColor: 856846 + MinColor: 917049 + MaxColor: 856846 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 96734A - RightColor: 806444 + MinColor: 96734A + MaxColor: 806444 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 816544 - RightColor: 896A45 + MinColor: 816544 + MaxColor: 896A45 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 796143 - RightColor: 896B47 + MinColor: 796143 + MaxColor: 896B47 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 765F43 - RightColor: 856947 + MinColor: 765F43 + MaxColor: 856947 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 785E41 - RightColor: 94724A + MinColor: 785E41 + MaxColor: 94724A ZOffset: -12 ZRamp: 0 Template@248: @@ -5725,43 +5727,43 @@ Size: 4, 2 Tiles: 0: DirtRoad - LeftColor: 97744B - RightColor: 7E6444 + MinColor: 97744B + MaxColor: 7E6444 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8C6D49 - RightColor: 816544 + MinColor: 8C6D49 + MaxColor: 816544 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7D6446 - RightColor: 776043 + MinColor: 7D6446 + MaxColor: 776043 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 92714C - RightColor: 7D6243 + MinColor: 92714C + MaxColor: 7D6243 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 896A46 - RightColor: 93714C + MinColor: 896A46 + MaxColor: 93714C ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7F6648 - RightColor: 90704B + MinColor: 7F6648 + MaxColor: 90704B ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 836847 - RightColor: 91724F + MinColor: 836847 + MaxColor: 91724F ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 866845 - RightColor: 95734C + MinColor: 866845 + MaxColor: 95734C ZOffset: -12 ZRamp: 0 Template@249: @@ -5771,43 +5773,43 @@ Size: 4, 2 Tiles: 0: DirtRoad - LeftColor: 8C6A44 - RightColor: 7E6140 + MinColor: 8C6A44 + MaxColor: 7E6140 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8B6B46 - RightColor: 896944 + MinColor: 8B6B46 + MaxColor: 896944 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 927049 - RightColor: 7E6343 + MinColor: 927049 + MaxColor: 7E6343 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8B6B46 - RightColor: 7E6343 + MinColor: 8B6B46 + MaxColor: 7E6343 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 7E6445 - RightColor: 947046 + MinColor: 7E6445 + MaxColor: 947046 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 806444 - RightColor: 8E6E48 + MinColor: 806444 + MaxColor: 8E6E48 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 7C6140 - RightColor: 927048 + MinColor: 7C6140 + MaxColor: 927048 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 7C6141 - RightColor: 916F47 + MinColor: 7C6141 + MaxColor: 916F47 ZOffset: -12 ZRamp: 0 Template@250: @@ -5817,33 +5819,33 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: 8A6B47 - RightColor: 7D6242 + MinColor: 8A6B47 + MaxColor: 7D6242 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 886945 - RightColor: 826544 + MinColor: 886945 + MaxColor: 826544 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 8D6C46 - RightColor: 826543 + MinColor: 8D6C46 + MaxColor: 826543 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 846745 - RightColor: 8C6C46 + MinColor: 846745 + MaxColor: 8C6C46 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 7E6242 - RightColor: 8E6D47 + MinColor: 7E6242 + MaxColor: 8E6D47 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7A5F40 - RightColor: 947047 + MinColor: 7A5F40 + MaxColor: 947047 ZOffset: -12 ZRamp: 0 Template@251: @@ -5853,23 +5855,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 8F6E48 - RightColor: 7C6143 + MinColor: 8F6E48 + MaxColor: 7C6143 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 866949 - RightColor: 7E6344 + MinColor: 866949 + MaxColor: 7E6344 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7F6342 - RightColor: 8E6E49 + MinColor: 7F6342 + MaxColor: 8E6E49 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 856947 - RightColor: 90704A + MinColor: 856947 + MaxColor: 90704A ZOffset: -12 ZRamp: 0 Template@252: @@ -5879,13 +5881,13 @@ Size: 1, 2 Tiles: 0: DirtRoad - LeftColor: 8F6E48 - RightColor: 7E6344 + MinColor: 8F6E48 + MaxColor: 7E6344 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 866846 - RightColor: 927048 + MinColor: 866846 + MaxColor: 927048 ZOffset: -12 ZRamp: 0 Template@253: @@ -5895,13 +5897,13 @@ Size: 1, 2 Tiles: 0: DirtRoad - LeftColor: 8F6D47 - RightColor: 7C6142 + MinColor: 8F6D47 + MaxColor: 7C6142 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 7F6240 - RightColor: 8B6B46 + MinColor: 7F6240 + MaxColor: 8B6B46 ZOffset: -12 ZRamp: 0 Template@254: @@ -5911,33 +5913,33 @@ Size: 3, 2 Tiles: 0: DirtRoad - LeftColor: 8C6C47 - RightColor: 7D6141 + MinColor: 8C6C47 + MaxColor: 7D6141 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 856745 - RightColor: 765D3F + MinColor: 856745 + MaxColor: 765D3F ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 785F41 - RightColor: 6F5A40 + MinColor: 785F41 + MaxColor: 6F5A40 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 816544 - RightColor: 916F48 + MinColor: 816544 + MaxColor: 916F48 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 806443 - RightColor: 856642 + MinColor: 806443 + MaxColor: 856642 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 745C41 - RightColor: 735B3E + MinColor: 745C41 + MaxColor: 735B3E ZOffset: -12 ZRamp: 0 Template@255: @@ -5947,23 +5949,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 97744B - RightColor: 715B3F + MinColor: 97744B + MaxColor: 715B3F ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 755E42 - RightColor: 6E5941 + MinColor: 755E42 + MaxColor: 6E5941 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 816544 - RightColor: 8C6D49 + MinColor: 816544 + MaxColor: 8C6D49 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 745D42 - RightColor: 745D42 + MinColor: 745D42 + MaxColor: 745D42 ZOffset: -12 ZRamp: 0 Template@256: @@ -5973,38 +5975,38 @@ Size: 3, 3 Tiles: 1: Clear - LeftColor: 715C42 - RightColor: 6F5A42 + MinColor: 715C42 + MaxColor: 6F5A42 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 755E44 - RightColor: 6D5941 + MinColor: 755E44 + MaxColor: 6D5941 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 886A47 - RightColor: 7A6143 + MinColor: 886A47 + MaxColor: 7A6143 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8A6B48 - RightColor: 806749 + MinColor: 8A6B48 + MaxColor: 806749 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 735D44 - RightColor: 755F44 + MinColor: 735D44 + MaxColor: 755F44 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 846847 - RightColor: 876A48 + MinColor: 846847 + MaxColor: 876A48 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 755E43 - RightColor: 775F42 + MinColor: 755E43 + MaxColor: 775F42 ZOffset: -12 ZRamp: 0 Template@257: @@ -6014,33 +6016,33 @@ Size: 3, 2 Tiles: 0: Clear - LeftColor: 795E40 - RightColor: 775E40 + MinColor: 795E40 + MaxColor: 775E40 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 886B49 - RightColor: 785F43 + MinColor: 886B49 + MaxColor: 785F43 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 8D6E49 - RightColor: 816544 + MinColor: 8D6E49 + MaxColor: 816544 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 755D41 - RightColor: 836643 + MinColor: 755D41 + MaxColor: 836643 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 796143 - RightColor: 8B6B47 + MinColor: 796143 + MaxColor: 8B6B47 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 846847 - RightColor: 9A764B + MinColor: 846847 + MaxColor: 9A764B ZOffset: -12 ZRamp: 0 Template@258: @@ -6050,23 +6052,23 @@ Size: 2, 2 Tiles: 0: Clear - LeftColor: 786145 - RightColor: 725B3F + MinColor: 786145 + MaxColor: 725B3F ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 846745 - RightColor: 806545 + MinColor: 846745 + MaxColor: 806545 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 775F43 - RightColor: 7E6242 + MinColor: 775F43 + MaxColor: 7E6242 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 715A3F - RightColor: 8D6E49 + MinColor: 715A3F + MaxColor: 8D6E49 ZOffset: -12 ZRamp: 0 Template@259: @@ -6076,23 +6078,23 @@ Size: 2, 2 Tiles: 0: Clear - LeftColor: 785E3F - RightColor: 7C6141 + MinColor: 785E3F + MaxColor: 7C6141 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8F6C45 - RightColor: 7C6243 + MinColor: 8F6C45 + MaxColor: 7C6243 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 775F41 - RightColor: 785F41 + MinColor: 775F41 + MaxColor: 785F41 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 7B6142 - RightColor: 927049 + MinColor: 7B6142 + MaxColor: 927049 ZOffset: -12 ZRamp: 0 Template@260: @@ -6102,43 +6104,43 @@ Size: 4, 3 Tiles: 0: DirtRoad - LeftColor: 906F48 - RightColor: 7C6142 + MinColor: 906F48 + MaxColor: 7C6142 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 846847 - RightColor: 735D40 + MinColor: 846847 + MaxColor: 735D40 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 7F6444 - RightColor: 8A6944 + MinColor: 7F6444 + MaxColor: 8A6944 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 816341 - RightColor: 967249 + MinColor: 816341 + MaxColor: 967249 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 886946 - RightColor: 7A6041 + MinColor: 886946 + MaxColor: 7A6041 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 896B48 - RightColor: 7E6344 + MinColor: 896B48 + MaxColor: 7E6344 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 735D43 - RightColor: 7B6143 + MinColor: 735D43 + MaxColor: 7B6143 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 785F41 - RightColor: 8B6C48 + MinColor: 785F41 + MaxColor: 8B6C48 ZOffset: -12 ZRamp: 0 Template@261: @@ -6148,43 +6150,43 @@ Size: 4, 3 Tiles: 2: Clear - LeftColor: 7C6141 - RightColor: 775E42 + MinColor: 7C6141 + MaxColor: 775E42 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 937149 - RightColor: 7D6242 + MinColor: 937149 + MaxColor: 7D6242 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 917049 - RightColor: 7F6344 + MinColor: 917049 + MaxColor: 7F6344 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 8B6B46 - RightColor: 856642 + MinColor: 8B6B46 + MaxColor: 856642 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 7B6040 - RightColor: 846745 + MinColor: 7B6040 + MaxColor: 846745 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 816443 - RightColor: 906E46 + MinColor: 816443 + MaxColor: 906E46 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 7A5F40 - RightColor: 826543 + MinColor: 7A5F40 + MaxColor: 826543 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 765E41 - RightColor: 796042 + MinColor: 765E41 + MaxColor: 796042 ZOffset: -12 ZRamp: 0 Template@262: @@ -6194,43 +6196,43 @@ Size: 4, 2 Tiles: 0: Clear - LeftColor: 755D40 - RightColor: 785E3F + MinColor: 755D40 + MaxColor: 785E3F ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 886946 - RightColor: 7D6342 + MinColor: 886946 + MaxColor: 7D6342 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 866745 - RightColor: 735D41 + MinColor: 866745 + MaxColor: 735D41 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 7A5F40 - RightColor: 70593F + MinColor: 7A5F40 + MaxColor: 70593F ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 705A40 - RightColor: 765D40 + MinColor: 705A40 + MaxColor: 765D40 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 735B3F - RightColor: 92704A + MinColor: 735B3F + MaxColor: 92704A ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 846643 - RightColor: 896843 + MinColor: 846643 + MaxColor: 896843 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 796144 - RightColor: 755D40 + MinColor: 796144 + MaxColor: 755D40 ZOffset: -12 ZRamp: 0 Template@263: @@ -6240,48 +6242,48 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: 775F41 - RightColor: 6E5A40 + MinColor: 775F41 + MaxColor: 6E5A40 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 715B40 - RightColor: 876946 + MinColor: 715B40 + MaxColor: 876946 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 906E48 - RightColor: 856846 + MinColor: 906E48 + MaxColor: 856846 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 7B6243 - RightColor: 6C5840 + MinColor: 7B6243 + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 725C41 - RightColor: 866845 + MinColor: 725C41 + MaxColor: 866845 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 916F48 - RightColor: 8D6D47 + MinColor: 916F48 + MaxColor: 8D6D47 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 816443 - RightColor: 70593E + MinColor: 816443 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 6E573D - RightColor: 826644 + MinColor: 6E573D + MaxColor: 826644 ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: 95734B - RightColor: 8E6E49 + MinColor: 95734B + MaxColor: 8E6E49 ZOffset: -12 ZRamp: 0 Template@264: @@ -6291,48 +6293,48 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: 7F6545 - RightColor: 6E5940 + MinColor: 7F6545 + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 715C43 - RightColor: 866946 + MinColor: 715C43 + MaxColor: 866946 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 906D46 - RightColor: 866844 + MinColor: 906D46 + MaxColor: 866844 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 7A6041 - RightColor: 6E583D + MinColor: 7A6041 + MaxColor: 6E583D ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 70593E - RightColor: 836745 + MinColor: 70593E + MaxColor: 836745 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 8B6B46 - RightColor: 896A45 + MinColor: 8B6B46 + MaxColor: 896A45 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 7F6342 - RightColor: 6E5A40 + MinColor: 7F6342 + MaxColor: 6E5A40 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 715C43 - RightColor: 7D6343 + MinColor: 715C43 + MaxColor: 7D6343 ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: 876845 - RightColor: 94714A + MinColor: 876845 + MaxColor: 94714A ZOffset: -12 ZRamp: 0 Template@265: @@ -6342,48 +6344,48 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: 886B47 - RightColor: 725B3F + MinColor: 886B47 + MaxColor: 725B3F ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 735E44 - RightColor: 866947 + MinColor: 735E44 + MaxColor: 866947 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 856947 - RightColor: 876946 + MinColor: 856947 + MaxColor: 876946 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 846947 - RightColor: 786042 + MinColor: 846947 + MaxColor: 786042 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 725A3E - RightColor: 866945 + MinColor: 725A3E + MaxColor: 866945 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 8C6D49 - RightColor: 846847 + MinColor: 8C6D49 + MaxColor: 846847 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 826645 - RightColor: 715A3E + MinColor: 826645 + MaxColor: 715A3E ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 725B40 - RightColor: 816645 + MinColor: 725B40 + MaxColor: 816645 ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: 8B6C48 - RightColor: 866845 + MinColor: 8B6C48 + MaxColor: 866845 ZOffset: -12 ZRamp: 0 Template@266: @@ -6393,48 +6395,48 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: 7A6041 - RightColor: 6E5940 + MinColor: 7A6041 + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 735D41 - RightColor: 876A47 + MinColor: 735D41 + MaxColor: 876A47 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 886A47 - RightColor: 846745 + MinColor: 886A47 + MaxColor: 846745 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 816645 - RightColor: 6E5940 + MinColor: 816645 + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 715B40 - RightColor: 836745 + MinColor: 715B40 + MaxColor: 836745 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 806442 - RightColor: 92714A + MinColor: 806442 + MaxColor: 92714A ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 816646 - RightColor: 735D42 + MinColor: 816646 + MaxColor: 735D42 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 735D42 - RightColor: 7C6344 + MinColor: 735D42 + MaxColor: 7C6344 ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: 906F4A - RightColor: 896B47 + MinColor: 906F4A + MaxColor: 896B47 ZOffset: -12 ZRamp: 0 Template@267: @@ -6444,33 +6446,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 816544 - RightColor: 70593E + MinColor: 816544 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 715A3E - RightColor: 816544 + MinColor: 715A3E + MaxColor: 816544 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8A6B47 - RightColor: 8A6B47 + MinColor: 8A6B47 + MaxColor: 8A6B47 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 876A47 - RightColor: 765E41 + MinColor: 876A47 + MaxColor: 765E41 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 725B3F - RightColor: 816443 + MinColor: 725B3F + MaxColor: 816443 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 93714A - RightColor: 91704A + MinColor: 93714A + MaxColor: 91704A ZOffset: -12 ZRamp: 0 Template@268: @@ -6480,18 +6482,18 @@ Size: 2, 2 Tiles: 1: DirtRoad - LeftColor: 826644 - RightColor: 70593E + MinColor: 826644 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 735C40 - RightColor: 866947 + MinColor: 735C40 + MaxColor: 866947 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8E6D48 - RightColor: 91714B + MinColor: 8E6D48 + MaxColor: 91714B ZOffset: -12 ZRamp: 0 Template@269: @@ -6501,18 +6503,18 @@ Size: 2, 2 Tiles: 1: DirtRoad - LeftColor: 7B6040 - RightColor: 6E583D + MinColor: 7B6040 + MaxColor: 6E583D ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 725B3F - RightColor: 856846 + MinColor: 725B3F + MaxColor: 856846 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8B6C47 - RightColor: 8C6C48 + MinColor: 8B6C47 + MaxColor: 8C6C48 ZOffset: -12 ZRamp: 0 Template@270: @@ -6522,48 +6524,48 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: 8B6C48 - RightColor: 735C3F + MinColor: 8B6C48 + MaxColor: 735C3F ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 6E583F - RightColor: 856947 + MinColor: 6E583F + MaxColor: 856947 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 92704A - RightColor: 906F49 + MinColor: 92704A + MaxColor: 906F49 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 7D6243 - RightColor: 70593E + MinColor: 7D6243 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 705B41 - RightColor: 816646 + MinColor: 705B41 + MaxColor: 816646 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 816545 - RightColor: 826645 + MinColor: 816545 + MaxColor: 826645 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 755C40 - RightColor: 70593E + MinColor: 755C40 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 14: Clear - LeftColor: 70583D - RightColor: 7A6042 + MinColor: 70583D + MaxColor: 7A6042 ZOffset: -12 ZRamp: 0 15: Clear - LeftColor: 755E42 - RightColor: 775F42 + MinColor: 755E42 + MaxColor: 775F42 ZOffset: -12 ZRamp: 0 Template@271: @@ -6573,53 +6575,53 @@ Size: 4, 5 Tiles: 1: DirtRoad - LeftColor: 94724B - RightColor: 745C41 + MinColor: 94724B + MaxColor: 745C41 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 6E583F - RightColor: 866A48 + MinColor: 6E583F + MaxColor: 866A48 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 92714B - RightColor: 91704A + MinColor: 92714B + MaxColor: 91704A ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 7B6042 - RightColor: 6F5A40 + MinColor: 7B6042 + MaxColor: 6F5A40 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 796043 - RightColor: 816545 + MinColor: 796043 + MaxColor: 816545 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 7D6142 - RightColor: 7B6041 + MinColor: 7D6142 + MaxColor: 7B6041 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 725A3E - RightColor: 715A3F + MinColor: 725A3E + MaxColor: 715A3F ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 725B40 - RightColor: 765D40 + MinColor: 725B40 + MaxColor: 765D40 ZOffset: -12 ZRamp: 0 14: Clear - LeftColor: 735B3F - RightColor: 735B3F + MinColor: 735B3F + MaxColor: 735B3F ZOffset: -12 ZRamp: 0 18: Clear - LeftColor: 725C42 - RightColor: 755D41 + MinColor: 725C42 + MaxColor: 755D41 ZOffset: -12 ZRamp: 0 Template@272: @@ -6629,33 +6631,33 @@ Size: 3, 3 Tiles: 1: DirtRoad - LeftColor: 806444 - RightColor: 6F593E + MinColor: 806444 + MaxColor: 6F593E ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 705B41 - RightColor: 866948 + MinColor: 705B41 + MaxColor: 866948 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8B6B47 - RightColor: 836645 + MinColor: 8B6B47 + MaxColor: 836645 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 755D40 - RightColor: 70593E + MinColor: 755D40 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 6E573D - RightColor: 7A6042 + MinColor: 6E573D + MaxColor: 7A6042 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 796144 - RightColor: 7B6143 + MinColor: 796144 + MaxColor: 7B6143 ZOffset: -12 ZRamp: 0 Template@273: @@ -6665,48 +6667,48 @@ Size: 4, 4 Tiles: 1: Clear - LeftColor: 765F42 - RightColor: 765E41 + MinColor: 765F42 + MaxColor: 765E41 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 725B40 - RightColor: 765D41 + MinColor: 725B40 + MaxColor: 765D41 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 785E41 - RightColor: 7D6243 + MinColor: 785E41 + MaxColor: 7D6243 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 7C6346 - RightColor: 705A3F + MinColor: 7C6346 + MaxColor: 705A3F ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 725C41 - RightColor: 7F6444 + MinColor: 725C41 + MaxColor: 7F6444 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 896C4A - RightColor: 806546 + MinColor: 896C4A + MaxColor: 806546 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 836745 - RightColor: 725C41 + MinColor: 836745 + MaxColor: 725C41 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 735C3F - RightColor: 7E6343 + MinColor: 735C3F + MaxColor: 7E6343 ZOffset: -12 ZRamp: 0 15: DirtRoad - LeftColor: 886945 - RightColor: 8D6D48 + MinColor: 886945 + MaxColor: 8D6D48 ZOffset: -12 ZRamp: 0 Template@274: @@ -6716,33 +6718,33 @@ Size: 2, 3 Tiles: 0: Clear - LeftColor: 725B41 - RightColor: 725B3F + MinColor: 725B41 + MaxColor: 725B3F ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 745C3F - RightColor: 6E583D + MinColor: 745C3F + MaxColor: 6E583D ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 70583D - RightColor: 7F6444 + MinColor: 70583D + MaxColor: 7F6444 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 886A48 - RightColor: 755E41 + MinColor: 886A48 + MaxColor: 755E41 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 70593F - RightColor: 745C41 + MinColor: 70593F + MaxColor: 745C41 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 8C6D48 - RightColor: 906E48 + MinColor: 8C6D48 + MaxColor: 906E48 ZOffset: -12 ZRamp: 0 Template@275: @@ -6752,33 +6754,33 @@ Size: 3, 3 Tiles: 1: Clear - LeftColor: 735A3D - RightColor: 6E583D + MinColor: 735A3D + MaxColor: 6E583D ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 6E573D - RightColor: 6F583C + MinColor: 6E573D + MaxColor: 6F583C ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 795F40 - RightColor: 7C6041 + MinColor: 795F40 + MaxColor: 7C6041 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7C603F - RightColor: 725A3E + MinColor: 7C603F + MaxColor: 725A3E ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 755D41 - RightColor: 81633F + MinColor: 755D41 + MaxColor: 81633F ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 876946 - RightColor: 8C6C48 + MinColor: 876946 + MaxColor: 8C6C48 ZOffset: -12 ZRamp: 0 Template@276: @@ -6788,58 +6790,58 @@ Size: 5, 3 Tiles: 1: DirtRoad - LeftColor: 8D6D47 - RightColor: 785E41 + MinColor: 8D6D47 + MaxColor: 785E41 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 7D6141 - RightColor: 735B3F + MinColor: 7D6141 + MaxColor: 735B3F ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 715A40 - RightColor: 8B6C47 + MinColor: 715A40 + MaxColor: 8B6C47 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 8E6D47 - RightColor: 8D6B44 + MinColor: 8E6D47 + MaxColor: 8D6B44 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 8C6B44 - RightColor: 856744 + MinColor: 8C6B44 + MaxColor: 856744 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 836645 - RightColor: 7D6242 + MinColor: 836645 + MaxColor: 7D6242 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 826646 - RightColor: 6F5A40 + MinColor: 826646 + MaxColor: 6F5A40 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 786042 - RightColor: 7F6443 + MinColor: 786042 + MaxColor: 7F6443 ZOffset: -12 ZRamp: 0 12: DirtRoad - LeftColor: 735C40 - RightColor: 836644 + MinColor: 735C40 + MaxColor: 836644 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 816443 - RightColor: 8D6B45 + MinColor: 816443 + MaxColor: 8D6B45 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 93724C - RightColor: 8E6E48 + MinColor: 93724C + MaxColor: 8E6E48 ZOffset: -12 ZRamp: 0 Template@277: @@ -6849,53 +6851,53 @@ Size: 3, 5 Tiles: 1: DirtRoad - LeftColor: 785F41 - RightColor: 735B3E + MinColor: 785F41 + MaxColor: 735B3E ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 796043 - RightColor: 8B6C47 + MinColor: 796043 + MaxColor: 8B6C47 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 8F704C - RightColor: 7E6343 + MinColor: 8F704C + MaxColor: 7E6343 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 725B3F - RightColor: 7A6143 + MinColor: 725B3F + MaxColor: 7A6143 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 8F704B - RightColor: 96754E + MinColor: 8F704B + MaxColor: 96754E ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 7F6647 - RightColor: 6F5A3F + MinColor: 7F6647 + MaxColor: 6F5A3F ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 7D6447 - RightColor: 8B6D49 + MinColor: 7D6447 + MaxColor: 8B6D49 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 92714A - RightColor: 775E41 + MinColor: 92714A + MaxColor: 775E41 ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 6F5A40 - RightColor: 7E6547 + MinColor: 6F5A40 + MaxColor: 7E6547 ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 866948 - RightColor: 8C6D4A + MinColor: 866948 + MaxColor: 8C6D4A ZOffset: -12 ZRamp: 0 Template@278: @@ -6905,48 +6907,48 @@ Size: 4, 4 Tiles: 1: Clear - LeftColor: 735C40 - RightColor: 70593E + MinColor: 735C40 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 70593F - RightColor: 715B40 + MinColor: 70593F + MaxColor: 715B40 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 816747 - RightColor: 7F6444 + MinColor: 816747 + MaxColor: 7F6444 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 735C40 - RightColor: 6F5A41 + MinColor: 735C40 + MaxColor: 6F5A41 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 6F5A40 - RightColor: 765F44 + MinColor: 6F5A40 + MaxColor: 765F44 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 806545 - RightColor: 7F6445 + MinColor: 806545 + MaxColor: 7F6445 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 7A6043 - RightColor: 6F583D + MinColor: 7A6043 + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 14: Clear - LeftColor: 6E573D - RightColor: 775F41 + MinColor: 6E573D + MaxColor: 775F41 ZOffset: -12 ZRamp: 0 15: Clear - LeftColor: 786042 - RightColor: 7B6143 + MinColor: 786042 + MaxColor: 7B6143 ZOffset: -12 ZRamp: 0 Template@279: @@ -6956,43 +6958,43 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: 7D6243 - RightColor: 916F48 + MinColor: 7D6243 + MaxColor: 916F48 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 96734A - RightColor: 7F6545 + MinColor: 96734A + MaxColor: 7F6545 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7D6547 - RightColor: 896B48 + MinColor: 7D6547 + MaxColor: 896B48 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F704B - RightColor: 836745 + MinColor: 8F704B + MaxColor: 836745 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 7A6142 - RightColor: 896B48 + MinColor: 7A6142 + MaxColor: 896B48 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 866A48 - RightColor: 796144 + MinColor: 866A48 + MaxColor: 796144 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 7F6444 - RightColor: 876946 + MinColor: 7F6444 + MaxColor: 876946 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 8F6F48 - RightColor: 775E40 + MinColor: 8F6F48 + MaxColor: 775E40 ZOffset: -12 ZRamp: 0 Template@280: @@ -7002,43 +7004,43 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: 876A48 - RightColor: 92714B + MinColor: 876A48 + MaxColor: 92714B ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 866845 - RightColor: 7B6142 + MinColor: 866845 + MaxColor: 7B6142 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7F6445 - RightColor: 91714B + MinColor: 7F6445 + MaxColor: 91714B ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 876A47 - RightColor: 765E41 + MinColor: 876A47 + MaxColor: 765E41 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 7C6447 - RightColor: 7F6444 + MinColor: 7C6447 + MaxColor: 7F6444 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 816746 - RightColor: 816645 + MinColor: 816746 + MaxColor: 816645 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 806443 - RightColor: 93714A + MinColor: 806443 + MaxColor: 93714A ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 886A47 - RightColor: 796042 + MinColor: 886A47 + MaxColor: 796042 ZOffset: -12 ZRamp: 0 Template@281: @@ -7048,43 +7050,43 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: 7C6243 - RightColor: 957148 + MinColor: 7C6243 + MaxColor: 957148 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8F6F49 - RightColor: 7B6141 + MinColor: 8F6F49 + MaxColor: 7B6141 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7F6444 - RightColor: 8E6F4A + MinColor: 7F6444 + MaxColor: 8E6F4A ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 90714C - RightColor: 786042 + MinColor: 90714C + MaxColor: 786042 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 806545 - RightColor: 8A6D49 + MinColor: 806545 + MaxColor: 8A6D49 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 91714B - RightColor: 786144 + MinColor: 91714B + MaxColor: 786144 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 816645 - RightColor: 906F48 + MinColor: 816645 + MaxColor: 906F48 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 92704A - RightColor: 7C6242 + MinColor: 92704A + MaxColor: 7C6242 ZOffset: -12 ZRamp: 0 Template@282: @@ -7094,43 +7096,43 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: 7D6345 - RightColor: 8F6E48 + MinColor: 7D6345 + MaxColor: 8F6E48 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 896B47 - RightColor: 775E40 + MinColor: 896B47 + MaxColor: 775E40 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 816747 - RightColor: 8E6F4A + MinColor: 816747 + MaxColor: 8E6F4A ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F704B - RightColor: 7E6445 + MinColor: 8F704B + MaxColor: 7E6445 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 866947 - RightColor: 8C6E49 + MinColor: 866947 + MaxColor: 8C6E49 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 94734D - RightColor: 886A46 + MinColor: 94734D + MaxColor: 886A46 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 836745 - RightColor: 95744D + MinColor: 836745 + MaxColor: 95744D ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 896C49 - RightColor: 745D40 + MinColor: 896C49 + MaxColor: 745D40 ZOffset: -12 ZRamp: 0 Template@283: @@ -7140,33 +7142,33 @@ Size: 2, 3 Tiles: 0: DirtRoad - LeftColor: 7B6143 - RightColor: 92714B + MinColor: 7B6143 + MaxColor: 92714B ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8F6E48 - RightColor: 7D6242 + MinColor: 8F6E48 + MaxColor: 7D6242 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7E6548 - RightColor: 896B48 + MinColor: 7E6548 + MaxColor: 896B48 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8E6E49 - RightColor: 806545 + MinColor: 8E6E49 + MaxColor: 806545 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 816543 - RightColor: 957249 + MinColor: 816543 + MaxColor: 957249 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 8A6B47 - RightColor: 7A6244 + MinColor: 8A6B47 + MaxColor: 7A6244 ZOffset: -12 ZRamp: 0 Template@284: @@ -7176,23 +7178,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 816544 - RightColor: 8F6E48 + MinColor: 816544 + MaxColor: 8F6E48 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 93714A - RightColor: 7D6343 + MinColor: 93714A + MaxColor: 7D6343 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7E6446 - RightColor: 8D6E49 + MinColor: 7E6446 + MaxColor: 8D6E49 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F6F49 - RightColor: 7D6444 + MinColor: 8F6F49 + MaxColor: 7D6444 ZOffset: -12 ZRamp: 0 Template@285: @@ -7202,13 +7204,13 @@ Size: 2, 1 Tiles: 0: DirtRoad - LeftColor: 7E6444 - RightColor: 94714A + MinColor: 7E6444 + MaxColor: 94714A ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 886A46 - RightColor: 745D41 + MinColor: 886A46 + MaxColor: 745D41 ZOffset: -12 ZRamp: 0 Template@286: @@ -7218,13 +7220,13 @@ Size: 2, 1 Tiles: 0: DirtRoad - LeftColor: 836745 - RightColor: 917049 + MinColor: 836745 + MaxColor: 917049 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8D6D48 - RightColor: 826747 + MinColor: 8D6D48 + MaxColor: 826747 ZOffset: -12 ZRamp: 0 Template@287: @@ -7234,43 +7236,43 @@ Size: 2, 4 Tiles: 0: Clear - LeftColor: 725C41 - RightColor: 725B40 + MinColor: 725C41 + MaxColor: 725B40 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 70593F - RightColor: 6F593E + MinColor: 70593F + MaxColor: 6F593E ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 725B41 - RightColor: 765F44 + MinColor: 725B41 + MaxColor: 765F44 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 7A644A - RightColor: 6F5B42 + MinColor: 7A644A + MaxColor: 6F5B42 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 846A4C - RightColor: 846A4B + MinColor: 846A4C + MaxColor: 846A4B ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 8B6F4E - RightColor: 786044 + MinColor: 8B6F4E + MaxColor: 786044 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 806444 - RightColor: 96744C + MinColor: 806444 + MaxColor: 96744C ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 8D6F4B - RightColor: 816748 + MinColor: 8D6F4B + MaxColor: 816748 ZOffset: -12 ZRamp: 0 Template@288: @@ -7280,38 +7282,38 @@ Size: 3, 3 Tiles: 0: Clear - LeftColor: 725B40 - RightColor: 705B41 + MinColor: 725B40 + MaxColor: 705B41 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 70593E - RightColor: 6F593E + MinColor: 70593E + MaxColor: 6F593E ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 765D40 - RightColor: 846644 + MinColor: 765D40 + MaxColor: 846644 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 7D6447 - RightColor: 705A3F + MinColor: 7D6447 + MaxColor: 705A3F ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 765F43 - RightColor: 765E41 + MinColor: 765F43 + MaxColor: 765E41 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 7F6546 - RightColor: 886A48 + MinColor: 7F6546 + MaxColor: 886A48 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 93714A - RightColor: 866946 + MinColor: 93714A + MaxColor: 866946 ZOffset: -12 ZRamp: 0 Template@289: @@ -7321,28 +7323,28 @@ Size: 2, 3 Tiles: 0: Clear - LeftColor: 735B3F - RightColor: 70593E + MinColor: 735B3F + MaxColor: 70593E ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 7C6345 - RightColor: 775F42 + MinColor: 7C6345 + MaxColor: 775F42 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 786043 - RightColor: 755E42 + MinColor: 786043 + MaxColor: 755E42 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 7B6142 - RightColor: 876945 + MinColor: 7B6142 + MaxColor: 876945 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 906F49 - RightColor: 7E6445 + MinColor: 906F49 + MaxColor: 7E6445 ZOffset: -12 ZRamp: 0 Template@290: @@ -7352,38 +7354,38 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: 816646 - RightColor: 937048 + MinColor: 816646 + MaxColor: 937048 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8E6F4A - RightColor: 806646 + MinColor: 8E6F4A + MaxColor: 806646 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 7E6547 - RightColor: 8B6D4C + MinColor: 7E6547 + MaxColor: 8B6D4C ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 866845 - RightColor: 806444 + MinColor: 866845 + MaxColor: 806444 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 765D40 - RightColor: 7B6244 + MinColor: 765D40 + MaxColor: 7B6244 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 765E42 - RightColor: 775E41 + MinColor: 765E42 + MaxColor: 775E41 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 725D43 - RightColor: 725B40 + MinColor: 725D43 + MaxColor: 725B40 ZOffset: -12 ZRamp: 0 Template@291: @@ -7393,43 +7395,43 @@ Size: 2, 4 Tiles: 0: DirtRoad - LeftColor: 7A6143 - RightColor: 92714A + MinColor: 7A6143 + MaxColor: 92714A ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 927049 - RightColor: 7E6342 + MinColor: 927049 + MaxColor: 7E6342 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 785E40 - RightColor: 8D6C47 + MinColor: 785E40 + MaxColor: 8D6C47 ZOffset: -12 ZRamp: 0 3: DirtRoad - LeftColor: 8F6E49 - RightColor: 7F6444 + MinColor: 8F6E49 + MaxColor: 7F6444 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 7C6447 - RightColor: 876846 + MinColor: 7C6447 + MaxColor: 876846 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 7D6345 - RightColor: 7A6143 + MinColor: 7D6345 + MaxColor: 7A6143 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 6F593D - RightColor: 7A6143 + MinColor: 6F593D + MaxColor: 7A6143 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 6F593F - RightColor: 6F5A40 + MinColor: 6F593F + MaxColor: 6F5A40 ZOffset: -12 ZRamp: 0 Template@292: @@ -7439,23 +7441,23 @@ Size: 2, 2 Tiles: 0: DirtRoad - LeftColor: 7B6245 - RightColor: 90714D + MinColor: 7B6245 + MaxColor: 90714D ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 836849 - RightColor: 796043 + MinColor: 836849 + MaxColor: 796043 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 725D41 - RightColor: 7D6445 + MinColor: 725D41 + MaxColor: 7D6445 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 745C41 - RightColor: 765E40 + MinColor: 745C41 + MaxColor: 765E40 ZOffset: -12 ZRamp: 0 Template@293: @@ -7465,43 +7467,43 @@ Size: 3, 4 Tiles: 1: DirtRoad - LeftColor: 7A6143 - RightColor: 8F6D47 + MinColor: 7A6143 + MaxColor: 8F6D47 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 916F48 - RightColor: 7C6142 + MinColor: 916F48 + MaxColor: 7C6142 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 886A47 - RightColor: 8F6F4A + MinColor: 886A47 + MaxColor: 8F6F4A ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 7B6142 - RightColor: 745E43 + MinColor: 7B6142 + MaxColor: 745E43 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 7A6043 - RightColor: 836746 + MinColor: 7A6043 + MaxColor: 836746 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 906E49 - RightColor: 896A46 + MinColor: 906E49 + MaxColor: 896A46 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 7E6547 - RightColor: 896A47 + MinColor: 7E6547 + MaxColor: 896A47 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 8E6D48 - RightColor: 7F6545 + MinColor: 8E6D48 + MaxColor: 7F6545 ZOffset: -12 ZRamp: 0 Template@294: @@ -7511,43 +7513,43 @@ Size: 3, 4 Tiles: 0: DirtRoad - LeftColor: 775E41 - RightColor: 906F4A + MinColor: 775E41 + MaxColor: 906F4A ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 90714D - RightColor: 7A6144 + MinColor: 90714D + MaxColor: 7A6144 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 735D42 - RightColor: 785F43 + MinColor: 735D42 + MaxColor: 785F43 ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 92714B - RightColor: 826645 + MinColor: 92714B + MaxColor: 826645 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 836644 - RightColor: 9B774D + MinColor: 836644 + MaxColor: 9B774D ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 806546 - RightColor: 715A3E + MinColor: 806546 + MaxColor: 715A3E ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 826747 - RightColor: 90704A + MinColor: 826747 + MaxColor: 90704A ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 896B48 - RightColor: 786042 + MinColor: 896B48 + MaxColor: 786042 ZOffset: -12 ZRamp: 0 Template@295: @@ -7557,28 +7559,28 @@ Size: 2, 3 Tiles: 0: Clear - LeftColor: 755D41 - RightColor: 7A6144 + MinColor: 755D41 + MaxColor: 7A6144 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 866A4B - RightColor: 725C41 + MinColor: 866A4B + MaxColor: 725C41 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 70593E - RightColor: 7A6143 + MinColor: 70593E + MaxColor: 7A6143 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 8A6C49 - RightColor: 7E6445 + MinColor: 8A6C49 + MaxColor: 7E6445 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 725A3E - RightColor: 7C6243 + MinColor: 725A3E + MaxColor: 7C6243 ZOffset: -12 ZRamp: 0 Template@296: @@ -7589,85 +7591,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 6F6B66 - RightColor: 554F46 + MinColor: 6F6B66 + MaxColor: 554F46 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6E6A61 - RightColor: 635E57 + MinColor: 6E6A61 + MaxColor: 635E57 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 6E5A41 - RightColor: 6C5840 + MinColor: 6E5A41 + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 33312F - RightColor: 4B4A48 + MinColor: 33312F + MaxColor: 4B4A48 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 313131 - RightColor: 585855 + MinColor: 313131 + MaxColor: 585855 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 6C573F - RightColor: 6B5E4D + MinColor: 6C573F + MaxColor: 6B5E4D ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 302D27 - RightColor: 2D2B27 + MinColor: 302D27 + MaxColor: 2D2B27 ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 2C2B28 - RightColor: 2D2B27 + MinColor: 2C2B28 + MaxColor: 2D2B27 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 705C44 - RightColor: 625D55 + MinColor: 705C44 + MaxColor: 625D55 ZOffset: -12 ZRamp: 0 9: Road Height: 4 - LeftColor: 4C4A48 - RightColor: 35322F + MinColor: 4C4A48 + MaxColor: 35322F ZOffset: -12 ZRamp: 0 10: Road Height: 4 - LeftColor: 4D4C4A - RightColor: 32312F + MinColor: 4D4C4A + MaxColor: 32312F ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 6F583E - RightColor: 5F584F + MinColor: 6F583E + MaxColor: 5F584F ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 5B564E - RightColor: 777571 + MinColor: 5B564E + MaxColor: 777571 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 6E6150 - RightColor: 858279 + MinColor: 6E6150 + MaxColor: 858279 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 705A40 - RightColor: 70593E + MinColor: 705A40 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 Template@297: @@ -7678,85 +7680,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 6F6B66 - RightColor: 554F47 + MinColor: 6F6B66 + MaxColor: 554F47 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6F6C66 - RightColor: 5E5C58 + MinColor: 6F6C66 + MaxColor: 5E5C58 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 15273B - RightColor: 0F2339 + MinColor: 15273B + MaxColor: 0F2339 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 33312F - RightColor: 4B4A48 + MinColor: 33312F + MaxColor: 4B4A48 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 313131 - RightColor: 585855 + MinColor: 313131 + MaxColor: 585855 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 1E2933 - RightColor: 3E454B + MinColor: 1E2933 + MaxColor: 3E454B ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 302D27 - RightColor: 2D2B27 + MinColor: 302D27 + MaxColor: 2D2B27 ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 2C2B28 - RightColor: 2D2B27 + MinColor: 2C2B28 + MaxColor: 2D2B27 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 1F2C39 - RightColor: 515355 + MinColor: 1F2C39 + MaxColor: 515355 ZOffset: -12 ZRamp: 0 9: Road Height: 4 - LeftColor: 4C4A48 - RightColor: 35322F + MinColor: 4C4A48 + MaxColor: 35322F ZOffset: -12 ZRamp: 0 10: Road Height: 4 - LeftColor: 4D4C4A - RightColor: 32312F + MinColor: 4D4C4A + MaxColor: 32312F ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 233344 - RightColor: 4D4F4F + MinColor: 233344 + MaxColor: 4D4F4F ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 5B564E - RightColor: 777571 + MinColor: 5B564E + MaxColor: 777571 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 504F4B - RightColor: 84827A + MinColor: 504F4B + MaxColor: 84827A ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 243341 - RightColor: 16273C + MinColor: 243341 + MaxColor: 16273C ZOffset: -12 ZRamp: 0 Template@298: @@ -7766,61 +7768,61 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 726F6A - RightColor: 585147 + MinColor: 726F6A + MaxColor: 585147 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 33312F - RightColor: 605E5A + MinColor: 33312F + MaxColor: 605E5A ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 313131 - RightColor: 494846 + MinColor: 313131 + MaxColor: 494846 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 302D27 - RightColor: 2D2B27 + MinColor: 302D27 + MaxColor: 2D2B27 ZOffset: -12 ZRamp: 0 5: Road Height: 4 - LeftColor: 2C2B28 - RightColor: 2D2B27 + MinColor: 2C2B28 + MaxColor: 2D2B27 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 4C4C4B - RightColor: 35322F + MinColor: 4C4C4B + MaxColor: 35322F ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 4B4945 - RightColor: 323130 + MinColor: 4B4945 + MaxColor: 323130 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 8C8579 - RightColor: 8A857A + MinColor: 8C8579 + MaxColor: 8A857A ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 534D43 - RightColor: 6A6865 + MinColor: 534D43 + MaxColor: 6A6865 ZOffset: -12 ZRamp: 0 Template@299: @@ -7831,85 +7833,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4F4940 - RightColor: 63605B + MinColor: 4F4940 + MaxColor: 63605B ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 4B4A48 - RightColor: 33312F + MinColor: 4B4A48 + MaxColor: 33312F ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 2D2B27 - RightColor: 302D27 + MinColor: 2D2B27 + MaxColor: 302D27 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 34322F - RightColor: 494844 + MinColor: 34322F + MaxColor: 494844 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 5B5955 - RightColor: 564D42 + MinColor: 5B5955 + MaxColor: 564D42 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 998E7D - RightColor: 98958D + MinColor: 998E7D + MaxColor: 98958D ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 494845 - RightColor: 484745 + MinColor: 494845 + MaxColor: 484745 ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 2D2B28 - RightColor: 2D2C2A + MinColor: 2D2B28 + MaxColor: 2D2C2A ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 32312E - RightColor: 4B4945 + MinColor: 32312E + MaxColor: 4B4945 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 645A4C - RightColor: 6A655B + MinColor: 645A4C + MaxColor: 6A655B ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 6D573D - RightColor: 6F593E + MinColor: 6D573D + MaxColor: 6F593E ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 6E583D - RightColor: 887A68 + MinColor: 6E583D + MaxColor: 887A68 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 725C41 - RightColor: 8D867A + MinColor: 725C41 + MaxColor: 8D867A ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 6F5A40 - RightColor: 8B8478 + MinColor: 6F5A40 + MaxColor: 8B8478 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 705C43 - RightColor: 6C573E + MinColor: 705C43 + MaxColor: 6C573E ZOffset: -12 ZRamp: 0 Template@300: @@ -7920,85 +7922,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4F4940 - RightColor: 63605B + MinColor: 4F4940 + MaxColor: 63605B ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 4B4A48 - RightColor: 33312F + MinColor: 4B4A48 + MaxColor: 33312F ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 2D2B27 - RightColor: 302D27 + MinColor: 2D2B27 + MaxColor: 302D27 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 34322F - RightColor: 494844 + MinColor: 34322F + MaxColor: 494844 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 5B5955 - RightColor: 564D43 + MinColor: 5B5955 + MaxColor: 564D43 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 888989 - RightColor: 98958D + MinColor: 888989 + MaxColor: 98958D ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 494845 - RightColor: 484745 + MinColor: 494845 + MaxColor: 484745 ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 2D2B28 - RightColor: 2D2C2A + MinColor: 2D2B28 + MaxColor: 2D2C2A ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 32312E - RightColor: 4B4945 + MinColor: 32312E + MaxColor: 4B4945 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 5D584F - RightColor: 67635B + MinColor: 5D584F + MaxColor: 67635B ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 0E2036 - RightColor: 192A3E + MinColor: 0E2036 + MaxColor: 192A3E ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 102135 - RightColor: 666B6E + MinColor: 102135 + MaxColor: 666B6E ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 122439 - RightColor: 7F7F7C + MinColor: 122439 + MaxColor: 7F7F7C ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 112337 - RightColor: 80817E + MinColor: 112337 + MaxColor: 80817E ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 112135 - RightColor: 223041 + MinColor: 112135 + MaxColor: 223041 ZOffset: -12 ZRamp: 0 Template@301: @@ -8008,61 +8010,61 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 4C4C4C - RightColor: 4C4B4A + MinColor: 4C4C4C + MaxColor: 4C4B4A ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 2D2B27 - RightColor: 302D27 + MinColor: 2D2B27 + MaxColor: 302D27 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 35332F - RightColor: 4D4C4B + MinColor: 35332F + MaxColor: 4D4C4B ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 685F55 - RightColor: 6B665F + MinColor: 685F55 + MaxColor: 6B665F ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 564D40 - RightColor: 605E5B + MinColor: 564D40 + MaxColor: 605E5B ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 4D4D4C - RightColor: 333230 + MinColor: 4D4D4C + MaxColor: 333230 ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 2D2B27 - RightColor: 2C2B28 + MinColor: 2D2B27 + MaxColor: 2C2B28 ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 313130 - RightColor: 4B4C4C + MinColor: 313130 + MaxColor: 4B4C4C ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 5E5B57 - RightColor: 56534E + MinColor: 5E5B57 + MaxColor: 56534E ZOffset: -12 ZRamp: 0 Template@302: @@ -8072,56 +8074,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 706E6A - RightColor: 64625D + MinColor: 706E6A + MaxColor: 64625D ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6E5A41 - RightColor: 6C5840 + MinColor: 6E5A41 + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 313131 - RightColor: 626262 + MinColor: 313131 + MaxColor: 626262 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 6C573F - RightColor: 6B5F50 + MinColor: 6C573F + MaxColor: 6B5F50 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 2C2B28 - RightColor: 2D2B27 + MinColor: 2C2B28 + MaxColor: 2D2B27 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 705C44 - RightColor: 625D56 + MinColor: 705C44 + MaxColor: 625D56 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 4E4D4B - RightColor: 323130 + MinColor: 4E4D4B + MaxColor: 323130 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 6F583E - RightColor: 5F5A52 + MinColor: 6F583E + MaxColor: 5F5A52 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 9B958B - RightColor: 918F8A + MinColor: 9B958B + MaxColor: 918F8A ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 705A40 - RightColor: 70593E + MinColor: 705A40 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 Template@303: @@ -8131,56 +8133,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 706E6A - RightColor: 64625D + MinColor: 706E6A + MaxColor: 64625D ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6E5A41 - RightColor: 6C5840 + MinColor: 6E5A41 + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3B3B3A - RightColor: 646364 + MinColor: 3B3B3A + MaxColor: 646364 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 6C573F - RightColor: 6B5F50 + MinColor: 6C573F + MaxColor: 6B5F50 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 343432 - RightColor: 363430 + MinColor: 343432 + MaxColor: 363430 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 705C44 - RightColor: 625D56 + MinColor: 705C44 + MaxColor: 625D56 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 464645 - RightColor: 363635 + MinColor: 464645 + MaxColor: 363635 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 6F583E - RightColor: 5F5A52 + MinColor: 6F583E + MaxColor: 5F5A52 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 8F8981 - RightColor: 8C8A85 + MinColor: 8F8981 + MaxColor: 8C8A85 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 715C42 - RightColor: 70593E + MinColor: 715C42 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 Template@304: @@ -8190,56 +8192,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706C - RightColor: 64625E + MinColor: 71706C + MaxColor: 64625E ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 746552 - RightColor: 6B5740 + MinColor: 746552 + MaxColor: 6B5740 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 333230 - RightColor: 656565 + MinColor: 333230 + MaxColor: 656565 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 6C6357 - RightColor: 6F6559 + MinColor: 6C6357 + MaxColor: 6F6559 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 333230 - RightColor: 343330 + MinColor: 333230 + MaxColor: 343330 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 665643 - RightColor: 5F5B54 + MinColor: 665643 + MaxColor: 5F5B54 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 525252 - RightColor: 3A3A3A + MinColor: 525252 + MaxColor: 3A3A3A ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 6B5840 - RightColor: 5A554E + MinColor: 6B5840 + MaxColor: 5A554E ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 989289 - RightColor: 8A8884 + MinColor: 989289 + MaxColor: 8A8884 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 705A40 - RightColor: 705A3E + MinColor: 705A40 + MaxColor: 705A3E ZOffset: -12 ZRamp: 0 Template@305: @@ -8249,56 +8251,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706C - RightColor: 63615C + MinColor: 71706C + MaxColor: 63615C ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 786958 - RightColor: 73614D + MinColor: 786958 + MaxColor: 73614D ZOffset: -12 ZRamp: 0 2: Rough Height: 4 - LeftColor: 3B3B3B - RightColor: 5B5B5C + MinColor: 3B3B3B + MaxColor: 5B5B5C ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 6C6357 - RightColor: 6F6559 + MinColor: 6C6357 + MaxColor: 6F6559 ZOffset: -12 ZRamp: 0 4: Rough Height: 4 - LeftColor: 3B3B39 - RightColor: 373634 + MinColor: 3B3B39 + MaxColor: 373634 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 5C5245 - RightColor: 5F5B54 + MinColor: 5C5245 + MaxColor: 5F5B54 ZOffset: -12 ZRamp: 0 6: Rough Height: 4 - LeftColor: 4B4B4B - RightColor: 3C3C3C + MinColor: 4B4B4B + MaxColor: 3C3C3C ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 6B5840 - RightColor: 59544E + MinColor: 6B5840 + MaxColor: 59544E ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 8F8981 - RightColor: 8B8884 + MinColor: 8F8981 + MaxColor: 8B8884 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 715C42 - RightColor: 705A3E + MinColor: 715C42 + MaxColor: 705A3E ZOffset: -12 ZRamp: 0 Template@306: @@ -8308,53 +8310,53 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 7B7A77 - RightColor: 878580 + MinColor: 7B7A77 + MaxColor: 878580 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 786958 - RightColor: 73614D + MinColor: 786958 + MaxColor: 73614D ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 656562 - RightColor: 72716F + MinColor: 656562 + MaxColor: 72716F ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 6A6358 - RightColor: 685743 + MinColor: 6A6358 + MaxColor: 685743 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6C6B6A - RightColor: 84837F + MinColor: 6C6B6A + MaxColor: 84837F ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 575147 - RightColor: 5F513F + MinColor: 575147 + MaxColor: 5F513F ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 747371 - RightColor: 8F8E89 + MinColor: 747371 + MaxColor: 8F8E89 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 61584B - RightColor: 62533F + MinColor: 61584B + MaxColor: 62533F ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 90877C - RightColor: 747068 + MinColor: 90877C + MaxColor: 747068 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 5D5040 - RightColor: 63533F + MinColor: 5D5040 + MaxColor: 63533F ZOffset: -12 ZRamp: 0 Template@307: @@ -8365,50 +8367,50 @@ Tiles: 1: Road Height: 4 - LeftColor: 4C4C4C - RightColor: 4C4B4A + MinColor: 4C4C4C + MaxColor: 4C4B4A ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 2D2B28 - RightColor: 2D2C2A + MinColor: 2D2B28 + MaxColor: 2D2C2A ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 32312F - RightColor: 4E4D4C + MinColor: 32312F + MaxColor: 4E4D4C ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 756D63 - RightColor: 807D78 + MinColor: 756D63 + MaxColor: 807D78 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 6D573D - RightColor: 988F83 + MinColor: 6D573D + MaxColor: 988F83 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 6E583D - RightColor: 928C83 + MinColor: 6E583D + MaxColor: 928C83 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 725C41 - RightColor: 918A80 + MinColor: 725C41 + MaxColor: 918A80 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 6F5A40 - RightColor: 908A81 + MinColor: 6F5A40 + MaxColor: 908A81 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 Template@308: @@ -8419,50 +8421,50 @@ Tiles: 1: Road Height: 4 - LeftColor: 4E4E4E - RightColor: 4E4E4D + MinColor: 4E4E4E + MaxColor: 4E4E4D ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 32302D - RightColor: 353430 + MinColor: 32302D + MaxColor: 353430 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 363736 - RightColor: 606061 + MinColor: 363736 + MaxColor: 606061 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 756D63 - RightColor: 807D78 + MinColor: 756D63 + MaxColor: 807D78 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 6D573D - RightColor: 988F83 + MinColor: 6D573D + MaxColor: 988F83 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 6E583D - RightColor: 928C83 + MinColor: 6E583D + MaxColor: 928C83 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 725C41 - RightColor: 918A80 + MinColor: 725C41 + MaxColor: 918A80 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 6F5A40 - RightColor: 908A81 + MinColor: 6F5A40 + MaxColor: 908A81 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 Template@309: @@ -8473,50 +8475,50 @@ Tiles: 1: Road Height: 4 - LeftColor: 545454 - RightColor: 4B4A49 + MinColor: 545454 + MaxColor: 4B4A49 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3A3833 - RightColor: 312E29 + MinColor: 3A3833 + MaxColor: 312E29 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 333231 - RightColor: 4D4C4C + MinColor: 333231 + MaxColor: 4D4C4C ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 756E63 - RightColor: 7F7C77 + MinColor: 756E63 + MaxColor: 7F7C77 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 6D573E - RightColor: 90887D + MinColor: 6D573E + MaxColor: 90887D ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 6E593F - RightColor: 827D75 + MinColor: 6E593F + MaxColor: 827D75 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 705E48 - RightColor: 878178 + MinColor: 705E48 + MaxColor: 878178 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 6D5940 - RightColor: 87847D + MinColor: 6D5940 + MaxColor: 87847D ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 705D46 - RightColor: 6A563E + MinColor: 705D46 + MaxColor: 6A563E ZOffset: -12 ZRamp: 0 Template@310: @@ -8527,50 +8529,50 @@ Tiles: 1: Rough Height: 4 - LeftColor: 414142 - RightColor: 4C4C4C + MinColor: 414142 + MaxColor: 4C4C4C ZOffset: -12 ZRamp: 0 2: Rough Height: 4 - LeftColor: 363430 - RightColor: 32302D + MinColor: 363430 + MaxColor: 32302D ZOffset: -12 ZRamp: 0 3: Rough Height: 4 - LeftColor: 313131 - RightColor: 555555 + MinColor: 313131 + MaxColor: 555555 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 757068 - RightColor: 7B7872 + MinColor: 757068 + MaxColor: 7B7872 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 6E593F - RightColor: 8F877D + MinColor: 6E593F + MaxColor: 8F877D ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 695843 - RightColor: 827E78 + MinColor: 695843 + MaxColor: 827E78 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 6E5E49 - RightColor: 878178 + MinColor: 6E5E49 + MaxColor: 878178 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 6D5940 - RightColor: 8C8882 + MinColor: 6D5940 + MaxColor: 8C8882 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 705D46 - RightColor: 726351 + MinColor: 705D46 + MaxColor: 726351 ZOffset: -12 ZRamp: 0 Template@311: @@ -8581,50 +8583,50 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 757068 - RightColor: 76726D + MinColor: 757068 + MaxColor: 76726D ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 6E5A42 - RightColor: 817567 + MinColor: 6E5A42 + MaxColor: 817567 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 695843 - RightColor: 827D76 + MinColor: 695843 + MaxColor: 827D76 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 6E5E49 - RightColor: 8F8B84 + MinColor: 6E5E49 + MaxColor: 8F8B84 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 61584C - RightColor: 85837D + MinColor: 61584C + MaxColor: 85837D ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 756C62 - RightColor: 706353 + MinColor: 756C62 + MaxColor: 706353 ZOffset: -12 ZRamp: 0 Template@312: @@ -8634,18 +8636,18 @@ Size: 1, 3 Tiles: 0: Road - LeftColor: 42403C - RightColor: 4D4D4B + MinColor: 42403C + MaxColor: 4D4D4B ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 403C34 - RightColor: 3C3934 + MinColor: 403C34 + MaxColor: 3C3934 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 4D4B46 - RightColor: 44413C + MinColor: 4D4B46 + MaxColor: 44413C ZOffset: -12 ZRamp: 0 Template@313: @@ -8655,18 +8657,18 @@ Size: 3, 1 Tiles: 0: Road - LeftColor: 4D4D4B - RightColor: 42403C + MinColor: 4D4D4B + MaxColor: 42403C ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 3C3934 - RightColor: 403C34 + MinColor: 3C3934 + MaxColor: 403C34 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 44413C - RightColor: 4D4B46 + MinColor: 44413C + MaxColor: 4D4B46 ZOffset: -12 ZRamp: 0 Template@314: @@ -8676,48 +8678,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 3E3E3C - RightColor: 3E3E3C + MinColor: 3E3E3C + MaxColor: 3E3E3C ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 383838 - RightColor: 3A3B3B + MinColor: 383838 + MaxColor: 3A3B3B ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 383838 - RightColor: 444443 + MinColor: 383838 + MaxColor: 444443 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 3B3B3B - RightColor: 3A3A3A + MinColor: 3B3B3B + MaxColor: 3A3A3A ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 363636 - RightColor: 383838 + MinColor: 363636 + MaxColor: 383838 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 3A3A3A - RightColor: 3B3B3B + MinColor: 3A3A3A + MaxColor: 3B3B3B ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 454443 - RightColor: 393939 + MinColor: 454443 + MaxColor: 393939 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 3B3C3C - RightColor: 393939 + MinColor: 3B3C3C + MaxColor: 393939 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 3F3E3D - RightColor: 3F3E3C + MinColor: 3F3E3D + MaxColor: 3F3E3C ZOffset: -12 ZRamp: 0 Template@315: @@ -8727,48 +8729,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 3F3F3D - RightColor: 42403D + MinColor: 3F3F3D + MaxColor: 42403D ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 3C3934 - RightColor: 403C34 + MinColor: 3C3934 + MaxColor: 403C34 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 3E3C39 - RightColor: 424240 + MinColor: 3E3C39 + MaxColor: 424240 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 3B3B3B - RightColor: 3E3D3A + MinColor: 3B3B3B + MaxColor: 3E3D3A ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 3C3A35 - RightColor: 3B3935 + MinColor: 3C3A35 + MaxColor: 3B3935 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 3C3B3B - RightColor: 3A3A3A + MinColor: 3C3B3B + MaxColor: 3A3A3A ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 424241 - RightColor: 3D3C39 + MinColor: 424241 + MaxColor: 3D3C39 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 3C3A36 - RightColor: 3C3B38 + MinColor: 3C3A36 + MaxColor: 3C3B38 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 41403D - RightColor: 3F3E3B + MinColor: 41403D + MaxColor: 3F3E3B ZOffset: -12 ZRamp: 0 Template@316: @@ -8778,48 +8780,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 43403D - RightColor: 403F3D + MinColor: 43403D + MaxColor: 403F3D ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 3E3C3A - RightColor: 3C3D3C + MinColor: 3E3C3A + MaxColor: 3C3D3C ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 3D3D3D - RightColor: 424241 + MinColor: 3D3D3D + MaxColor: 424241 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 3B3935 - RightColor: 3C3A35 + MinColor: 3B3935 + MaxColor: 3C3A35 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 403C34 - RightColor: 3C3934 + MinColor: 403C34 + MaxColor: 3C3934 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 3B3A35 - RightColor: 3C3934 + MinColor: 3B3A35 + MaxColor: 3C3934 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 424242 - RightColor: 3C3C3B + MinColor: 424242 + MaxColor: 3C3C3B ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 3C3C3C - RightColor: 3E3D3B + MinColor: 3C3C3C + MaxColor: 3E3D3B ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 3F3E3B - RightColor: 413F3C + MinColor: 3F3E3B + MaxColor: 413F3C ZOffset: -12 ZRamp: 0 Template@317: @@ -8829,48 +8831,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 42403C - RightColor: 4D4D4B + MinColor: 42403C + MaxColor: 4D4D4B ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 41403D - RightColor: 4C4B48 + MinColor: 41403D + MaxColor: 4C4B48 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 404040 - RightColor: 4C4C4A + MinColor: 404040 + MaxColor: 4C4C4A ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 3C3A36 - RightColor: 3C3A34 + MinColor: 3C3A36 + MaxColor: 3C3A34 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 3F3C35 - RightColor: 3C3934 + MinColor: 3F3C35 + MaxColor: 3C3934 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 3B3A35 - RightColor: 3C3934 + MinColor: 3B3A35 + MaxColor: 3C3934 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 424242 - RightColor: 3C3C3B + MinColor: 424242 + MaxColor: 3C3C3B ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 3C3C3C - RightColor: 3E3D3B + MinColor: 3C3C3C + MaxColor: 3E3D3B ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 3F3E3B - RightColor: 413F3C + MinColor: 3F3E3B + MaxColor: 413F3C ZOffset: -12 ZRamp: 0 Template@318: @@ -8880,48 +8882,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 3F3F3D - RightColor: 42403D + MinColor: 3F3F3D + MaxColor: 42403D ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 3C3A36 - RightColor: 3D3B37 + MinColor: 3C3A36 + MaxColor: 3D3B37 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 413F3D - RightColor: 504F4B + MinColor: 413F3D + MaxColor: 504F4B ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 3B3B3B - RightColor: 3E3D3A + MinColor: 3B3B3B + MaxColor: 3E3D3A ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 3C3A35 - RightColor: 3B3935 + MinColor: 3C3A35 + MaxColor: 3B3935 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 403F3E - RightColor: 4F4D4A + MinColor: 403F3E + MaxColor: 4F4D4A ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 424241 - RightColor: 3D3C39 + MinColor: 424241 + MaxColor: 3D3C39 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 3C3934 - RightColor: 3C3A36 + MinColor: 3C3934 + MaxColor: 3C3A36 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 403F3D - RightColor: 4C4D4C + MinColor: 403F3D + MaxColor: 4C4D4C ZOffset: -12 ZRamp: 0 Template@319: @@ -8931,48 +8933,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 43403D - RightColor: 403F3D + MinColor: 43403D + MaxColor: 403F3D ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 3E3C3A - RightColor: 3C3D3C + MinColor: 3E3C3A + MaxColor: 3C3D3C ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 3D3D3D - RightColor: 424241 + MinColor: 3D3D3D + MaxColor: 424241 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 3B3935 - RightColor: 3C3A35 + MinColor: 3B3935 + MaxColor: 3C3A35 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 3C3A36 - RightColor: 3C3A34 + MinColor: 3C3A36 + MaxColor: 3C3A34 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 3C3B37 - RightColor: 3B3A35 + MinColor: 3C3B37 + MaxColor: 3B3A35 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 4F4D4A - RightColor: 403F3E + MinColor: 4F4D4A + MaxColor: 403F3E ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 4C4D4C - RightColor: 403F3D + MinColor: 4C4D4C + MaxColor: 403F3D ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 504F4B - RightColor: 413F3D + MinColor: 504F4B + MaxColor: 413F3D ZOffset: -12 ZRamp: 0 Template@320: @@ -8982,48 +8984,48 @@ Size: 3, 3 Tiles: 0: Road - LeftColor: 4C4B48 - RightColor: 41403D + MinColor: 4C4B48 + MaxColor: 41403D ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 3C3934 - RightColor: 3F3C35 + MinColor: 3C3934 + MaxColor: 3F3C35 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 3E3C39 - RightColor: 424240 + MinColor: 3E3C39 + MaxColor: 424240 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 4E4D4A - RightColor: 42413E + MinColor: 4E4D4A + MaxColor: 42413E ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 3C3A35 - RightColor: 3B3935 + MinColor: 3C3A35 + MaxColor: 3B3935 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 3C3B3B - RightColor: 3A3A3A + MinColor: 3C3B3B + MaxColor: 3A3A3A ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 4D4D4B - RightColor: 42403C + MinColor: 4D4D4B + MaxColor: 42403C ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 3C3A36 - RightColor: 3D3B37 + MinColor: 3C3A36 + MaxColor: 3D3B37 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 41403D - RightColor: 3F3E3B + MinColor: 41403D + MaxColor: 3F3E3B ZOffset: -12 ZRamp: 0 Template@321: @@ -9033,63 +9035,63 @@ Size: 4, 3 Tiles: 0: Clear - LeftColor: 6C5940 - RightColor: 6C5A42 + MinColor: 6C5940 + MaxColor: 6C5A42 ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 4C4439 - RightColor: 534D44 + MinColor: 4C4439 + MaxColor: 534D44 ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 62513F - RightColor: 5E503F + MinColor: 62513F + MaxColor: 5E503F ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 45403B - RightColor: 4F4C47 + MinColor: 45403B + MaxColor: 4F4C47 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 68543C - RightColor: 5E4F3D + MinColor: 68543C + MaxColor: 5E4F3D ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 695741 - RightColor: 64523D + MinColor: 695741 + MaxColor: 64523D ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 5D4E3C - RightColor: 50473D + MinColor: 5D4E3C + MaxColor: 50473D ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 453F35 - RightColor: 3D3A34 + MinColor: 453F35 + MaxColor: 3D3A34 ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 615546 - RightColor: 4F463C + MinColor: 615546 + MaxColor: 4F463C ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 655746 - RightColor: 67553F + MinColor: 655746 + MaxColor: 67553F ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 655544 - RightColor: 62513E + MinColor: 655544 + MaxColor: 62513E ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 554B3F - RightColor: 45413C + MinColor: 554B3F + MaxColor: 45413C ZOffset: -12 ZRamp: 0 Template@322: @@ -9099,63 +9101,63 @@ Size: 4, 3 Tiles: 0: Road - LeftColor: 42403C - RightColor: 544C43 + MinColor: 42403C + MaxColor: 544C43 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 4B453C - RightColor: 63523D + MinColor: 4B453C + MaxColor: 63523D ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 5C4E3D - RightColor: 655643 + MinColor: 5C4E3D + MaxColor: 655643 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 63503B - RightColor: 6E573D + MinColor: 63503B + MaxColor: 6E573D ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 403C34 - RightColor: 3C3934 + MinColor: 403C34 + MaxColor: 3C3934 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 454038 - RightColor: 403C35 + MinColor: 454038 + MaxColor: 403C35 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 443F36 - RightColor: 524739 + MinColor: 443F36 + MaxColor: 524739 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 544A3E - RightColor: 6D573D + MinColor: 544A3E + MaxColor: 6D573D ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 4E4A44 - RightColor: 48423B + MinColor: 4E4A44 + MaxColor: 48423B ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 61503D - RightColor: 5D5040 + MinColor: 61503D + MaxColor: 5D5040 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 695D4F - RightColor: 5C4F3F + MinColor: 695D4F + MaxColor: 5C4F3F ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 65543F - RightColor: 68553E + MinColor: 65543F + MaxColor: 68553E ZOffset: -12 ZRamp: 0 Template@323: @@ -9165,63 +9167,63 @@ Size: 4, 3 Tiles: 0: DirtRoad - LeftColor: 47423B - RightColor: 63523D + MinColor: 47423B + MaxColor: 63523D ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 423E37 - RightColor: 544A3D + MinColor: 423E37 + MaxColor: 544A3D ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 4F4A43 - RightColor: 565047 + MinColor: 4F4A43 + MaxColor: 565047 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 534D45 - RightColor: 564E43 + MinColor: 534D45 + MaxColor: 564E43 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 423C34 - RightColor: 413B32 + MinColor: 423C34 + MaxColor: 413B32 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 484339 - RightColor: 433E37 + MinColor: 484339 + MaxColor: 433E37 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 49453D - RightColor: 44433F + MinColor: 49453D + MaxColor: 44433F ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 4F483F - RightColor: 45413B + MinColor: 4F483F + MaxColor: 45413B ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 504B43 - RightColor: 53493C + MinColor: 504B43 + MaxColor: 53493C ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 605342 - RightColor: 45423E + MinColor: 605342 + MaxColor: 45423E ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: 544D45 - RightColor: 4C4843 + MinColor: 544D45 + MaxColor: 4C4843 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 524F4A - RightColor: 403E3B + MinColor: 524F4A + MaxColor: 403E3B ZOffset: -12 ZRamp: 0 Template@324: @@ -9231,63 +9233,63 @@ Size: 3, 4 Tiles: 0: DirtRoad - LeftColor: 4E4D4A - RightColor: 42413E + MinColor: 4E4D4A + MaxColor: 42413E ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 403C34 - RightColor: 3C3A35 + MinColor: 403C34 + MaxColor: 3C3A35 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 403F3D - RightColor: 4C4D4C + MinColor: 403F3D + MaxColor: 4C4D4C ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 574C3F - RightColor: 4A443C + MinColor: 574C3F + MaxColor: 4A443C ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 484034 - RightColor: 433E34 + MinColor: 484034 + MaxColor: 433E34 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 4B443B - RightColor: 504E49 + MinColor: 4B443B + MaxColor: 504E49 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 6C5942 - RightColor: 63513E + MinColor: 6C5942 + MaxColor: 63513E ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 5E4F3C - RightColor: 51483D + MinColor: 5E4F3C + MaxColor: 51483D ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 63523E - RightColor: 645441 + MinColor: 63523E + MaxColor: 645441 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 6D583E - RightColor: 6D5940 + MinColor: 6D583E + MaxColor: 6D5940 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 6F5A40 - RightColor: 6B573E + MinColor: 6F5A40 + MaxColor: 6B573E ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 705B41 - RightColor: 67553E + MinColor: 705B41 + MaxColor: 67553E ZOffset: -12 ZRamp: 0 Template@325: @@ -9297,63 +9299,63 @@ Size: 3, 4 Tiles: 0: Clear - LeftColor: 615341 - RightColor: 66543E + MinColor: 615341 + MaxColor: 66543E ZOffset: -12 ZRamp: 0 1: Clear - LeftColor: 67533C - RightColor: 6D583E + MinColor: 67533C + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 6F583E - RightColor: 6E583D + MinColor: 6F583E + MaxColor: 6E583D ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 5D5040 - RightColor: 62523F + MinColor: 5D5040 + MaxColor: 62523F ZOffset: -12 ZRamp: 0 4: DirtRoad - LeftColor: 50473D - RightColor: 5C4E3D + MinColor: 50473D + MaxColor: 5C4E3D ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 62503E - RightColor: 6C583F + MinColor: 62503E + MaxColor: 6C583F ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 5E5449 - RightColor: 53493E + MinColor: 5E5449 + MaxColor: 53493E ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 433E35 - RightColor: 494135 + MinColor: 433E35 + MaxColor: 494135 ZOffset: -12 ZRamp: 0 8: DirtRoad - LeftColor: 46423C - RightColor: 554B3E + MinColor: 46423C + MaxColor: 554B3E ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 4C4C4A - RightColor: 484440 + MinColor: 4C4C4A + MaxColor: 484440 ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 474036 - RightColor: 453F36 + MinColor: 474036 + MaxColor: 453F36 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 41403E - RightColor: 4F4D4A + MinColor: 41403E + MaxColor: 4F4D4A ZOffset: -12 ZRamp: 0 Template@326: @@ -9363,63 +9365,63 @@ Size: 3, 4 Tiles: 0: DirtRoad - LeftColor: 4D4C4A - RightColor: 404040 + MinColor: 4D4C4A + MaxColor: 404040 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 373631 - RightColor: 373531 + MinColor: 373631 + MaxColor: 373531 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 3E3A33 - RightColor: 4D4C49 + MinColor: 3E3A33 + MaxColor: 4D4C49 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 4C4C49 - RightColor: 3E3D3B + MinColor: 4C4C49 + MaxColor: 3E3D3B ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: 2D2C2A - RightColor: 2F2C26 + MinColor: 2D2C2A + MaxColor: 2F2C26 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 4F4336 - RightColor: 5E5345 + MinColor: 4F4336 + MaxColor: 5E5345 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 524B42 - RightColor: 3C3935 + MinColor: 524B42 + MaxColor: 3C3935 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 363532 - RightColor: 36332E + MinColor: 363532 + MaxColor: 36332E ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 403E39 - RightColor: 4D4A44 + MinColor: 403E39 + MaxColor: 4D4A44 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 494845 - RightColor: 3E3C3A + MinColor: 494845 + MaxColor: 3E3C3A ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 3C3A36 - RightColor: 373632 + MinColor: 3C3A36 + MaxColor: 373632 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 41403D - RightColor: 514F4C + MinColor: 41403D + MaxColor: 514F4C ZOffset: -12 ZRamp: 0 Template@327: @@ -9429,83 +9431,83 @@ Size: 4, 5 Tiles: 0: Road - LeftColor: 43403C - RightColor: 4E4D4B + MinColor: 43403C + MaxColor: 4E4D4B ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 41403F - RightColor: 4C4C4A + MinColor: 41403F + MaxColor: 4C4C4A ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 43413E - RightColor: 4E4D4A + MinColor: 43413E + MaxColor: 4E4D4A ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 42403D - RightColor: 4C4B48 + MinColor: 42403D + MaxColor: 4C4B48 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 474035 - RightColor: 413C34 + MinColor: 474035 + MaxColor: 413C34 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 453F36 - RightColor: 413C34 + MinColor: 453F36 + MaxColor: 413C34 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 50473B - RightColor: 4B4337 + MinColor: 50473B + MaxColor: 4B4337 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 51493E - RightColor: 413D37 + MinColor: 51493E + MaxColor: 413D37 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 544E46 - RightColor: 52493E + MinColor: 544E46 + MaxColor: 52493E ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 756047 - RightColor: 62513F + MinColor: 756047 + MaxColor: 62513F ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 7F684C - RightColor: 665643 + MinColor: 7F684C + MaxColor: 665643 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 57534D - RightColor: 44423D + MinColor: 57534D + MaxColor: 44423D ZOffset: -12 ZRamp: 0 12: DirtRoad - LeftColor: 866948 - RightColor: 826747 + MinColor: 866948 + MaxColor: 826747 ZOffset: -12 ZRamp: 0 13: DirtRoad - LeftColor: 957148 - RightColor: 9A764D + MinColor: 957148 + MaxColor: 9A764D ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 886B4A - RightColor: 856B4B + MinColor: 886B4A + MaxColor: 856B4B ZOffset: -12 ZRamp: 0 17: DirtRoad - LeftColor: 8A6A46 - RightColor: 8A6B48 + MinColor: 8A6A46 + MaxColor: 8A6B48 ZOffset: -12 ZRamp: 0 Template@328: @@ -9515,73 +9517,73 @@ Size: 4, 4 Tiles: 1: DirtRoad - LeftColor: 876B4B - RightColor: 806443 + MinColor: 876B4B + MaxColor: 806443 ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: A0794D - RightColor: 9E784D + MinColor: A0794D + MaxColor: 9E784D ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 45423D - RightColor: 574F44 + MinColor: 45423D + MaxColor: 574F44 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 625341 - RightColor: 80674B + MinColor: 625341 + MaxColor: 80674B ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 755F46 - RightColor: 7F674B + MinColor: 755F46 + MaxColor: 7F674B ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 55493C - RightColor: 5A4F40 + MinColor: 55493C + MaxColor: 5A4F40 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 3C3A35 - RightColor: 453F35 + MinColor: 3C3A35 + MaxColor: 453F35 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 494237 - RightColor: 514738 + MinColor: 494237 + MaxColor: 514738 ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 4C4337 - RightColor: 504638 + MinColor: 4C4337 + MaxColor: 504638 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 474137 - RightColor: 413C33 + MinColor: 474137 + MaxColor: 413C33 ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 4F4D4A - RightColor: 42403C + MinColor: 4F4D4A + MaxColor: 42403C ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 52504B - RightColor: 44413C + MinColor: 52504B + MaxColor: 44413C ZOffset: -12 ZRamp: 0 14: Road - LeftColor: 4F4F4D - RightColor: 47433E + MinColor: 4F4F4D + MaxColor: 47433E ZOffset: -12 ZRamp: 0 15: Road - LeftColor: 514E47 - RightColor: 46423D + MinColor: 514E47 + MaxColor: 46423D ZOffset: -12 ZRamp: 0 Template@329: @@ -9591,83 +9593,83 @@ Size: 4, 5 Tiles: 1: DirtRoad - LeftColor: 816545 - RightColor: 94714A + MinColor: 816545 + MaxColor: 94714A ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 98754B - RightColor: 7F6545 + MinColor: 98754B + MaxColor: 7F6545 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 46433F - RightColor: 514E49 + MinColor: 46433F + MaxColor: 514E49 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 5C5041 - RightColor: 826B4F + MinColor: 5C5041 + MaxColor: 826B4F ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 7B6447 - RightColor: 73614A + MinColor: 7B6447 + MaxColor: 73614A ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 4D463E - RightColor: 4F4C48 + MinColor: 4D463E + MaxColor: 4F4C48 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 3E3B36 - RightColor: 433E36 + MinColor: 3E3B36 + MaxColor: 433E36 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 53493D - RightColor: 5F513E + MinColor: 53493D + MaxColor: 5F513E ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 6B5841 - RightColor: 5D4D39 + MinColor: 6B5841 + MaxColor: 5D4D39 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 443E36 - RightColor: 3E3B34 + MinColor: 443E36 + MaxColor: 3E3B34 ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 4C4D4C - RightColor: 43413D + MinColor: 4C4D4C + MaxColor: 43413D ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 6B5D4B - RightColor: 715D45 + MinColor: 6B5D4B + MaxColor: 715D45 ZOffset: -12 ZRamp: 0 14: Road - LeftColor: 7F694E - RightColor: 625442 + MinColor: 7F694E + MaxColor: 625442 ZOffset: -12 ZRamp: 0 15: Road - LeftColor: 59544C - RightColor: 44423E + MinColor: 59544C + MaxColor: 44423E ZOffset: -12 ZRamp: 0 17: DirtRoad - LeftColor: 7E6444 - RightColor: 896A46 + MinColor: 7E6444 + MaxColor: 896A46 ZOffset: -12 ZRamp: 0 18: DirtRoad - LeftColor: 8F6F48 - RightColor: 785F40 + MinColor: 8F6F48 + MaxColor: 785F40 ZOffset: -12 ZRamp: 0 Template@330: @@ -9677,83 +9679,83 @@ Size: 5, 4 Tiles: 2: Road - LeftColor: 60584E - RightColor: 4E473F + MinColor: 60584E + MaxColor: 4E473F ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 554B3D - RightColor: 423D35 + MinColor: 554B3D + MaxColor: 423D35 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 44413C - RightColor: 4D4B46 + MinColor: 44413C + MaxColor: 4D4B46 ZOffset: -12 ZRamp: 0 6: DirtRoad - LeftColor: 7D6548 - RightColor: 7B6143 + MinColor: 7D6548 + MaxColor: 7B6143 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 937450 - RightColor: 846A4C + MinColor: 937450 + MaxColor: 846A4C ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 5F513F - RightColor: 51483C + MinColor: 5F513F + MaxColor: 51483C ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 46433F - RightColor: 514F4A + MinColor: 46433F + MaxColor: 514F4A ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 8D6D47 - RightColor: 866744 + MinColor: 8D6D47 + MaxColor: 866744 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 876946 - RightColor: 93714A + MinColor: 876946 + MaxColor: 93714A ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 7C6446 - RightColor: 7E6446 + MinColor: 7C6446 + MaxColor: 7E6446 ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 61523F - RightColor: 534A3D + MinColor: 61523F + MaxColor: 534A3D ZOffset: -12 ZRamp: 0 14: Road - LeftColor: 42413E - RightColor: 4D4D4C + MinColor: 42413E + MaxColor: 4D4D4C ZOffset: -12 ZRamp: 0 16: DirtRoad - LeftColor: 846745 - RightColor: 836745 + MinColor: 846745 + MaxColor: 836745 ZOffset: -12 ZRamp: 0 17: Road - LeftColor: 534D44 - RightColor: 584E41 + MinColor: 534D44 + MaxColor: 584E41 ZOffset: -12 ZRamp: 0 18: Road - LeftColor: 433F38 - RightColor: 51493D + MinColor: 433F38 + MaxColor: 51493D ZOffset: -12 ZRamp: 0 19: Road - LeftColor: 44423D - RightColor: 53514C + MinColor: 44423D + MaxColor: 53514C ZOffset: -12 ZRamp: 0 Template@331: @@ -9763,73 +9765,73 @@ Size: 4, 4 Tiles: 0: Road - LeftColor: 4E4D4A - RightColor: 424240 + MinColor: 4E4D4A + MaxColor: 424240 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 403C35 - RightColor: 3D3B36 + MinColor: 403C35 + MaxColor: 3D3B36 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 4C463F - RightColor: 574D40 + MinColor: 4C463F + MaxColor: 574D40 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 4C4B48 - RightColor: 43413E + MinColor: 4C4B48 + MaxColor: 43413E ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 423E37 - RightColor: 48443C + MinColor: 423E37 + MaxColor: 48443C ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 78634A - RightColor: 766249 + MinColor: 78634A + MaxColor: 766249 ZOffset: -12 ZRamp: 0 7: DirtRoad - LeftColor: 9C764B - RightColor: 9D774C + MinColor: 9C764B + MaxColor: 9D774C ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 4F4E4B - RightColor: 44413E + MinColor: 4F4E4B + MaxColor: 44413E ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 4B4439 - RightColor: 5D503E + MinColor: 4B4439 + MaxColor: 5D503E ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 846A4C - RightColor: 8A6F4F + MinColor: 846A4C + MaxColor: 8A6F4F ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 795F40 - RightColor: 7F6343 + MinColor: 795F40 + MaxColor: 7F6343 ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 4D4D4B - RightColor: 44413D + MinColor: 4D4D4B + MaxColor: 44413D ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 3E3B35 - RightColor: 554A3C + MinColor: 3E3B35 + MaxColor: 554A3C ZOffset: -12 ZRamp: 0 14: Road - LeftColor: 574E42 - RightColor: 655B4C + MinColor: 574E42 + MaxColor: 655B4C ZOffset: -12 ZRamp: 0 Template@332: @@ -9839,83 +9841,83 @@ Size: 5, 4 Tiles: 1: Road - LeftColor: 4D4D4B - RightColor: 42403C + MinColor: 4D4D4B + MaxColor: 42403C ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 3C3A35 - RightColor: 403C34 + MinColor: 3C3A35 + MaxColor: 403C34 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 45413C - RightColor: 4D4B46 + MinColor: 45413C + MaxColor: 4D4B46 ZOffset: -12 ZRamp: 0 5: DirtRoad - LeftColor: 8B6C48 - RightColor: 806545 + MinColor: 8B6C48 + MaxColor: 806545 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 766550 - RightColor: 574E44 + MinColor: 766550 + MaxColor: 574E44 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 574C3D - RightColor: 51473B + MinColor: 574C3D + MaxColor: 51473B ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 5F5243 - RightColor: 635747 + MinColor: 5F5243 + MaxColor: 635747 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 8B6C48 - RightColor: 816443 + MinColor: 8B6C48 + MaxColor: 816443 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 846745 - RightColor: 8D6D48 + MinColor: 846745 + MaxColor: 8D6D48 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 776148 - RightColor: 846A4D + MinColor: 776148 + MaxColor: 846A4D ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 6B5A45 - RightColor: 6F5C47 + MinColor: 6B5A45 + MaxColor: 6F5C47 ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 72604A - RightColor: 7F684D + MinColor: 72604A + MaxColor: 7F684D ZOffset: -12 ZRamp: 0 14: DirtRoad - LeftColor: 836644 - RightColor: 99754B + MinColor: 836644 + MaxColor: 99754B ZOffset: -12 ZRamp: 0 16: Road - LeftColor: 4D4B48 - RightColor: 47433E + MinColor: 4D4B48 + MaxColor: 47433E ZOffset: -12 ZRamp: 0 17: Road - LeftColor: 3C3A34 - RightColor: 4B443A + MinColor: 3C3A34 + MaxColor: 4B443A ZOffset: -12 ZRamp: 0 18: Road - LeftColor: 49443F - RightColor: 5F564B + MinColor: 49443F + MaxColor: 5F564B ZOffset: -12 ZRamp: 0 Template@333: @@ -9925,23 +9927,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 12253D - RightColor: 152944 + MinColor: 12253D + MaxColor: 152944 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 1B2F50 - RightColor: 10243B + MinColor: 1B2F50 + MaxColor: 10243B ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 0F2237 - RightColor: 132640 + MinColor: 0F2237 + MaxColor: 132640 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 142842 - RightColor: 132640 + MinColor: 142842 + MaxColor: 132640 ZOffset: -12 ZRamp: 0 Template@334: @@ -9951,23 +9953,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 0D1F33 - RightColor: 0E2035 + MinColor: 0D1F33 + MaxColor: 0E2035 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 0F2137 - RightColor: 0F2338 + MinColor: 0F2137 + MaxColor: 0F2338 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 0E2136 - RightColor: 0B1B2E + MinColor: 0E2136 + MaxColor: 0B1B2E ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 0F2238 - RightColor: 0F2137 + MinColor: 0F2238 + MaxColor: 0F2137 ZOffset: -12 ZRamp: 0 Template@335: @@ -9977,23 +9979,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 10233A - RightColor: 12253E + MinColor: 10233A + MaxColor: 12253E ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 132741 - RightColor: 10233A + MinColor: 132741 + MaxColor: 10233A ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 0F2138 - RightColor: 0E2136 + MinColor: 0F2138 + MaxColor: 0E2136 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 0F2138 - RightColor: 0F2237 + MinColor: 0F2138 + MaxColor: 0F2237 ZOffset: -12 ZRamp: 0 Template@336: @@ -10003,23 +10005,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 0E2136 - RightColor: 0F2137 + MinColor: 0E2136 + MaxColor: 0F2137 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 11233B - RightColor: 112339 + MinColor: 11233B + MaxColor: 112339 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 13263F - RightColor: 112338 + MinColor: 13263F + MaxColor: 112338 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 142742 - RightColor: 142843 + MinColor: 142742 + MaxColor: 142843 ZOffset: -12 ZRamp: 0 Template@337: @@ -10029,23 +10031,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 0D2035 - RightColor: 0A1B2D + MinColor: 0D2035 + MaxColor: 0A1B2D ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 10233A - RightColor: 12243E + MinColor: 10233A + MaxColor: 12243E ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 0F2137 - RightColor: 10233A + MinColor: 0F2137 + MaxColor: 10233A ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 0F2136 - RightColor: 10233C + MinColor: 0F2136 + MaxColor: 10233C ZOffset: -12 ZRamp: 0 Template@338: @@ -10055,23 +10057,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 0F2239 - RightColor: 102238 + MinColor: 0F2239 + MaxColor: 102238 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 12253D - RightColor: 0F2137 + MinColor: 12253D + MaxColor: 0F2137 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 0E2036 - RightColor: 11243C + MinColor: 0E2036 + MaxColor: 11243C ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 0E1E33 - RightColor: 102239 + MinColor: 0E1E33 + MaxColor: 102239 ZOffset: -12 ZRamp: 0 Template@339: @@ -10081,23 +10083,23 @@ Size: 2, 2 Tiles: 0: Cliff - LeftColor: 30373E - RightColor: 293340 + MinColor: 30373E + MaxColor: 293340 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 1F3352 - RightColor: 12243C + MinColor: 1F3352 + MaxColor: 12243C ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 102339 - RightColor: 12243A + MinColor: 102339 + MaxColor: 12243A ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 11243B - RightColor: 142842 + MinColor: 11243B + MaxColor: 142842 ZOffset: -12 ZRamp: 0 Template@340: @@ -10107,23 +10109,23 @@ Size: 2, 2 Tiles: 0: Cliff - LeftColor: 404A55 - RightColor: 28313A + MinColor: 404A55 + MaxColor: 28313A ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 15273D - RightColor: 10243C + MinColor: 15273D + MaxColor: 10243C ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 162B44 - RightColor: 253348 + MinColor: 162B44 + MaxColor: 253348 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 2C3748 - RightColor: 2C3744 + MinColor: 2C3748 + MaxColor: 2C3744 ZOffset: -12 ZRamp: 0 Template@341: @@ -10133,8 +10135,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 0E1F34 - RightColor: 11243B + MinColor: 0E1F34 + MaxColor: 11243B ZOffset: -12 ZRamp: 0 Template@342: @@ -10144,8 +10146,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 11233B - RightColor: 11243C + MinColor: 11233B + MaxColor: 11243C ZOffset: -12 ZRamp: 0 Template@343: @@ -10155,8 +10157,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 0F2136 - RightColor: 102238 + MinColor: 0F2136 + MaxColor: 102238 ZOffset: -12 ZRamp: 0 Template@344: @@ -10166,8 +10168,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 0D1E33 - RightColor: 102239 + MinColor: 0D1E33 + MaxColor: 102239 ZOffset: -12 ZRamp: 0 Template@345: @@ -10177,8 +10179,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 102238 - RightColor: 102238 + MinColor: 102238 + MaxColor: 102238 ZOffset: -12 ZRamp: 0 Template@346: @@ -10188,8 +10190,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 2C3642 - RightColor: 27313A + MinColor: 2C3642 + MaxColor: 27313A ZOffset: -12 ZRamp: 0 Template@387: @@ -10200,14 +10202,14 @@ Tiles: 0: DirtRoad RampType: 1 - LeftColor: 8C6C47 - RightColor: 7C6345 + MinColor: 8C6C47 + MaxColor: 7C6345 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 1 - LeftColor: 7F674A - RightColor: 785D3E + MinColor: 7F674A + MaxColor: 785D3E ZOffset: -12 ZRamp: 0 Template@388: @@ -10218,14 +10220,14 @@ Tiles: 0: DirtRoad RampType: 1 - LeftColor: 977349 - RightColor: 82694A + MinColor: 977349 + MaxColor: 82694A ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 1 - LeftColor: 826A4B - RightColor: 826644 + MinColor: 826A4B + MaxColor: 826644 ZOffset: -12 ZRamp: 0 Template@389: @@ -10236,14 +10238,14 @@ Tiles: 0: DirtRoad RampType: 2 - LeftColor: 6C5840 - RightColor: 8E6C46 + MinColor: 6C5840 + MaxColor: 8E6C46 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 2 - LeftColor: 755E42 - RightColor: 63533E + MinColor: 755E42 + MaxColor: 63533E ZOffset: -12 ZRamp: 0 Template@390: @@ -10254,14 +10256,14 @@ Tiles: 0: DirtRoad RampType: 2 - LeftColor: 6D5941 - RightColor: 906D47 + MinColor: 6D5941 + MaxColor: 906D47 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 2 - LeftColor: 765D41 - RightColor: 64533F + MinColor: 765D41 + MaxColor: 64533F ZOffset: -12 ZRamp: 0 Template@391: @@ -10272,14 +10274,14 @@ Tiles: 0: DirtRoad RampType: 3 - LeftColor: 806544 - RightColor: 6E5B43 + MinColor: 806544 + MaxColor: 6E5B43 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 3 - LeftColor: 675641 - RightColor: 7B674D + MinColor: 675641 + MaxColor: 7B674D ZOffset: -12 ZRamp: 0 Template@392: @@ -10290,14 +10292,14 @@ Tiles: 0: DirtRoad RampType: 3 - LeftColor: 7C6141 - RightColor: 6B5842 + MinColor: 7C6141 + MaxColor: 6B5842 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 3 - LeftColor: 685641 - RightColor: 725C41 + MinColor: 685641 + MaxColor: 725C41 ZOffset: -12 ZRamp: 0 Template@393: @@ -10308,14 +10310,14 @@ Tiles: 0: DirtRoad RampType: 4 - LeftColor: 7A6144 - RightColor: 94724A + MinColor: 7A6144 + MaxColor: 94724A ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 4 - LeftColor: 7D6243 - RightColor: 6E593E + MinColor: 7D6243 + MaxColor: 6E593E ZOffset: -12 ZRamp: 0 Template@394: @@ -10326,14 +10328,14 @@ Tiles: 0: DirtRoad RampType: 4 - LeftColor: 755C3F - RightColor: 8C6C46 + MinColor: 755C3F + MaxColor: 8C6C46 ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 4 - LeftColor: 8C6B44 - RightColor: 735C40 + MinColor: 8C6B44 + MaxColor: 735C40 ZOffset: -12 ZRamp: 0 Template@403: @@ -10345,65 +10347,65 @@ 1: Clear Height: 3 RampType: 11 - LeftColor: 524637 - RightColor: 60503D + MinColor: 524637 + MaxColor: 60503D ZOffset: -12 ZRamp: 0 2: Clear Height: 3 RampType: 4 - LeftColor: 5D4E3B - RightColor: 67533A + MinColor: 5D4E3B + MaxColor: 67533A ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 4E4539 - RightColor: 3F372B + MinColor: 4E4539 + MaxColor: 3F372B ZOffset: -12 ZRamp: 0 4: Cliff Height: 3 RampType: 3 - LeftColor: 514636 - RightColor: 574C3D + MinColor: 514636 + MaxColor: 574C3D ZOffset: -12 ZRamp: 0 5: Clear Height: 2 RampType: 4 - LeftColor: 554938 - RightColor: 5F513E + MinColor: 554938 + MaxColor: 5F513E ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 695742 - RightColor: 50483C + MinColor: 695742 + MaxColor: 50483C ZOffset: -12 ZRamp: 0 7: Cliff RampType: 1 - LeftColor: 695A46 - RightColor: 61523E + MinColor: 695A46 + MaxColor: 61523E ZOffset: -12 ZRamp: 0 8: Clear Height: 1 RampType: 4 - LeftColor: 5A4B38 - RightColor: 544837 + MinColor: 5A4B38 + MaxColor: 544837 ZOffset: -12 ZRamp: 0 10: Clear RampType: 8 - LeftColor: 6C5941 - RightColor: 685741 + MinColor: 6C5941 + MaxColor: 685741 ZOffset: -12 ZRamp: 0 11: Clear RampType: 4 - LeftColor: 69543C - RightColor: 65533D + MinColor: 69543C + MaxColor: 65533D ZOffset: -12 ZRamp: 0 Template@404: @@ -10415,65 +10417,65 @@ 0: Clear Height: 3 RampType: 4 - LeftColor: 574B3A - RightColor: 5F513F + MinColor: 574B3A + MaxColor: 5F513F ZOffset: -12 ZRamp: 0 1: Clear Height: 3 RampType: 12 - LeftColor: 6A5C48 - RightColor: 68553E + MinColor: 6A5C48 + MaxColor: 68553E ZOffset: -12 ZRamp: 0 3: Clear Height: 2 RampType: 4 - LeftColor: 5A4D3C - RightColor: 574C3D + MinColor: 5A4D3C + MaxColor: 574C3D ZOffset: -12 ZRamp: 0 4: Cliff Height: 3 RampType: 1 - LeftColor: 4E463A - RightColor: 625543 + MinColor: 4E463A + MaxColor: 625543 ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 504537 - RightColor: 42392C + MinColor: 504537 + MaxColor: 42392C ZOffset: -12 ZRamp: 0 6: Clear Height: 1 RampType: 4 - LeftColor: 5D5040 - RightColor: 584C3C + MinColor: 5D5040 + MaxColor: 584C3C ZOffset: -12 ZRamp: 0 7: Cliff RampType: 3 - LeftColor: 564D41 - RightColor: 4D4438 + MinColor: 564D41 + MaxColor: 4D4438 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 675845 - RightColor: 3F3A31 + MinColor: 675845 + MaxColor: 3F3A31 ZOffset: -12 ZRamp: 0 9: Clear RampType: 4 - LeftColor: 6A563E - RightColor: 5C4E3A + MinColor: 6A563E + MaxColor: 5C4E3A ZOffset: -12 ZRamp: 0 10: Clear RampType: 7 - LeftColor: 665640 - RightColor: 594C3B + MinColor: 665640 + MaxColor: 594C3B ZOffset: -12 ZRamp: 0 Template@405: @@ -10485,65 +10487,65 @@ 0: Clear Height: 3 RampType: 3 - LeftColor: 605444 - RightColor: 625442 + MinColor: 605444 + MaxColor: 625442 ZOffset: -12 ZRamp: 0 1: Clear Height: 2 RampType: 3 - LeftColor: 554D41 - RightColor: 584E3F + MinColor: 554D41 + MaxColor: 584E3F ZOffset: -12 ZRamp: 0 2: Clear Height: 1 RampType: 3 - LeftColor: 544D43 - RightColor: 605445 + MinColor: 544D43 + MaxColor: 605445 ZOffset: -12 ZRamp: 0 3: Clear RampType: 3 - LeftColor: 50483D - RightColor: 625544 + MinColor: 50483D + MaxColor: 625544 ZOffset: -12 ZRamp: 0 4: Clear Height: 3 RampType: 10 - LeftColor: 6C5841 - RightColor: 4F473C + MinColor: 6C5841 + MaxColor: 4F473C ZOffset: -12 ZRamp: 0 5: Cliff Height: 3 RampType: 2 - LeftColor: 4E4537 - RightColor: 4D463A + MinColor: 4E4537 + MaxColor: 4D463A ZOffset: -12 ZRamp: 0 6: Cliff RampType: 4 - LeftColor: 665846 - RightColor: 5D5244 + MinColor: 665846 + MaxColor: 5D5244 ZOffset: -12 ZRamp: 0 7: Clear RampType: 7 - LeftColor: 6C5B45 - RightColor: 62523D + MinColor: 6C5B45 + MaxColor: 62523D ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 4B4033 - RightColor: 413A2F + MinColor: 4B4033 + MaxColor: 413A2F ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 564D40 - RightColor: 3F3B33 + MinColor: 564D40 + MaxColor: 3F3B33 ZOffset: -12 ZRamp: 0 Template@406: @@ -10554,66 +10556,66 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 473E33 - RightColor: 403A32 + MinColor: 473E33 + MaxColor: 403A32 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 3B3831 - RightColor: 35332E + MinColor: 3B3831 + MaxColor: 35332E ZOffset: -12 ZRamp: 0 4: Clear Height: 3 RampType: 11 - LeftColor: 605648 - RightColor: 63594A + MinColor: 605648 + MaxColor: 63594A ZOffset: -12 ZRamp: 0 5: Cliff Height: 3 RampType: 4 - LeftColor: 655B4B - RightColor: 5D5447 + MinColor: 655B4B + MaxColor: 5D5447 ZOffset: -12 ZRamp: 0 6: Cliff RampType: 2 - LeftColor: 4E4537 - RightColor: 4A4236 + MinColor: 4E4537 + MaxColor: 4A4236 ZOffset: -12 ZRamp: 0 7: Clear RampType: 6 - LeftColor: 4C4337 - RightColor: 5F5240 + MinColor: 4C4337 + MaxColor: 5F5240 ZOffset: -12 ZRamp: 0 8: Clear Height: 3 RampType: 3 - LeftColor: 645645 - RightColor: 5A5042 + MinColor: 645645 + MaxColor: 5A5042 ZOffset: -12 ZRamp: 0 9: Clear Height: 2 RampType: 3 - LeftColor: 584D3D - RightColor: 574E42 + MinColor: 584D3D + MaxColor: 574E42 ZOffset: -12 ZRamp: 0 10: Clear Height: 1 RampType: 3 - LeftColor: 5A5041 - RightColor: 423C33 + MinColor: 5A5041 + MaxColor: 423C33 ZOffset: -12 ZRamp: 0 11: Clear RampType: 3 - LeftColor: 5C4E3D - RightColor: 61523F + MinColor: 5C4E3D + MaxColor: 61523F ZOffset: -12 ZRamp: 0 Template@407: @@ -10624,65 +10626,65 @@ Tiles: 1: Clear RampType: 5 - LeftColor: 544A3C - RightColor: 4F463A + MinColor: 544A3C + MaxColor: 4F463A ZOffset: -12 ZRamp: 0 2: Clear RampType: 2 - LeftColor: 443D31 - RightColor: 504535 + MinColor: 443D31 + MaxColor: 504535 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 544C40 - RightColor: 544C3F + MinColor: 544C40 + MaxColor: 544C3F ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 4A4338 - RightColor: 443D33 + MinColor: 4A4338 + MaxColor: 443D33 ZOffset: -12 ZRamp: 0 5: Clear Height: 1 RampType: 2 - LeftColor: 474238 - RightColor: 474035 + MinColor: 474238 + MaxColor: 474035 ZOffset: -12 ZRamp: 0 6: Cliff Height: 4 - LeftColor: 504535 - RightColor: 4D463B + MinColor: 504535 + MaxColor: 4D463B ZOffset: -12 ZRamp: 0 7: Cliff Height: 3 RampType: 3 - LeftColor: 4E4A41 - RightColor: 554E42 + MinColor: 4E4A41 + MaxColor: 554E42 ZOffset: -12 ZRamp: 0 8: Clear Height: 2 RampType: 2 - LeftColor: 4A4338 - RightColor: 50473A + MinColor: 4A4338 + MaxColor: 50473A ZOffset: -12 ZRamp: 0 10: Clear Height: 3 RampType: 10 - LeftColor: 665947 - RightColor: 4E473B + MinColor: 665947 + MaxColor: 4E473B ZOffset: -12 ZRamp: 0 11: Clear Height: 3 RampType: 2 - LeftColor: 5A5348 - RightColor: 4A443A + MinColor: 5A5348 + MaxColor: 4A443A ZOffset: -12 ZRamp: 0 Template@408: @@ -10693,46 +10695,46 @@ Tiles: 0: Clear RampType: 2 - LeftColor: 544C40 - RightColor: 4F483D + MinColor: 544C40 + MaxColor: 4F483D ZOffset: -12 ZRamp: 0 1: Clear RampType: 6 - LeftColor: 4E463A - RightColor: 5D503F + MinColor: 4E463A + MaxColor: 5D503F ZOffset: -12 ZRamp: 0 3: Clear Height: 1 RampType: 2 - LeftColor: 453F34 - RightColor: 4E473A + MinColor: 453F34 + MaxColor: 4E473A ZOffset: -12 ZRamp: 0 4: Cliff RampType: 3 - LeftColor: 5A4F3F - RightColor: 605647 + MinColor: 5A4F3F + MaxColor: 605647 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 6B5A45 - RightColor: 6D5A41 + MinColor: 6B5A45 + MaxColor: 6D5A41 ZOffset: -12 ZRamp: 0 6: Clear Height: 2 RampType: 2 - LeftColor: 413C32 - RightColor: 484137 + MinColor: 413C32 + MaxColor: 484137 ZOffset: -12 ZRamp: 0 9: Clear Height: 3 RampType: 2 - LeftColor: 453E32 - RightColor: 433E34 + MinColor: 453E32 + MaxColor: 433E34 ZOffset: -12 ZRamp: 0 Template@409: @@ -10744,21 +10746,21 @@ 0: Cliff Height: 3 RampType: 1 - LeftColor: 74634D - RightColor: 74654F + MinColor: 74634D + MaxColor: 74654F ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 524636 - RightColor: 494034 + MinColor: 524636 + MaxColor: 494034 ZOffset: -12 ZRamp: 0 2: Clear Height: 3 RampType: 9 - LeftColor: 625544 - RightColor: 6A5842 + MinColor: 625544 + MaxColor: 6A5842 ZOffset: -12 ZRamp: 0 Template@410: @@ -10768,66 +10770,66 @@ Size: 4, 3 Tiles: 1: Cliff - LeftColor: 685C4B - RightColor: 645B4C + MinColor: 685C4B + MaxColor: 645B4C ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 4C453A - RightColor: 4C4234 + MinColor: 4C453A + MaxColor: 4C4234 ZOffset: -12 ZRamp: 0 4: Clear RampType: 5 - LeftColor: 70604A - RightColor: 615545 + MinColor: 70604A + MaxColor: 615545 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 746149 - RightColor: 706049 + MinColor: 746149 + MaxColor: 706049 ZOffset: -12 ZRamp: 0 6: Cliff Height: 3 RampType: 4 - LeftColor: 665D4F - RightColor: 61594D + MinColor: 665D4F + MaxColor: 61594D ZOffset: -12 ZRamp: 0 7: Clear Height: 3 RampType: 12 - LeftColor: 6C5F4C - RightColor: 73634D + MinColor: 6C5F4C + MaxColor: 73634D ZOffset: -12 ZRamp: 0 8: Clear RampType: 1 - LeftColor: 715F47 - RightColor: 72624C + MinColor: 715F47 + MaxColor: 72624C ZOffset: -12 ZRamp: 0 9: Clear Height: 1 RampType: 1 - LeftColor: 77654D - RightColor: 746149 + MinColor: 77654D + MaxColor: 746149 ZOffset: -12 ZRamp: 0 10: Clear Height: 2 RampType: 1 - LeftColor: 746149 - RightColor: 6A5D4B + MinColor: 746149 + MaxColor: 6A5D4B ZOffset: -12 ZRamp: 0 11: Clear Height: 3 RampType: 1 - LeftColor: 72624C - RightColor: 695D4D + MinColor: 72624C + MaxColor: 695D4D ZOffset: -12 ZRamp: 0 Template@411: @@ -10838,46 +10840,46 @@ Tiles: 0: Clear RampType: 1 - LeftColor: 6A5C49 - RightColor: 6D6353 + MinColor: 6A5C49 + MaxColor: 6D6353 ZOffset: -12 ZRamp: 0 1: Clear Height: 1 RampType: 1 - LeftColor: 695F4F - RightColor: 6F614C + MinColor: 695F4F + MaxColor: 6F614C ZOffset: -12 ZRamp: 0 2: Clear Height: 2 RampType: 1 - LeftColor: 73624B - RightColor: 716049 + MinColor: 73624B + MaxColor: 716049 ZOffset: -12 ZRamp: 0 3: Clear Height: 3 RampType: 1 - LeftColor: 756249 - RightColor: 715F48 + MinColor: 756249 + MaxColor: 715F48 ZOffset: -12 ZRamp: 0 4: Clear RampType: 8 - LeftColor: 6B5943 - RightColor: 655947 + MinColor: 6B5943 + MaxColor: 655947 ZOffset: -12 ZRamp: 0 5: Cliff RampType: 4 - LeftColor: 695F50 - RightColor: 5C5244 + MinColor: 695F50 + MaxColor: 5C5244 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 705D45 - RightColor: 6E5C46 + MinColor: 705D45 + MaxColor: 6E5C46 ZOffset: -12 ZRamp: 0 Template@412: @@ -10889,21 +10891,21 @@ 0: Cliff Height: 3 RampType: 2 - LeftColor: 655B4B - RightColor: 524A3D + MinColor: 655B4B + MaxColor: 524A3D ZOffset: -12 ZRamp: 0 1: Clear Height: 3 RampType: 9 - LeftColor: 6A5A44 - RightColor: 665B4A + MinColor: 6A5A44 + MaxColor: 665B4A ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 464037 - RightColor: 484137 + MinColor: 464037 + MaxColor: 484137 ZOffset: -12 ZRamp: 0 Template@423: @@ -10913,131 +10915,131 @@ Size: 5, 8 Tiles: 0: Cliff - LeftColor: ABADC2 - RightColor: 7C7E89 + MinColor: ABADC2 + MaxColor: 7C7E89 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 585A5F - RightColor: BCBDDD + MinColor: 585A5F + MaxColor: BCBDDD ZOffset: -12 ZRamp: 0 2: Water RampType: 4 - LeftColor: B0B2C8 - RightColor: C4C5E2 + MinColor: B0B2C8 + MaxColor: C4C5E2 ZOffset: -12 ZRamp: 0 3: Water RampType: 12 - LeftColor: 7B7D85 - RightColor: A4A5B5 + MinColor: 7B7D85 + MaxColor: A4A5B5 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 3F4D58 - RightColor: 7D828C + MinColor: 3F4D58 + MaxColor: 7D828C ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 53565A - RightColor: 545556 + MinColor: 53565A + MaxColor: 545556 ZOffset: -12 ZRamp: 0 7: Water - LeftColor: 757B8A - RightColor: 747C8E + MinColor: 757B8A + MaxColor: 747C8E ZOffset: -12 ZRamp: 0 8: Water RampType: 8 - LeftColor: 515862 - RightColor: 979AA8 + MinColor: 515862 + MaxColor: 979AA8 ZOffset: -12 ZRamp: 0 10: Water - LeftColor: 293840 - RightColor: 324049 + MinColor: 293840 + MaxColor: 324049 ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 3C4850 - RightColor: 535557 + MinColor: 3C4850 + MaxColor: 535557 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 454D51 - RightColor: 67707D + MinColor: 454D51 + MaxColor: 67707D ZOffset: -12 ZRamp: 0 13: Water - LeftColor: 38444C - RightColor: 35424C + MinColor: 38444C + MaxColor: 35424C ZOffset: -12 ZRamp: 0 16: Water - LeftColor: 293840 - RightColor: 2C3A42 + MinColor: 293840 + MaxColor: 2C3A42 ZOffset: -12 ZRamp: 0 17: Cliff - LeftColor: 354249 - RightColor: 3C4951 + MinColor: 354249 + MaxColor: 3C4951 ZOffset: -12 ZRamp: 0 18: Water - LeftColor: 303D44 - RightColor: 2A3840 + MinColor: 303D44 + MaxColor: 2A3840 ZOffset: -12 ZRamp: 0 22: Cliff - LeftColor: 303C43 - RightColor: 3A444C + MinColor: 303C43 + MaxColor: 3A444C ZOffset: -12 ZRamp: 0 23: Cliff - LeftColor: 40484E - RightColor: 3B4852 + MinColor: 40484E + MaxColor: 3B4852 ZOffset: -12 ZRamp: 0 27: Cliff - LeftColor: 38444D - RightColor: 323E44 + MinColor: 38444D + MaxColor: 323E44 ZOffset: -12 ZRamp: 0 28: Cliff - LeftColor: 4B4C4D - RightColor: 434649 + MinColor: 4B4C4D + MaxColor: 434649 ZOffset: -12 ZRamp: 0 29: Water - LeftColor: 2A373E - RightColor: 28373F + MinColor: 2A373E + MaxColor: 28373F ZOffset: -12 ZRamp: 0 32: Cliff - LeftColor: 293840 - RightColor: 4E5864 + MinColor: 293840 + MaxColor: 4E5864 ZOffset: -12 ZRamp: 0 33: Cliff - LeftColor: 454D53 - RightColor: 515152 + MinColor: 454D53 + MaxColor: 515152 ZOffset: -12 ZRamp: 0 34: Cliff - LeftColor: 34373A - RightColor: 27333B + MinColor: 34373A + MaxColor: 27333B ZOffset: -12 ZRamp: 0 38: Cliff - LeftColor: 293840 - RightColor: 464D50 + MinColor: 293840 + MaxColor: 464D50 ZOffset: -12 ZRamp: 0 39: Cliff - LeftColor: 313538 - RightColor: 31363A + MinColor: 313538 + MaxColor: 31363A ZOffset: -12 ZRamp: 0 Template@424: @@ -11047,38 +11049,38 @@ Size: 3, 3 Tiles: 1: Cliff - LeftColor: 757677 - RightColor: 707380 + MinColor: 757677 + MaxColor: 707380 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 7E8291 - RightColor: 8A8DA1 + MinColor: 7E8291 + MaxColor: 8A8DA1 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 757880 - RightColor: 6A6D75 + MinColor: 757880 + MaxColor: 6A6D75 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 7B7E8B - RightColor: 898C9A + MinColor: 7B7E8B + MaxColor: 898C9A ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: B7B8CA - RightColor: 878787 + MinColor: B7B8CA + MaxColor: 878787 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: BDBCC7 - RightColor: B9B9BD + MinColor: BDBCC7 + MaxColor: B9B9BD ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C6C7DA - RightColor: 888998 + MinColor: C6C7DA + MaxColor: 888998 ZOffset: -12 ZRamp: 0 Template@435: @@ -11089,46 +11091,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 3F362A - RightColor: 423A2F + MinColor: 3F362A + MaxColor: 423A2F ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 172231 - RightColor: 101C2B + MinColor: 172231 + MaxColor: 101C2B ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 433C31 - RightColor: 453E34 + MinColor: 433C31 + MaxColor: 453E34 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 41434A - RightColor: 313D51 + MinColor: 41434A + MaxColor: 313D51 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 66543C - RightColor: 4C463B + MinColor: 66543C + MaxColor: 4C463B ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 475261 - RightColor: 626769 + MinColor: 475261 + MaxColor: 626769 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 604F3B - RightColor: 373F4A + MinColor: 604F3B + MaxColor: 373F4A ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 253650 - RightColor: 1F314D + MinColor: 253650 + MaxColor: 1F314D ZOffset: -12 ZRamp: 0 Template@436: @@ -11139,24 +11141,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 142238 - RightColor: 0D1C2E + MinColor: 142238 + MaxColor: 0D1C2E ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 545D6D - RightColor: 343F50 + MinColor: 545D6D + MaxColor: 343F50 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 6F7B8D - RightColor: 93989E + MinColor: 6F7B8D + MaxColor: 93989E ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 152841 - RightColor: 283F63 + MinColor: 152841 + MaxColor: 283F63 ZOffset: -12 ZRamp: 0 Template@437: @@ -11167,46 +11169,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 0C1A2C - RightColor: 0D1B2C + MinColor: 0C1A2C + MaxColor: 0D1B2C ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 182331 - RightColor: 0E1B2C + MinColor: 182331 + MaxColor: 0E1B2C ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 565E6A - RightColor: 27364E + MinColor: 565E6A + MaxColor: 27364E ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 4D586D - RightColor: 2E394C + MinColor: 4D586D + MaxColor: 2E394C ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 616D7D - RightColor: A4A8AD + MinColor: 616D7D + MaxColor: A4A8AD ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 8E95A2 - RightColor: B6B8BF + MinColor: 8E95A2 + MaxColor: B6B8BF ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 152943 - RightColor: 23395C + MinColor: 152943 + MaxColor: 23395C ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 182C49 - RightColor: 354A6F + MinColor: 182C49 + MaxColor: 354A6F ZOffset: -12 ZRamp: 0 Template@438: @@ -11217,46 +11219,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 151F2A - RightColor: 1F252D + MinColor: 151F2A + MaxColor: 1F252D ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 443B2F - RightColor: 50412F + MinColor: 443B2F + MaxColor: 50412F ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 525A68 - RightColor: 32363C + MinColor: 525A68 + MaxColor: 32363C ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 524635 - RightColor: 483E31 + MinColor: 524635 + MaxColor: 483E31 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 7F8690 - RightColor: A09E9E + MinColor: 7F8690 + MaxColor: A09E9E ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 544B3D - RightColor: 4F4638 + MinColor: 544B3D + MaxColor: 4F4638 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 2A3647 - RightColor: 474A4E + MinColor: 2A3647 + MaxColor: 474A4E ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 5F503D - RightColor: 605341 + MinColor: 5F503D + MaxColor: 605341 ZOffset: -12 ZRamp: 0 Template@439: @@ -11266,8 +11268,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6D573D - RightColor: 6F593E + MinColor: 6D573D + MaxColor: 6F593E ZOffset: -12 ZRamp: 0 Template@440: @@ -11277,8 +11279,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6E583D - RightColor: 6E583D + MinColor: 6E583D + MaxColor: 6E583D ZOffset: -12 ZRamp: 0 Template@441: @@ -11288,8 +11290,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 725C41 - RightColor: 735C40 + MinColor: 725C41 + MaxColor: 735C40 ZOffset: -12 ZRamp: 0 Template@442: @@ -11299,8 +11301,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6F5A40 - RightColor: 6C5840 + MinColor: 6F5A40 + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 Template@443: @@ -11310,8 +11312,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 705A40 - RightColor: 70593E + MinColor: 705A40 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 Template@444: @@ -11321,8 +11323,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6F583D - RightColor: 6F583D + MinColor: 6F583D + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 Template@445: @@ -11332,8 +11334,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 Template@446: @@ -11343,8 +11345,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 Template@447: @@ -11354,8 +11356,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 464036 - RightColor: 474137 + MinColor: 464036 + MaxColor: 474137 ZOffset: -12 ZRamp: 0 Template@448: @@ -11365,8 +11367,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 484338 - RightColor: 423D33 + MinColor: 484338 + MaxColor: 423D33 ZOffset: -12 ZRamp: 0 Template@449: @@ -11376,8 +11378,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 443F36 - RightColor: 474237 + MinColor: 443F36 + MaxColor: 474237 ZOffset: -12 ZRamp: 0 Template@450: @@ -11387,8 +11389,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4A443A - RightColor: 454036 + MinColor: 4A443A + MaxColor: 454036 ZOffset: -12 ZRamp: 0 Template@451: @@ -11398,8 +11400,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 474137 - RightColor: 484238 + MinColor: 474137 + MaxColor: 484238 ZOffset: -12 ZRamp: 0 Template@452: @@ -11409,8 +11411,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 454036 - RightColor: 484237 + MinColor: 454036 + MaxColor: 484237 ZOffset: -12 ZRamp: 0 Template@453: @@ -11420,8 +11422,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 484339 - RightColor: 474136 + MinColor: 484339 + MaxColor: 474136 ZOffset: -12 ZRamp: 0 Template@454: @@ -11431,8 +11433,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 474137 - RightColor: 484238 + MinColor: 474137 + MaxColor: 484238 ZOffset: -12 ZRamp: 0 Template@455: @@ -11442,8 +11444,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 534839 - RightColor: 544939 + MinColor: 534839 + MaxColor: 544939 ZOffset: -12 ZRamp: 0 Template@456: @@ -11453,8 +11455,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4A4439 - RightColor: 584A38 + MinColor: 4A4439 + MaxColor: 584A38 ZOffset: -12 ZRamp: 0 Template@457: @@ -11464,8 +11466,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 464036 - RightColor: 574A39 + MinColor: 464036 + MaxColor: 574A39 ZOffset: -12 ZRamp: 0 Template@458: @@ -11475,8 +11477,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4C463B - RightColor: 5E4F3C + MinColor: 4C463B + MaxColor: 5E4F3C ZOffset: -12 ZRamp: 0 Template@459: @@ -11486,8 +11488,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 554939 - RightColor: 494338 + MinColor: 554939 + MaxColor: 494338 ZOffset: -12 ZRamp: 0 Template@460: @@ -11497,8 +11499,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 554938 - RightColor: 574A3A + MinColor: 554938 + MaxColor: 574A3A ZOffset: -12 ZRamp: 0 Template@461: @@ -11508,8 +11510,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 584C3C - RightColor: 584A39 + MinColor: 584C3C + MaxColor: 584A39 ZOffset: -12 ZRamp: 0 Template@462: @@ -11519,8 +11521,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 564B3B - RightColor: 61523F + MinColor: 564B3B + MaxColor: 61523F ZOffset: -12 ZRamp: 0 Template@463: @@ -11530,8 +11532,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 564939 - RightColor: 494338 + MinColor: 564939 + MaxColor: 494338 ZOffset: -12 ZRamp: 0 Template@464: @@ -11541,8 +11543,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 544939 - RightColor: 564937 + MinColor: 544939 + MaxColor: 564937 ZOffset: -12 ZRamp: 0 Template@465: @@ -11552,8 +11554,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5A4E3D - RightColor: 5B4C39 + MinColor: 5A4E3D + MaxColor: 5B4C39 ZOffset: -12 ZRamp: 0 Template@466: @@ -11563,8 +11565,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 574C3C - RightColor: 60503D + MinColor: 574C3C + MaxColor: 60503D ZOffset: -12 ZRamp: 0 Template@467: @@ -11574,8 +11576,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 64533D - RightColor: 4A4438 + MinColor: 64533D + MaxColor: 4A4438 ZOffset: -12 ZRamp: 0 Template@468: @@ -11585,8 +11587,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 67533B - RightColor: 584B3A + MinColor: 67533B + MaxColor: 584B3A ZOffset: -12 ZRamp: 0 Template@469: @@ -11596,8 +11598,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 635440 - RightColor: 554939 + MinColor: 635440 + MaxColor: 554939 ZOffset: -12 ZRamp: 0 Template@470: @@ -11607,8 +11609,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5B4D3A - RightColor: 5D4F3D + MinColor: 5B4D3A + MaxColor: 5D4F3D ZOffset: -12 ZRamp: 0 Template@471: @@ -11618,8 +11620,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 55493A - RightColor: 514739 + MinColor: 55493A + MaxColor: 514739 ZOffset: -12 ZRamp: 0 Template@472: @@ -11629,8 +11631,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 504638 - RightColor: 5E4E3B + MinColor: 504638 + MaxColor: 5E4E3B ZOffset: -12 ZRamp: 0 Template@473: @@ -11640,8 +11642,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 51483A - RightColor: 594B39 + MinColor: 51483A + MaxColor: 594B39 ZOffset: -12 ZRamp: 0 Template@474: @@ -11651,8 +11653,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 544B3D - RightColor: 64523E + MinColor: 544B3D + MaxColor: 64523E ZOffset: -12 ZRamp: 0 Template@475: @@ -11662,8 +11664,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5E4F3B - RightColor: 50473A + MinColor: 5E4F3B + MaxColor: 50473A ZOffset: -12 ZRamp: 0 Template@476: @@ -11673,8 +11675,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5E4D39 - RightColor: 5C4D3A + MinColor: 5E4D39 + MaxColor: 5C4D3A ZOffset: -12 ZRamp: 0 Template@477: @@ -11684,8 +11686,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 594C3B - RightColor: 5C4D3A + MinColor: 594C3B + MaxColor: 5C4D3A ZOffset: -12 ZRamp: 0 Template@478: @@ -11695,8 +11697,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5D4E3C - RightColor: 655440 + MinColor: 5D4E3C + MaxColor: 655440 ZOffset: -12 ZRamp: 0 Template@479: @@ -11706,8 +11708,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 564A3A - RightColor: 4E4639 + MinColor: 564A3A + MaxColor: 4E4639 ZOffset: -12 ZRamp: 0 Template@480: @@ -11717,8 +11719,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 584B39 - RightColor: 62513B + MinColor: 584B39 + MaxColor: 62513B ZOffset: -12 ZRamp: 0 Template@481: @@ -11728,8 +11730,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5A4D3D - RightColor: 574A38 + MinColor: 5A4D3D + MaxColor: 574A38 ZOffset: -12 ZRamp: 0 Template@482: @@ -11739,8 +11741,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 5D503E - RightColor: 63523E + MinColor: 5D503E + MaxColor: 63523E ZOffset: -12 ZRamp: 0 Template@483: @@ -11750,8 +11752,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 68543C - RightColor: 574A39 + MinColor: 68543C + MaxColor: 574A39 ZOffset: -12 ZRamp: 0 Template@484: @@ -11761,8 +11763,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 61503B - RightColor: 5C4D3A + MinColor: 61503B + MaxColor: 5C4D3A ZOffset: -12 ZRamp: 0 Template@485: @@ -11772,8 +11774,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 67553F - RightColor: 5B4D3B + MinColor: 67553F + MaxColor: 5B4D3B ZOffset: -12 ZRamp: 0 Template@486: @@ -11783,8 +11785,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 62513D - RightColor: 5F503D + MinColor: 62513D + MaxColor: 5F503D ZOffset: -12 ZRamp: 0 Template@487: @@ -11794,8 +11796,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6D573D - RightColor: 6F593E + MinColor: 6D573D + MaxColor: 6F593E ZOffset: -12 ZRamp: 0 Template@488: @@ -11805,8 +11807,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6E583D - RightColor: 6E583D + MinColor: 6E583D + MaxColor: 6E583D ZOffset: -12 ZRamp: 0 Template@489: @@ -11816,8 +11818,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 725C41 - RightColor: 735C40 + MinColor: 725C41 + MaxColor: 735C40 ZOffset: -12 ZRamp: 0 Template@490: @@ -11827,8 +11829,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6F5A40 - RightColor: 6C5840 + MinColor: 6F5A40 + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 Template@491: @@ -11838,8 +11840,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 705A40 - RightColor: 70593E + MinColor: 705A40 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 Template@492: @@ -11849,8 +11851,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6F583D - RightColor: 6F583D + MinColor: 6F583D + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 Template@493: @@ -11860,8 +11862,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 Template@494: @@ -11871,8 +11873,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 Template@495: @@ -11882,8 +11884,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 8B6D48 - RightColor: 8A6D48 + MinColor: 8B6D48 + MaxColor: 8A6D48 ZOffset: -12 ZRamp: 0 Template@496: @@ -11893,8 +11895,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 8C6F49 - RightColor: 896D48 + MinColor: 8C6F49 + MaxColor: 896D48 ZOffset: -12 ZRamp: 0 Template@497: @@ -11904,8 +11906,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 8A6D48 - RightColor: 896C47 + MinColor: 8A6D48 + MaxColor: 896C47 ZOffset: -12 ZRamp: 0 Template@498: @@ -11915,8 +11917,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 8D704A - RightColor: 8C6E49 + MinColor: 8D704A + MaxColor: 8C6E49 ZOffset: -12 ZRamp: 0 Template@499: @@ -11926,8 +11928,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 896D47 - RightColor: 876A46 + MinColor: 896D47 + MaxColor: 876A46 ZOffset: -12 ZRamp: 0 Template@500: @@ -11937,8 +11939,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 8A6D48 - RightColor: 8C6F49 + MinColor: 8A6D48 + MaxColor: 8C6F49 ZOffset: -12 ZRamp: 0 Template@501: @@ -11948,8 +11950,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 8B6D48 - RightColor: 876B47 + MinColor: 8B6D48 + MaxColor: 876B47 ZOffset: -12 ZRamp: 0 Template@502: @@ -11959,8 +11961,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 896C48 - RightColor: 876B46 + MinColor: 896C48 + MaxColor: 876B46 ZOffset: -12 ZRamp: 0 Template@503: @@ -11970,8 +11972,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7C6243 - RightColor: 816645 + MinColor: 7C6243 + MaxColor: 816645 ZOffset: -12 ZRamp: 0 Template@504: @@ -11981,8 +11983,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 745C3F - RightColor: 806543 + MinColor: 745C3F + MaxColor: 806543 ZOffset: -12 ZRamp: 0 Template@505: @@ -11992,8 +11994,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 725B40 - RightColor: 7D6342 + MinColor: 725B40 + MaxColor: 7D6342 ZOffset: -12 ZRamp: 0 Template@506: @@ -12003,8 +12005,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6D583E - RightColor: 836845 + MinColor: 6D583E + MaxColor: 836845 ZOffset: -12 ZRamp: 0 Template@507: @@ -12014,8 +12016,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 745D41 - RightColor: 6B553C + MinColor: 745D41 + MaxColor: 6B553C ZOffset: -12 ZRamp: 0 Template@508: @@ -12025,8 +12027,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 806644 - RightColor: 7C6343 + MinColor: 806644 + MaxColor: 7C6343 ZOffset: -12 ZRamp: 0 Template@509: @@ -12036,8 +12038,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 765E41 - RightColor: 755D40 + MinColor: 765E41 + MaxColor: 755D40 ZOffset: -12 ZRamp: 0 Template@510: @@ -12047,8 +12049,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 755E41 - RightColor: 7F6544 + MinColor: 755E41 + MaxColor: 7F6544 ZOffset: -12 ZRamp: 0 Template@511: @@ -12058,8 +12060,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7B6141 - RightColor: 6C573D + MinColor: 7B6141 + MaxColor: 6C573D ZOffset: -12 ZRamp: 0 Template@512: @@ -12069,8 +12071,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 775E40 - RightColor: 735C3F + MinColor: 775E40 + MaxColor: 735C3F ZOffset: -12 ZRamp: 0 Template@513: @@ -12080,8 +12082,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7E6343 - RightColor: 7C6242 + MinColor: 7E6343 + MaxColor: 7C6242 ZOffset: -12 ZRamp: 0 Template@514: @@ -12091,8 +12093,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 7B6142 - RightColor: 886C48 + MinColor: 7B6142 + MaxColor: 886C48 ZOffset: -12 ZRamp: 0 Template@515: @@ -12102,8 +12104,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 866A47 - RightColor: 6C573D + MinColor: 866A47 + MaxColor: 6C573D ZOffset: -12 ZRamp: 0 Template@516: @@ -12113,8 +12115,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 836845 - RightColor: 796042 + MinColor: 836845 + MaxColor: 796042 ZOffset: -12 ZRamp: 0 Template@517: @@ -12124,8 +12126,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 886B47 - RightColor: 785F41 + MinColor: 886B47 + MaxColor: 785F41 ZOffset: -12 ZRamp: 0 Template@518: @@ -12135,8 +12137,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 745C3F - RightColor: 775F40 + MinColor: 745C3F + MaxColor: 775F40 ZOffset: -12 ZRamp: 0 Template@519: @@ -12146,8 +12148,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 826745 - RightColor: 7A6143 + MinColor: 826745 + MaxColor: 7A6143 ZOffset: -12 ZRamp: 0 Template@520: @@ -12157,8 +12159,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 765E40 - RightColor: 7E6443 + MinColor: 765E40 + MaxColor: 7E6443 ZOffset: -12 ZRamp: 0 Template@521: @@ -12168,8 +12170,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 735D41 - RightColor: 816644 + MinColor: 735D41 + MaxColor: 816644 ZOffset: -12 ZRamp: 0 Template@522: @@ -12179,8 +12181,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 725B3E - RightColor: 886C47 + MinColor: 725B3E + MaxColor: 886C47 ZOffset: -12 ZRamp: 0 Template@523: @@ -12190,8 +12192,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 816745 - RightColor: 715B40 + MinColor: 816745 + MaxColor: 715B40 ZOffset: -12 ZRamp: 0 Template@524: @@ -12201,8 +12203,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 765E41 - RightColor: 715C42 + MinColor: 765E41 + MaxColor: 715C42 ZOffset: -12 ZRamp: 0 Template@525: @@ -12212,8 +12214,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 796041 - RightColor: 7F6543 + MinColor: 796041 + MaxColor: 7F6543 ZOffset: -12 ZRamp: 0 Template@526: @@ -12223,8 +12225,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 806645 - RightColor: 8C6F49 + MinColor: 806645 + MaxColor: 8C6F49 ZOffset: -12 ZRamp: 0 Template@527: @@ -12234,8 +12236,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 806544 - RightColor: 735C3F + MinColor: 806544 + MaxColor: 735C3F ZOffset: -12 ZRamp: 0 Template@528: @@ -12245,8 +12247,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 765F42 - RightColor: 786144 + MinColor: 765F42 + MaxColor: 786144 ZOffset: -12 ZRamp: 0 Template@529: @@ -12256,8 +12258,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 836845 - RightColor: 796041 + MinColor: 836845 + MaxColor: 796041 ZOffset: -12 ZRamp: 0 Template@530: @@ -12267,8 +12269,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 765D3F - RightColor: 7D6242 + MinColor: 765D3F + MaxColor: 7D6242 ZOffset: -12 ZRamp: 0 Template@531: @@ -12278,8 +12280,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 8A6D48 - RightColor: 735C3F + MinColor: 8A6D48 + MaxColor: 735C3F ZOffset: -12 ZRamp: 0 Template@532: @@ -12289,8 +12291,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 876A46 - RightColor: 775D40 + MinColor: 876A46 + MaxColor: 775D40 ZOffset: -12 ZRamp: 0 Template@533: @@ -12300,8 +12302,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 886C47 - RightColor: 765E40 + MinColor: 886C47 + MaxColor: 765E40 ZOffset: -12 ZRamp: 0 Template@534: @@ -12311,8 +12313,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 765E40 - RightColor: 755D3F + MinColor: 765E40 + MaxColor: 755D3F ZOffset: -12 ZRamp: 0 Template@535: @@ -12322,8 +12324,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 8B6D48 - RightColor: 8A6D48 + MinColor: 8B6D48 + MaxColor: 8A6D48 ZOffset: -12 ZRamp: 0 Template@536: @@ -12333,8 +12335,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 7C6243 - RightColor: 816645 + MinColor: 7C6243 + MaxColor: 816645 ZOffset: -12 ZRamp: 0 Template@537: @@ -12344,8 +12346,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 886B47 - RightColor: 785F41 + MinColor: 886B47 + MaxColor: 785F41 ZOffset: -12 ZRamp: 0 Template@538: @@ -12355,8 +12357,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 836845 - RightColor: 796042 + MinColor: 836845 + MaxColor: 796042 ZOffset: -12 ZRamp: 0 Template@539: @@ -12366,8 +12368,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 866A47 - RightColor: 6C573D + MinColor: 866A47 + MaxColor: 6C573D ZOffset: -12 ZRamp: 0 Template@540: @@ -12377,8 +12379,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 7B6142 - RightColor: 886C48 + MinColor: 7B6142 + MaxColor: 886C48 ZOffset: -12 ZRamp: 0 Template@541: @@ -12388,8 +12390,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 7E6343 - RightColor: 7C6242 + MinColor: 7E6343 + MaxColor: 7C6242 ZOffset: -12 ZRamp: 0 Template@542: @@ -12399,8 +12401,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 775E40 - RightColor: 735C3F + MinColor: 775E40 + MaxColor: 735C3F ZOffset: -12 ZRamp: 0 Template@543: @@ -12410,8 +12412,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 7B6141 - RightColor: 6C573D + MinColor: 7B6141 + MaxColor: 6C573D ZOffset: -12 ZRamp: 0 Template@544: @@ -12421,8 +12423,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 755E41 - RightColor: 7F6544 + MinColor: 755E41 + MaxColor: 7F6544 ZOffset: -12 ZRamp: 0 Template@545: @@ -12432,8 +12434,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 765E41 - RightColor: 755D40 + MinColor: 765E41 + MaxColor: 755D40 ZOffset: -12 ZRamp: 0 Template@546: @@ -12443,8 +12445,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 806644 - RightColor: 7C6343 + MinColor: 806644 + MaxColor: 7C6343 ZOffset: -12 ZRamp: 0 Template@547: @@ -12454,8 +12456,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 745D41 - RightColor: 6B553C + MinColor: 745D41 + MaxColor: 6B553C ZOffset: -12 ZRamp: 0 Template@548: @@ -12465,8 +12467,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 6D583E - RightColor: 836845 + MinColor: 6D583E + MaxColor: 836845 ZOffset: -12 ZRamp: 0 Template@549: @@ -12476,8 +12478,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 725B40 - RightColor: 7D6342 + MinColor: 725B40 + MaxColor: 7D6342 ZOffset: -12 ZRamp: 0 Template@550: @@ -12487,8 +12489,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 745C3F - RightColor: 806543 + MinColor: 745C3F + MaxColor: 806543 ZOffset: -12 ZRamp: 0 Template@551: @@ -12498,8 +12500,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 745C3F - RightColor: 775F40 + MinColor: 745C3F + MaxColor: 775F40 ZOffset: -12 ZRamp: 0 Template@552: @@ -12509,183 +12511,183 @@ Size: 9, 7 Tiles: 2: Rough - LeftColor: 6A5740 - RightColor: 5B4A35 + MinColor: 6A5740 + MaxColor: 5B4A35 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 4E4231 - RightColor: 64523C + MinColor: 4E4231 + MaxColor: 64523C ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: 63523C - RightColor: 5E4F3B + MinColor: 63523C + MaxColor: 5E4F3B ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: 524636 - RightColor: 4B3D2B + MinColor: 524636 + MaxColor: 4B3D2B ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 604F3A - RightColor: 67553E + MinColor: 604F3A + MaxColor: 67553E ZOffset: -12 ZRamp: 0 18: Rough - LeftColor: 6D5A43 - RightColor: 68563F + MinColor: 6D5A43 + MaxColor: 68563F ZOffset: -12 ZRamp: 0 19: Rough - LeftColor: 5A4B38 - RightColor: 6A5943 + MinColor: 5A4B38 + MaxColor: 6A5943 ZOffset: -12 ZRamp: 0 20: Rough - LeftColor: 5D4D37 - RightColor: 5D4E39 + MinColor: 5D4D37 + MaxColor: 5D4E39 ZOffset: -12 ZRamp: 0 21: Rough - LeftColor: 514331 - RightColor: 5A4D3C + MinColor: 514331 + MaxColor: 5A4D3C ZOffset: -12 ZRamp: 0 22: Rough - LeftColor: 3E3427 - RightColor: 5D4C38 + MinColor: 3E3427 + MaxColor: 5D4C38 ZOffset: -12 ZRamp: 0 23: Rough - LeftColor: 574C3E - RightColor: 66533B + MinColor: 574C3E + MaxColor: 66533B ZOffset: -12 ZRamp: 0 24: Rough - LeftColor: 62513C - RightColor: 604F3A + MinColor: 62513C + MaxColor: 604F3A ZOffset: -12 ZRamp: 0 25: Rough - LeftColor: 4E4232 - RightColor: 62513C + MinColor: 4E4232 + MaxColor: 62513C ZOffset: -12 ZRamp: 0 26: Rough - LeftColor: 6A5A45 - RightColor: 66533C + MinColor: 6A5A45 + MaxColor: 66533C ZOffset: -12 ZRamp: 0 28: Rough - LeftColor: 6D5941 - RightColor: 635340 + MinColor: 6D5941 + MaxColor: 635340 ZOffset: -12 ZRamp: 0 29: Rough - LeftColor: 5D4D39 - RightColor: 60523F + MinColor: 5D4D39 + MaxColor: 60523F ZOffset: -12 ZRamp: 0 30: Rough - LeftColor: 594A36 - RightColor: 60513D + MinColor: 594A36 + MaxColor: 60513D ZOffset: -12 ZRamp: 0 31: Rough - LeftColor: 564938 - RightColor: 574835 + MinColor: 564938 + MaxColor: 574835 ZOffset: -12 ZRamp: 0 32: Rough - LeftColor: 3A3226 - RightColor: 4F4537 + MinColor: 3A3226 + MaxColor: 4F4537 ZOffset: -12 ZRamp: 0 33: Rough - LeftColor: 574B3B - RightColor: 5B4E3D + MinColor: 574B3B + MaxColor: 5B4E3D ZOffset: -12 ZRamp: 0 34: Rough - LeftColor: 41382A - RightColor: 4D4132 + MinColor: 41382A + MaxColor: 4D4132 ZOffset: -12 ZRamp: 0 35: Rough - LeftColor: 504434 - RightColor: 61513C + MinColor: 504434 + MaxColor: 61513C ZOffset: -12 ZRamp: 0 38: Rough - LeftColor: 6F593F - RightColor: 60503D + MinColor: 6F593F + MaxColor: 60503D ZOffset: -12 ZRamp: 0 39: Rough - LeftColor: 6A563E - RightColor: 66543E + MinColor: 6A563E + MaxColor: 66543E ZOffset: -12 ZRamp: 0 40: Rough - LeftColor: 655541 - RightColor: 514635 + MinColor: 655541 + MaxColor: 514635 ZOffset: -12 ZRamp: 0 41: Rough - LeftColor: 3C3324 - RightColor: 463C2E + MinColor: 3C3324 + MaxColor: 463C2E ZOffset: -12 ZRamp: 0 42: Rough - LeftColor: 504434 - RightColor: 514638 + MinColor: 504434 + MaxColor: 514638 ZOffset: -12 ZRamp: 0 43: Rough - LeftColor: 544C40 - RightColor: 564A3A + MinColor: 544C40 + MaxColor: 564A3A ZOffset: -12 ZRamp: 0 44: Rough - LeftColor: 594B3B - RightColor: 62523E + MinColor: 594B3B + MaxColor: 62523E ZOffset: -12 ZRamp: 0 49: Rough - LeftColor: 6E5B44 - RightColor: 615341 + MinColor: 6E5B44 + MaxColor: 615341 ZOffset: -12 ZRamp: 0 50: Rough - LeftColor: 5A4D3B - RightColor: 524635 + MinColor: 5A4D3B + MaxColor: 524635 ZOffset: -12 ZRamp: 0 51: Rough - LeftColor: 594C3A - RightColor: 574B3B + MinColor: 594C3A + MaxColor: 574B3B ZOffset: -12 ZRamp: 0 52: Rough - LeftColor: 5B4B36 - RightColor: 5E4E3A + MinColor: 5B4B36 + MaxColor: 5E4E3A ZOffset: -12 ZRamp: 0 53: Rough - LeftColor: 695841 - RightColor: 62513D + MinColor: 695841 + MaxColor: 62513D ZOffset: -12 ZRamp: 0 60: Rough - LeftColor: 6D5940 - RightColor: 5E4D37 + MinColor: 6D5940 + MaxColor: 5E4D37 ZOffset: -12 ZRamp: 0 61: Rough - LeftColor: 6C5840 - RightColor: 635440 + MinColor: 6C5840 + MaxColor: 635440 ZOffset: -12 ZRamp: 0 Template@553: @@ -12695,53 +12697,53 @@ Size: 4, 4 Tiles: 1: Rough - LeftColor: 635340 - RightColor: 62523E + MinColor: 635340 + MaxColor: 62523E ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 534533 - RightColor: 685742 + MinColor: 534533 + MaxColor: 685742 ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: 64523B - RightColor: 6B5B46 + MinColor: 64523B + MaxColor: 6B5B46 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 5F5342 - RightColor: 554A39 + MinColor: 5F5342 + MaxColor: 554A39 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 574937 - RightColor: 564939 + MinColor: 574937 + MaxColor: 564939 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 5A4A36 - RightColor: 64513B + MinColor: 5A4A36 + MaxColor: 64513B ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: 725F47 - RightColor: 5F503E + MinColor: 725F47 + MaxColor: 5F503E ZOffset: -12 ZRamp: 0 9: Rough - LeftColor: 60523F - RightColor: 5B4E3B + MinColor: 60523F + MaxColor: 5B4E3B ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: 695945 - RightColor: 6A5A46 + MinColor: 695945 + MaxColor: 6A5A46 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 6B5841 - RightColor: 60513C + MinColor: 6B5841 + MaxColor: 60513C ZOffset: -12 ZRamp: 0 Template@554: @@ -12751,58 +12753,58 @@ Size: 5, 3 Tiles: 0: Rough - LeftColor: 6B5942 - RightColor: 61523F + MinColor: 6B5942 + MaxColor: 61523F ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 605342 - RightColor: 645644 + MinColor: 605342 + MaxColor: 645644 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 5B4F3F - RightColor: 6B5A43 + MinColor: 5B4F3F + MaxColor: 6B5A43 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 5E4F3C - RightColor: 6F5C44 + MinColor: 5E4F3C + MaxColor: 6F5C44 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 695844 - RightColor: 54493A + MinColor: 695844 + MaxColor: 54493A ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 544635 - RightColor: 534738 + MinColor: 544635 + MaxColor: 534738 ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: 50473A - RightColor: 5C4D3A + MinColor: 50473A + MaxColor: 5C4D3A ZOffset: -12 ZRamp: 0 9: Rough - LeftColor: 51483A - RightColor: 6B5942 + MinColor: 51483A + MaxColor: 6B5942 ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: 69573F - RightColor: 5D503F + MinColor: 69573F + MaxColor: 5D503F ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 65543F - RightColor: 5E5243 + MinColor: 65543F + MaxColor: 5E5243 ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: 635341 - RightColor: 554836 + MinColor: 635341 + MaxColor: 554836 ZOffset: -12 ZRamp: 0 Template@555: @@ -12812,43 +12814,43 @@ Size: 4, 3 Tiles: 0: Rough - LeftColor: 6C5944 - RightColor: 5F503C + MinColor: 6C5944 + MaxColor: 5F503C ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 67553F - RightColor: 5B4E3D + MinColor: 67553F + MaxColor: 5B4E3D ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 493F30 - RightColor: 6B5942 + MinColor: 493F30 + MaxColor: 6B5942 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 675643 - RightColor: 504537 + MinColor: 675643 + MaxColor: 504537 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 3F3B33 - RightColor: 3E3529 + MinColor: 3F3B33 + MaxColor: 3E3529 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 4C4031 - RightColor: 62523D + MinColor: 4C4031 + MaxColor: 62523D ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: 64543F - RightColor: 4B4336 + MinColor: 64543F + MaxColor: 4B4336 ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: 60513E - RightColor: 625545 + MinColor: 60513E + MaxColor: 625545 ZOffset: -12 ZRamp: 0 Template@556: @@ -12858,63 +12860,63 @@ Size: 3, 5 Tiles: 1: Rough - LeftColor: 62523E - RightColor: 6C5B45 + MinColor: 62523E + MaxColor: 6C5B45 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 645440 - RightColor: 65533E + MinColor: 645440 + MaxColor: 65533E ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: 564F45 - RightColor: 504434 + MinColor: 564F45 + MaxColor: 504434 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 534839 - RightColor: 685845 + MinColor: 534839 + MaxColor: 685845 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 605343 - RightColor: 5C4E3B + MinColor: 605343 + MaxColor: 5C4E3B ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 453B2D - RightColor: 5C4E3C + MinColor: 453B2D + MaxColor: 5C4E3C ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: 5D4F3F - RightColor: 625341 + MinColor: 5D4F3F + MaxColor: 625341 ZOffset: -12 ZRamp: 0 9: Rough - LeftColor: 64543F - RightColor: 5F513E + MinColor: 64543F + MaxColor: 5F513E ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: 4A4134 - RightColor: 484136 + MinColor: 4A4134 + MaxColor: 484136 ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: 493F32 - RightColor: 584937 + MinColor: 493F32 + MaxColor: 584937 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 6C5941 - RightColor: 60513D + MinColor: 6C5941 + MaxColor: 60513D ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: 615443 - RightColor: 5A4C3A + MinColor: 615443 + MaxColor: 5A4C3A ZOffset: -12 ZRamp: 0 Template@557: @@ -12924,68 +12926,68 @@ Size: 4, 4 Tiles: 1: Clear - LeftColor: 65533D - RightColor: 64523D + MinColor: 65533D + MaxColor: 64523D ZOffset: -12 ZRamp: 0 2: Clear - LeftColor: 685846 - RightColor: 6B573F + MinColor: 685846 + MaxColor: 6B573F ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 6C5841 - RightColor: 6E5C45 + MinColor: 6C5841 + MaxColor: 6E5C45 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 4D4435 - RightColor: 5B4D3B + MinColor: 4D4435 + MaxColor: 5B4D3B ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 4F4536 - RightColor: 443C30 + MinColor: 4F4536 + MaxColor: 443C30 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 55493A - RightColor: 6E583F + MinColor: 55493A + MaxColor: 6E583F ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 715E46 - RightColor: 675845 + MinColor: 715E46 + MaxColor: 675845 ZOffset: -12 ZRamp: 0 9: Rough - LeftColor: 514738 - RightColor: 494134 + MinColor: 514738 + MaxColor: 494134 ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: 4F4436 - RightColor: 4C4337 + MinColor: 4F4436 + MaxColor: 4C4337 ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: 554939 - RightColor: 635440 + MinColor: 554939 + MaxColor: 635440 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 6D583E - RightColor: 62513C + MinColor: 6D583E + MaxColor: 62513C ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: 63533F - RightColor: 625340 + MinColor: 63533F + MaxColor: 625340 ZOffset: -12 ZRamp: 0 15: Rough - LeftColor: 564A3A - RightColor: 584B3A + MinColor: 564A3A + MaxColor: 584B3A ZOffset: -12 ZRamp: 0 Template@558: @@ -12995,43 +12997,43 @@ Size: 3, 3 Tiles: 0: Rough - LeftColor: 61513E - RightColor: 5D4C38 + MinColor: 61513E + MaxColor: 5D4C38 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 554A39 - RightColor: 64533D + MinColor: 554A39 + MaxColor: 64533D ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 5E4E39 - RightColor: 705D47 + MinColor: 5E4E39 + MaxColor: 705D47 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 6D5C47 - RightColor: 5F5242 + MinColor: 6D5C47 + MaxColor: 5F5242 ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: 63523D - RightColor: 484035 + MinColor: 63523D + MaxColor: 484035 ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 554939 - RightColor: 665541 + MinColor: 554939 + MaxColor: 665541 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 68553D - RightColor: 524635 + MinColor: 68553D + MaxColor: 524635 ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: 62533F - RightColor: 554735 + MinColor: 62533F + MaxColor: 554735 ZOffset: -12 ZRamp: 0 Template@559: @@ -13041,113 +13043,113 @@ Size: 6, 10 Tiles: 1: Rough - LeftColor: 68553E - RightColor: 655440 + MinColor: 68553E + MaxColor: 655440 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 6E5C46 - RightColor: 5C4C38 + MinColor: 6E5C46 + MaxColor: 5C4C38 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 5B4D3A - RightColor: 5D5142 + MinColor: 5B4D3A + MaxColor: 5D5142 ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: 6C5942 - RightColor: 514636 + MinColor: 6C5942 + MaxColor: 514636 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 544838 - RightColor: 5A4C3A + MinColor: 544838 + MaxColor: 5A4C3A ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: 514737 - RightColor: 625039 + MinColor: 514737 + MaxColor: 625039 ZOffset: -12 ZRamp: 0 15: Rough - LeftColor: 5B4D39 - RightColor: 6B5740 + MinColor: 5B4D39 + MaxColor: 6B5740 ZOffset: -12 ZRamp: 0 20: Rough - LeftColor: 655540 - RightColor: 5C4C37 + MinColor: 655540 + MaxColor: 5C4C37 ZOffset: -12 ZRamp: 0 21: Rough - LeftColor: 4D4131 - RightColor: 604F38 + MinColor: 4D4131 + MaxColor: 604F38 ZOffset: -12 ZRamp: 0 22: Rough - LeftColor: 423728 - RightColor: 6A5741 + MinColor: 423728 + MaxColor: 6A5741 ZOffset: -12 ZRamp: 0 26: Rough - LeftColor: 68563F - RightColor: 63533E + MinColor: 68563F + MaxColor: 63533E ZOffset: -12 ZRamp: 0 27: Rough - LeftColor: 544737 - RightColor: 494135 + MinColor: 544737 + MaxColor: 494135 ZOffset: -12 ZRamp: 0 28: Rough - LeftColor: 4D3F2D - RightColor: 544531 + MinColor: 4D3F2D + MaxColor: 544531 ZOffset: -12 ZRamp: 0 33: Rough - LeftColor: 685640 - RightColor: 594B39 + MinColor: 685640 + MaxColor: 594B39 ZOffset: -12 ZRamp: 0 34: Rough - LeftColor: 564A3A - RightColor: 574834 + MinColor: 564A3A + MaxColor: 574834 ZOffset: -12 ZRamp: 0 35: Rough - LeftColor: 695740 - RightColor: 6F5B42 + MinColor: 695740 + MaxColor: 6F5B42 ZOffset: -12 ZRamp: 0 40: Rough - LeftColor: 625546 - RightColor: 5F513F + MinColor: 625546 + MaxColor: 5F513F ZOffset: -12 ZRamp: 0 45: Rough - LeftColor: 5C4E3B - RightColor: 61523E + MinColor: 5C4E3B + MaxColor: 61523E ZOffset: -12 ZRamp: 0 46: Rough - LeftColor: 67553F - RightColor: 61513D + MinColor: 67553F + MaxColor: 61513D ZOffset: -12 ZRamp: 0 51: Rough - LeftColor: 5A4C39 - RightColor: 4F4332 + MinColor: 5A4C39 + MaxColor: 4F4332 ZOffset: -12 ZRamp: 0 52: Rough - LeftColor: 65523C - RightColor: 67543D + MinColor: 65523C + MaxColor: 67543D ZOffset: -12 ZRamp: 0 57: Rough - LeftColor: 6C5942 - RightColor: 594B39 + MinColor: 6C5942 + MaxColor: 594B39 ZOffset: -12 ZRamp: 0 Template@560: @@ -13157,83 +13159,83 @@ Size: 8, 3 Tiles: 0: Clear - LeftColor: 624F36 - RightColor: 715B40 + MinColor: 624F36 + MaxColor: 715B40 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 5C4E3B - RightColor: 5F4F3A + MinColor: 5C4E3B + MaxColor: 5F4F3A ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 544938 - RightColor: 5F4E39 + MinColor: 544938 + MaxColor: 5F4E39 ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 4D4131 - RightColor: 6C583F + MinColor: 4D4131 + MaxColor: 6C583F ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: 544837 - RightColor: 675641 + MinColor: 544837 + MaxColor: 675641 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 5F5241 - RightColor: 6B5841 + MinColor: 5F5241 + MaxColor: 6B5841 ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: 645440 - RightColor: 544939 + MinColor: 645440 + MaxColor: 544939 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 6F5B42 - RightColor: 6F5D47 + MinColor: 6F5B42 + MaxColor: 6F5D47 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 705B42 - RightColor: 685947 + MinColor: 705B42 + MaxColor: 685947 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 705D45 - RightColor: 5F5240 + MinColor: 705D45 + MaxColor: 5F5240 ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: 5E503C - RightColor: 524533 + MinColor: 5E503C + MaxColor: 524533 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 524636 - RightColor: 53483A + MinColor: 524636 + MaxColor: 53483A ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: 574D3E - RightColor: 665743 + MinColor: 574D3E + MaxColor: 665743 ZOffset: -12 ZRamp: 0 15: Rough - LeftColor: 60523F - RightColor: 655541 + MinColor: 60523F + MaxColor: 655541 ZOffset: -12 ZRamp: 0 21: Clear - LeftColor: 6E5A42 - RightColor: 665947 + MinColor: 6E5A42 + MaxColor: 665947 ZOffset: -12 ZRamp: 0 22: Clear - LeftColor: 665540 - RightColor: 725D44 + MinColor: 665540 + MaxColor: 725D44 ZOffset: -12 ZRamp: 0 Template@561: @@ -13243,43 +13245,43 @@ Size: 3, 4 Tiles: 0: Rough - LeftColor: 65533D - RightColor: 5F4E39 + MinColor: 65533D + MaxColor: 5F4E39 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 615546 - RightColor: 6A573F + MinColor: 615546 + MaxColor: 6A573F ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 60513E - RightColor: 554B3E + MinColor: 60513E + MaxColor: 554B3E ZOffset: -12 ZRamp: 0 4: Rough - LeftColor: 5A4B38 - RightColor: 50463A + MinColor: 5A4B38 + MaxColor: 50463A ZOffset: -12 ZRamp: 0 5: Rough - LeftColor: 5E4F3B - RightColor: 695842 + MinColor: 5E4F3B + MaxColor: 695842 ZOffset: -12 ZRamp: 0 7: Rough - LeftColor: 65543E - RightColor: 4F4538 + MinColor: 65543E + MaxColor: 4F4538 ZOffset: -12 ZRamp: 0 8: Rough - LeftColor: 5A4A36 - RightColor: 60513C + MinColor: 5A4A36 + MaxColor: 60513C ZOffset: -12 ZRamp: 0 10: Rough - LeftColor: 695741 - RightColor: 64543F + MinColor: 695741 + MaxColor: 64543F ZOffset: -12 ZRamp: 0 Template@562: @@ -13289,18 +13291,18 @@ Size: 1, 3 Tiles: 0: Rough - LeftColor: 393734 - RightColor: 4D483F + MinColor: 393734 + MaxColor: 4D483F ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 3B3730 - RightColor: 423C33 + MinColor: 3B3730 + MaxColor: 423C33 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 4D4A45 - RightColor: 453F36 + MinColor: 4D4A45 + MaxColor: 453F36 ZOffset: -12 ZRamp: 0 Template@563: @@ -13310,18 +13312,18 @@ Size: 3, 1 Tiles: 0: Rough - LeftColor: 504E4A - RightColor: 3E3A34 + MinColor: 504E4A + MaxColor: 3E3A34 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 3E3B34 - RightColor: 403B36 + MinColor: 3E3B34 + MaxColor: 403B36 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 3F3C38 - RightColor: 625441 + MinColor: 3F3C38 + MaxColor: 625441 ZOffset: -12 ZRamp: 0 Template@564: @@ -13331,18 +13333,18 @@ Size: 1, 3 Tiles: 0: Rough - LeftColor: 3F3A33 - RightColor: 4A4641 + MinColor: 3F3A33 + MaxColor: 4A4641 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 4F4436 - RightColor: 37332D + MinColor: 4F4436 + MaxColor: 37332D ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 4A4339 - RightColor: 423C33 + MinColor: 4A4339 + MaxColor: 423C33 ZOffset: -12 ZRamp: 0 Template@565: @@ -13352,18 +13354,18 @@ Size: 3, 1 Tiles: 0: Rough - LeftColor: 5B4E3E - RightColor: 3B3936 + MinColor: 5B4E3E + MaxColor: 3B3936 ZOffset: -12 ZRamp: 0 1: Rough - LeftColor: 463D2F - RightColor: 3E3B34 + MinColor: 463D2F + MaxColor: 3E3B34 ZOffset: -12 ZRamp: 0 2: Rough - LeftColor: 453E34 - RightColor: 4A453E + MinColor: 453E34 + MaxColor: 4A453E ZOffset: -12 ZRamp: 0 Template@566: @@ -13374,85 +13376,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 6F6B66 - RightColor: 554F46 + MinColor: 6F6B66 + MaxColor: 554F46 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6E6A61 - RightColor: 635E57 + MinColor: 6E6A61 + MaxColor: 635E57 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 6E5A41 - RightColor: 6C5840 + MinColor: 6E5A41 + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 33312F - RightColor: 4B4A48 + MinColor: 33312F + MaxColor: 4B4A48 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 313131 - RightColor: 585855 + MinColor: 313131 + MaxColor: 585855 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 6C573F - RightColor: 6B5E4D + MinColor: 6C573F + MaxColor: 6B5E4D ZOffset: -12 ZRamp: 0 6: Rail Height: 4 - LeftColor: 363739 - RightColor: 393A3C + MinColor: 363739 + MaxColor: 393A3C ZOffset: -12 ZRamp: 0 7: Rail Height: 4 - LeftColor: 353739 - RightColor: 393A3C + MinColor: 353739 + MaxColor: 393A3C ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 705C44 - RightColor: 625D55 + MinColor: 705C44 + MaxColor: 625D55 ZOffset: -12 ZRamp: 0 9: Road Height: 4 - LeftColor: 4C4A48 - RightColor: 35322F + MinColor: 4C4A48 + MaxColor: 35322F ZOffset: -12 ZRamp: 0 10: Road Height: 4 - LeftColor: 4D4C4A - RightColor: 32312F + MinColor: 4D4C4A + MaxColor: 32312F ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 6F583E - RightColor: 5F584F + MinColor: 6F583E + MaxColor: 5F584F ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 5B564E - RightColor: 777571 + MinColor: 5B564E + MaxColor: 777571 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 6E6150 - RightColor: 858279 + MinColor: 6E6150 + MaxColor: 858279 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 705A40 - RightColor: 70593E + MinColor: 705A40 + MaxColor: 70593E ZOffset: -12 ZRamp: 0 Template@567: @@ -13463,85 +13465,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 6F6B66 - RightColor: 554F46 + MinColor: 6F6B66 + MaxColor: 554F46 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6F6C66 - RightColor: 5E5C58 + MinColor: 6F6C66 + MaxColor: 5E5C58 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 15273B - RightColor: 0F2339 + MinColor: 15273B + MaxColor: 0F2339 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 33312F - RightColor: 4B4A48 + MinColor: 33312F + MaxColor: 4B4A48 ZOffset: -12 ZRamp: 0 4: Road Height: 4 - LeftColor: 313131 - RightColor: 585855 + MinColor: 313131 + MaxColor: 585855 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 1E2933 - RightColor: 3E454B + MinColor: 1E2933 + MaxColor: 3E454B ZOffset: -12 ZRamp: 0 6: Rail Height: 4 - LeftColor: 363739 - RightColor: 393A3C + MinColor: 363739 + MaxColor: 393A3C ZOffset: -12 ZRamp: 0 7: Rail Height: 4 - LeftColor: 353739 - RightColor: 393A3C + MinColor: 353739 + MaxColor: 393A3C ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 1F2C39 - RightColor: 515355 + MinColor: 1F2C39 + MaxColor: 515355 ZOffset: -12 ZRamp: 0 9: Road Height: 4 - LeftColor: 4C4A48 - RightColor: 35322F + MinColor: 4C4A48 + MaxColor: 35322F ZOffset: -12 ZRamp: 0 10: Road Height: 4 - LeftColor: 4D4C4A - RightColor: 32312F + MinColor: 4D4C4A + MaxColor: 32312F ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 233344 - RightColor: 4D4F4F + MinColor: 233344 + MaxColor: 4D4F4F ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 5B564E - RightColor: 777571 + MinColor: 5B564E + MaxColor: 777571 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 504F4B - RightColor: 84827A + MinColor: 504F4B + MaxColor: 84827A ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 243341 - RightColor: 16273C + MinColor: 243341 + MaxColor: 16273C ZOffset: -12 ZRamp: 0 Template@568: @@ -13551,61 +13553,61 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 726F6A - RightColor: 585147 + MinColor: 726F6A + MaxColor: 585147 ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 33312F - RightColor: 605E5A + MinColor: 33312F + MaxColor: 605E5A ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 313131 - RightColor: 494846 + MinColor: 313131 + MaxColor: 494846 ZOffset: -12 ZRamp: 0 4: Rail Height: 4 - LeftColor: 363739 - RightColor: 393A3C + MinColor: 363739 + MaxColor: 393A3C ZOffset: -12 ZRamp: 0 5: Rail Height: 4 - LeftColor: 353739 - RightColor: 393A3C + MinColor: 353739 + MaxColor: 393A3C ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 4C4C4B - RightColor: 35322F + MinColor: 4C4C4B + MaxColor: 35322F ZOffset: -12 ZRamp: 0 7: Road Height: 4 - LeftColor: 4B4945 - RightColor: 323130 + MinColor: 4B4945 + MaxColor: 323130 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 8C8579 - RightColor: 8A857A + MinColor: 8C8579 + MaxColor: 8A857A ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 534D43 - RightColor: 6A6865 + MinColor: 534D43 + MaxColor: 6A6865 ZOffset: -12 ZRamp: 0 Template@569: @@ -13616,85 +13618,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4F4940 - RightColor: 63605B + MinColor: 4F4940 + MaxColor: 63605B ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 4B4A48 - RightColor: 33312F + MinColor: 4B4A48 + MaxColor: 33312F ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 37383A - RightColor: 353738 + MinColor: 37383A + MaxColor: 353738 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 34322F - RightColor: 494844 + MinColor: 34322F + MaxColor: 494844 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 5B5955 - RightColor: 564D42 + MinColor: 5B5955 + MaxColor: 564D42 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 998E7D - RightColor: 98958D + MinColor: 998E7D + MaxColor: 98958D ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 494845 - RightColor: 484745 + MinColor: 494845 + MaxColor: 484745 ZOffset: -12 ZRamp: 0 7: Rail Height: 4 - LeftColor: 37383A - RightColor: 353639 + MinColor: 37383A + MaxColor: 353639 ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 32312E - RightColor: 4B4945 + MinColor: 32312E + MaxColor: 4B4945 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 645A4C - RightColor: 6A655B + MinColor: 645A4C + MaxColor: 6A655B ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 6D573D - RightColor: 6F593E + MinColor: 6D573D + MaxColor: 6F593E ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 6E583D - RightColor: 887A68 + MinColor: 6E583D + MaxColor: 887A68 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 725C41 - RightColor: 8D867A + MinColor: 725C41 + MaxColor: 8D867A ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 6F5A40 - RightColor: 8B8478 + MinColor: 6F5A40 + MaxColor: 8B8478 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 705C43 - RightColor: 6C573E + MinColor: 705C43 + MaxColor: 6C573E ZOffset: -12 ZRamp: 0 Template@570: @@ -13705,85 +13707,85 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4F4940 - RightColor: 63605B + MinColor: 4F4940 + MaxColor: 63605B ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 4B4A48 - RightColor: 33312F + MinColor: 4B4A48 + MaxColor: 33312F ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 37383A - RightColor: 353738 + MinColor: 37383A + MaxColor: 353738 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 34322F - RightColor: 494844 + MinColor: 34322F + MaxColor: 494844 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 5B5955 - RightColor: 564D42 + MinColor: 5B5955 + MaxColor: 564D42 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 888989 - RightColor: 98958D + MinColor: 888989 + MaxColor: 98958D ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 494845 - RightColor: 484745 + MinColor: 494845 + MaxColor: 484745 ZOffset: -12 ZRamp: 0 7: Rail Height: 4 - LeftColor: 37383A - RightColor: 353639 + MinColor: 37383A + MaxColor: 353639 ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 32312E - RightColor: 4B4945 + MinColor: 32312E + MaxColor: 4B4945 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 5D584F - RightColor: 67635B + MinColor: 5D584F + MaxColor: 67635B ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 0E2036 - RightColor: 192A3E + MinColor: 0E2036 + MaxColor: 192A3E ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 102135 - RightColor: 666B6E + MinColor: 102135 + MaxColor: 666B6E ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 122439 - RightColor: 7F7F7C + MinColor: 122439 + MaxColor: 7F7F7C ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 112337 - RightColor: 80817E + MinColor: 112337 + MaxColor: 80817E ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 112135 - RightColor: 223041 + MinColor: 112135 + MaxColor: 223041 ZOffset: -12 ZRamp: 0 Template@571: @@ -13793,61 +13795,61 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: 000000 - RightColor: 000000 + MinColor: 000000 + MaxColor: 000000 ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 4C4C4C - RightColor: 4C4B4A + MinColor: 4C4C4C + MaxColor: 4C4B4A ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 37383A - RightColor: 353738 + MinColor: 37383A + MaxColor: 353738 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 35332F - RightColor: 4D4C4B + MinColor: 35332F + MaxColor: 4D4C4B ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 685F55 - RightColor: 6B665F + MinColor: 685F55 + MaxColor: 6B665F ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 564D40 - RightColor: 605E5B + MinColor: 564D40 + MaxColor: 605E5B ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 4D4D4C - RightColor: 333230 + MinColor: 4D4D4C + MaxColor: 333230 ZOffset: -12 ZRamp: 0 7: Rail Height: 4 - LeftColor: 373839 - RightColor: 353639 + MinColor: 373839 + MaxColor: 353639 ZOffset: -12 ZRamp: 0 8: Road Height: 4 - LeftColor: 313130 - RightColor: 4B4C4C + MinColor: 313130 + MaxColor: 4B4C4C ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 5E5B57 - RightColor: 56534E + MinColor: 5E5B57 + MaxColor: 56534E ZOffset: -12 ZRamp: 0 Template@572: @@ -13857,56 +13859,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 6A6967 + MinColor: 71706D + MaxColor: 6A6967 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: CCCDDD - RightColor: D1D2EE + MinColor: CCCDDD + MaxColor: D1D2EE ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 454646 - RightColor: 6D6D6E + MinColor: 454646 + MaxColor: 6D6D6E ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: CCCDDD - RightColor: 9F9FAB + MinColor: CCCDDD + MaxColor: 9F9FAB ZOffset: -12 ZRamp: 0 4: Rail Height: 4 - LeftColor: 373633 - RightColor: 373632 + MinColor: 373633 + MaxColor: 373632 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C8CADE - RightColor: 747478 + MinColor: C8CADE + MaxColor: 747478 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 626262 - RightColor: 464646 + MinColor: 626262 + MaxColor: 464646 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: C8CADF - RightColor: 737379 + MinColor: C8CADF + MaxColor: 737379 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B5B5B9 - RightColor: 999896 + MinColor: B5B5B9 + MaxColor: 999896 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C8CBE6 - RightColor: C3C5F7 + MinColor: C8CBE6 + MaxColor: C3C5F7 ZOffset: -12 ZRamp: 0 Template@573: @@ -13916,56 +13918,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 696867 + MinColor: 71706D + MaxColor: 696867 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: CCCDDD - RightColor: D1D2EE + MinColor: CCCDDD + MaxColor: D1D2EE ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 3F4041 - RightColor: 666667 + MinColor: 3F4041 + MaxColor: 666667 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: CCCDDD - RightColor: 9F9FAB + MinColor: CCCDDD + MaxColor: 9F9FAB ZOffset: -12 ZRamp: 0 4: Rough Height: 4 - LeftColor: 343331 - RightColor: 383734 + MinColor: 343331 + MaxColor: 383734 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C8CADE - RightColor: 747478 + MinColor: C8CADE + MaxColor: 747478 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 4A4A4A - RightColor: 414141 + MinColor: 4A4A4A + MaxColor: 414141 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: C8CADF - RightColor: 737379 + MinColor: C8CADF + MaxColor: 737379 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: A6A6AA - RightColor: 939290 + MinColor: A6A6AA + MaxColor: 939290 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C6C8E3 - RightColor: C3C5F7 + MinColor: C6C8E3 + MaxColor: C3C5F7 ZOffset: -12 ZRamp: 0 Template@574: @@ -13975,56 +13977,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 6A6967 + MinColor: 71706D + MaxColor: 6A6967 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C8CAD9 - RightColor: D1D2EE + MinColor: C8CAD9 + MaxColor: D1D2EE ZOffset: -12 ZRamp: 0 2: Road Height: 4 - LeftColor: 404040 - RightColor: 656565 + MinColor: 404040 + MaxColor: 656565 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B9BBCA - RightColor: 8E8F97 + MinColor: B9BBCA + MaxColor: 8E8F97 ZOffset: -12 ZRamp: 0 4: Rail Height: 4 - LeftColor: 363533 - RightColor: 31312F + MinColor: 363533 + MaxColor: 31312F ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: B8BBCB - RightColor: 727276 + MinColor: B8BBCB + MaxColor: 727276 ZOffset: -12 ZRamp: 0 6: Road Height: 4 - LeftColor: 5B5B5B - RightColor: 404040 + MinColor: 5B5B5B + MaxColor: 404040 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: BFC0CE - RightColor: 6E6E73 + MinColor: BFC0CE + MaxColor: 6E6E73 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B3B2B6 - RightColor: 91908F + MinColor: B3B2B6 + MaxColor: 91908F ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C6C8E3 - RightColor: B1B3DA + MinColor: C6C8E3 + MaxColor: B1B3DA ZOffset: -12 ZRamp: 0 Template@575: @@ -14034,56 +14036,56 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 71706D - RightColor: 686765 + MinColor: 71706D + MaxColor: 686765 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C8CAD9 - RightColor: D1D2EE + MinColor: C8CAD9 + MaxColor: D1D2EE ZOffset: -12 ZRamp: 0 2: Rough Height: 4 - LeftColor: 3C3C3D - RightColor: 5B5B5B + MinColor: 3C3C3D + MaxColor: 5B5B5B ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: B9BBCA - RightColor: 8E8F97 + MinColor: B9BBCA + MaxColor: 8E8F97 ZOffset: -12 ZRamp: 0 4: Rough Height: 4 - LeftColor: 353533 - RightColor: 343330 + MinColor: 353533 + MaxColor: 343330 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: B8BBCB - RightColor: 727276 + MinColor: B8BBCB + MaxColor: 727276 ZOffset: -12 ZRamp: 0 6: Rough Height: 4 - LeftColor: 4B4B4B - RightColor: 3D3D3D + MinColor: 4B4B4B + MaxColor: 3D3D3D ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: BFC0CE - RightColor: 6E6E73 + MinColor: BFC0CE + MaxColor: 6E6E73 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: A6A6AA - RightColor: 91918F + MinColor: A6A6AA + MaxColor: 91918F ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C6C8E3 - RightColor: B1B3DA + MinColor: C6C8E3 + MaxColor: B1B3DA ZOffset: -12 ZRamp: 0 Template@576: @@ -14093,53 +14095,53 @@ Size: 2, 5 Tiles: 0: Cliff - LeftColor: 7A7977 - RightColor: 90908F + MinColor: 7A7977 + MaxColor: 90908F ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: C3C4D0 - RightColor: B5B6C7 + MinColor: C3C4D0 + MaxColor: B5B6C7 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 636260 - RightColor: 6C6C6A + MinColor: 636260 + MaxColor: 6C6C6A ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 7A7C84 - RightColor: B0B1C6 + MinColor: 7A7C84 + MaxColor: B0B1C6 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6E6D6B - RightColor: 848380 + MinColor: 6E6D6B + MaxColor: 848380 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 979AA7 - RightColor: 7D7F89 + MinColor: 979AA7 + MaxColor: 7D7F89 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 797875 - RightColor: 979692 + MinColor: 797875 + MaxColor: 979692 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: BABBC6 - RightColor: B9BBDD + MinColor: BABBC6 + MaxColor: B9BBDD ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: B3B3BA - RightColor: A9A9AD + MinColor: B3B3BA + MaxColor: A9A9AD ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C6C8E3 - RightColor: B0B2D6 + MinColor: C6C8E3 + MaxColor: B0B2D6 ZOffset: -12 ZRamp: 0 Template@577: @@ -14149,56 +14151,56 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: BDBDC5 - RightColor: 9D9C98 + MinColor: BDBDC5 + MaxColor: 9D9C98 ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 616161 - RightColor: 565657 + MinColor: 616161 + MaxColor: 565657 ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 363531 - RightColor: 373632 + MinColor: 363531 + MaxColor: 373632 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 454545 - RightColor: 606061 + MinColor: 454545 + MaxColor: 606061 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 8F8F97 - RightColor: 898889 + MinColor: 8F8F97 + MaxColor: 898889 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: D3D3F1 - RightColor: CDCEE4 + MinColor: D3D3F1 + MaxColor: CDCEE4 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: CBCDE2 - RightColor: B7B8C4 + MinColor: CBCDE2 + MaxColor: B7B8C4 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: CFD0EF - RightColor: A6A4A6 + MinColor: CFD0EF + MaxColor: A6A4A6 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C8CAF5 - RightColor: A3A3A5 + MinColor: C8CAF5 + MaxColor: A3A3A5 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C8CAF5 - RightColor: CBCDEC + MinColor: C8CAF5 + MaxColor: CBCDEC ZOffset: -12 ZRamp: 0 Template@578: @@ -14209,50 +14211,50 @@ Tiles: 1: Road Height: 4 - LeftColor: 585858 - RightColor: 4E4E4E + MinColor: 585858 + MaxColor: 4E4E4E ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 33322F - RightColor: 343330 + MinColor: 33322F + MaxColor: 343330 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 444444 - RightColor: 535353 + MinColor: 444444 + MaxColor: 535353 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 8F8F97 - RightColor: 898989 + MinColor: 8F8F97 + MaxColor: 898989 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: D3D3F1 - RightColor: BABAC2 + MinColor: D3D3F1 + MaxColor: BABAC2 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: CBCDE2 - RightColor: A3A3A4 + MinColor: CBCDE2 + MaxColor: A3A3A4 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: CFD0EF - RightColor: A6A4A6 + MinColor: CFD0EF + MaxColor: A6A4A6 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C8CAF5 - RightColor: A3A3A5 + MinColor: C8CAF5 + MaxColor: A3A3A5 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C8CAF5 - RightColor: CBCDEC + MinColor: C8CAF5 + MaxColor: CBCDEC ZOffset: -12 ZRamp: 0 Template@579: @@ -14262,56 +14264,56 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: A3A3AA - RightColor: 8E8D89 + MinColor: A3A3AA + MaxColor: 8E8D89 ZOffset: -12 ZRamp: 0 1: Road Height: 4 - LeftColor: 565656 - RightColor: 515151 + MinColor: 565656 + MaxColor: 515151 ZOffset: -12 ZRamp: 0 2: Rail Height: 4 - LeftColor: 33322E - RightColor: 373633 + MinColor: 33322E + MaxColor: 373633 ZOffset: -12 ZRamp: 0 3: Road Height: 4 - LeftColor: 3F3F3F - RightColor: 5F6060 + MinColor: 3F3F3F + MaxColor: 5F6060 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 8F8F97 - RightColor: 888788 + MinColor: 8F8F97 + MaxColor: 888788 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: D3D3F1 - RightColor: BEBFD3 + MinColor: D3D3F1 + MaxColor: BEBFD3 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: C0C2D5 - RightColor: A5A6B0 + MinColor: C0C2D5 + MaxColor: A5A6B0 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: C5C7DF - RightColor: 969494 + MinColor: C5C7DF + MaxColor: 969494 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C3C5E4 - RightColor: 9E9D9F + MinColor: C3C5E4 + MaxColor: 9E9D9F ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C7C9F3 - RightColor: CBCDEC + MinColor: C7C9F3 + MaxColor: CBCDEC ZOffset: -12 ZRamp: 0 Template@580: @@ -14322,50 +14324,50 @@ Tiles: 1: Rough Height: 4 - LeftColor: 414242 - RightColor: 4B4B4B + MinColor: 414242 + MaxColor: 4B4B4B ZOffset: -12 ZRamp: 0 2: Rough Height: 4 - LeftColor: 2E2D2B - RightColor: 2D2B28 + MinColor: 2E2D2B + MaxColor: 2D2B28 ZOffset: -12 ZRamp: 0 3: Rough Height: 4 - LeftColor: 313131 - RightColor: 4D4D4D + MinColor: 313131 + MaxColor: 4D4D4D ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 86868A - RightColor: 848384 + MinColor: 86868A + MaxColor: 848384 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C7C8E2 - RightColor: AAAAB0 + MinColor: C7C8E2 + MaxColor: AAAAB0 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: C0C2D5 - RightColor: 909091 + MinColor: C0C2D5 + MaxColor: 909091 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: C2C3DB - RightColor: 949392 + MinColor: C2C3DB + MaxColor: 949392 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C3C5E4 - RightColor: A2A1A3 + MinColor: C3C5E4 + MaxColor: A2A1A3 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: C3C5F0 - RightColor: B9BAD4 + MinColor: C3C5F0 + MaxColor: B9BAD4 ZOffset: -12 ZRamp: 0 Template@581: @@ -14375,53 +14377,53 @@ Size: 5, 2 Tiles: 0: Cliff - LeftColor: A2A3AA - RightColor: 8A8987 + MinColor: A2A3AA + MaxColor: 8A8987 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 979797 - RightColor: 969491 + MinColor: 979797 + MaxColor: 969491 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 8A8883 - RightColor: 888783 + MinColor: 8A8883 + MaxColor: 888783 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 959390 - RightColor: 787776 + MinColor: 959390 + MaxColor: 787776 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 848489 - RightColor: 919199 + MinColor: 848489 + MaxColor: 919199 ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: C7C8E2 - RightColor: BBBCC9 + MinColor: C7C8E2 + MaxColor: BBBCC9 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: B7B9C7 - RightColor: A7A9BA + MinColor: B7B9C7 + MaxColor: A7A9BA ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: B0B0BC - RightColor: 707178 + MinColor: B0B0BC + MaxColor: 707178 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: C2C4E4 - RightColor: A2A3AD + MinColor: C2C4E4 + MaxColor: A2A3AD ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: BFC1EB - RightColor: B7B9D3 + MinColor: BFC1EB + MaxColor: B7B9D3 ZOffset: -12 ZRamp: 0 Template@582: @@ -14431,8 +14433,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 565553 - RightColor: 535250 + MinColor: 565553 + MaxColor: 535250 ZOffset: -12 ZRamp: 0 Template@583: @@ -14442,8 +14444,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 585754 - RightColor: 545250 + MinColor: 585754 + MaxColor: 545250 ZOffset: -12 ZRamp: 0 Template@584: @@ -14453,8 +14455,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 545350 - RightColor: 525251 + MinColor: 545350 + MaxColor: 525251 ZOffset: -12 ZRamp: 0 Template@585: @@ -14464,8 +14466,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 504F4D - RightColor: 4D4D4C + MinColor: 504F4D + MaxColor: 4D4D4C ZOffset: -12 ZRamp: 0 Template@586: @@ -14475,23 +14477,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 57534E - RightColor: 55524E + MinColor: 57534E + MaxColor: 55524E ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 55514D - RightColor: 54524F + MinColor: 55514D + MaxColor: 54524F ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 52514F - RightColor: 54514C + MinColor: 52514F + MaxColor: 54514C ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 53524F - RightColor: 59544F + MinColor: 53524F + MaxColor: 59544F ZOffset: -12 ZRamp: 0 Template@587: @@ -14501,23 +14503,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 565553 - RightColor: 535250 + MinColor: 565553 + MaxColor: 535250 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 535251 - RightColor: 525251 + MinColor: 535251 + MaxColor: 525251 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 565452 - RightColor: 545251 + MinColor: 565452 + MaxColor: 545251 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 565554 - RightColor: 575756 + MinColor: 565554 + MaxColor: 575756 ZOffset: -12 ZRamp: 0 Template@588: @@ -14527,23 +14529,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 52514F - RightColor: 4E4D4D + MinColor: 52514F + MaxColor: 4E4D4D ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 545352 - RightColor: 565552 + MinColor: 545352 + MaxColor: 565552 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 565553 - RightColor: 565552 + MinColor: 565553 + MaxColor: 565552 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 4F4E4C - RightColor: 51504E + MinColor: 4F4E4C + MaxColor: 51504E ZOffset: -12 ZRamp: 0 Template@589: @@ -14553,23 +14555,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 595855 - RightColor: 555451 + MinColor: 595855 + MaxColor: 555451 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 5A5956 - RightColor: 5A5855 + MinColor: 5A5956 + MaxColor: 5A5855 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 565452 - RightColor: 565553 + MinColor: 565452 + MaxColor: 565553 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 575653 - RightColor: 5A5854 + MinColor: 575653 + MaxColor: 5A5854 ZOffset: -12 ZRamp: 0 Template@590: @@ -14579,23 +14581,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 5B5A58 - RightColor: 5B5855 + MinColor: 5B5A58 + MaxColor: 5B5855 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 5B5B58 - RightColor: 595855 + MinColor: 5B5B58 + MaxColor: 595855 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 53524F - RightColor: 545351 + MinColor: 53524F + MaxColor: 545351 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 555350 - RightColor: 585654 + MinColor: 555350 + MaxColor: 585654 ZOffset: -12 ZRamp: 0 Template@591: @@ -14605,23 +14607,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 585552 - RightColor: 535252 + MinColor: 585552 + MaxColor: 535252 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 565553 - RightColor: 555451 + MinColor: 565553 + MaxColor: 555451 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 555351 - RightColor: 545452 + MinColor: 555351 + MaxColor: 545452 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 57534F - RightColor: 545353 + MinColor: 57534F + MaxColor: 545353 ZOffset: -12 ZRamp: 0 Template@592: @@ -14631,23 +14633,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 57534D - RightColor: 5B5651 + MinColor: 57534D + MaxColor: 5B5651 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 5D5952 - RightColor: 5A5753 + MinColor: 5D5952 + MaxColor: 5A5753 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 55524F - RightColor: 5B554D + MinColor: 55524F + MaxColor: 5B554D ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 5B5751 - RightColor: 5B5955 + MinColor: 5B5751 + MaxColor: 5B5955 ZOffset: -12 ZRamp: 0 Template@593: @@ -14657,23 +14659,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 58544F - RightColor: 5F584F + MinColor: 58544F + MaxColor: 5F584F ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 5F5A53 - RightColor: 5A5651 + MinColor: 5F5A53 + MaxColor: 5A5651 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 5A5652 - RightColor: 615B53 + MinColor: 5A5652 + MaxColor: 615B53 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 5B554E - RightColor: 55534F + MinColor: 5B554E + MaxColor: 55534F ZOffset: -12 ZRamp: 0 Template@594: @@ -14683,23 +14685,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 56534E - RightColor: 59554F + MinColor: 56534E + MaxColor: 59554F ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 5C5750 - RightColor: 575551 + MinColor: 5C5750 + MaxColor: 575551 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 565450 - RightColor: 5A5650 + MinColor: 565450 + MaxColor: 5A5650 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 5C5750 - RightColor: 555452 + MinColor: 5C5750 + MaxColor: 555452 ZOffset: -12 ZRamp: 0 Template@595: @@ -14709,23 +14711,23 @@ Size: 2, 2 Tiles: 0: Road - LeftColor: 56534E - RightColor: 59554F + MinColor: 56534E + MaxColor: 59554F ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 5C5750 - RightColor: 575551 + MinColor: 5C5750 + MaxColor: 575551 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 565450 - RightColor: 5A5650 + MinColor: 565450 + MaxColor: 5A5650 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 5C5750 - RightColor: 555452 + MinColor: 5C5750 + MaxColor: 555452 ZOffset: -12 ZRamp: 0 Template@596: @@ -14735,8 +14737,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 5E554A - RightColor: 615548 + MinColor: 5E554A + MaxColor: 615548 ZOffset: -12 ZRamp: 0 Template@597: @@ -14746,8 +14748,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 58544C - RightColor: 615546 + MinColor: 58544C + MaxColor: 615546 ZOffset: -12 ZRamp: 0 Template@598: @@ -14757,8 +14759,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 58544E - RightColor: 635747 + MinColor: 58544E + MaxColor: 635747 ZOffset: -12 ZRamp: 0 Template@599: @@ -14768,8 +14770,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 5F574D - RightColor: 705A3E + MinColor: 5F574D + MaxColor: 705A3E ZOffset: -12 ZRamp: 0 Template@600: @@ -14779,8 +14781,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 625546 - RightColor: 56524D + MinColor: 625546 + MaxColor: 56524D ZOffset: -12 ZRamp: 0 Template@601: @@ -14790,8 +14792,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 655644 - RightColor: 645644 + MinColor: 655644 + MaxColor: 645644 ZOffset: -12 ZRamp: 0 Template@602: @@ -14801,8 +14803,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 675642 - RightColor: 695844 + MinColor: 675642 + MaxColor: 695844 ZOffset: -12 ZRamp: 0 Template@603: @@ -14812,8 +14814,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 5B5348 - RightColor: 675540 + MinColor: 5B5348 + MaxColor: 675540 ZOffset: -12 ZRamp: 0 Template@604: @@ -14823,8 +14825,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 665A49 - RightColor: 5C574E + MinColor: 665A49 + MaxColor: 5C574E ZOffset: -12 ZRamp: 0 Template@605: @@ -14834,8 +14836,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 695C49 - RightColor: 63594A + MinColor: 695C49 + MaxColor: 63594A ZOffset: -12 ZRamp: 0 Template@606: @@ -14845,8 +14847,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 64594B - RightColor: 645849 + MinColor: 64594B + MaxColor: 645849 ZOffset: -12 ZRamp: 0 Template@607: @@ -14856,8 +14858,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 625547 - RightColor: 6C573E + MinColor: 625547 + MaxColor: 6C573E ZOffset: -12 ZRamp: 0 Template@608: @@ -14867,8 +14869,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 6D5941 - RightColor: 56544E + MinColor: 6D5941 + MaxColor: 56544E ZOffset: -12 ZRamp: 0 Template@609: @@ -14878,8 +14880,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 6F5A3F - RightColor: 64584A + MinColor: 6F5A3F + MaxColor: 64584A ZOffset: -12 ZRamp: 0 Template@610: @@ -14889,8 +14891,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 6C5943 - RightColor: 635747 + MinColor: 6C5943 + MaxColor: 635747 ZOffset: -12 ZRamp: 0 Template@611: @@ -14900,8 +14902,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 645645 - RightColor: 655745 + MinColor: 645645 + MaxColor: 655745 ZOffset: -12 ZRamp: 0 Template@612: @@ -14911,8 +14913,8 @@ Size: 1, 1 Tiles: 0: DirtRoad - LeftColor: 3E3B38 - RightColor: 443F3A + MinColor: 3E3B38 + MaxColor: 443F3A ZOffset: -12 ZRamp: 0 Template@613: @@ -14922,8 +14924,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 494139 - RightColor: 4B433A + MinColor: 494139 + MaxColor: 4B433A ZOffset: -12 ZRamp: 0 Template@614: @@ -14933,8 +14935,8 @@ Size: 1, 1 Tiles: 0: DirtRoad - LeftColor: 413D38 - RightColor: 3F3D39 + MinColor: 413D38 + MaxColor: 3F3D39 ZOffset: -12 ZRamp: 0 Template@615: @@ -14944,8 +14946,8 @@ Size: 1, 1 Tiles: 0: DirtRoad - LeftColor: 3A3937 - RightColor: 453F37 + MinColor: 3A3937 + MaxColor: 453F37 ZOffset: -12 ZRamp: 0 Template@616: @@ -14955,8 +14957,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4B433A - RightColor: 494139 + MinColor: 4B433A + MaxColor: 494139 ZOffset: -12 ZRamp: 0 Template@617: @@ -14966,8 +14968,8 @@ Size: 1, 1 Tiles: 0: DirtRoad - LeftColor: 464038 - RightColor: 393838 + MinColor: 464038 + MaxColor: 393838 ZOffset: -12 ZRamp: 0 Template@618: @@ -14977,8 +14979,8 @@ Size: 1, 1 Tiles: 0: DirtRoad - LeftColor: 403E3B - RightColor: 49443F + MinColor: 403E3B + MaxColor: 49443F ZOffset: -12 ZRamp: 0 Template@619: @@ -14988,8 +14990,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4A423A - RightColor: 4D453B + MinColor: 4A423A + MaxColor: 4D453B ZOffset: -12 ZRamp: 0 Template@620: @@ -14999,8 +15001,8 @@ Size: 1, 1 Tiles: 0: DirtRoad - LeftColor: 47433F - RightColor: 43413D + MinColor: 47433F + MaxColor: 43413D ZOffset: -12 ZRamp: 0 Template@621: @@ -15010,8 +15012,8 @@ Size: 1, 1 Tiles: 0: DirtRoad - LeftColor: 403F3D - RightColor: 474139 + MinColor: 403F3D + MaxColor: 474139 ZOffset: -12 ZRamp: 0 Template@622: @@ -15021,8 +15023,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 4D453B - RightColor: 4A423A + MinColor: 4D453B + MaxColor: 4A423A ZOffset: -12 ZRamp: 0 Template@623: @@ -15032,8 +15034,8 @@ Size: 1, 1 Tiles: 0: DirtRoad - LeftColor: 48423A - RightColor: 40403F + MinColor: 48423A + MaxColor: 40403F ZOffset: -12 ZRamp: 0 Template@624: @@ -15043,18 +15045,18 @@ Size: 1, 3 Tiles: 0: Road - LeftColor: 494846 - RightColor: 52504E + MinColor: 494846 + MaxColor: 52504E ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 464542 - RightColor: 454340 + MinColor: 464542 + MaxColor: 454340 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 565552 - RightColor: 484745 + MinColor: 565552 + MaxColor: 484745 ZOffset: -12 ZRamp: 0 Template@625: @@ -15064,18 +15066,18 @@ Size: 3, 1 Tiles: 0: Road - LeftColor: 52504E - RightColor: 494846 + MinColor: 52504E + MaxColor: 494846 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 454340 - RightColor: 464542 + MinColor: 454340 + MaxColor: 464542 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 484745 - RightColor: 565552 + MinColor: 484745 + MaxColor: 565552 ZOffset: -12 ZRamp: 0 Template@626: @@ -15085,8 +15087,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 2B300C - RightColor: 2B330C + MinColor: 2B300C + MaxColor: 2B330C ZOffset: -12 ZRamp: 0 Template@627: @@ -15096,8 +15098,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 4D452C - RightColor: 494328 + MinColor: 4D452C + MaxColor: 494328 ZOffset: -12 ZRamp: 0 Template@628: @@ -15107,8 +15109,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 363518 - RightColor: 5A4C34 + MinColor: 363518 + MaxColor: 5A4C34 ZOffset: -12 ZRamp: 0 Template@629: @@ -15118,8 +15120,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 3D3A21 - RightColor: 4D432A + MinColor: 3D3A21 + MaxColor: 4D432A ZOffset: -12 ZRamp: 0 Template@630: @@ -15129,8 +15131,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 484426 - RightColor: 62513C + MinColor: 484426 + MaxColor: 62513C ZOffset: -12 ZRamp: 0 Template@631: @@ -15140,8 +15142,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 594C34 - RightColor: 444220 + MinColor: 594C34 + MaxColor: 444220 ZOffset: -12 ZRamp: 0 Template@632: @@ -15151,8 +15153,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 57492E - RightColor: 54492F + MinColor: 57492E + MaxColor: 54492F ZOffset: -12 ZRamp: 0 Template@633: @@ -15162,8 +15164,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 4D4529 - RightColor: 564931 + MinColor: 4D4529 + MaxColor: 564931 ZOffset: -12 ZRamp: 0 Template@634: @@ -15173,8 +15175,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 504629 - RightColor: 64533F + MinColor: 504629 + MaxColor: 64533F ZOffset: -12 ZRamp: 0 Template@635: @@ -15184,8 +15186,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 50472D - RightColor: 454125 + MinColor: 50472D + MaxColor: 454125 ZOffset: -12 ZRamp: 0 Template@636: @@ -15195,8 +15197,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 4C422B - RightColor: 594C31 + MinColor: 4C422B + MaxColor: 594C31 ZOffset: -12 ZRamp: 0 Template@637: @@ -15206,8 +15208,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 50482E - RightColor: 4F4728 + MinColor: 50482E + MaxColor: 4F4728 ZOffset: -12 ZRamp: 0 Template@638: @@ -15217,8 +15219,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 544A30 - RightColor: 60503B + MinColor: 544A30 + MaxColor: 60503B ZOffset: -12 ZRamp: 0 Template@639: @@ -15228,8 +15230,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 66533B - RightColor: 4D4528 + MinColor: 66533B + MaxColor: 4D4528 ZOffset: -12 ZRamp: 0 Template@640: @@ -15239,8 +15241,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 5F4F38 - RightColor: 574A31 + MinColor: 5F4F38 + MaxColor: 574A31 ZOffset: -12 ZRamp: 0 Template@641: @@ -15250,8 +15252,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 64533B - RightColor: 51472E + MinColor: 64533B + MaxColor: 51472E ZOffset: -12 ZRamp: 0 Template@642: @@ -15261,8 +15263,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 5D4E36 - RightColor: 5B4D37 + MinColor: 5D4E36 + MaxColor: 5B4D37 ZOffset: -12 ZRamp: 0 Template@643: @@ -15273,8 +15275,8 @@ Tiles: 0: Clear RampType: 1 - LeftColor: 705A3F - RightColor: 705E46 + MinColor: 705A3F + MaxColor: 705E46 ZOffset: -12 ZRamp: 0 Template@644: @@ -15285,8 +15287,8 @@ Tiles: 0: Clear RampType: 1 - LeftColor: 746148 - RightColor: 705B41 + MinColor: 746148 + MaxColor: 705B41 ZOffset: -12 ZRamp: 0 Template@645: @@ -15297,8 +15299,8 @@ Tiles: 0: Clear RampType: 1 - LeftColor: 726047 - RightColor: 705B41 + MinColor: 726047 + MaxColor: 705B41 ZOffset: -12 ZRamp: 0 Template@646: @@ -15309,8 +15311,8 @@ Tiles: 0: Clear RampType: 2 - LeftColor: 4C4539 - RightColor: 564939 + MinColor: 4C4539 + MaxColor: 564939 ZOffset: -12 ZRamp: 0 Template@647: @@ -15321,8 +15323,8 @@ Tiles: 0: Clear RampType: 2 - LeftColor: 574A39 - RightColor: 464034 + MinColor: 574A39 + MaxColor: 464034 ZOffset: -12 ZRamp: 0 Template@648: @@ -15333,8 +15335,8 @@ Tiles: 0: Clear RampType: 2 - LeftColor: 594C3B - RightColor: 564A39 + MinColor: 594C3B + MaxColor: 564A39 ZOffset: -12 ZRamp: 0 Template@649: @@ -15345,8 +15347,8 @@ Tiles: 0: Clear RampType: 3 - LeftColor: 594D3D - RightColor: 61523F + MinColor: 594D3D + MaxColor: 61523F ZOffset: -12 ZRamp: 0 Template@650: @@ -15357,8 +15359,8 @@ Tiles: 0: Clear RampType: 3 - LeftColor: 5B4E3C - RightColor: 584D3E + MinColor: 5B4E3C + MaxColor: 584D3E ZOffset: -12 ZRamp: 0 Template@651: @@ -15369,8 +15371,8 @@ Tiles: 0: Clear RampType: 3 - LeftColor: 5B4E3C - RightColor: 61523F + MinColor: 5B4E3C + MaxColor: 61523F ZOffset: -12 ZRamp: 0 Template@652: @@ -15381,8 +15383,8 @@ Tiles: 0: Clear RampType: 4 - LeftColor: 66543E - RightColor: 5D4E3A + MinColor: 66543E + MaxColor: 5D4E3A ZOffset: -12 ZRamp: 0 Template@653: @@ -15393,8 +15395,8 @@ Tiles: 0: Clear RampType: 4 - LeftColor: 60523E - RightColor: 604F3B + MinColor: 60523E + MaxColor: 604F3B ZOffset: -12 ZRamp: 0 Template@654: @@ -15405,8 +15407,8 @@ Tiles: 0: Clear RampType: 4 - LeftColor: 67553F - RightColor: 62513C + MinColor: 67553F + MaxColor: 62513C ZOffset: -12 ZRamp: 0 Template@667: @@ -15417,26 +15419,26 @@ Tiles: 0: Cliff RampType: 1 - LeftColor: 686159 - RightColor: 6E5B43 + MinColor: 686159 + MaxColor: 6E5B43 ZOffset: -12 ZRamp: 0 1: Cliff RampType: 1 - LeftColor: 445064 - RightColor: 505E79 + MinColor: 445064 + MaxColor: 505E79 ZOffset: -12 ZRamp: 0 2: Cliff RampType: 1 - LeftColor: 56565A - RightColor: 425269 + MinColor: 56565A + MaxColor: 425269 ZOffset: -12 ZRamp: 0 3: Cliff RampType: 1 - LeftColor: 765E41 - RightColor: 725D42 + MinColor: 765E41 + MaxColor: 725D42 ZOffset: -12 ZRamp: 0 Template@668: @@ -15447,26 +15449,26 @@ Tiles: 0: Cliff RampType: 2 - LeftColor: 544A3B - RightColor: 5B5856 + MinColor: 544A3B + MaxColor: 5B5856 ZOffset: -12 ZRamp: 0 1: Cliff RampType: 2 - LeftColor: 495771 - RightColor: 404F6A + MinColor: 495771 + MaxColor: 404F6A ZOffset: -12 ZRamp: 0 2: Cliff RampType: 2 - LeftColor: 4D586D - RightColor: 544E46 + MinColor: 4D586D + MaxColor: 544E46 ZOffset: -12 ZRamp: 0 3: Cliff RampType: 2 - LeftColor: 544A3A - RightColor: 443D30 + MinColor: 544A3A + MaxColor: 443D30 ZOffset: -12 ZRamp: 0 Template@669: @@ -15477,26 +15479,26 @@ Tiles: 0: Cliff RampType: 3 - LeftColor: 635A4F - RightColor: 5B5041 + MinColor: 635A4F + MaxColor: 5B5041 ZOffset: -12 ZRamp: 0 1: Cliff RampType: 3 - LeftColor: 6C7995 - RightColor: 57657F + MinColor: 6C7995 + MaxColor: 57657F ZOffset: -12 ZRamp: 0 2: Cliff RampType: 3 - LeftColor: 6B6C71 - RightColor: 616C83 + MinColor: 6B6C71 + MaxColor: 616C83 ZOffset: -12 ZRamp: 0 3: Cliff RampType: 3 - LeftColor: 5A4E3D - RightColor: 5C4F3E + MinColor: 5A4E3D + MaxColor: 5C4F3E ZOffset: -12 ZRamp: 0 Template@670: @@ -15507,26 +15509,26 @@ Tiles: 0: Cliff RampType: 4 - LeftColor: 604F3A - RightColor: 564E45 + MinColor: 604F3A + MaxColor: 564E45 ZOffset: -12 ZRamp: 0 1: Cliff RampType: 4 - LeftColor: 697389 - RightColor: 4E5B72 + MinColor: 697389 + MaxColor: 4E5B72 ZOffset: -12 ZRamp: 0 2: Cliff RampType: 4 - LeftColor: 4C5665 - RightColor: 616368 + MinColor: 4C5665 + MaxColor: 616368 ZOffset: -12 ZRamp: 0 3: Cliff RampType: 4 - LeftColor: 5F513E - RightColor: 60503B + MinColor: 5F513E + MaxColor: 60503B ZOffset: -12 ZRamp: 0 Template@671: @@ -15536,8 +15538,8 @@ Size: 1, 1 Tiles: 0: Road - LeftColor: 545350 - RightColor: 525252 + MinColor: 545350 + MaxColor: 525252 ZOffset: -12 ZRamp: 0 Template@672: @@ -15548,20 +15550,20 @@ Tiles: 0: Road RampType: 1 - LeftColor: 484744 - RightColor: 5A5A5A + MinColor: 484744 + MaxColor: 5A5A5A ZOffset: -12 ZRamp: 0 1: Road RampType: 1 - LeftColor: 45443F - RightColor: 4B4537 + MinColor: 45443F + MaxColor: 4B4537 ZOffset: -12 ZRamp: 0 2: Road RampType: 1 - LeftColor: 565553 - RightColor: 4B4B4A + MinColor: 565553 + MaxColor: 4B4B4A ZOffset: -12 ZRamp: 0 Template@673: @@ -15572,20 +15574,20 @@ Tiles: 0: Road RampType: 2 - LeftColor: 484847 - RightColor: 383734 + MinColor: 484847 + MaxColor: 383734 ZOffset: -12 ZRamp: 0 1: Road RampType: 2 - LeftColor: 3C362B - RightColor: 353430 + MinColor: 3C362B + MaxColor: 353430 ZOffset: -12 ZRamp: 0 2: Road RampType: 2 - LeftColor: 3B3B3A - RightColor: 444340 + MinColor: 3B3B3A + MaxColor: 444340 ZOffset: -12 ZRamp: 0 Template@674: @@ -15596,20 +15598,20 @@ Tiles: 0: Road RampType: 3 - LeftColor: 363430 - RightColor: 3D3C38 + MinColor: 363430 + MaxColor: 3D3C38 ZOffset: -12 ZRamp: 0 1: Road RampType: 3 - LeftColor: 323130 - RightColor: 36332E + MinColor: 323130 + MaxColor: 36332E ZOffset: -12 ZRamp: 0 2: Road RampType: 3 - LeftColor: 42403B - RightColor: 363635 + MinColor: 42403B + MaxColor: 363635 ZOffset: -12 ZRamp: 0 Template@675: @@ -15620,20 +15622,20 @@ Tiles: 0: DirtRoad RampType: 4 - LeftColor: 4F4B45 - RightColor: 3E3D3B + MinColor: 4F4B45 + MaxColor: 3E3D3B ZOffset: -12 ZRamp: 0 1: DirtRoad RampType: 4 - LeftColor: 3E3B34 - RightColor: 3C3B38 + MinColor: 3E3B34 + MaxColor: 3C3B38 ZOffset: -12 ZRamp: 0 2: DirtRoad RampType: 4 - LeftColor: 3F3F3D - RightColor: 4D4A45 + MinColor: 3F3F3D + MaxColor: 4D4A45 ZOffset: -12 ZRamp: 0 Template@676: @@ -15644,8 +15646,8 @@ Tiles: 0: Rail RampType: 1 - LeftColor: 4D4D4E - RightColor: 4E4B48 + MinColor: 4D4D4E + MaxColor: 4E4B48 ZOffset: -12 ZRamp: 0 Template@677: @@ -15656,8 +15658,8 @@ Tiles: 0: Rail RampType: 2 - LeftColor: 3E434A - RightColor: 454646 + MinColor: 3E434A + MaxColor: 454646 ZOffset: -12 ZRamp: 0 Template@678: @@ -15668,8 +15670,8 @@ Tiles: 0: Rail RampType: 3 - LeftColor: 4B4843 - RightColor: 484848 + MinColor: 4B4843 + MaxColor: 484848 ZOffset: -12 ZRamp: 0 Template@679: @@ -15680,8 +15682,8 @@ Tiles: 0: Rail RampType: 4 - LeftColor: 383A3C - RightColor: 4C4842 + MinColor: 383A3C + MaxColor: 4C4842 ZOffset: -12 ZRamp: 0 Template@680: @@ -15692,46 +15694,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 111F32 - RightColor: 162335 + MinColor: 111F32 + MaxColor: 162335 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 1E2E47 - RightColor: 33405A + MinColor: 1E2E47 + MaxColor: 33405A ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 808695 - RightColor: 848890 + MinColor: 808695 + MaxColor: 848890 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 1D3253 - RightColor: 132840 + MinColor: 1D3253 + MaxColor: 132840 ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 413D39 - RightColor: 29313A + MinColor: 413D39 + MaxColor: 29313A ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 3C3B3A - RightColor: 433C32 + MinColor: 3C3B3A + MaxColor: 433C32 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 41382B - RightColor: 3F3B32 + MinColor: 41382B + MaxColor: 3F3B32 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 4E4D4D - RightColor: 3B4350 + MinColor: 4E4D4D + MaxColor: 3B4350 ZOffset: -12 ZRamp: 0 Template@681: @@ -15742,24 +15744,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 0B192A - RightColor: 0E1C2E + MinColor: 0B192A + MaxColor: 0E1C2E ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 142339 - RightColor: 465167 + MinColor: 142339 + MaxColor: 465167 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 959BAB - RightColor: 9EA3AD + MinColor: 959BAB + MaxColor: 9EA3AD ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 142640 - RightColor: 11243B + MinColor: 142640 + MaxColor: 11243B ZOffset: -12 ZRamp: 0 Template@682: @@ -15770,46 +15772,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 0D1C2F - RightColor: 0E1C2E + MinColor: 0D1C2F + MaxColor: 0E1C2E ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 202F46 - RightColor: 5F6776 + MinColor: 202F46 + MaxColor: 5F6776 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 8E95A3 - RightColor: 8E949C + MinColor: 8E95A3 + MaxColor: 8E949C ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 1B2F4F - RightColor: 12253D + MinColor: 1B2F4F + MaxColor: 12253D ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 0B192A - RightColor: 111F34 + MinColor: 0B192A + MaxColor: 111F34 ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 212E42 - RightColor: 575E6A + MinColor: 212E42 + MaxColor: 575E6A ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 9AA0B1 - RightColor: A7ABB5 + MinColor: 9AA0B1 + MaxColor: A7ABB5 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 152843 - RightColor: 10243A + MinColor: 152843 + MaxColor: 10243A ZOffset: -12 ZRamp: 0 Template@683: @@ -15820,46 +15822,46 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 313336 - RightColor: 423A30 + MinColor: 313336 + MaxColor: 423A30 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 423C32 - RightColor: 393229 + MinColor: 423C32 + MaxColor: 393229 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 403A31 - RightColor: 3A352C + MinColor: 403A31 + MaxColor: 3A352C ZOffset: -12 ZRamp: 0 3: Rough - LeftColor: 3D4044 - RightColor: 5E503F + MinColor: 3D4044 + MaxColor: 5E503F ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 112032 - RightColor: 1A2532 + MinColor: 112032 + MaxColor: 1A2532 ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 25344B - RightColor: 514E4A + MinColor: 25344B + MaxColor: 514E4A ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 6C747D - RightColor: 626261 + MinColor: 6C747D + MaxColor: 626261 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 1A2B43 - RightColor: 1E314E + MinColor: 1A2B43 + MaxColor: 1E314E ZOffset: -12 ZRamp: 0 Template@684: @@ -15870,20 +15872,20 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4A3F31 - RightColor: 443F36 + MinColor: 4A3F31 + MaxColor: 443F36 ZOffset: -12 ZRamp: 0 2: Rough Height: 4 - LeftColor: 453C32 - RightColor: 2F333B + MinColor: 453C32 + MaxColor: 2F333B ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 1A283E - RightColor: 39404D + MinColor: 1A283E + MaxColor: 39404D ZOffset: -12 ZRamp: 0 Template@685: @@ -15894,8 +15896,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 112034 - RightColor: 374257 + MinColor: 112034 + MaxColor: 374257 ZOffset: -12 ZRamp: 0 Template@686: @@ -15906,14 +15908,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 112035 - RightColor: 3A455A + MinColor: 112035 + MaxColor: 3A455A ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 16253D - RightColor: 334057 + MinColor: 16253D + MaxColor: 334057 ZOffset: -12 ZRamp: 0 Template@687: @@ -15924,20 +15926,20 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 322F29 - RightColor: 413D35 + MinColor: 322F29 + MaxColor: 413D35 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 192637 - RightColor: 3D4553 + MinColor: 192637 + MaxColor: 3D4553 ZOffset: -12 ZRamp: 0 3: Rough Height: 4 - LeftColor: 3D3933 - RightColor: 463F34 + MinColor: 3D3933 + MaxColor: 463F34 ZOffset: -12 ZRamp: 0 Template@688: @@ -15948,20 +15950,20 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 212E42 - RightColor: 1D2C43 + MinColor: 212E42 + MaxColor: 1D2C43 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 433C31 - RightColor: 373531 + MinColor: 433C31 + MaxColor: 373531 ZOffset: -12 ZRamp: 0 3: Rough Height: 4 - LeftColor: 3E372E - RightColor: 353636 + MinColor: 3E372E + MaxColor: 353636 ZOffset: -12 ZRamp: 0 Template@689: @@ -15972,8 +15974,8 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 253349 - RightColor: 0F1E31 + MinColor: 253349 + MaxColor: 0F1E31 ZOffset: -12 ZRamp: 0 Template@690: @@ -15984,14 +15986,14 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 17263E - RightColor: 233043 + MinColor: 17263E + MaxColor: 233043 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 2A3850 - RightColor: 16263E + MinColor: 2A3850 + MaxColor: 16263E ZOffset: -12 ZRamp: 0 Template@691: @@ -16002,20 +16004,20 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 322F2A - RightColor: 453D31 + MinColor: 322F2A + MaxColor: 453D31 ZOffset: -12 ZRamp: 0 1: Rough Height: 4 - LeftColor: 363636 - RightColor: 463C30 + MinColor: 363636 + MaxColor: 463C30 ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 28303E - RightColor: 212B37 + MinColor: 28303E + MaxColor: 212B37 ZOffset: -12 ZRamp: 0 Template@707: @@ -16025,78 +16027,78 @@ Size: 3, 5 Tiles: 0: Cliff - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 453625 - RightColor: 463525 + MinColor: 453625 + MaxColor: 463525 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 42413E - RightColor: 4E4D4A + MinColor: 42413E + MaxColor: 4E4D4A ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 383939 - RightColor: 3B3A37 + MinColor: 383939 + MaxColor: 3B3A37 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 20201E - RightColor: 1C1B1A + MinColor: 20201E + MaxColor: 1C1B1A ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 3B3935 - RightColor: 3C3A35 + MinColor: 3B3935 + MaxColor: 3C3A35 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 36332F - RightColor: 2D2B28 + MinColor: 36332F + MaxColor: 2D2B28 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 1F1E1B - RightColor: 1A1918 + MinColor: 1F1E1B + MaxColor: 1A1918 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 4C4D4C - RightColor: 403F3D + MinColor: 4C4D4C + MaxColor: 403F3D ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 474541 - RightColor: 2F2F2F + MinColor: 474541 + MaxColor: 2F2F2F ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 252523 - RightColor: 1C1C1C + MinColor: 252523 + MaxColor: 1C1C1C ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 6F5A41 - RightColor: 6D583F + MinColor: 6F5A41 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 463525 - RightColor: 453525 + MinColor: 463525 + MaxColor: 453525 ZOffset: -12 ZRamp: 0 Template@708: @@ -16106,78 +16108,78 @@ Size: 5, 3 Tiles: 0: Cliff - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 4E4D4A - RightColor: 42413E + MinColor: 4E4D4A + MaxColor: 42413E ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 3C3A35 - RightColor: 3B3935 + MinColor: 3C3A35 + MaxColor: 3B3935 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 403F3D - RightColor: 4C4D4C + MinColor: 403F3D + MaxColor: 4C4D4C ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6D5A42 - RightColor: 6C583E + MinColor: 6D5A42 + MaxColor: 6C583E ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 3B3A37 - RightColor: 383939 + MinColor: 3B3A37 + MaxColor: 383939 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 2D2B28 - RightColor: 36332F + MinColor: 2D2B28 + MaxColor: 36332F ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 2F2F2F - RightColor: 474541 + MinColor: 2F2F2F + MaxColor: 474541 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 6D583E - RightColor: 6C5840 + MinColor: 6D583E + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 463525 - RightColor: 453625 + MinColor: 463525 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 1C1B1A - RightColor: 20201E + MinColor: 1C1B1A + MaxColor: 20201E ZOffset: -12 ZRamp: 0 12: Road - LeftColor: 1A1918 - RightColor: 1F1E1B + MinColor: 1A1918 + MaxColor: 1F1E1B ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 1C1C1C - RightColor: 252523 + MinColor: 1C1C1C + MaxColor: 252523 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 453525 - RightColor: 463525 + MinColor: 453525 + MaxColor: 463525 ZOffset: -12 ZRamp: 0 Template@709: @@ -16187,63 +16189,63 @@ Size: 3, 4 Tiles: 0: Cliff - LeftColor: 070707 - RightColor: 2F2A24 + MinColor: 070707 + MaxColor: 2F2A24 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5B574F - RightColor: 5C5954 + MinColor: 5B574F + MaxColor: 5C5954 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 6D6354 - RightColor: 6F583D + MinColor: 6D6354 + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 1C1C1C - RightColor: 090909 + MinColor: 1C1C1C + MaxColor: 090909 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 2F2F2F - RightColor: 474541 + MinColor: 2F2F2F + MaxColor: 474541 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 42413E - RightColor: 4E4C49 + MinColor: 42413E + MaxColor: 4E4C49 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 1A1918 - RightColor: 060605 + MinColor: 1A1918 + MaxColor: 060605 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 2D2B28 - RightColor: 36332F + MinColor: 2D2B28 + MaxColor: 36332F ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 3B3935 - RightColor: 3C3A35 + MinColor: 3B3935 + MaxColor: 3C3A35 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 050505 - RightColor: 20201E + MinColor: 050505 + MaxColor: 20201E ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 3B3A37 - RightColor: 383939 + MinColor: 3B3A37 + MaxColor: 383939 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 4F4E4C - RightColor: 403F3D + MinColor: 4F4E4C + MaxColor: 403F3D ZOffset: -12 ZRamp: 0 Template@710: @@ -16253,63 +16255,63 @@ Size: 4, 3 Tiles: 0: Cliff - LeftColor: 161616 - RightColor: 2A2620 + MinColor: 161616 + MaxColor: 2A2620 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 252523 - RightColor: 070707 + MinColor: 252523 + MaxColor: 070707 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 1F1E1B - RightColor: 050504 + MinColor: 1F1E1B + MaxColor: 050504 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 20201E - RightColor: 050505 + MinColor: 20201E + MaxColor: 050505 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 58544C - RightColor: 4D4B47 + MinColor: 58544C + MaxColor: 4D4B47 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 474541 - RightColor: 2F2F2F + MinColor: 474541 + MaxColor: 2F2F2F ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 36332F - RightColor: 2D2B28 + MinColor: 36332F + MaxColor: 2D2B28 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 383939 - RightColor: 3B3A37 + MinColor: 383939 + MaxColor: 3B3A37 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 6F583D - RightColor: 706659 + MinColor: 6F583D + MaxColor: 706659 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 4E4C49 - RightColor: 42413E + MinColor: 4E4C49 + MaxColor: 42413E ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 3C3A35 - RightColor: 3B3935 + MinColor: 3C3A35 + MaxColor: 3B3935 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 403F3D - RightColor: 4F4E4C + MinColor: 403F3D + MaxColor: 4F4E4C ZOffset: -12 ZRamp: 0 Template@711: @@ -16320,18 +16322,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 51422F - RightColor: 534839 + MinColor: 51422F + MaxColor: 534839 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 544633 - RightColor: 807B72 + MinColor: 544633 + MaxColor: 807B72 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 6F5C44 - RightColor: 736C61 + MinColor: 6F5C44 + MaxColor: 736C61 ZOffset: -12 ZRamp: 0 Template@712: @@ -16342,18 +16344,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 54493A - RightColor: 50422F + MinColor: 54493A + MaxColor: 50422F ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 413B33 - RightColor: 5E564B + MinColor: 413B33 + MaxColor: 5E564B ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 7E7870 - RightColor: 5A4B38 + MinColor: 7E7870 + MaxColor: 5A4B38 ZOffset: -12 ZRamp: 0 Template@713: @@ -16363,78 +16365,78 @@ Size: 3, 5 Tiles: 0: Cliff - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 453625 - RightColor: 463525 + MinColor: 453625 + MaxColor: 463525 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 42413E - RightColor: 4E4D4A + MinColor: 42413E + MaxColor: 4E4D4A ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 383939 - RightColor: 3B3A37 + MinColor: 383939 + MaxColor: 3B3A37 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 20201E - RightColor: 1C1B1A + MinColor: 20201E + MaxColor: 1C1B1A ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 47494C - RightColor: 4C4E50 + MinColor: 47494C + MaxColor: 4C4E50 ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 444649 - RightColor: 4A4C4E + MinColor: 444649 + MaxColor: 4A4C4E ZOffset: -12 ZRamp: 0 8: Rail - LeftColor: 32312F - RightColor: 363531 + MinColor: 32312F + MaxColor: 363531 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 4C4D4C - RightColor: 403F3D + MinColor: 4C4D4C + MaxColor: 403F3D ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 474541 - RightColor: 2F2F2F + MinColor: 474541 + MaxColor: 2F2F2F ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 252523 - RightColor: 1C1C1C + MinColor: 252523 + MaxColor: 1C1C1C ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 6F5A41 - RightColor: 6D583F + MinColor: 6F5A41 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 463525 - RightColor: 453525 + MinColor: 463525 + MaxColor: 453525 ZOffset: -12 ZRamp: 0 Template@714: @@ -16444,78 +16446,78 @@ Size: 5, 3 Tiles: 0: Cliff - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 4E4D4A - RightColor: 42413E + MinColor: 4E4D4A + MaxColor: 42413E ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 494B4D - RightColor: 46494C + MinColor: 494B4D + MaxColor: 46494C ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 403F3D - RightColor: 4C4D4C + MinColor: 403F3D + MaxColor: 4C4D4C ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6D5A42 - RightColor: 6C583E + MinColor: 6D5A42 + MaxColor: 6C583E ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 3B3A37 - RightColor: 383939 + MinColor: 3B3A37 + MaxColor: 383939 ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 47494B - RightColor: 444649 + MinColor: 47494B + MaxColor: 444649 ZOffset: -12 ZRamp: 0 8: Road - LeftColor: 2F2F2F - RightColor: 474541 + MinColor: 2F2F2F + MaxColor: 474541 ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 6D583E - RightColor: 6C5840 + MinColor: 6D583E + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 463525 - RightColor: 453625 + MinColor: 463525 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 1C1B1A - RightColor: 20201E + MinColor: 1C1B1A + MaxColor: 20201E ZOffset: -12 ZRamp: 0 12: Rail - LeftColor: 33322F - RightColor: 31302E + MinColor: 33322F + MaxColor: 31302E ZOffset: -12 ZRamp: 0 13: Road - LeftColor: 1C1C1C - RightColor: 252523 + MinColor: 1C1C1C + MaxColor: 252523 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 453525 - RightColor: 463525 + MinColor: 453525 + MaxColor: 463525 ZOffset: -12 ZRamp: 0 Template@715: @@ -16525,63 +16527,63 @@ Size: 3, 4 Tiles: 0: Cliff - LeftColor: 070707 - RightColor: 2F2B25 + MinColor: 070707 + MaxColor: 2F2B25 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5B574F - RightColor: 5C5954 + MinColor: 5B574F + MaxColor: 5C5954 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 6D6354 - RightColor: 6F583D + MinColor: 6D6354 + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 1C1C1C - RightColor: 090909 + MinColor: 1C1C1C + MaxColor: 090909 ZOffset: -12 ZRamp: 0 4: Road - LeftColor: 2F2F2F - RightColor: 474541 + MinColor: 2F2F2F + MaxColor: 474541 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 42413E - RightColor: 4E4C49 + MinColor: 42413E + MaxColor: 4E4C49 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 292620 - RightColor: 080806 + MinColor: 292620 + MaxColor: 080806 ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 363533 - RightColor: 3A3935 + MinColor: 363533 + MaxColor: 3A3935 ZOffset: -12 ZRamp: 0 8: Rail - LeftColor: 47494C - RightColor: 4C4E50 + MinColor: 47494C + MaxColor: 4C4E50 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 050505 - RightColor: 20201E + MinColor: 050505 + MaxColor: 20201E ZOffset: -12 ZRamp: 0 10: Road - LeftColor: 3B3A37 - RightColor: 383939 + MinColor: 3B3A37 + MaxColor: 383939 ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 4F4E4C - RightColor: 403F3D + MinColor: 4F4E4C + MaxColor: 403F3D ZOffset: -12 ZRamp: 0 Template@716: @@ -16591,63 +16593,63 @@ Size: 4, 3 Tiles: 0: Cliff - LeftColor: 161616 - RightColor: 2A2621 + MinColor: 161616 + MaxColor: 2A2621 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 252523 - RightColor: 070707 + MinColor: 252523 + MaxColor: 070707 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 2B2721 - RightColor: 080706 + MinColor: 2B2721 + MaxColor: 080706 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 20201E - RightColor: 050505 + MinColor: 20201E + MaxColor: 050505 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 58544C - RightColor: 4D4B47 + MinColor: 58544C + MaxColor: 4D4B47 ZOffset: -12 ZRamp: 0 5: Road - LeftColor: 474541 - RightColor: 2F2F2F + MinColor: 474541 + MaxColor: 2F2F2F ZOffset: -12 ZRamp: 0 6: Rail - LeftColor: 373634 - RightColor: 353533 + MinColor: 373634 + MaxColor: 353533 ZOffset: -12 ZRamp: 0 7: Road - LeftColor: 383939 - RightColor: 3B3A37 + MinColor: 383939 + MaxColor: 3B3A37 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 6F583D - RightColor: 706659 + MinColor: 6F583D + MaxColor: 706659 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 4E4C49 - RightColor: 42413E + MinColor: 4E4C49 + MaxColor: 42413E ZOffset: -12 ZRamp: 0 10: Rail - LeftColor: 494B4D - RightColor: 46494C + MinColor: 494B4D + MaxColor: 46494C ZOffset: -12 ZRamp: 0 11: Road - LeftColor: 403F3D - RightColor: 4F4E4C + MinColor: 403F3D + MaxColor: 4F4E4C ZOffset: -12 ZRamp: 0 Template@717: @@ -16658,112 +16660,112 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 453C2F - RightColor: 433A2D + MinColor: 453C2F + MaxColor: 433A2D ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 4E3F2C - RightColor: 473B2B + MinColor: 4E3F2C + MaxColor: 473B2B ZOffset: -12 ZRamp: 0 3: Cliff Height: 4 - LeftColor: 52422F - RightColor: 4B3E2E + MinColor: 52422F + MaxColor: 4B3E2E ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 4F4333 - RightColor: 4C3E2E + MinColor: 4F4333 + MaxColor: 4C3E2E ZOffset: -12 ZRamp: 0 6: Cliff Height: 4 - LeftColor: 4E4539 - RightColor: 3F372C + MinColor: 4E4539 + MaxColor: 3F372C ZOffset: -12 ZRamp: 0 7: Cliff Height: 4 - LeftColor: 504435 - RightColor: 453B2F + MinColor: 504435 + MaxColor: 453B2F ZOffset: -12 ZRamp: 0 8: Cliff Height: 4 - LeftColor: 50412F - RightColor: 584732 + MinColor: 50412F + MaxColor: 584732 ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 574530 - RightColor: 614E37 + MinColor: 574530 + MaxColor: 614E37 ZOffset: -12 ZRamp: 0 10: Cliff Height: 4 - LeftColor: 493E30 - RightColor: 524738 + MinColor: 493E30 + MaxColor: 524738 ZOffset: -12 ZRamp: 0 11: Cliff Height: 4 - LeftColor: 504537 - RightColor: 42392E + MinColor: 504537 + MaxColor: 42392E ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 615341 - RightColor: 564C3F + MinColor: 615341 + MaxColor: 564C3F ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 715A40 - RightColor: 65533C + MinColor: 715A40 + MaxColor: 65533C ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 725A3F - RightColor: 604D35 + MinColor: 725A3F + MaxColor: 604D35 ZOffset: -12 ZRamp: 0 15: Cliff - LeftColor: 7A6144 - RightColor: 6F583E + MinColor: 7A6144 + MaxColor: 6F583E ZOffset: -12 ZRamp: 0 16: Cliff - LeftColor: 745C40 - RightColor: 594F41 + MinColor: 745C40 + MaxColor: 594F41 ZOffset: -12 ZRamp: 0 17: Cliff - LeftColor: 6B5B46 - RightColor: 403B32 + MinColor: 6B5B46 + MaxColor: 403B32 ZOffset: -12 ZRamp: 0 19: Cliff - LeftColor: 6B553C - RightColor: 69543B + MinColor: 6B553C + MaxColor: 69543B ZOffset: -12 ZRamp: 0 20: Cliff - LeftColor: 745D42 - RightColor: 725A3F + MinColor: 745D42 + MaxColor: 725A3F ZOffset: -12 ZRamp: 0 21: Cliff - LeftColor: 765F43 - RightColor: 70583D + MinColor: 765F43 + MaxColor: 70583D ZOffset: -12 ZRamp: 0 22: Cliff - LeftColor: 6A553B - RightColor: 6C563D + MinColor: 6A553B + MaxColor: 6C563D ZOffset: -12 ZRamp: 0 Template@718: @@ -16774,112 +16776,112 @@ Tiles: 1: Cliff Height: 4 - LeftColor: 473E33 - RightColor: 403A32 + MinColor: 473E33 + MaxColor: 403A32 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 3A3731 - RightColor: 34322D + MinColor: 3A3731 + MaxColor: 34322D ZOffset: -12 ZRamp: 0 4: Cliff Height: 4 - LeftColor: 41392E - RightColor: 4F4639 + MinColor: 41392E + MaxColor: 4F4639 ZOffset: -12 ZRamp: 0 5: Cliff Height: 4 - LeftColor: 4C4337 - RightColor: 4D463B + MinColor: 4C4337 + MaxColor: 4D463B ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 4F402D - RightColor: 473C2D + MinColor: 4F402D + MaxColor: 473C2D ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 69533B - RightColor: 6B563E + MinColor: 69533B + MaxColor: 6B563E ZOffset: -12 ZRamp: 0 8: Cliff Height: 4 - LeftColor: 413930 - RightColor: 483E31 + MinColor: 413930 + MaxColor: 483E31 ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 5B4A35 - RightColor: 524433 + MinColor: 5B4A35 + MaxColor: 524433 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 645038 - RightColor: 69553D + MinColor: 645038 + MaxColor: 69553D ZOffset: -12 ZRamp: 0 11: Cliff - LeftColor: 6C563D - RightColor: 6C553B + MinColor: 6C563D + MaxColor: 6C553B ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 514433 - RightColor: 493E31 + MinColor: 514433 + MaxColor: 493E31 ZOffset: -12 ZRamp: 0 13: Cliff Height: 4 - LeftColor: 614F38 - RightColor: 554735 + MinColor: 614F38 + MaxColor: 554735 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 70583C - RightColor: 725B40 + MinColor: 70583C + MaxColor: 725B40 ZOffset: -12 ZRamp: 0 15: Cliff - LeftColor: 69543C - RightColor: 725A40 + MinColor: 69543C + MaxColor: 725A40 ZOffset: -12 ZRamp: 0 16: Cliff Height: 4 - LeftColor: 4D402F - RightColor: 493D2E + MinColor: 4D402F + MaxColor: 493D2E ZOffset: -12 ZRamp: 0 17: Cliff Height: 4 - LeftColor: 433B2F - RightColor: 493D2F + MinColor: 433B2F + MaxColor: 493D2F ZOffset: -12 ZRamp: 0 18: Cliff - LeftColor: 504232 - RightColor: 5B4C3A + MinColor: 504232 + MaxColor: 5B4C3A ZOffset: -12 ZRamp: 0 19: Cliff - LeftColor: 634E36 - RightColor: 6F593E + MinColor: 634E36 + MaxColor: 6F593E ZOffset: -12 ZRamp: 0 21: Cliff Height: 4 - LeftColor: 4B4033 - RightColor: 413A2F + MinColor: 4B4033 + MaxColor: 413A2F ZOffset: -12 ZRamp: 0 22: Cliff - LeftColor: 564D40 - RightColor: 3E3A33 + MinColor: 564D40 + MaxColor: 3E3A33 ZOffset: -12 ZRamp: 0 Template@719: @@ -16890,24 +16892,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 41382B - RightColor: 4D4030 + MinColor: 41382B + MaxColor: 4D4030 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 3A3226 - RightColor: 4A3F2F + MinColor: 3A3226 + MaxColor: 4A3F2F ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 323639 - RightColor: 4D4233 + MinColor: 323639 + MaxColor: 4D4233 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 212C39 - RightColor: 2A2B2B + MinColor: 212C39 + MaxColor: 2A2B2B ZOffset: -12 ZRamp: 0 Template@720: @@ -16918,24 +16920,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 423A2E - RightColor: 473C2D + MinColor: 423A2E + MaxColor: 473C2D ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 3E362B - RightColor: 504333 + MinColor: 3E362B + MaxColor: 504333 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 20344E - RightColor: 1A1F23 + MinColor: 20344E + MaxColor: 1A1F23 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 2B333B - RightColor: 272521 + MinColor: 2B333B + MaxColor: 272521 ZOffset: -12 ZRamp: 0 Template@721: @@ -16946,13 +16948,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 383127 - RightColor: 4D4131 + MinColor: 383127 + MaxColor: 4D4131 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 24354B - RightColor: 161A1E + MinColor: 24354B + MaxColor: 161A1E ZOffset: -12 ZRamp: 0 Template@722: @@ -16963,24 +16965,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 483E30 - RightColor: 504130 + MinColor: 483E30 + MaxColor: 504130 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 484034 - RightColor: 4E4130 + MinColor: 484034 + MaxColor: 4E4130 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 223553 - RightColor: 161A1E + MinColor: 223553 + MaxColor: 161A1E ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 383B3E - RightColor: 474137 + MinColor: 383B3E + MaxColor: 474137 ZOffset: -12 ZRamp: 0 Template@723: @@ -16991,24 +16993,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4D4131 - RightColor: 3A3227 + MinColor: 4D4131 + MaxColor: 3A3227 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 213046 - RightColor: 1B2129 + MinColor: 213046 + MaxColor: 1B2129 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 483E30 - RightColor: 3D362C + MinColor: 483E30 + MaxColor: 3D362C ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 31353B - RightColor: 2F2F2D + MinColor: 31353B + MaxColor: 2F2F2D ZOffset: -12 ZRamp: 0 Template@724: @@ -17019,24 +17021,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 443C30 - RightColor: 423B30 + MinColor: 443C30 + MaxColor: 423B30 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 253249 - RightColor: 171E28 + MinColor: 253249 + MaxColor: 171E28 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 473E31 - RightColor: 302C24 + MinColor: 473E31 + MaxColor: 302C24 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 1D3151 - RightColor: 1C232D + MinColor: 1D3151 + MaxColor: 1C232D ZOffset: -12 ZRamp: 0 Template@725: @@ -17047,13 +17049,13 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 463E32 - RightColor: 3F382E + MinColor: 463E32 + MaxColor: 3F382E ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 1D3252 - RightColor: 17202A + MinColor: 1D3252 + MaxColor: 17202A ZOffset: -12 ZRamp: 0 Template@726: @@ -17064,24 +17066,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 463B2E - RightColor: 463E32 + MinColor: 463B2E + MaxColor: 463E32 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 2F2F2B - RightColor: 2E2E2C + MinColor: 2F2F2B + MaxColor: 2E2E2C ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 504232 - RightColor: 463E33 + MinColor: 504232 + MaxColor: 463E33 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 223553 - RightColor: 282C2E + MinColor: 223553 + MaxColor: 282C2E ZOffset: -12 ZRamp: 0 Template@940: @@ -17092,158 +17094,158 @@ Tiles: 2: Clear RampType: 15 - LeftColor: 5E503E - RightColor: 62523D + MinColor: 5E503E + MaxColor: 62523D ZOffset: -12 ZRamp: 0 3: Clear RampType: 12 - LeftColor: 756046 - RightColor: 705C43 + MinColor: 756046 + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 6: Clear RampType: 15 - LeftColor: 392F1B - RightColor: 604E38 + MinColor: 392F1B + MaxColor: 604E38 ZOffset: -12 ZRamp: 0 7: Clear RampType: 4 - LeftColor: 453927 - RightColor: 614F38 + MinColor: 453927 + MaxColor: 614F38 ZOffset: -12 ZRamp: 0 8: Clear RampType: 7 - LeftColor: 423524 - RightColor: 5B4C38 + MinColor: 423524 + MaxColor: 5B4C38 ZOffset: -12 ZRamp: 0 9: Clear RampType: 8 - LeftColor: 564732 - RightColor: 6E5A40 + MinColor: 564732 + MaxColor: 6E5A40 ZOffset: -12 ZRamp: 0 10: Clear RampType: 12 - LeftColor: 705A3F - RightColor: 6F5B43 + MinColor: 705A3F + MaxColor: 6F5B43 ZOffset: -12 ZRamp: 0 12: Clear RampType: 3 - LeftColor: 2A2414 - RightColor: 2A2413 + MinColor: 2A2414 + MaxColor: 2A2413 ZOffset: -12 ZRamp: 0 13: Rough - LeftColor: 342B1C - RightColor: 2F2716 + MinColor: 342B1C + MaxColor: 2F2716 ZOffset: -12 ZRamp: 0 14: Rough - LeftColor: 2F2717 - RightColor: 2E2313 + MinColor: 2F2717 + MaxColor: 2E2313 ZOffset: -12 ZRamp: 0 15: Rough - LeftColor: 423321 - RightColor: 52412D + MinColor: 423321 + MaxColor: 52412D ZOffset: -12 ZRamp: 0 16: Clear RampType: 1 - LeftColor: 594531 - RightColor: 423626 + MinColor: 594531 + MaxColor: 423626 ZOffset: -12 ZRamp: 0 18: Clear RampType: 3 - LeftColor: 2C2617 - RightColor: 2A2617 + MinColor: 2C2617 + MaxColor: 2A2617 ZOffset: -12 ZRamp: 0 19: Rough - LeftColor: 3C3323 - RightColor: 332B1C + MinColor: 3C3323 + MaxColor: 332B1C ZOffset: -12 ZRamp: 0 20: Rough - LeftColor: 2E281B - RightColor: 493B2B + MinColor: 2E281B + MaxColor: 493B2B ZOffset: -12 ZRamp: 0 21: Rough - LeftColor: 433928 - RightColor: 453928 + MinColor: 433928 + MaxColor: 453928 ZOffset: -12 ZRamp: 0 22: Cliff - LeftColor: 312B1E - RightColor: 2A2415 + MinColor: 312B1E + MaxColor: 2A2415 ZOffset: -12 ZRamp: 0 24: Cliff RampType: 14 - LeftColor: 332B1B - RightColor: 251F10 + MinColor: 332B1B + MaxColor: 251F10 ZOffset: -12 ZRamp: 0 25: Cliff - LeftColor: 1B170B - RightColor: 332D1D + MinColor: 1B170B + MaxColor: 332D1D ZOffset: -12 ZRamp: 0 26: Rough - LeftColor: 2D2818 - RightColor: 4C3F2D + MinColor: 2D2818 + MaxColor: 4C3F2D ZOffset: -12 ZRamp: 0 27: Rough - LeftColor: 493D2C - RightColor: 3B3425 + MinColor: 493D2C + MaxColor: 3B3425 ZOffset: -12 ZRamp: 0 28: Cliff - LeftColor: 322C23 - RightColor: 171613 + MinColor: 322C23 + MaxColor: 171613 ZOffset: -12 ZRamp: 0 32: Cliff - LeftColor: 1C190B - RightColor: 1D1A0D + MinColor: 1C190B + MaxColor: 1D1A0D ZOffset: -12 ZRamp: 0 33: Cliff - LeftColor: 1E1A0D - RightColor: 282515 + MinColor: 1E1A0D + MaxColor: 282515 ZOffset: -12 ZRamp: 0 34: Cliff - LeftColor: 2B2518 - RightColor: 2A251F + MinColor: 2B2518 + MaxColor: 2A251F ZOffset: -12 ZRamp: 0 35: Cliff - LeftColor: 1A1815 - RightColor: 2D2820 + MinColor: 1A1815 + MaxColor: 2D2820 ZOffset: -12 ZRamp: 0 39: Cliff - LeftColor: 493E2E - RightColor: 29271A + MinColor: 493E2E + MaxColor: 29271A ZOffset: -12 ZRamp: 0 40: Cliff - LeftColor: 2B281C - RightColor: 222017 + MinColor: 2B281C + MaxColor: 222017 ZOffset: -12 ZRamp: 0 41: Cliff - LeftColor: 29271F - RightColor: 222019 + MinColor: 29271F + MaxColor: 222019 ZOffset: -12 ZRamp: 0 Template@941: @@ -17254,84 +17256,84 @@ Tiles: 1: Clear RampType: 11 - LeftColor: 5E4D39 - RightColor: 675640 + MinColor: 5E4D39 + MaxColor: 675640 ZOffset: -12 ZRamp: 0 2: Clear RampType: 12 - LeftColor: 705E47 - RightColor: 705B42 + MinColor: 705E47 + MaxColor: 705B42 ZOffset: -12 ZRamp: 0 3: Clear RampType: 11 - LeftColor: 5A4B38 - RightColor: 6A5740 + MinColor: 5A4B38 + MaxColor: 6A5740 ZOffset: -12 ZRamp: 0 4: Clear RampType: 4 - LeftColor: 574835 - RightColor: 685640 + MinColor: 574835 + MaxColor: 685640 ZOffset: -12 ZRamp: 0 5: Clear RampType: 11 - LeftColor: 504332 - RightColor: 5E4E3B + MinColor: 504332 + MaxColor: 5E4E3B ZOffset: -12 ZRamp: 0 6: Clear RampType: 7 - LeftColor: 69553F - RightColor: 6D5740 + MinColor: 69553F + MaxColor: 6D5740 ZOffset: -12 ZRamp: 0 7: Clear RampType: 8 - LeftColor: 64533D - RightColor: 68563F + MinColor: 64533D + MaxColor: 68563F ZOffset: -12 ZRamp: 0 10: Clear RampType: 3 - LeftColor: 3E3321 - RightColor: 483B29 + MinColor: 3E3321 + MaxColor: 483B29 ZOffset: -12 ZRamp: 0 11: Rough - LeftColor: 342D1B - RightColor: 423725 + MinColor: 342D1B + MaxColor: 423725 ZOffset: -12 ZRamp: 0 12: Rough - LeftColor: 362F1E - RightColor: 3F3524 + MinColor: 362F1E + MaxColor: 3F3524 ZOffset: -12 ZRamp: 0 15: Clear RampType: 10 - LeftColor: 69543C - RightColor: 5A4833 + MinColor: 69543C + MaxColor: 5A4833 ZOffset: -12 ZRamp: 0 16: Clear RampType: 2 - LeftColor: 584732 - RightColor: 292314 + MinColor: 584732 + MaxColor: 292314 ZOffset: -12 ZRamp: 0 17: Clear RampType: 6 - LeftColor: 272217 - RightColor: 252113 + MinColor: 272217 + MaxColor: 252113 ZOffset: -12 ZRamp: 0 22: Clear RampType: 10 - LeftColor: 675843 - RightColor: 504330 + MinColor: 675843 + MaxColor: 504330 ZOffset: -12 ZRamp: 0 Template@942: @@ -17341,239 +17343,239 @@ Size: 9, 8 Tiles: 0: DirtRoad - LeftColor: 906F48 - RightColor: 7E6342 + MinColor: 906F48 + MaxColor: 7E6342 ZOffset: -12 ZRamp: 0 1: DirtRoad - LeftColor: 8B6D4A - RightColor: 79644E + MinColor: 8B6D4A + MaxColor: 79644E ZOffset: -12 ZRamp: 0 2: DirtRoad - LeftColor: 816F5E - RightColor: 564A3A + MinColor: 816F5E + MaxColor: 564A3A ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 554734 - RightColor: 675642 + MinColor: 554734 + MaxColor: 675642 ZOffset: -12 ZRamp: 0 9: DirtRoad - LeftColor: 7F6444 - RightColor: 8A6944 + MinColor: 7F6444 + MaxColor: 8A6944 ZOffset: -12 ZRamp: 0 10: DirtRoad - LeftColor: 886945 - RightColor: 977349 + MinColor: 886945 + MaxColor: 977349 ZOffset: -12 ZRamp: 0 11: DirtRoad - LeftColor: 927049 - RightColor: 98744A + MinColor: 927049 + MaxColor: 98744A ZOffset: -12 ZRamp: 0 12: Clear - LeftColor: 5E4C37 - RightColor: 4D3F2F + MinColor: 5E4C37 + MaxColor: 4D3F2F ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 463C2F - RightColor: 5D4C38 + MinColor: 463C2F + MaxColor: 5D4C38 ZOffset: -12 ZRamp: 0 14: Clear - LeftColor: 625443 - RightColor: 6E583D + MinColor: 625443 + MaxColor: 6E583D ZOffset: -12 ZRamp: 0 19: DirtRoad - LeftColor: 5F5240 - RightColor: 7F6A50 + MinColor: 5F5240 + MaxColor: 7F6A50 ZOffset: -12 ZRamp: 0 20: Clear - LeftColor: 675946 - RightColor: 96734B + MinColor: 675946 + MaxColor: 96734B ZOffset: -12 ZRamp: 0 21: DirtRoad - LeftColor: 97744C - RightColor: 7B6144 + MinColor: 97744C + MaxColor: 7B6144 ZOffset: -12 ZRamp: 0 22: Clear - LeftColor: 886D4D - RightColor: 856B4D + MinColor: 886D4D + MaxColor: 856B4D ZOffset: -12 ZRamp: 0 23: Clear - LeftColor: 846D51 - RightColor: 6C563B + MinColor: 846D51 + MaxColor: 6C563B ZOffset: -12 ZRamp: 0 24: Clear - LeftColor: 574935 - RightColor: 6D583E + MinColor: 574935 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 28: DirtRoad - LeftColor: 70593E - RightColor: 5D5242 + MinColor: 70593E + MaxColor: 5D5242 ZOffset: -12 ZRamp: 0 29: DirtRoad - LeftColor: 77654D - RightColor: 5D5344 + MinColor: 77654D + MaxColor: 5D5344 ZOffset: -12 ZRamp: 0 30: Clear - LeftColor: 98764E - RightColor: 9E7B50 + MinColor: 98764E + MaxColor: 9E7B50 ZOffset: -12 ZRamp: 0 31: DirtRoad - LeftColor: 9C7B52 - RightColor: 98784E + MinColor: 9C7B52 + MaxColor: 98784E ZOffset: -12 ZRamp: 0 32: Clear - LeftColor: 8B765B - RightColor: 806C53 + MinColor: 8B765B + MaxColor: 806C53 ZOffset: -12 ZRamp: 0 33: Clear - LeftColor: 856E55 - RightColor: 715E49 + MinColor: 856E55 + MaxColor: 715E49 ZOffset: -12 ZRamp: 0 38: Clear - LeftColor: 765E42 - RightColor: 82694C + MinColor: 765E42 + MaxColor: 82694C ZOffset: -12 ZRamp: 0 39: DirtRoad - LeftColor: 92704A - RightColor: 97754D + MinColor: 92704A + MaxColor: 97754D ZOffset: -12 ZRamp: 0 40: DirtRoad - LeftColor: 9D794F - RightColor: 9E7C54 + MinColor: 9D794F + MaxColor: 9E7C54 ZOffset: -12 ZRamp: 0 41: DirtRoad - LeftColor: 99754B - RightColor: 8D6F4E + MinColor: 99754B + MaxColor: 8D6F4E ZOffset: -12 ZRamp: 0 42: Clear - LeftColor: 917451 - RightColor: 796247 + MinColor: 917451 + MaxColor: 796247 ZOffset: -12 ZRamp: 0 47: Clear - LeftColor: 604C35 - RightColor: 6F583D + MinColor: 604C35 + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 48: DirtRoad - LeftColor: 745D41 - RightColor: 8C6D4A + MinColor: 745D41 + MaxColor: 8C6D4A ZOffset: -12 ZRamp: 0 49: DirtRoad - LeftColor: 92714A - RightColor: 997750 + MinColor: 92714A + MaxColor: 997750 ZOffset: -12 ZRamp: 0 50: DirtRoad - LeftColor: 856B4C - RightColor: 8F704C + MinColor: 856B4C + MaxColor: 8F704C ZOffset: -12 ZRamp: 0 51: Rough - LeftColor: 433829 - RightColor: 7F6C4B + MinColor: 433829 + MaxColor: 7F6C4B ZOffset: -12 ZRamp: 0 52: Cliff - LeftColor: 705E49 - RightColor: 68553D + MinColor: 705E49 + MaxColor: 68553D ZOffset: -12 ZRamp: 0 56: Cliff - LeftColor: 332A19 - RightColor: 453828 + MinColor: 332A19 + MaxColor: 453828 ZOffset: -12 ZRamp: 0 57: Clear - LeftColor: 70593D - RightColor: 6F583D + MinColor: 70593D + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 58: Clear - LeftColor: 6F593E - RightColor: 836644 + MinColor: 6F593E + MaxColor: 836644 ZOffset: -12 ZRamp: 0 59: Clear - LeftColor: 7F6343 - RightColor: 685B4D + MinColor: 7F6343 + MaxColor: 685B4D ZOffset: -12 ZRamp: 0 60: Cliff - LeftColor: 735E44 - RightColor: 8C775B + MinColor: 735E44 + MaxColor: 8C775B ZOffset: -12 ZRamp: 0 61: Cliff - LeftColor: 7B6C57 - RightColor: 675846 + MinColor: 7B6C57 + MaxColor: 675846 ZOffset: -12 ZRamp: 0 65: Cliff - LeftColor: 161411 - RightColor: 221F15 + MinColor: 161411 + MaxColor: 221F15 ZOffset: -12 ZRamp: 0 66: Clear RampType: 2 - LeftColor: 27241C - RightColor: 1A1A18 + MinColor: 27241C + MaxColor: 1A1A18 ZOffset: -12 ZRamp: 0 67: Clear RampType: 2 - LeftColor: 6F583D - RightColor: 6F583D + MinColor: 6F583D + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 68: Clear RampType: 2 - LeftColor: 6F583D - RightColor: 6F583D + MinColor: 6F583D + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 69: Cliff RampType: 2 - LeftColor: 6F583D - RightColor: 6F583D + MinColor: 6F583D + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 70: Cliff RampType: 2 - LeftColor: 6F583D - RightColor: 604E36 + MinColor: 6F583D + MaxColor: 604E36 ZOffset: -12 ZRamp: 0 71: Cliff RampType: 9 - LeftColor: 3D3426 - RightColor: 5F4D38 + MinColor: 3D3426 + MaxColor: 5F4D38 ZOffset: -12 ZRamp: 0 Template@943: @@ -17583,43 +17585,43 @@ Size: 8, 6 Tiles: 0: Rough - LeftColor: 6C563D - RightColor: 574734 + MinColor: 6C563D + MaxColor: 574734 ZOffset: -12 ZRamp: 0 18: Rough - LeftColor: 705A40 - RightColor: 645440 + MinColor: 705A40 + MaxColor: 645440 ZOffset: -12 ZRamp: 0 28: Cliff - LeftColor: 6E5A42 - RightColor: 594934 + MinColor: 6E5A42 + MaxColor: 594934 ZOffset: -12 ZRamp: 0 29: Cliff - LeftColor: 413726 - RightColor: 251F10 + MinColor: 413726 + MaxColor: 251F10 ZOffset: -12 ZRamp: 0 37: Cliff - LeftColor: 715A3F - RightColor: 473C2C + MinColor: 715A3F + MaxColor: 473C2C ZOffset: -12 ZRamp: 0 38: Cliff - LeftColor: 483E2E - RightColor: 252111 + MinColor: 483E2E + MaxColor: 252111 ZOffset: -12 ZRamp: 0 46: Clear - LeftColor: 745F46 - RightColor: 765F44 + MinColor: 745F46 + MaxColor: 765F44 ZOffset: -12 ZRamp: 0 47: Cliff - LeftColor: 6F5A41 - RightColor: 514534 + MinColor: 6F5A41 + MaxColor: 514534 ZOffset: -12 ZRamp: 0 Template@944: @@ -17629,188 +17631,188 @@ Size: 8, 6 Tiles: 2: Clear - LeftColor: 2C271F - RightColor: 1D1A16 + MinColor: 2C271F + MaxColor: 1D1A16 ZOffset: -12 ZRamp: 0 3: Clear - LeftColor: 141513 - RightColor: 1C1A15 + MinColor: 141513 + MaxColor: 1C1A15 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 1B1E21 - RightColor: 24231D + MinColor: 1B1E21 + MaxColor: 24231D ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 27251D - RightColor: 1F1C14 + MinColor: 27251D + MaxColor: 1F1C14 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 272319 - RightColor: 20201D + MinColor: 272319 + MaxColor: 20201D ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 26231E - RightColor: 353024 + MinColor: 26231E + MaxColor: 353024 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 1A1815 - RightColor: 29251F + MinColor: 1A1815 + MaxColor: 29251F ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 1E1C17 - RightColor: 171513 + MinColor: 1E1C17 + MaxColor: 171513 ZOffset: -12 ZRamp: 0 12: Clear - LeftColor: 262420 - RightColor: 1B1B1A + MinColor: 262420 + MaxColor: 1B1B1A ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 161513 - RightColor: 1E2224 + MinColor: 161513 + MaxColor: 1E2224 ZOffset: -12 ZRamp: 0 14: Clear - LeftColor: 242624 - RightColor: 343738 + MinColor: 242624 + MaxColor: 343738 ZOffset: -12 ZRamp: 0 15: Clear - LeftColor: 3E4C5C - RightColor: 1D2022 + MinColor: 3E4C5C + MaxColor: 1D2022 ZOffset: -12 ZRamp: 0 16: Cliff - LeftColor: 493E2E - RightColor: 2B271B + MinColor: 493E2E + MaxColor: 2B271B ZOffset: -12 ZRamp: 0 17: Cliff - LeftColor: 2B281C - RightColor: 27241B + MinColor: 2B281C + MaxColor: 27241B ZOffset: -12 ZRamp: 0 18: Cliff - LeftColor: 29271F - RightColor: 222019 + MinColor: 29271F + MaxColor: 222019 ZOffset: -12 ZRamp: 0 19: Clear - LeftColor: 2A2823 - RightColor: 1E1C18 + MinColor: 2A2823 + MaxColor: 1E1C18 ZOffset: -12 ZRamp: 0 20: Clear - LeftColor: 1A1916 - RightColor: 302C25 + MinColor: 1A1916 + MaxColor: 302C25 ZOffset: -12 ZRamp: 0 21: Clear - LeftColor: 352F26 - RightColor: 1B1811 + MinColor: 352F26 + MaxColor: 1B1811 ZOffset: -12 ZRamp: 0 22: Clear - LeftColor: 544838 - RightColor: 464037 + MinColor: 544838 + MaxColor: 464037 ZOffset: -12 ZRamp: 0 23: Clear - LeftColor: 514D46 - RightColor: 3E3D3A + MinColor: 514D46 + MaxColor: 3E3D3A ZOffset: -12 ZRamp: 0 24: Clear - LeftColor: 715C42 - RightColor: 745E43 + MinColor: 715C42 + MaxColor: 745E43 ZOffset: -12 ZRamp: 0 25: Clear - LeftColor: 755E43 - RightColor: 5A4933 + MinColor: 755E43 + MaxColor: 5A4933 ZOffset: -12 ZRamp: 0 26: Cliff - LeftColor: 655139 - RightColor: 2D2A1F + MinColor: 655139 + MaxColor: 2D2A1F ZOffset: -12 ZRamp: 0 27: Cliff - LeftColor: 26251E - RightColor: 2C2C28 + MinColor: 26251E + MaxColor: 2C2C28 ZOffset: -12 ZRamp: 0 28: Clear - LeftColor: 33322E - RightColor: 31302C + MinColor: 33322E + MaxColor: 31302C ZOffset: -12 ZRamp: 0 29: Clear - LeftColor: 2D2B24 - RightColor: 181915 + MinColor: 2D2B24 + MaxColor: 181915 ZOffset: -12 ZRamp: 0 30: Cliff - LeftColor: 2A3039 - RightColor: 262523 + MinColor: 2A3039 + MaxColor: 262523 ZOffset: -12 ZRamp: 0 31: Cliff - LeftColor: 1B180F - RightColor: 393227 + MinColor: 1B180F + MaxColor: 393227 ZOffset: -12 ZRamp: 0 34: Clear - LeftColor: 6F5A40 - RightColor: 6B563D + MinColor: 6F5A40 + MaxColor: 6B563D ZOffset: -12 ZRamp: 0 35: Cliff - LeftColor: 6F5A3F - RightColor: 473D2E + MinColor: 6F5A3F + MaxColor: 473D2E ZOffset: -12 ZRamp: 0 36: Cliff - LeftColor: 584A3A - RightColor: 4E4537 + MinColor: 584A3A + MaxColor: 4E4537 ZOffset: -12 ZRamp: 0 37: Cliff - LeftColor: 484034 - RightColor: 55524D + MinColor: 484034 + MaxColor: 55524D ZOffset: -12 ZRamp: 0 38: Cliff - LeftColor: 73706F - RightColor: 454646 + MinColor: 73706F + MaxColor: 454646 ZOffset: -12 ZRamp: 0 39: Cliff - LeftColor: 463A26 - RightColor: 2E2614 + MinColor: 463A26 + MaxColor: 2E2614 ZOffset: -12 ZRamp: 0 45: Cliff - LeftColor: 715A3F - RightColor: 544530 + MinColor: 715A3F + MaxColor: 544530 ZOffset: -12 ZRamp: 0 46: Cliff - LeftColor: 5B4B36 - RightColor: 635543 + MinColor: 5B4B36 + MaxColor: 635543 ZOffset: -12 ZRamp: 0 47: Cliff - LeftColor: 5B554C - RightColor: 544F48 + MinColor: 5B554C + MaxColor: 544F48 ZOffset: -12 ZRamp: 0 Template@945: @@ -17820,238 +17822,238 @@ Size: 7, 10 Tiles: 0: Cliff - LeftColor: 61503C - RightColor: 614F3A + MinColor: 61503C + MaxColor: 614F3A ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 463E2F - RightColor: 453B2C + MinColor: 463E2F + MaxColor: 453B2C ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 4B4336 - RightColor: 745E43 + MinColor: 4B4336 + MaxColor: 745E43 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 111314 - RightColor: 2A271F + MinColor: 111314 + MaxColor: 2A271F ZOffset: -12 ZRamp: 0 15: Cliff - LeftColor: 4F412E - RightColor: 4E4230 + MinColor: 4F412E + MaxColor: 4E4230 ZOffset: -12 ZRamp: 0 16: Cliff - LeftColor: 53442F - RightColor: 65533B + MinColor: 53442F + MaxColor: 65533B ZOffset: -12 ZRamp: 0 17: Rough - LeftColor: 5A4C3A - RightColor: 5F4E39 + MinColor: 5A4C3A + MaxColor: 5F4E39 ZOffset: -12 ZRamp: 0 21: Cliff - LeftColor: 2D3748 - RightColor: 393C3C + MinColor: 2D3748 + MaxColor: 393C3C ZOffset: -12 ZRamp: 0 22: Cliff - LeftColor: 4C4334 - RightColor: 4F402E + MinColor: 4C4334 + MaxColor: 4F402E ZOffset: -12 ZRamp: 0 23: Cliff - LeftColor: 5F4E39 - RightColor: 55452F + MinColor: 5F4E39 + MaxColor: 55452F ZOffset: -12 ZRamp: 0 24: Cliff - LeftColor: 564631 - RightColor: 372F20 + MinColor: 564631 + MaxColor: 372F20 ZOffset: -12 ZRamp: 0 25: Rough - LeftColor: 473A27 - RightColor: 6B573F + MinColor: 473A27 + MaxColor: 6B573F ZOffset: -12 ZRamp: 0 28: Cliff - LeftColor: 484133 - RightColor: 635C58 + MinColor: 484133 + MaxColor: 635C58 ZOffset: -12 ZRamp: 0 29: Cliff - LeftColor: 80684E - RightColor: 65523E + MinColor: 80684E + MaxColor: 65523E ZOffset: -12 ZRamp: 0 30: Cliff - LeftColor: 65513A - RightColor: 63513C + MinColor: 65513A + MaxColor: 63513C ZOffset: -12 ZRamp: 0 31: Cliff - LeftColor: 6F5B44 - RightColor: 584733 + MinColor: 6F5B44 + MaxColor: 584733 ZOffset: -12 ZRamp: 0 32: Cliff - LeftColor: 453724 - RightColor: 3B301F + MinColor: 453724 + MaxColor: 3B301F ZOffset: -12 ZRamp: 0 33: Rough - LeftColor: 544533 - RightColor: 6F5B43 + MinColor: 544533 + MaxColor: 6F5B43 ZOffset: -12 ZRamp: 0 34: Clear - LeftColor: 6D5A42 - RightColor: 6A553D + MinColor: 6D5A42 + MaxColor: 6A553D ZOffset: -12 ZRamp: 0 35: Cliff - LeftColor: 2E2818 - RightColor: 262214 + MinColor: 2E2818 + MaxColor: 262214 ZOffset: -12 ZRamp: 0 36: Cliff - LeftColor: 312A17 - RightColor: 483C2B + MinColor: 312A17 + MaxColor: 483C2B ZOffset: -12 ZRamp: 0 37: Cliff - LeftColor: 453A28 - RightColor: 5D4C38 + MinColor: 453A28 + MaxColor: 5D4C38 ZOffset: -12 ZRamp: 0 38: Cliff - LeftColor: 634F38 - RightColor: 624F38 + MinColor: 634F38 + MaxColor: 624F38 ZOffset: -12 ZRamp: 0 39: Cliff - LeftColor: 493B29 - RightColor: 443828 + MinColor: 493B29 + MaxColor: 443828 ZOffset: -12 ZRamp: 0 40: Rough - LeftColor: 3B3221 - RightColor: 514332 + MinColor: 3B3221 + MaxColor: 514332 ZOffset: -12 ZRamp: 0 41: Clear - LeftColor: 64533D - RightColor: 6D5A42 + MinColor: 64533D + MaxColor: 6D5A42 ZOffset: -12 ZRamp: 0 42: Cliff - LeftColor: 443F34 - RightColor: 4F4637 + MinColor: 443F34 + MaxColor: 4F4637 ZOffset: -12 ZRamp: 0 43: Cliff - LeftColor: 51483A - RightColor: 393120 + MinColor: 51483A + MaxColor: 393120 ZOffset: -12 ZRamp: 0 44: Cliff - LeftColor: 534836 - RightColor: 2B2615 + MinColor: 534836 + MaxColor: 2B2615 ZOffset: -12 ZRamp: 0 45: Cliff - LeftColor: 2F2917 - RightColor: 4D3D2B + MinColor: 2F2917 + MaxColor: 4D3D2B ZOffset: -12 ZRamp: 0 46: Cliff - LeftColor: 473928 - RightColor: 453827 + MinColor: 473928 + MaxColor: 453827 ZOffset: -12 ZRamp: 0 47: Rough - LeftColor: 3E3425 - RightColor: 483D2D + MinColor: 3E3425 + MaxColor: 483D2D ZOffset: -12 ZRamp: 0 48: Clear - LeftColor: 60503C - RightColor: 574935 + MinColor: 60503C + MaxColor: 574935 ZOffset: -12 ZRamp: 0 49: Clear - LeftColor: 6E5A42 - RightColor: 78644C + MinColor: 6E5A42 + MaxColor: 78644C ZOffset: -12 ZRamp: 0 50: Clear - LeftColor: 7F6649 - RightColor: 7D664C + MinColor: 7F6649 + MaxColor: 7D664C ZOffset: -12 ZRamp: 0 51: Cliff - LeftColor: 6C5943 - RightColor: 453A29 + MinColor: 6C5943 + MaxColor: 453A29 ZOffset: -12 ZRamp: 0 52: Cliff - LeftColor: 443A2A - RightColor: 514430 + MinColor: 443A2A + MaxColor: 514430 ZOffset: -12 ZRamp: 0 53: Cliff - LeftColor: 614F38 - RightColor: 433724 + MinColor: 614F38 + MaxColor: 433724 ZOffset: -12 ZRamp: 0 54: Cliff - LeftColor: 53432E - RightColor: 5D4A35 + MinColor: 53432E + MaxColor: 5D4A35 ZOffset: -12 ZRamp: 0 55: Clear - LeftColor: 594B3A - RightColor: 65523C + MinColor: 594B3A + MaxColor: 65523C ZOffset: -12 ZRamp: 0 57: Clear - LeftColor: 534535 - RightColor: 61503D + MinColor: 534535 + MaxColor: 61503D ZOffset: -12 ZRamp: 0 58: Clear - LeftColor: 4D4130 - RightColor: 4E4130 + MinColor: 4D4130 + MaxColor: 4E4130 ZOffset: -12 ZRamp: 0 59: Clear - LeftColor: 473D2B - RightColor: 604F39 + MinColor: 473D2B + MaxColor: 604F39 ZOffset: -12 ZRamp: 0 62: Clear - LeftColor: 69563F - RightColor: 5E5447 + MinColor: 69563F + MaxColor: 5E5447 ZOffset: -12 ZRamp: 0 64: Clear - LeftColor: 6F583D - RightColor: 6F583D + MinColor: 6F583D + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 65: Clear - LeftColor: 665641 - RightColor: 524533 + MinColor: 665641 + MaxColor: 524533 ZOffset: -12 ZRamp: 0 66: Clear - LeftColor: 5B4A34 - RightColor: 5E4C35 + MinColor: 5B4A34 + MaxColor: 5E4C35 ZOffset: -12 ZRamp: 0 Template@952: @@ -18061,78 +18063,78 @@ Size: 3, 5 Tiles: 0: Cliff - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 453625 - RightColor: 463525 + MinColor: 453625 + MaxColor: 463525 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 453625 - RightColor: 463525 + MinColor: 453625 + MaxColor: 463525 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 54514E - RightColor: 585552 + MinColor: 54514E + MaxColor: 585552 ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 54514D - RightColor: 585653 + MinColor: 54514D + MaxColor: 585653 ZOffset: -12 ZRamp: 0 8: Rail - LeftColor: 4A4847 - RightColor: 4F4E4D + MinColor: 4A4847 + MaxColor: 4F4E4D ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 453625 - RightColor: 463525 + MinColor: 453625 + MaxColor: 463525 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 6F5A41 - RightColor: 6D583F + MinColor: 6F5A41 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 463525 - RightColor: 453525 + MinColor: 463525 + MaxColor: 453525 ZOffset: -12 ZRamp: 0 Template@953: @@ -18142,78 +18144,78 @@ Size: 5, 3 Tiles: 0: Cliff - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 55524F - RightColor: 53514E + MinColor: 55524F + MaxColor: 53514E ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6D5A42 - RightColor: 6C583E + MinColor: 6D5A42 + MaxColor: 6C583E ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 555350 - RightColor: 54514D + MinColor: 555350 + MaxColor: 54514D ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 6D583E - RightColor: 6C5840 + MinColor: 6D583E + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 463525 - RightColor: 453625 + MinColor: 463525 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 463525 - RightColor: 453625 + MinColor: 463525 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 12: Rail - LeftColor: 4C4B4A - RightColor: 494847 + MinColor: 4C4B4A + MaxColor: 494847 ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 463525 - RightColor: 453625 + MinColor: 463525 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 453525 - RightColor: 463525 + MinColor: 453525 + MaxColor: 463525 ZOffset: -12 ZRamp: 0 Template@954: @@ -18223,63 +18225,63 @@ Size: 3, 4 Tiles: 0: Cliff - LeftColor: 070707 - RightColor: 2F2B25 + MinColor: 070707 + MaxColor: 2F2B25 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5B574F - RightColor: 5C5954 + MinColor: 5B574F + MaxColor: 5C5954 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 6D6354 - RightColor: 6F583D + MinColor: 6D6354 + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 463525 - RightColor: 100C09 + MinColor: 463525 + MaxColor: 100C09 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 4B4847 - RightColor: 0F0F0F + MinColor: 4B4847 + MaxColor: 0F0F0F ZOffset: -12 ZRamp: 0 7: Rail - LeftColor: 55524F - RightColor: 585552 + MinColor: 55524F + MaxColor: 585552 ZOffset: -12 ZRamp: 0 8: Rail - LeftColor: 55514E - RightColor: 585552 + MinColor: 55514E + MaxColor: 585552 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 0E0A07 - RightColor: 453625 + MinColor: 0E0A07 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 Template@955: @@ -18289,63 +18291,63 @@ Size: 4, 3 Tiles: 0: Cliff - LeftColor: 161616 - RightColor: 2A2621 + MinColor: 161616 + MaxColor: 2A2621 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 453625 - RightColor: 100C09 + MinColor: 453625 + MaxColor: 100C09 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 4C4B4A - RightColor: 0E0E0E + MinColor: 4C4B4A + MaxColor: 0E0E0E ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 453625 - RightColor: 0E0A07 + MinColor: 453625 + MaxColor: 0E0A07 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 58544C - RightColor: 4D4B47 + MinColor: 58544C + MaxColor: 4D4B47 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 6: Rail - LeftColor: 55524F - RightColor: 54524F + MinColor: 55524F + MaxColor: 54524F ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 6F583D - RightColor: 706659 + MinColor: 6F583D + MaxColor: 706659 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 10: Rail - LeftColor: 54524F - RightColor: 54514E + MinColor: 54524F + MaxColor: 54514E ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 Template@956: @@ -18355,78 +18357,78 @@ Size: 3, 5 Tiles: 0: Cliff - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 453625 - RightColor: 463525 + MinColor: 453625 + MaxColor: 463525 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 6F5A41 - RightColor: 6D583F + MinColor: 6F5A41 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 463525 - RightColor: 453525 + MinColor: 463525 + MaxColor: 453525 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 6F5A41 - RightColor: 6D583F + MinColor: 6F5A41 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 463525 - RightColor: 453525 + MinColor: 463525 + MaxColor: 453525 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 6F5A41 - RightColor: 6D583F + MinColor: 6F5A41 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 463525 - RightColor: 453525 + MinColor: 463525 + MaxColor: 453525 ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 6F5A41 - RightColor: 6D583F + MinColor: 6F5A41 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 463525 - RightColor: 453525 + MinColor: 463525 + MaxColor: 453525 ZOffset: -12 ZRamp: 0 Template@957: @@ -18436,78 +18438,78 @@ Size: 5, 3 Tiles: 0: Cliff - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6D5A42 - RightColor: 6C583E + MinColor: 6D5A42 + MaxColor: 6C583E ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 6D583E - RightColor: 6C5840 + MinColor: 6D583E + MaxColor: 6C5840 ZOffset: -12 ZRamp: 0 10: Cliff - LeftColor: 463525 - RightColor: 453625 + MinColor: 463525 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 463525 - RightColor: 453625 + MinColor: 463525 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 12: Clear - LeftColor: 463525 - RightColor: 453625 + MinColor: 463525 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 463525 - RightColor: 453625 + MinColor: 463525 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 453525 - RightColor: 463525 + MinColor: 453525 + MaxColor: 463525 ZOffset: -12 ZRamp: 0 Template@958: @@ -18517,63 +18519,63 @@ Size: 3, 4 Tiles: 0: Cliff - LeftColor: 070707 - RightColor: 2F2A24 + MinColor: 070707 + MaxColor: 2F2A24 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5B574F - RightColor: 5C5954 + MinColor: 5B574F + MaxColor: 5C5954 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 6D6354 - RightColor: 6F583D + MinColor: 6D6354 + MaxColor: 6F583D ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 463525 - RightColor: 100C09 + MinColor: 463525 + MaxColor: 100C09 ZOffset: -12 ZRamp: 0 4: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 6: Road - LeftColor: 463525 - RightColor: 0D0A07 + MinColor: 463525 + MaxColor: 0D0A07 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 9: Road - LeftColor: 0E0A07 - RightColor: 453625 + MinColor: 0E0A07 + MaxColor: 453625 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 6D583E - RightColor: 6E5940 + MinColor: 6D583E + MaxColor: 6E5940 ZOffset: -12 ZRamp: 0 Template@959: @@ -18583,63 +18585,63 @@ Size: 4, 3 Tiles: 0: Cliff - LeftColor: 161616 - RightColor: 2A2620 + MinColor: 161616 + MaxColor: 2A2620 ZOffset: -12 ZRamp: 0 1: Road - LeftColor: 453625 - RightColor: 100C09 + MinColor: 453625 + MaxColor: 100C09 ZOffset: -12 ZRamp: 0 2: Road - LeftColor: 453625 - RightColor: 0E0A07 + MinColor: 453625 + MaxColor: 0E0A07 ZOffset: -12 ZRamp: 0 3: Road - LeftColor: 453625 - RightColor: 0E0A07 + MinColor: 453625 + MaxColor: 0E0A07 ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 58544C - RightColor: 4D4B47 + MinColor: 58544C + MaxColor: 4D4B47 ZOffset: -12 ZRamp: 0 5: Clear - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 6D583F - RightColor: 705C43 + MinColor: 6D583F + MaxColor: 705C43 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 6F583D - RightColor: 706659 + MinColor: 6F583D + MaxColor: 706659 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 6E5940 - RightColor: 6D583E + MinColor: 6E5940 + MaxColor: 6D583E ZOffset: -12 ZRamp: 0 Template@960: @@ -18649,8 +18651,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 349324 - RightColor: 349023 + MinColor: 349324 + MaxColor: 349023 ZOffset: -12 ZRamp: 0 Template@961: @@ -18660,8 +18662,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 427E28 - RightColor: 4A762B + MinColor: 427E28 + MaxColor: 4A762B ZOffset: -12 ZRamp: 0 Template@962: @@ -18671,8 +18673,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 348D22 - RightColor: 4A6F2B + MinColor: 348D22 + MaxColor: 4A6F2B ZOffset: -12 ZRamp: 0 Template@963: @@ -18682,8 +18684,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 307A1C - RightColor: 557E36 + MinColor: 307A1C + MaxColor: 557E36 ZOffset: -12 ZRamp: 0 Template@964: @@ -18693,8 +18695,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 399426 - RightColor: 606538 + MinColor: 399426 + MaxColor: 606538 ZOffset: -12 ZRamp: 0 Template@965: @@ -18704,8 +18706,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 4E692E - RightColor: 337D1D + MinColor: 4E692E + MaxColor: 337D1D ZOffset: -12 ZRamp: 0 Template@966: @@ -18715,8 +18717,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 517532 - RightColor: 49862F + MinColor: 517532 + MaxColor: 49862F ZOffset: -12 ZRamp: 0 Template@967: @@ -18726,8 +18728,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 4A702D - RightColor: 4A732B + MinColor: 4A702D + MaxColor: 4A732B ZOffset: -12 ZRamp: 0 Template@968: @@ -18737,8 +18739,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 44712A - RightColor: 68593D + MinColor: 44712A + MaxColor: 68593D ZOffset: -12 ZRamp: 0 Template@969: @@ -18748,8 +18750,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 467D2D - RightColor: 3A9D29 + MinColor: 467D2D + MaxColor: 3A9D29 ZOffset: -12 ZRamp: 0 Template@970: @@ -18759,8 +18761,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 4D712E - RightColor: 4B6E2A + MinColor: 4D712E + MaxColor: 4B6E2A ZOffset: -12 ZRamp: 0 Template@971: @@ -18770,8 +18772,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 4E7532 - RightColor: 497E2F + MinColor: 4E7532 + MaxColor: 497E2F ZOffset: -12 ZRamp: 0 Template@972: @@ -18781,8 +18783,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 586F37 - RightColor: 6B5A3E + MinColor: 586F37 + MaxColor: 6B5A3E ZOffset: -12 ZRamp: 0 Template@973: @@ -18792,8 +18794,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 696140 - RightColor: 32781D + MinColor: 696140 + MaxColor: 32781D ZOffset: -12 ZRamp: 0 Template@974: @@ -18803,8 +18805,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 665A39 - RightColor: 507330 + MinColor: 665A39 + MaxColor: 507330 ZOffset: -12 ZRamp: 0 Template@975: @@ -18814,8 +18816,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 675A3A - RightColor: 577C35 + MinColor: 675A3A + MaxColor: 577C35 ZOffset: -12 ZRamp: 0 Template@976: @@ -18825,8 +18827,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 51682E - RightColor: 586433 + MinColor: 51682E + MaxColor: 586433 ZOffset: -12 ZRamp: 0 Template@977: @@ -18836,8 +18838,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 252A0D - RightColor: 292D10 + MinColor: 252A0D + MaxColor: 292D10 ZOffset: -12 ZRamp: 0 Template@978: @@ -18847,23 +18849,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 293328 - RightColor: 2F3526 + MinColor: 293328 + MaxColor: 2F3526 ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 384138 - RightColor: 292D0F + MinColor: 384138 + MaxColor: 292D0F ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 27311F - RightColor: 2A372A + MinColor: 27311F + MaxColor: 2A372A ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 28332D - RightColor: 2A321F + MinColor: 28332D + MaxColor: 2A321F ZOffset: -12 ZRamp: 0 Template@979: @@ -18873,23 +18875,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 2A3016 - RightColor: 2E351F + MinColor: 2A3016 + MaxColor: 2E351F ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 2F3B2D - RightColor: 2B3012 + MinColor: 2F3B2D + MaxColor: 2B3012 ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 272D13 - RightColor: 2B3523 + MinColor: 272D13 + MaxColor: 2B3523 ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 28321D - RightColor: 262E0E + MinColor: 28321D + MaxColor: 262E0E ZOffset: -12 ZRamp: 0 Template@980: @@ -18899,23 +18901,23 @@ Size: 2, 2 Tiles: 0: Water - LeftColor: 252B0C - RightColor: 21270A + MinColor: 252B0C + MaxColor: 21270A ZOffset: -12 ZRamp: 0 1: Water - LeftColor: 2A2F0E - RightColor: 2A2E0F + MinColor: 2A2F0E + MaxColor: 2A2E0F ZOffset: -12 ZRamp: 0 2: Water - LeftColor: 282D0E - RightColor: 2A2E0F + MinColor: 282D0E + MaxColor: 2A2E0F ZOffset: -12 ZRamp: 0 3: Water - LeftColor: 272C0E - RightColor: 292D0E + MinColor: 272C0E + MaxColor: 292D0E ZOffset: -12 ZRamp: 0 Template@981: @@ -18925,8 +18927,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 252E1D - RightColor: 262D17 + MinColor: 252E1D + MaxColor: 262D17 ZOffset: -12 ZRamp: 0 Template@982: @@ -18936,8 +18938,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 2A300D - RightColor: 28321D + MinColor: 2A300D + MaxColor: 28321D ZOffset: -12 ZRamp: 0 Template@983: @@ -18947,8 +18949,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 272C0E - RightColor: 2C3110 + MinColor: 272C0E + MaxColor: 2C3110 ZOffset: -12 ZRamp: 0 Template@984: @@ -18958,8 +18960,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 292E0E - RightColor: 292F0E + MinColor: 292E0E + MaxColor: 292F0E ZOffset: -12 ZRamp: 0 Template@985: @@ -18969,8 +18971,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 292E0E - RightColor: 292F0E + MinColor: 292E0E + MaxColor: 292F0E ZOffset: -12 ZRamp: 0 Template@986: @@ -18980,8 +18982,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 1E271A - RightColor: 202819 + MinColor: 1E271A + MaxColor: 202819 ZOffset: -12 ZRamp: 0 Template@987: @@ -18991,8 +18993,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 21280F - RightColor: 1C2827 + MinColor: 21280F + MaxColor: 1C2827 ZOffset: -12 ZRamp: 0 Template@988: @@ -19002,8 +19004,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 262B0D - RightColor: 21291C + MinColor: 262B0D + MaxColor: 21291C ZOffset: -12 ZRamp: 0 Template@989: @@ -19013,8 +19015,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 222A16 - RightColor: 152639 + MinColor: 222A16 + MaxColor: 152639 ZOffset: -12 ZRamp: 0 Template@990: @@ -19024,8 +19026,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 1C261E - RightColor: 262C10 + MinColor: 1C261E + MaxColor: 262C10 ZOffset: -12 ZRamp: 0 Template@991: @@ -19035,8 +19037,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 1C2824 - RightColor: 20291C + MinColor: 1C2824 + MaxColor: 20291C ZOffset: -12 ZRamp: 0 Template@992: @@ -19046,8 +19048,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 1E2618 - RightColor: 1E2921 + MinColor: 1E2618 + MaxColor: 1E2921 ZOffset: -12 ZRamp: 0 Template@993: @@ -19057,8 +19059,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 17252C - RightColor: 122339 + MinColor: 17252C + MaxColor: 122339 ZOffset: -12 ZRamp: 0 Template@994: @@ -19068,8 +19070,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 222A17 - RightColor: 272C0D + MinColor: 222A17 + MaxColor: 272C0D ZOffset: -12 ZRamp: 0 Template@995: @@ -19079,8 +19081,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 192525 - RightColor: 1F291F + MinColor: 192525 + MaxColor: 1F291F ZOffset: -12 ZRamp: 0 Template@996: @@ -19090,8 +19092,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 1B2729 - RightColor: 1B2729 + MinColor: 1B2729 + MaxColor: 1B2729 ZOffset: -12 ZRamp: 0 Template@997: @@ -19101,8 +19103,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 182528 - RightColor: 122339 + MinColor: 182528 + MaxColor: 122339 ZOffset: -12 ZRamp: 0 Template@998: @@ -19112,8 +19114,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 152431 - RightColor: 222A13 + MinColor: 152431 + MaxColor: 222A13 ZOffset: -12 ZRamp: 0 Template@999: @@ -19123,8 +19125,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 152534 - RightColor: 1F2A24 + MinColor: 152534 + MaxColor: 1F2A24 ZOffset: -12 ZRamp: 0 Template@1000: @@ -19134,8 +19136,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 102133 - RightColor: 1D2926 + MinColor: 102133 + MaxColor: 1D2926 ZOffset: -12 ZRamp: 0 Template@1001: @@ -19145,8 +19147,8 @@ Size: 1, 1 Tiles: 0: Water - LeftColor: 19272C - RightColor: 1B2723 + MinColor: 19272C + MaxColor: 1B2723 ZOffset: -12 ZRamp: 0 Template@1002: @@ -19156,8 +19158,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 4C5666 - RightColor: 576274 + MinColor: 4C5666 + MaxColor: 576274 ZOffset: -12 ZRamp: 0 Template@1003: @@ -19167,8 +19169,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 636364 - RightColor: 5F5C5A + MinColor: 636364 + MaxColor: 5F5C5A ZOffset: -12 ZRamp: 0 Template@1004: @@ -19178,8 +19180,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 57606F - RightColor: 696054 + MinColor: 57606F + MaxColor: 696054 ZOffset: -12 ZRamp: 0 Template@1005: @@ -19189,8 +19191,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 495463 - RightColor: 5B5A59 + MinColor: 495463 + MaxColor: 5B5A59 ZOffset: -12 ZRamp: 0 Template@1006: @@ -19200,8 +19202,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 5B6576 - RightColor: 6B5E4E + MinColor: 5B6576 + MaxColor: 6B5E4E ZOffset: -12 ZRamp: 0 Template@1007: @@ -19211,8 +19213,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 625E57 - RightColor: 5A616C + MinColor: 625E57 + MaxColor: 5A616C ZOffset: -12 ZRamp: 0 Template@1008: @@ -19222,8 +19224,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 6B6660 - RightColor: 636063 + MinColor: 6B6660 + MaxColor: 636063 ZOffset: -12 ZRamp: 0 Template@1009: @@ -19233,8 +19235,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 646468 - RightColor: 5E5D5B + MinColor: 646468 + MaxColor: 5E5D5B ZOffset: -12 ZRamp: 0 Template@1010: @@ -19244,8 +19246,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 635C54 - RightColor: 6D5A42 + MinColor: 635C54 + MaxColor: 6D5A42 ZOffset: -12 ZRamp: 0 Template@1011: @@ -19255,8 +19257,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 605A56 - RightColor: 5F6368 + MinColor: 605A56 + MaxColor: 5F6368 ZOffset: -12 ZRamp: 0 Template@1012: @@ -19266,8 +19268,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 636468 - RightColor: 68645F + MinColor: 636468 + MaxColor: 68645F ZOffset: -12 ZRamp: 0 Template@1013: @@ -19277,8 +19279,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 625F60 - RightColor: 656363 + MinColor: 625F60 + MaxColor: 656363 ZOffset: -12 ZRamp: 0 Template@1014: @@ -19288,8 +19290,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 655D54 - RightColor: 6D5940 + MinColor: 655D54 + MaxColor: 6D5940 ZOffset: -12 ZRamp: 0 Template@1015: @@ -19299,8 +19301,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 6D5F4E - RightColor: 566174 + MinColor: 6D5F4E + MaxColor: 566174 ZOffset: -12 ZRamp: 0 Template@1016: @@ -19310,8 +19312,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 705B41 - RightColor: 655C4F + MinColor: 705B41 + MaxColor: 655C4F ZOffset: -12 ZRamp: 0 Template@1017: @@ -19321,8 +19323,8 @@ Size: 1, 1 Tiles: 0: Clear - LeftColor: 6E583F - RightColor: 695D50 + MinColor: 6E583F + MaxColor: 695D50 ZOffset: -12 ZRamp: 0 Template@1018: @@ -19332,8 +19334,8 @@ Size: 1, 1 Tiles: 0: Rough - LeftColor: 6A5F55 - RightColor: 655A4F + MinColor: 6A5F55 + MaxColor: 655A4F ZOffset: -12 ZRamp: 0 Template@1019: @@ -19344,24 +19346,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 325E22 - RightColor: 2E6E1F + MinColor: 325E22 + MaxColor: 2E6E1F ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 2C5F1E - RightColor: 405B2C + MinColor: 2C5F1E + MaxColor: 405B2C ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 615443 - RightColor: 3B7325 + MinColor: 615443 + MaxColor: 3B7325 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 4D7331 - RightColor: 3E5A2A + MinColor: 4D7331 + MaxColor: 3E5A2A ZOffset: -12 ZRamp: 0 Template@1020: @@ -19372,24 +19374,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 455E30 - RightColor: 4B5931 + MinColor: 455E30 + MaxColor: 4B5931 ZOffset: -12 ZRamp: 0 1: Cliff Height: 4 - LeftColor: 515539 - RightColor: 514536 + MinColor: 515539 + MaxColor: 514536 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 4C8935 - RightColor: 405C26 + MinColor: 4C8935 + MaxColor: 405C26 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 3B7926 - RightColor: 555D3D + MinColor: 3B7926 + MaxColor: 555D3D ZOffset: -12 ZRamp: 0 Template@1021: @@ -19400,18 +19402,18 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 3C5B28 - RightColor: 415A2B + MinColor: 3C5B28 + MaxColor: 415A2B ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 366E23 - RightColor: 425D27 + MinColor: 366E23 + MaxColor: 425D27 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 4C4B3B - RightColor: 497035 + MinColor: 4C4B3B + MaxColor: 497035 ZOffset: -12 ZRamp: 0 Template@1022: @@ -19421,8 +19423,8 @@ Size: 1, 1 Tiles: 0: Cliff - LeftColor: 486632 - RightColor: 4B5739 + MinColor: 486632 + MaxColor: 4B5739 ZOffset: -12 ZRamp: 0 Template@1023: @@ -19433,24 +19435,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 2C701D - RightColor: 3E632A + MinColor: 2C701D + MaxColor: 3E632A ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 3F692A - RightColor: 39461F + MinColor: 3F692A + MaxColor: 39461F ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 304920 - RightColor: 3B502C + MinColor: 304920 + MaxColor: 3B502C ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 4A4728 - RightColor: 374D23 + MinColor: 4A4728 + MaxColor: 374D23 ZOffset: -12 ZRamp: 0 Template@1024: @@ -19461,24 +19463,24 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 414A2C - RightColor: 3B4726 + MinColor: 414A2C + MaxColor: 3B4726 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 366F20 - RightColor: 355120 + MinColor: 366F20 + MaxColor: 355120 ZOffset: -12 ZRamp: 0 2: Cliff Height: 4 - LeftColor: 4B4330 - RightColor: 345724 + MinColor: 4B4330 + MaxColor: 345724 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 575034 - RightColor: 2F6A1F + MinColor: 575034 + MaxColor: 2F6A1F ZOffset: -12 ZRamp: 0 Template@1025: @@ -19488,218 +19490,218 @@ Size: 6, 9 Tiles: 0: Clear - LeftColor: 705A40 - RightColor: 6C573D + MinColor: 705A40 + MaxColor: 6C573D ZOffset: -12 ZRamp: 0 6: Clear - LeftColor: 69533A - RightColor: 635038 + MinColor: 69533A + MaxColor: 635038 ZOffset: -12 ZRamp: 0 7: Clear - LeftColor: 4E3E29 - RightColor: 4C3B25 + MinColor: 4E3E29 + MaxColor: 4C3B25 ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 4E3B23 - RightColor: 513E25 + MinColor: 4E3B23 + MaxColor: 513E25 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 45351F - RightColor: 413119 + MinColor: 45351F + MaxColor: 413119 ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 433420 - RightColor: 42331E + MinColor: 433420 + MaxColor: 42331E ZOffset: -12 ZRamp: 0 12: Clear - LeftColor: 69543A - RightColor: 5D4A33 + MinColor: 69543A + MaxColor: 5D4A33 ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 4A3A27 - RightColor: 463520 + MinColor: 4A3A27 + MaxColor: 463520 ZOffset: -12 ZRamp: 0 14: Clear - LeftColor: 42341F - RightColor: 473723 + MinColor: 42341F + MaxColor: 473723 ZOffset: -12 ZRamp: 0 15: Clear - LeftColor: 4A3924 - RightColor: 47341E + MinColor: 4A3924 + MaxColor: 47341E ZOffset: -12 ZRamp: 0 16: Clear - LeftColor: 362815 - RightColor: 332715 + MinColor: 362815 + MaxColor: 332715 ZOffset: -12 ZRamp: 0 18: Clear - LeftColor: 69553E - RightColor: 5D4930 + MinColor: 69553E + MaxColor: 5D4930 ZOffset: -12 ZRamp: 0 19: Clear - LeftColor: 493721 - RightColor: 44331E + MinColor: 493721 + MaxColor: 44331E ZOffset: -12 ZRamp: 0 20: Clear - LeftColor: 3B2E1C - RightColor: 43321C + MinColor: 3B2E1C + MaxColor: 43321C ZOffset: -12 ZRamp: 0 21: Clear - LeftColor: 2E2210 - RightColor: 3C2F1B + MinColor: 2E2210 + MaxColor: 3C2F1B ZOffset: -12 ZRamp: 0 22: Clear - LeftColor: 342713 - RightColor: 473621 + MinColor: 342713 + MaxColor: 473621 ZOffset: -12 ZRamp: 0 24: Clear - LeftColor: 6C583E - RightColor: 635039 + MinColor: 6C583E + MaxColor: 635039 ZOffset: -12 ZRamp: 0 25: Clear - LeftColor: 51402C - RightColor: 44341E + MinColor: 51402C + MaxColor: 44341E ZOffset: -12 ZRamp: 0 26: Clear - LeftColor: 392C17 - RightColor: 312512 + MinColor: 392C17 + MaxColor: 312512 ZOffset: -12 ZRamp: 0 27: Clear - LeftColor: 3B2E1B - RightColor: 382814 + MinColor: 3B2E1B + MaxColor: 382814 ZOffset: -12 ZRamp: 0 28: Clear - LeftColor: 41301A - RightColor: 332512 + MinColor: 41301A + MaxColor: 332512 ZOffset: -12 ZRamp: 0 30: Clear - LeftColor: 66523C - RightColor: 634F38 + MinColor: 66523C + MaxColor: 634F38 ZOffset: -12 ZRamp: 0 31: Clear - LeftColor: 554330 - RightColor: 53412E + MinColor: 554330 + MaxColor: 53412E ZOffset: -12 ZRamp: 0 32: Clear - LeftColor: 53412D - RightColor: 483622 + MinColor: 53412D + MaxColor: 483622 ZOffset: -12 ZRamp: 0 33: Clear - LeftColor: 463522 - RightColor: 473520 + MinColor: 463522 + MaxColor: 473520 ZOffset: -12 ZRamp: 0 34: Clear - LeftColor: 43311B - RightColor: 3F2E1A + MinColor: 43311B + MaxColor: 3F2E1A ZOffset: -12 ZRamp: 0 35: Cliff - LeftColor: 2A1E0D - RightColor: 352714 + MinColor: 2A1E0D + MaxColor: 352714 ZOffset: -12 ZRamp: 0 36: Clear - LeftColor: 6C573F - RightColor: 624D37 + MinColor: 6C573F + MaxColor: 624D37 ZOffset: -12 ZRamp: 0 37: Clear - LeftColor: 54422F - RightColor: 4F3C2A + MinColor: 54422F + MaxColor: 4F3C2A ZOffset: -12 ZRamp: 0 38: Clear - LeftColor: 463724 - RightColor: 433523 + MinColor: 463724 + MaxColor: 433523 ZOffset: -12 ZRamp: 0 39: Clear - LeftColor: 3B2C17 - RightColor: 3F2F1B + MinColor: 3B2C17 + MaxColor: 3F2F1B ZOffset: -12 ZRamp: 0 40: Clear - LeftColor: 604A28 - RightColor: 4D3A1F + MinColor: 604A28 + MaxColor: 4D3A1F ZOffset: -12 ZRamp: 0 41: Cliff - LeftColor: 927043 - RightColor: 5E4A2B + MinColor: 927043 + MaxColor: 5E4A2B ZOffset: -12 ZRamp: 0 42: Clear - LeftColor: 6D5941 - RightColor: 64503B + MinColor: 6D5941 + MaxColor: 64503B ZOffset: -12 ZRamp: 0 43: Clear - LeftColor: 55432F - RightColor: 4E3D29 + MinColor: 55432F + MaxColor: 4E3D29 ZOffset: -12 ZRamp: 0 44: Clear - LeftColor: 45341F - RightColor: 483621 + MinColor: 45341F + MaxColor: 483621 ZOffset: -12 ZRamp: 0 45: Clear - LeftColor: 3E2E18 - RightColor: 3E2E19 + MinColor: 3E2E18 + MaxColor: 3E2E19 ZOffset: -12 ZRamp: 0 46: Cliff - LeftColor: 755F34 - RightColor: 8D713E + MinColor: 755F34 + MaxColor: 8D713E ZOffset: -12 ZRamp: 0 48: Clear - LeftColor: 705A40 - RightColor: 6E573D + MinColor: 705A40 + MaxColor: 6E573D ZOffset: -12 ZRamp: 0 49: Clear - LeftColor: 6C573E - RightColor: 604D37 + MinColor: 6C573E + MaxColor: 604D37 ZOffset: -12 ZRamp: 0 50: Clear - LeftColor: 675139 - RightColor: 4E3D28 + MinColor: 675139 + MaxColor: 4E3D28 ZOffset: -12 ZRamp: 0 51: Clear - LeftColor: 64513A - RightColor: 58442B + MinColor: 64513A + MaxColor: 58442B ZOffset: -12 ZRamp: 0 52: Clear - LeftColor: 5A4730 - RightColor: 4F3C26 + MinColor: 5A4730 + MaxColor: 4F3C26 ZOffset: -12 ZRamp: 0 Template@1026: @@ -19709,43 +19711,43 @@ Size: 4, 3 Tiles: 1: Cliff - LeftColor: 715B39 - RightColor: 48381F + MinColor: 715B39 + MaxColor: 48381F ZOffset: -12 ZRamp: 0 4: Cliff - LeftColor: 6C512C - RightColor: 87693B + MinColor: 6C512C + MaxColor: 87693B ZOffset: -12 ZRamp: 0 5: Cliff - LeftColor: 413219 - RightColor: 3D3628 + MinColor: 413219 + MaxColor: 3D3628 ZOffset: -12 ZRamp: 0 6: Cliff - LeftColor: 423523 - RightColor: 2E2616 + MinColor: 423523 + MaxColor: 2E2616 ZOffset: -12 ZRamp: 0 8: Clear - LeftColor: 6E5935 - RightColor: 453722 + MinColor: 6E5935 + MaxColor: 453722 ZOffset: -12 ZRamp: 0 9: Clear - LeftColor: 634E36 - RightColor: 58462E + MinColor: 634E36 + MaxColor: 58462E ZOffset: -12 ZRamp: 0 10: Clear - LeftColor: 6F5A40 - RightColor: 6D573D + MinColor: 6F5A40 + MaxColor: 6D573D ZOffset: -12 ZRamp: 0 11: Clear - LeftColor: 685239 - RightColor: 503D27 + MinColor: 685239 + MaxColor: 503D27 ZOffset: -12 ZRamp: 0 Template@1027: @@ -19755,348 +19757,348 @@ Size: 12, 9 Tiles: 0: Cliff - LeftColor: 745B33 - RightColor: 4E3D20 + MinColor: 745B33 + MaxColor: 4E3D20 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 5F4929 - RightColor: 4E3C20 + MinColor: 5F4929 + MaxColor: 4E3C20 ZOffset: -12 ZRamp: 0 2: Cliff - LeftColor: 5E4623 - RightColor: 4C3C21 + MinColor: 5E4623 + MaxColor: 4C3C21 ZOffset: -12 ZRamp: 0 3: Cliff - LeftColor: 382F1D - RightColor: 52432C + MinColor: 382F1D + MaxColor: 52432C ZOffset: -12 ZRamp: 0 12: Cliff - LeftColor: 5E4726 - RightColor: 49381E + MinColor: 5E4726 + MaxColor: 49381E ZOffset: -12 ZRamp: 0 13: Cliff - LeftColor: 5E4927 - RightColor: 69502C + MinColor: 5E4927 + MaxColor: 69502C ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 5A4525 - RightColor: 584425 + MinColor: 5A4525 + MaxColor: 584425 ZOffset: -12 ZRamp: 0 15: Cliff - LeftColor: 604A28 - RightColor: 423A2E + MinColor: 604A28 + MaxColor: 423A2E ZOffset: -12 ZRamp: 0 16: Cliff - LeftColor: 4C3F29 - RightColor: 392F1D + MinColor: 4C3F29 + MaxColor: 392F1D ZOffset: -12 ZRamp: 0 17: Cliff - LeftColor: 312713 - RightColor: 372914 + MinColor: 312713 + MaxColor: 372914 ZOffset: -12 ZRamp: 0 18: Cliff - LeftColor: 352912 - RightColor: 342812 + MinColor: 352912 + MaxColor: 342812 ZOffset: -12 ZRamp: 0 19: Cliff - LeftColor: 362C1C - RightColor: 281F0F + MinColor: 362C1C + MaxColor: 281F0F ZOffset: -12 ZRamp: 0 24: Cliff - LeftColor: 2D210F - RightColor: 41321A + MinColor: 2D210F + MaxColor: 41321A ZOffset: -12 ZRamp: 0 25: Cliff - LeftColor: 3D2E18 - RightColor: 7D5E35 + MinColor: 3D2E18 + MaxColor: 7D5E35 ZOffset: -12 ZRamp: 0 26: Cliff - LeftColor: 715630 - RightColor: 5D4625 + MinColor: 715630 + MaxColor: 5D4625 ZOffset: -12 ZRamp: 0 27: Cliff - LeftColor: 69502C - RightColor: 564425 + MinColor: 69502C + MaxColor: 564425 ZOffset: -12 ZRamp: 0 28: Clear - LeftColor: 48391C - RightColor: 4E3D1E + MinColor: 48391C + MaxColor: 4E3D1E ZOffset: -12 ZRamp: 0 29: Clear - LeftColor: 45371B - RightColor: 1D170C + MinColor: 45371B + MaxColor: 1D170C ZOffset: -12 ZRamp: 0 30: Clear - LeftColor: 453825 - RightColor: 524128 + MinColor: 453825 + MaxColor: 524128 ZOffset: -12 ZRamp: 0 31: Clear - LeftColor: 53432B - RightColor: 372C1A + MinColor: 53432B + MaxColor: 372C1A ZOffset: -12 ZRamp: 0 32: Cliff - LeftColor: 564530 - RightColor: 443725 + MinColor: 564530 + MaxColor: 443725 ZOffset: -12 ZRamp: 0 33: Cliff - LeftColor: 50402B - RightColor: 54442E + MinColor: 50402B + MaxColor: 54442E ZOffset: -12 ZRamp: 0 37: Cliff - LeftColor: 211A0C - RightColor: 1F180C + MinColor: 211A0C + MaxColor: 1F180C ZOffset: -12 ZRamp: 0 38: Cliff - LeftColor: 2D2214 - RightColor: 5A4525 + MinColor: 2D2214 + MaxColor: 5A4525 ZOffset: -12 ZRamp: 0 39: Cliff - LeftColor: A6874B - RightColor: 6F5836 + MinColor: A6874B + MaxColor: 6F5836 ZOffset: -12 ZRamp: 0 40: Clear - LeftColor: 81653B - RightColor: 5B4927 + MinColor: 81653B + MaxColor: 5B4927 ZOffset: -12 ZRamp: 0 41: Clear - LeftColor: 624F2A - RightColor: 3A2D15 + MinColor: 624F2A + MaxColor: 3A2D15 ZOffset: -12 ZRamp: 0 42: Clear - LeftColor: 352913 - RightColor: 3B2E19 + MinColor: 352913 + MaxColor: 3B2E19 ZOffset: -12 ZRamp: 0 43: Clear - LeftColor: 524028 - RightColor: 5C4B32 + MinColor: 524028 + MaxColor: 5C4B32 ZOffset: -12 ZRamp: 0 44: Clear - LeftColor: 5B4832 - RightColor: 5A4933 + MinColor: 5B4832 + MaxColor: 5A4933 ZOffset: -12 ZRamp: 0 45: Rough - LeftColor: 654F34 - RightColor: 645036 + MinColor: 654F34 + MaxColor: 645036 ZOffset: -12 ZRamp: 0 46: Cliff - LeftColor: 554533 - RightColor: 68543A + MinColor: 554533 + MaxColor: 68543A ZOffset: -12 ZRamp: 0 50: Cliff - LeftColor: 2D2414 - RightColor: 322715 + MinColor: 2D2414 + MaxColor: 322715 ZOffset: -12 ZRamp: 0 51: Cliff - LeftColor: 352B1B - RightColor: 947743 + MinColor: 352B1B + MaxColor: 947743 ZOffset: -12 ZRamp: 0 52: Cliff - LeftColor: 836B42 - RightColor: B38E54 + MinColor: 836B42 + MaxColor: B38E54 ZOffset: -12 ZRamp: 0 53: Cliff - LeftColor: 786138 - RightColor: 5E4A27 + MinColor: 786138 + MaxColor: 5E4A27 ZOffset: -12 ZRamp: 0 54: Cliff - LeftColor: 302613 - RightColor: 332815 + MinColor: 302613 + MaxColor: 332815 ZOffset: -12 ZRamp: 0 55: Clear - LeftColor: 665239 - RightColor: 69543A + MinColor: 665239 + MaxColor: 69543A ZOffset: -12 ZRamp: 0 56: Clear - LeftColor: 705B42 - RightColor: 6B563E + MinColor: 705B42 + MaxColor: 6B563E ZOffset: -12 ZRamp: 0 57: Clear - LeftColor: 6C573F - RightColor: 624E38 + MinColor: 6C573F + MaxColor: 624E38 ZOffset: -12 ZRamp: 0 58: Rough - LeftColor: 523F29 - RightColor: 423623 + MinColor: 523F29 + MaxColor: 423623 ZOffset: -12 ZRamp: 0 59: Cliff - LeftColor: 3F321E - RightColor: 725A34 + MinColor: 3F321E + MaxColor: 725A34 ZOffset: -12 ZRamp: 0 63: Clear - LeftColor: 453621 - RightColor: 493923 + MinColor: 453621 + MaxColor: 493923 ZOffset: -12 ZRamp: 0 64: Cliff - LeftColor: 473622 - RightColor: 40301A + MinColor: 473622 + MaxColor: 40301A ZOffset: -12 ZRamp: 0 65: Cliff - LeftColor: 4A3820 - RightColor: 372A17 + MinColor: 4A3820 + MaxColor: 372A17 ZOffset: -12 ZRamp: 0 66: Clear - LeftColor: 58462F - RightColor: 624D33 + MinColor: 58462F + MaxColor: 624D33 ZOffset: -12 ZRamp: 0 67: Clear - LeftColor: 5E4931 - RightColor: 67523A + MinColor: 5E4931 + MaxColor: 67523A ZOffset: -12 ZRamp: 0 68: Clear - LeftColor: 6B573E - RightColor: 6D573D + MinColor: 6B573E + MaxColor: 6D573D ZOffset: -12 ZRamp: 0 69: Clear - LeftColor: 6B563E - RightColor: 634E36 + MinColor: 6B563E + MaxColor: 634E36 ZOffset: -12 ZRamp: 0 70: Clear - LeftColor: 4F3F2E - RightColor: 443724 + MinColor: 4F3F2E + MaxColor: 443724 ZOffset: -12 ZRamp: 0 71: Rough - LeftColor: 4E402F - RightColor: 443828 + MinColor: 4E402F + MaxColor: 443828 ZOffset: -12 ZRamp: 0 76: Clear - LeftColor: 564834 - RightColor: 5E4931 + MinColor: 564834 + MaxColor: 5E4931 ZOffset: -12 ZRamp: 0 77: Clear - LeftColor: 685137 - RightColor: 59452E + MinColor: 685137 + MaxColor: 59452E ZOffset: -12 ZRamp: 0 78: Clear - LeftColor: 51412E - RightColor: 69543C + MinColor: 51412E + MaxColor: 69543C ZOffset: -12 ZRamp: 0 79: Clear - LeftColor: 523F2A - RightColor: 57432D + MinColor: 523F2A + MaxColor: 57432D ZOffset: -12 ZRamp: 0 80: Clear - LeftColor: 5C4831 - RightColor: 68533B + MinColor: 5C4831 + MaxColor: 68533B ZOffset: -12 ZRamp: 0 81: Clear - LeftColor: 594530 - RightColor: 5E4B35 + MinColor: 594530 + MaxColor: 5E4B35 ZOffset: -12 ZRamp: 0 82: Clear - LeftColor: 4E3C28 - RightColor: 503E29 + MinColor: 4E3C28 + MaxColor: 503E29 ZOffset: -12 ZRamp: 0 83: Clear - LeftColor: 574129 - RightColor: 4C3C28 + MinColor: 574129 + MaxColor: 4C3C28 ZOffset: -12 ZRamp: 0 90: Clear - LeftColor: 705B43 - RightColor: 5C4935 + MinColor: 705B43 + MaxColor: 5C4935 ZOffset: -12 ZRamp: 0 91: Clear - LeftColor: 6C563D - RightColor: 695233 + MinColor: 6C563D + MaxColor: 695233 ZOffset: -12 ZRamp: 0 92: Clear - LeftColor: 5E4A31 - RightColor: 54422C + MinColor: 5E4A31 + MaxColor: 54422C ZOffset: -12 ZRamp: 0 93: Clear - LeftColor: 604B34 - RightColor: 54422D + MinColor: 604B34 + MaxColor: 54422D ZOffset: -12 ZRamp: 0 94: Clear - LeftColor: 4F3C28 - RightColor: 4E3C27 + MinColor: 4F3C28 + MaxColor: 4E3C27 ZOffset: -12 ZRamp: 0 95: Rough - LeftColor: 554228 - RightColor: 574628 + MinColor: 554228 + MaxColor: 574628 ZOffset: -12 ZRamp: 0 104: Clear - LeftColor: 705A40 - RightColor: 6E593E + MinColor: 705A40 + MaxColor: 6E593E ZOffset: -12 ZRamp: 0 105: Clear - LeftColor: 6B573F - RightColor: 65523B + MinColor: 6B573F + MaxColor: 65523B ZOffset: -12 ZRamp: 0 106: Clear - LeftColor: 604C38 - RightColor: 51412F + MinColor: 604C38 + MaxColor: 51412F ZOffset: -12 ZRamp: 0 107: Clear - LeftColor: 5E4B35 - RightColor: 5D4A34 + MinColor: 5E4B35 + MaxColor: 5D4A34 ZOffset: -12 ZRamp: 0 Template@1028: @@ -20106,93 +20108,93 @@ Size: 6, 4 Tiles: 0: Cliff - LeftColor: 352C1C - RightColor: 4B3C28 + MinColor: 352C1C + MaxColor: 4B3C28 ZOffset: -12 ZRamp: 0 1: Cliff - LeftColor: 56462E - RightColor: 775C34 + MinColor: 56462E + MaxColor: 775C34 ZOffset: -12 ZRamp: 0 6: Rough - LeftColor: 504432 - RightColor: 403728 + MinColor: 504432 + MaxColor: 403728 ZOffset: -12 ZRamp: 0 7: Cliff - LeftColor: 362D1C - RightColor: 4E3F29 + MinColor: 362D1C + MaxColor: 4E3F29 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 433624 - RightColor: 4B3F2C + MinColor: 433624 + MaxColor: 4B3F2C ZOffset: -12 ZRamp: 0 9: Cliff - LeftColor: 564835 - RightColor: 524430 + MinColor: 564835 + MaxColor: 524430 ZOffset: -12 ZRamp: 0 12: Clear - LeftColor: 3F321F - RightColor: 3C301E + MinColor: 3F321F + MaxColor: 3C301E ZOffset: -12 ZRamp: 0 13: Clear - LeftColor: 54432F - RightColor: 473A29 + MinColor: 54432F + MaxColor: 473A29 ZOffset: -12 ZRamp: 0 14: Clear - LeftColor: 493D2E - RightColor: 463927 + MinColor: 493D2E + MaxColor: 463927 ZOffset: -12 ZRamp: 0 15: Clear - LeftColor: 524430 - RightColor: 483A26 + MinColor: 524430 + MaxColor: 483A26 ZOffset: -12 ZRamp: 0 16: Clear - LeftColor: 4E3F2C - RightColor: 524332 + MinColor: 4E3F2C + MaxColor: 524332 ZOffset: -12 ZRamp: 0 17: Clear - LeftColor: 63503B - RightColor: 6C583F + MinColor: 63503B + MaxColor: 6C583F ZOffset: -12 ZRamp: 0 18: Clear - LeftColor: 69543D - RightColor: 66513A + MinColor: 69543D + MaxColor: 66513A ZOffset: -12 ZRamp: 0 19: Clear - LeftColor: 6C573D - RightColor: 66523A + MinColor: 6C573D + MaxColor: 66523A ZOffset: -12 ZRamp: 0 20: Clear - LeftColor: 6F5A42 - RightColor: 65523B + MinColor: 6F5A42 + MaxColor: 65523B ZOffset: -12 ZRamp: 0 21: Clear - LeftColor: 6C573E - RightColor: 5E4B35 + MinColor: 6C573E + MaxColor: 5E4B35 ZOffset: -12 ZRamp: 0 22: Clear - LeftColor: 6D5941 - RightColor: 6E5A42 + MinColor: 6D5941 + MaxColor: 6E5A42 ZOffset: -12 ZRamp: 0 23: Clear - LeftColor: 705C43 - RightColor: 6D583F + MinColor: 705C43 + MaxColor: 6D583F ZOffset: -12 ZRamp: 0 Template@1029: @@ -20203,90 +20205,90 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 524637 - RightColor: 594B38 + MinColor: 524637 + MaxColor: 594B38 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 594F3F - RightColor: 4F4A41 + MinColor: 594F3F + MaxColor: 4F4A41 ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 49463F - RightColor: 494338 + MinColor: 49463F + MaxColor: 494338 ZOffset: -12 ZRamp: 0 10: Cliff Height: 4 - LeftColor: 2B2824 - RightColor: 4F4537 + MinColor: 2B2824 + MaxColor: 4F4537 ZOffset: -12 ZRamp: 0 11: Cliff Height: 4 - LeftColor: 353028 - RightColor: 473F34 + MinColor: 353028 + MaxColor: 473F34 ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 433D34 - RightColor: 483E32 + MinColor: 433D34 + MaxColor: 483E32 ZOffset: -12 ZRamp: 0 17: Cliff - LeftColor: 5D4D38 - RightColor: 554B3C + MinColor: 5D4D38 + MaxColor: 554B3C ZOffset: -12 ZRamp: 0 18: Cliff - LeftColor: 51412D - RightColor: 504739 + MinColor: 51412D + MaxColor: 504739 ZOffset: -12 ZRamp: 0 19: Cliff - LeftColor: 483925 - RightColor: 4E4335 + MinColor: 483925 + MaxColor: 4E4335 ZOffset: -12 ZRamp: 0 20: Cliff - LeftColor: 4B3B22 - RightColor: 413C34 + MinColor: 4B3B22 + MaxColor: 413C34 ZOffset: -12 ZRamp: 0 21: Cliff Height: 4 - LeftColor: 2D2C28 - RightColor: 37322B + MinColor: 2D2C28 + MaxColor: 37322B ZOffset: -12 ZRamp: 0 22: Cliff Height: 4 - LeftColor: 4A4338 - RightColor: 4F4436 + MinColor: 4A4338 + MaxColor: 4F4436 ZOffset: -12 ZRamp: 0 23: Cliff Height: 4 - LeftColor: 494237 - RightColor: 4D4233 + MinColor: 494237 + MaxColor: 4D4233 ZOffset: -12 ZRamp: 0 29: Cliff - LeftColor: 3B3019 - RightColor: 42351E + MinColor: 3B3019 + MaxColor: 42351E ZOffset: -12 ZRamp: 0 30: Cliff - LeftColor: 544023 - RightColor: 493F2E + MinColor: 544023 + MaxColor: 493F2E ZOffset: -12 ZRamp: 0 31: Cliff - LeftColor: 5E4928 - RightColor: 584D3D + MinColor: 5E4928 + MaxColor: 584D3D ZOffset: -12 ZRamp: 0 Template@1030: @@ -20297,90 +20299,90 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 524637 - RightColor: 594B38 + MinColor: 524637 + MaxColor: 594B38 ZOffset: -12 ZRamp: 0 8: Cliff - LeftColor: 534225 - RightColor: 5B4E39 + MinColor: 534225 + MaxColor: 5B4E39 ZOffset: -12 ZRamp: 0 9: Cliff Height: 4 - LeftColor: 49463F - RightColor: 494338 + MinColor: 49463F + MaxColor: 494338 ZOffset: -12 ZRamp: 0 10: Cliff Height: 4 - LeftColor: 4D463A - RightColor: 4C4234 + MinColor: 4D463A + MaxColor: 4C4234 ZOffset: -12 ZRamp: 0 11: Cliff Height: 4 - LeftColor: 4A4135 - RightColor: 4F4436 + MinColor: 4A4135 + MaxColor: 4F4436 ZOffset: -12 ZRamp: 0 12: Cliff Height: 4 - LeftColor: 433D34 - RightColor: 483E32 + MinColor: 433D34 + MaxColor: 483E32 ZOffset: -12 ZRamp: 0 17: Cliff - LeftColor: 5A462B - RightColor: 493A22 + MinColor: 5A462B + MaxColor: 493A22 ZOffset: -12 ZRamp: 0 18: Cliff - LeftColor: 3E3117 - RightColor: 534939 + MinColor: 3E3117 + MaxColor: 534939 ZOffset: -12 ZRamp: 0 19: Cliff - LeftColor: 392C15 - RightColor: 433D33 + MinColor: 392C15 + MaxColor: 433D33 ZOffset: -12 ZRamp: 0 20: Cliff - LeftColor: 403729 - RightColor: 3E3A34 + MinColor: 403729 + MaxColor: 3E3A34 ZOffset: -12 ZRamp: 0 21: Cliff Height: 4 - LeftColor: 2D2C28 - RightColor: 37322B + MinColor: 2D2C28 + MaxColor: 37322B ZOffset: -12 ZRamp: 0 22: Cliff Height: 4 - LeftColor: 524637 - RightColor: 594B38 + MinColor: 524637 + MaxColor: 594B38 ZOffset: -12 ZRamp: 0 29: Cliff - LeftColor: 453723 - RightColor: 473A2A + MinColor: 453723 + MaxColor: 473A2A ZOffset: -12 ZRamp: 0 30: Cliff - LeftColor: 584B38 - RightColor: 4F4A41 + MinColor: 584B38 + MaxColor: 4F4A41 ZOffset: -12 ZRamp: 0 31: Cliff Height: 4 - LeftColor: 49463F - RightColor: 494338 + MinColor: 49463F + MaxColor: 494338 ZOffset: -12 ZRamp: 0 39: Cliff - LeftColor: 513F21 - RightColor: 262319 + MinColor: 513F21 + MaxColor: 262319 ZOffset: -12 ZRamp: 0 Template@1031: @@ -20391,84 +20393,84 @@ Tiles: 0: Cliff Height: 4 - LeftColor: 4B4337 - RightColor: 4B4030 + MinColor: 4B4337 + MaxColor: 4B4030 ZOffset: -12 ZRamp: 0 7: Cliff Height: 4 - LeftColor: 3F3B34 - RightColor: 504537 + MinColor: 3F3B34 + MaxColor: 504537 ZOffset: -12 ZRamp: 0 14: Cliff - LeftColor: 836337 - RightColor: 43351C + MinColor: 836337 + MaxColor: 43351C ZOffset: -12 ZRamp: 0 15: Cliff Height: 4 - LeftColor: 1F1D19 - RightColor: 3F3B34 + MinColor: 1F1D19 + MaxColor: 3F3B34 ZOffset: -12 ZRamp: 0 16: Cliff Height: 4 - LeftColor: 46423B - RightColor: 4D4437 + MinColor: 46423B + MaxColor: 4D4437 ZOffset: -12 ZRamp: 0 22: Cliff - LeftColor: 654E2C - RightColor: 4B3A1E + MinColor: 654E2C + MaxColor: 4B3A1E ZOffset: -12 ZRamp: 0 23: Cliff - LeftColor: 624B2A - RightColor: 3A3221 + MinColor: 624B2A + MaxColor: 3A3221 ZOffset: -12 ZRamp: 0 24: Cliff Height: 4 - LeftColor: 3A3730 - RightColor: 3B352C + MinColor: 3A3730 + MaxColor: 3B352C ZOffset: -12 ZRamp: 0 25: Cliff Height: 4 - LeftColor: 46423B - RightColor: 51422F + MinColor: 46423B + MaxColor: 51422F ZOffset: -12 ZRamp: 0 31: Cliff - LeftColor: 624B2C - RightColor: 4E3E26 + MinColor: 624B2C + MaxColor: 4E3E26 ZOffset: -12 ZRamp: 0 32: Cliff - LeftColor: 413625 - RightColor: 4E483E + MinColor: 413625 + MaxColor: 4E483E ZOffset: -12 ZRamp: 0 33: Cliff Height: 4 - LeftColor: 48453E - RightColor: 413A30 + MinColor: 48453E + MaxColor: 413A30 ZOffset: -12 ZRamp: 0 34: Cliff Height: 4 - LeftColor: 4F4639 - RightColor: 514536 + MinColor: 4F4639 + MaxColor: 514536 ZOffset: -12 ZRamp: 0 40: Cliff - LeftColor: 392D1A - RightColor: 40392D + MinColor: 392D1A + MaxColor: 40392D ZOffset: -12 ZRamp: 0 41: Cliff - LeftColor: 5C5041 - RightColor: 585349 + MinColor: 5C5041 + MaxColor: 585349 ZOffset: -12 ZRamp: 0 Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/uibits/glyphs-2x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/uibits/glyphs-2x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/uibits/glyphs-3x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/uibits/glyphs-3x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/mods/ts/uibits/glyphs.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/mods/ts/uibits/glyphs.png differ diff -Nru openra-20200503/mods/ts/weapons/energyweapons.yaml openra-20210321/mods/ts/weapons/energyweapons.yaml --- openra-20200503/mods/ts/weapons/energyweapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/weapons/energyweapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -23,13 +23,13 @@ LtRail: Inherits: ^Railgun Warhead@1Dam: SpreadDamage - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy Warhead@2Dam: SpreadDamage Range: 0, 32 Falloff: 50, 50 # Only does half damage to friendly units Damage: 15000 AffectsParent: false - ValidStances: Ally + ValidRelationships: Ally Versus: None: 100 Wood: 130 @@ -73,7 +73,7 @@ Falloff: 100, 100 Damage: 800 AffectsParent: false - ValidStances: Neutral, Enemy + ValidRelationships: Neutral, Enemy Versus: Heavy: 80 Concrete: 60 @@ -84,7 +84,7 @@ Damage: 800 InvalidTargets: Disruptor # Does not affect friendly disruptors at all AffectsParent: false - ValidStances: Ally + ValidRelationships: Ally Versus: Heavy: 80 Concrete: 60 @@ -117,7 +117,7 @@ Projectile: Missile MaximumLaunchSpeed: 192 Blockable: false - HorizontalRateOfTurn: 2 + HorizontalRateOfTurn: 8 Shadow: true Image: TORPEDO MinimumLaunchSpeed: 75 diff -Nru openra-20200503/mods/ts/weapons/explosions.yaml openra-20210321/mods/ts/weapons/explosions.yaml --- openra-20200503/mods/ts/weapons/explosions.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/weapons/explosions.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -66,3 +66,8 @@ Explosions: large_twlt ExplosionPalette: effect-ignore-lighting-alpha75 ImpactSounds: expnew09.aud + +DropPodExplode: + Warhead@1Eff: CreateEffect + Explosions: droppod_explosion, droppod2_explosion, droppody_explosion, droppody2_explosion + ExplosionPalette: effect-ignore-lighting-alpha75 diff -Nru openra-20200503/mods/ts/weapons/missiles.yaml openra-20210321/mods/ts/weapons/missiles.yaml --- openra-20200503/mods/ts/weapons/missiles.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/weapons/missiles.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -11,16 +11,16 @@ Image: DRAGON TrailImage: small_smoke_trail TrailPalette: effectalpha75 - HorizontalRateOfTurn: 8 - RangeLimit: 8c0 + HorizontalRateOfTurn: 100 + RangeLimit: 15c0 Palette: ra MinimumLaunchSpeed: 75 Speed: 216 - Acceleration: 6 + Acceleration: 96 MinimumLaunchAngle: 128 MaximumLaunchAngle: 192 - VerticalRateOfTurn: 11 - CruiseAltitude: 2c124 + VerticalRateOfTurn: 100 + CruiseAltitude: 5c512 AllowSnapping: true TerrainHeightAware: true Warhead@1Dam: SpreadDamage @@ -60,8 +60,6 @@ Burst: 2 Range: 8c0 Report: hovrmis1.aud - Projectile: Missile - RangeLimit: 11c0 Warhead@1Dam: SpreadDamage Damage: 3000 @@ -71,9 +69,6 @@ Report: misl1.aud ValidTargets: Air Burst: 2 - Projectile: Missile - HorizontalRateOfTurn: 10 - RangeLimit: 9c0 Warhead@1Dam: SpreadDamage Spread: 144 Damage: 4000 @@ -96,8 +91,6 @@ Range: 5c0 Report: misl1.aud ValidTargets: Ground - Projectile: Missile - RangeLimit: 7c0 Warhead@1Dam: SpreadDamage Damage: 4000 ValidTargets: Ground, Air @@ -134,9 +127,8 @@ Report: samshot1.aud ValidTargets: Air Projectile: Missile - MaximumLaunchSpeed: 144 Arm: 1 - HorizontalRateOfTurn: 5 + VerticalRateOfTurn: 140 RangeLimit: 25c0 Speed: 288 Warhead@1Dam: SpreadDamage diff -Nru openra-20200503/mods/ts/weapons/superweapons.yaml openra-20210321/mods/ts/weapons/superweapons.yaml --- openra-20200503/mods/ts/weapons/superweapons.yaml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/mods/ts/weapons/superweapons.yaml 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,7 @@ MaximumLaunchAngle: 255 RangeLimit: 10c0 AllowSnapping: false - VerticalRateOfTurn: 16 + VerticalRateOfTurn: 64 Warhead@1Dam: SpreadDamage Spread: 216 Damage: 13000 @@ -47,7 +47,7 @@ ExplosionPalette: effect-ignore-lighting-alpha75 ImpactSounds: expnew19.aud ImpactActors: false - ValidTargets: Ground Water, Air + ValidTargets: Ground, Water, Air Warhead@Cluster: FireCluster Weapon: MultiCluster RandomClusterCount: 10 diff -Nru openra-20200503/OpenRA.Game/Activities/Activity.cs openra-20210321/OpenRA.Game/Activities/Activity.cs --- openra-20200503/OpenRA.Game/Activities/Activity.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Activities/Activity.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,7 +26,7 @@ public readonly Color Color; public readonly Sprite Tile; - public TargetLineNode(Target target, Color color, Sprite tile = null) + public TargetLineNode(in Target target, Color color, Sprite tile = null) { // Note: Not all activities are drawable. In that case, pass Target.Invalid as target, // if "yield break" in TargetLineNode(Actor self) is not feasible. @@ -185,8 +185,7 @@ /// internal void OnActorDisposeOuter(Actor self) { - if (ChildActivity != null) - ChildActivity.OnActorDisposeOuter(self); + ChildActivity?.OnActorDisposeOuter(self); OnActorDispose(self); } @@ -199,8 +198,7 @@ if (!IsInterruptible) return; - if (ChildActivity != null) - ChildActivity.Cancel(self); + ChildActivity?.Cancel(self); // Directly mark activities that are queued and therefore didn't run yet as done State = State == ActivityState.Queued ? ActivityState.Done : ActivityState.Canceling; @@ -243,11 +241,9 @@ Console.WriteLine(GetType().ToString().Split('.').Last()); - if (ChildActivity != null) - ChildActivity.PrintActivityTree(self, origin, level + 1); + ChildActivity?.PrintActivityTree(self, origin, level + 1); - if (NextActivity != null) - NextActivity.PrintActivityTree(self, origin, level); + NextActivity?.PrintActivityTree(self, origin, level); } } diff -Nru openra-20200503/OpenRA.Game/Activities/CallFunc.cs openra-20210321/OpenRA.Game/Activities/CallFunc.cs --- openra-20200503/OpenRA.Game/Activities/CallFunc.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Activities/CallFunc.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,7 +26,7 @@ public override bool Tick(Actor self) { - if (a != null) a(); + a?.Invoke(); return true; } } diff -Nru openra-20200503/OpenRA.Game/Actor.cs openra-20210321/OpenRA.Game/Actor.cs --- openra-20200503/OpenRA.Game/Actor.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Actor.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using Eluant; using Eluant.ObjectBinding; @@ -68,16 +69,40 @@ { get { - // TODO: Support non-zero pitch/roll in IFacing (IOrientation?) - var facingValue = facing != null ? facing.Facing : 0; - return new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facingValue)); + return facing != null ? facing.Orientation : WRot.None; } } + /// Value used to represent an invalid token. + public static readonly int InvalidConditionToken = -1; + + class ConditionState + { + /// Delegates that have registered to be notified when this condition changes. + public readonly List Notifiers = new List(); + + /// Unique integers identifying granted instances of the condition. + public readonly HashSet Tokens = new HashSet(); + } + + readonly Dictionary conditionStates = new Dictionary(); + + /// Each granted condition receives a unique token that is used when revoking. + readonly Dictionary conditionTokens = new Dictionary(); + + int nextConditionToken = 1; + + /// Cache of condition -> enabled state for quick evaluation of token counter conditions. + readonly Dictionary conditionCache = new Dictionary(); + + /// Read-only version of conditionCache that is passed to IConditionConsumers. + readonly IReadOnlyDictionary readOnlyConditionCache; + internal SyncHash[] SyncHashes { get; private set; } readonly IFacing facing; readonly IHealth health; + readonly IResolveOrder[] resolveOrders; readonly IRenderModifier[] renderModifiers; readonly IRender[] renders; readonly IMouseBounds[] mouseBounds; @@ -85,18 +110,28 @@ readonly IDefaultVisibility defaultVisibility; readonly INotifyBecomingIdle[] becomingIdles; readonly INotifyIdle[] tickIdles; - readonly ITargetablePositions[] targetablePositions; + readonly IEnumerable enabledTargetablePositions; WPos[] staticTargetablePositions; bool created; + bool setStaticTargetablePositions; internal Actor(World world, string name, TypeDictionary initDict) { + var duplicateInit = initDict.WithInterface().GroupBy(i => i.GetType()) + .FirstOrDefault(i => i.Count() > 1); + + if (duplicateInit != null) + throw new InvalidDataException("Duplicate initializer '{0}'".F(duplicateInit.Key.Name)); + var init = new ActorInitializer(this, initDict); + readOnlyConditionCache = new ReadOnlyDictionary(conditionCache); + World = world; ActorID = world.NextAID(); - if (initDict.Contains()) - Owner = init.Get(); + var ownerInit = init.GetOrDefault(); + if (ownerInit != null) + Owner = ownerInit.Value(world); if (name != null) { @@ -106,51 +141,102 @@ throw new NotImplementedException("No rules definition for unit " + name); Info = world.Map.Rules.Actors[name]; - foreach (var trait in Info.TraitsInConstructOrder()) + + IPositionable positionable = null; + var resolveOrdersList = new List(); + var renderModifiersList = new List(); + var rendersList = new List(); + var mouseBoundsList = new List(); + var visibilityModifiersList = new List(); + var becomingIdlesList = new List(); + var tickIdlesList = new List(); + var targetablesList = new List(); + var targetablePositionsList = new List(); + var syncHashesList = new List(); + + foreach (var traitInfo in Info.TraitsInConstructOrder()) { - AddTrait(trait.Create(init)); + var trait = traitInfo.Create(init); + AddTrait(trait); - // Some traits rely on properties provided by IOccupySpace in their initialization, - // so we must ready it now, we cannot wait until all traits have finished construction. - if (trait is IOccupySpaceInfo) - OccupiesSpace = Trait(); + // PERF: Cache all these traits as soon as the actor is created. This is a fairly cheap one-off cost per + // actor that allows us to provide some fast implementations of commonly used methods that are relied on by + // performance-sensitive parts of the core game engine, such as pathfinding, visibility and rendering. + // Note: The blocks are required to limit the scope of the t's, so we make an exception to our normal style + // rules for spacing in order to keep these assignments compact and readable. + { if (trait is IPositionable t) positionable = t; } + { if (trait is IOccupySpace t) OccupiesSpace = t; } + { if (trait is IEffectiveOwner t) EffectiveOwner = t; } + { if (trait is IFacing t) facing = t; } + { if (trait is IHealth t) health = t; } + { if (trait is IResolveOrder t) resolveOrdersList.Add(t); } + { if (trait is IRenderModifier t) renderModifiersList.Add(t); } + { if (trait is IRender t) rendersList.Add(t); } + { if (trait is IMouseBounds t) mouseBoundsList.Add(t); } + { if (trait is IVisibilityModifier t) visibilityModifiersList.Add(t); } + { if (trait is IDefaultVisibility t) defaultVisibility = t; } + { if (trait is INotifyBecomingIdle t) becomingIdlesList.Add(t); } + { if (trait is INotifyIdle t) tickIdlesList.Add(t); } + { if (trait is ITargetable t) targetablesList.Add(t); } + { if (trait is ITargetablePositions t) targetablePositionsList.Add(t); } + { if (trait is ISync t) syncHashesList.Add(new SyncHash(t)); } } - } - // PERF: Cache all these traits as soon as the actor is created. This is a fairly cheap one-off cost per - // actor that allows us to provide some fast implementations of commonly used methods that are relied on by - // performance-sensitive parts of the core game engine, such as pathfinding, visibility and rendering. - EffectiveOwner = TraitOrDefault(); - facing = TraitOrDefault(); - health = TraitOrDefault(); - renderModifiers = TraitsImplementing().ToArray(); - renders = TraitsImplementing().ToArray(); - mouseBounds = TraitsImplementing().ToArray(); - visibilityModifiers = TraitsImplementing().ToArray(); - defaultVisibility = Trait(); - becomingIdles = TraitsImplementing().ToArray(); - tickIdles = TraitsImplementing().ToArray(); - Targetables = TraitsImplementing().ToArray(); - targetablePositions = TraitsImplementing().ToArray(); - world.AddFrameEndTask(w => - { - // Caching this in a AddFrameEndTask, because trait construction order might cause problems if done directly at creation time. - // All actors that can move or teleport should have IPositionable, if not it's pretty safe to assume the actor is completely immobile and - // all targetable positions can be cached if all ITargetablePositions have no conditional requirements. - if (!Info.HasTraitInfo() && targetablePositions.Any() && targetablePositions.All(tp => tp.AlwaysEnabled)) - staticTargetablePositions = targetablePositions.SelectMany(tp => tp.TargetablePositions(this)).ToArray(); - }); + resolveOrders = resolveOrdersList.ToArray(); + renderModifiers = renderModifiersList.ToArray(); + renders = rendersList.ToArray(); + mouseBounds = mouseBoundsList.ToArray(); + visibilityModifiers = visibilityModifiersList.ToArray(); + becomingIdles = becomingIdlesList.ToArray(); + tickIdles = tickIdlesList.ToArray(); + Targetables = targetablesList.ToArray(); + var targetablePositions = targetablePositionsList.ToArray(); + enabledTargetablePositions = targetablePositions.Where(Exts.IsTraitEnabled); + SyncHashes = syncHashesList.ToArray(); - SyncHashes = TraitsImplementing().Select(sync => new SyncHash(sync)).ToArray(); + setStaticTargetablePositions = positionable == null && targetablePositions.Any() && targetablePositions.All(tp => tp.AlwaysEnabled); + } } - internal void Created() + internal void Initialize(bool addToWorld = true) { created = true; + // Make sure traits are usable for condition notifiers foreach (var t in TraitsImplementing()) t.Created(this); + var allObserverNotifiers = new HashSet(); + foreach (var provider in TraitsImplementing()) + { + foreach (var variableUser in provider.GetVariableObservers()) + { + allObserverNotifiers.Add(variableUser.Notifier); + foreach (var variable in variableUser.Variables) + { + var cs = conditionStates.GetOrAdd(variable); + cs.Notifiers.Add(variableUser.Notifier); + + // Initialize conditions that have not yet been granted to 0 + // NOTE: Some conditions may have already been granted by INotifyCreated calling GrantCondition, + // and we choose to assign the token count to safely cover both cases instead of adding an if branch. + conditionCache[variable] = cs.Tokens.Count; + } + } + } + + // Update all traits with their initial condition state + foreach (var notify in allObserverNotifiers) + notify(this, readOnlyConditionCache); + + // All actors that can move or teleport should have IPositionable, if not it's pretty safe to assume the actor is completely immobile and + // all targetable positions can be cached if all ITargetablePositions have no conditional requirements. + if (setStaticTargetablePositions) + staticTargetablePositions = enabledTargetablePositions.SelectMany(tp => tp.TargetablePositions(this)).ToArray(); + + // TODO: Other traits may need initialization after being notified of initial condition state. + + // TODO: A post condition initialization notification phase may allow queueing activities instead. // The initial activity should run before any activities queued by INotifyCreated.Created // However, we need to know which traits are enabled (via conditions), so wait for after the calls and insert the activity as the first ICreationActivity creationActivity = null; @@ -171,6 +257,9 @@ activity.Queue(CurrentActivity); CurrentActivity = activity; } + + if (addToWorld) + World.Add(this); } public void Tick() @@ -233,7 +322,7 @@ yield return r; } - public Rectangle MouseBounds(WorldRenderer wr) + public Polygon MouseBounds(WorldRenderer wr) { foreach (var mb in mouseBounds) { @@ -242,7 +331,7 @@ return bounds; } - return Rectangle.Empty; + return Polygon.Empty; } public void QueueActivity(bool queued, Activity nextActivity) @@ -266,8 +355,7 @@ public void CancelActivity() { - if (CurrentActivity != null) - CurrentActivity.Cancel(this); + CurrentActivity?.Cancel(this); } public override int GetHashCode() @@ -319,8 +407,7 @@ { // If CurrentActivity isn't null, run OnActorDisposeOuter in case some cleanups are needed. // This should be done before the FrameEndTask to avoid dependency issues. - if (CurrentActivity != null) - CurrentActivity.OnActorDisposeOuter(this); + CurrentActivity?.OnActorDisposeOuter(this); // Allow traits/activities to prevent a race condition when they depend on disposing the actor (e.g. Transforms) WillDispose = true; @@ -339,11 +426,16 @@ World.TraitDict.RemoveActor(this); Disposed = true; - if (luaInterface != null) - luaInterface.Value.OnActorDestroyed(); + luaInterface?.Value.OnActorDestroyed(); }); } + public void ResolveOrder(Order order) + { + foreach (var r in resolveOrders) + r.ResolveOrder(this, order); + } + // TODO: move elsewhere. public void ChangeOwner(Player newOwner) { @@ -447,13 +539,71 @@ if (staticTargetablePositions != null) return staticTargetablePositions; - var enabledTargetablePositionTraits = targetablePositions.Where(Exts.IsTraitEnabled); - if (enabledTargetablePositionTraits.Any()) - return enabledTargetablePositionTraits.SelectMany(tp => tp.TargetablePositions(this)); + if (enabledTargetablePositions.Any()) + return enabledTargetablePositions.SelectMany(tp => tp.TargetablePositions(this)); return new[] { CenterPosition }; } + #region Conditions + + void UpdateConditionState(string condition, int token, bool isRevoke) + { + ConditionState conditionState = conditionStates.GetOrAdd(condition); + + if (isRevoke) + conditionState.Tokens.Remove(token); + else + conditionState.Tokens.Add(token); + + conditionCache[condition] = conditionState.Tokens.Count; + + // Conditions may be granted or revoked before the state is initialized. + // These notifications will be processed after INotifyCreated.Created. + if (created) + foreach (var notify in conditionState.Notifiers) + notify(this, readOnlyConditionCache); + } + + /// + /// Grants a specified condition if it is valid. + /// Otherwise, just returns InvalidConditionToken. + /// + /// The token that is used to revoke this condition. + public int GrantCondition(string condition) + { + if (string.IsNullOrEmpty(condition)) + return InvalidConditionToken; + + var token = nextConditionToken++; + conditionTokens.Add(token, condition); + UpdateConditionState(condition, token, false); + return token; + } + + /// + /// Revokes a previously granted condition. + /// + /// The token ID returned by GrantCondition. + /// The invalid token ID. + public int RevokeCondition(int token) + { + if (!conditionTokens.TryGetValue(token, out var condition)) + throw new InvalidOperationException("Attempting to revoke condition with invalid token {0} for {1}.".F(token, this)); + + conditionTokens.Remove(token); + UpdateConditionState(condition, token, true); + return InvalidConditionToken; + } + + /// Returns whether the specified token is valid for RevokeCondition + public bool TokenValid(int token) + { + return conditionTokens.ContainsKey(token); + } + + #endregion + #region Scripting interface Lazy luaInterface; @@ -471,8 +621,7 @@ public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right) { - Actor a, b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out Actor a) || !right.TryGetClrValue(out Actor b)) return false; return a == b; diff -Nru openra-20200503/OpenRA.Game/App.config openra-20210321/OpenRA.Game/App.config --- openra-20200503/OpenRA.Game/App.config 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/App.config 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff -Nru openra-20200503/OpenRA.Game/CPos.cs openra-20210321/OpenRA.Game/CPos.cs --- openra-20200503/OpenRA.Game/CPos.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/CPos.cs 2021-03-21 11:10:05.000000000 +0000 @@ -89,9 +89,7 @@ public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right) { - CPos a; - CVec b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out CPos a) || !right.TryGetClrValue(out CVec b)) throw new LuaException("Attempted to call CPos.Add(CPos, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name)); return new LuaCustomClrObject(a + b); @@ -99,21 +97,18 @@ public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right) { - CPos a; var rightType = right.WrappedClrType(); - if (!left.TryGetClrValue(out a)) + if (!left.TryGetClrValue(out CPos a)) throw new LuaException("Attempted to call CPos.Subtract(CPos, (CPos|CVec)) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, rightType.Name)); if (rightType == typeof(CPos)) { - CPos b; - right.TryGetClrValue(out b); + right.TryGetClrValue(out CPos b); return new LuaCustomClrObject(a - b); } else if (rightType == typeof(CVec)) { - CVec b; - right.TryGetClrValue(out b); + right.TryGetClrValue(out CVec b); return new LuaCustomClrObject(a - b); } @@ -122,8 +117,7 @@ public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right) { - CPos a, b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out CPos a) || !right.TryGetClrValue(out CPos b)) return false; return a == b; diff -Nru openra-20200503/OpenRA.Game/CVec.cs openra-20210321/OpenRA.Game/CVec.cs --- openra-20200503/OpenRA.Game/CVec.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/CVec.cs 2021-03-21 11:10:05.000000000 +0000 @@ -75,8 +75,7 @@ public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right) { - CVec a, b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out CVec b)) throw new LuaException("Attempted to call CVec.Add(CVec, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name)); return new LuaCustomClrObject(a + b); @@ -84,8 +83,7 @@ public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right) { - CVec a, b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out CVec b)) throw new LuaException("Attempted to call CVec.Subtract(CVec, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name)); return new LuaCustomClrObject(a - b); @@ -98,8 +96,7 @@ public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right) { - CVec a, b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out CVec b)) return false; return a == b; diff -Nru openra-20200503/OpenRA.Game/DefaultPlayer.cs openra-20210321/OpenRA.Game/DefaultPlayer.cs --- openra-20200503/OpenRA.Game/DefaultPlayer.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Game/DefaultPlayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,20 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Primitives; + +namespace OpenRA +{ + public class DefaultPlayer : IGlobalModData + { + public readonly Color Color = Color.FromAhsl(0, 0, 238); + } +} diff -Nru openra-20200503/OpenRA.Game/Download.cs openra-20210321/OpenRA.Game/Download.cs --- openra-20200503/OpenRA.Game/Download.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Download.cs 2021-03-21 11:10:05.000000000 +0000 @@ -90,8 +90,7 @@ public void CancelAsync() { lock (syncObject) - if (wc != null) - wc.CancelAsync(); + wc?.CancelAsync(); } } } diff -Nru openra-20200503/OpenRA.Game/ExternalMods.cs openra-20210321/OpenRA.Game/ExternalMods.cs --- openra-20200503/OpenRA.Game/ExternalMods.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/ExternalMods.cs 2021-03-21 11:10:05.000000000 +0000 @@ -121,7 +121,7 @@ mods[key] = mod; } - internal void Register(Manifest mod, string launchPath, ModRegistration registration) + internal void Register(Manifest mod, string launchPath, IEnumerable launchArgs, ModRegistration registration) { if (mod.Metadata.Hidden) return; @@ -133,7 +133,7 @@ new MiniYamlNode("Version", mod.Metadata.Version), new MiniYamlNode("Title", mod.Metadata.Title), new MiniYamlNode("LaunchPath", launchPath), - new MiniYamlNode("LaunchArgs", "Game.Mod=" + mod.Id) + new MiniYamlNode("LaunchArgs", new[] { "Game.Mod=" + mod.Id }.Concat(launchArgs).JoinWith(", ")) })); using (var stream = mod.Package.GetStream("icon.png")) diff -Nru openra-20200503/OpenRA.Game/Exts.cs openra-20210321/OpenRA.Game/Exts.cs --- openra-20200503/OpenRA.Game/Exts.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Exts.cs 2021-03-21 11:10:05.000000000 +0000 @@ -80,7 +80,7 @@ static int WindingDirectionTest(int2 v0, int2 v1, int2 p) { - return (v1.X - v0.X) * (p.Y - v0.Y) - (p.X - v0.X) * (v1.Y - v0.Y); + return Math.Sign((v1.X - v0.X) * (p.Y - v0.Y) - (p.X - v0.X) * (v1.Y - v0.Y)); } public static bool PolygonContains(this int2[] polygon, int2 p) @@ -101,6 +101,16 @@ return windingNumber != 0; } + public static bool LinesIntersect(int2 a, int2 b, int2 c, int2 d) + { + // If line segments AB and CD intersect: + // - the triangles ACD and BCD must have opposite sense (clockwise or anticlockwise) + // - the triangles CAB and DAB must have opposite sense + // Segments intersect if the orientation (clockwise or anticlockwise) of the two points in each line segment are opposite with respect to the other + // Assumes that lines are not colinear + return WindingDirectionTest(c, d, a) != WindingDirectionTest(c, d, b) && WindingDirectionTest(a, b, c) != WindingDirectionTest(a, b, d); + } + public static bool HasModifier(this Modifiers k, Modifiers mod) { // PERF: Enum.HasFlag is slower and requires allocations. @@ -110,13 +120,19 @@ public static V GetOrAdd(this Dictionary d, K k) where V : new() { - return d.GetOrAdd(k, _ => new V()); + return d.GetOrAdd(k, new V()); + } + + public static V GetOrAdd(this Dictionary d, K k, V v) + { + if (!d.TryGetValue(k, out var ret)) + d.Add(k, ret = v); + return ret; } public static V GetOrAdd(this Dictionary d, K k, Func createFn) { - V ret; - if (!d.TryGetValue(k, out ret)) + if (!d.TryGetValue(k, out var ret)) d.Add(k, ret = createFn(k)); return ret; } @@ -343,8 +359,7 @@ public static int IntegerDivisionRoundingAwayFromZero(int dividend, int divisor) { - int remainder; - var quotient = Math.DivRem(dividend, divisor, out remainder); + var quotient = Math.DivRem(dividend, divisor, out var remainder); if (remainder == 0) return quotient; return quotient + (Math.Sign(dividend) == Math.Sign(divisor) ? 1 : -1); @@ -395,8 +410,7 @@ // Check for a key conflict: if (d.ContainsKey(key)) { - List dupKeyMessages; - if (!dupKeys.TryGetValue(key, out dupKeyMessages)) + if (!dupKeys.TryGetValue(key, out var dupKeyMessages)) { // Log the initial conflicting value already inserted: dupKeyMessages = new List(); diff -Nru openra-20200503/OpenRA.Game/FieldLoader.cs openra-20210321/OpenRA.Game/FieldLoader.cs --- openra-20200503/OpenRA.Game/FieldLoader.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/FieldLoader.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,6 @@ using System.Reflection; using System.Runtime.Serialization; using System.Text.RegularExpressions; -using OpenRA.Graphics; using OpenRA.Primitives; using OpenRA.Support; @@ -122,8 +121,7 @@ { ret = null; - MiniYaml yaml; - if (!md.TryGetValue(yamlName, out yaml)) + if (!md.TryGetValue(yamlName, out var yaml)) return false; ret = GetValue(field.Name, field.FieldType, yaml, field); @@ -181,42 +179,36 @@ public static object GetValue(string fieldName, Type fieldType, MiniYaml yaml, MemberInfo field) { - var value = yaml.Value; - if (value != null) value = value.Trim(); + var value = yaml.Value?.Trim(); if (fieldType == typeof(int)) { - int res; - if (Exts.TryParseIntegerInvariant(value, out res)) + if (Exts.TryParseIntegerInvariant(value, out var res)) return res; return InvalidValueAction(value, fieldType, fieldName); } else if (fieldType == typeof(ushort)) { - ushort res; - if (ushort.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out res)) + if (ushort.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var res)) return res; return InvalidValueAction(value, fieldType, fieldName); } if (fieldType == typeof(long)) { - long res; - if (long.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out res)) + if (long.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var res)) return res; return InvalidValueAction(value, fieldType, fieldName); } else if (fieldType == typeof(float)) { - float res; - if (value != null && float.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) + if (value != null && float.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var res)) return res * (value.Contains('%') ? 0.01f : 1f); return InvalidValueAction(value, fieldType, fieldName); } else if (fieldType == typeof(decimal)) { - decimal res; - if (value != null && decimal.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) + if (value != null && decimal.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var res)) return res * (value.Contains('%') ? 0.01m : 1m); return InvalidValueAction(value, fieldType, fieldName); } @@ -228,16 +220,14 @@ } else if (fieldType == typeof(Color)) { - Color color; - if (value != null && Color.TryParse(value, out color)) + if (value != null && Color.TryParse(value, out var color)) return color; return InvalidValueAction(value, fieldType, fieldName); } else if (fieldType == typeof(Hotkey)) { - Hotkey res; - if (Hotkey.TryParse(value, out res)) + if (Hotkey.TryParse(value, out var res)) return res; return InvalidValueAction(value, fieldType, fieldName); @@ -248,8 +238,7 @@ } else if (fieldType == typeof(WDist)) { - WDist res; - if (WDist.TryParse(value, out res)) + if (WDist.TryParse(value, out var res)) return res; return InvalidValueAction(value, fieldType, fieldName); @@ -261,8 +250,7 @@ var parts = value.Split(','); if (parts.Length == 3) { - WDist rx, ry, rz; - if (WDist.TryParse(parts[0], out rx) && WDist.TryParse(parts[1], out ry) && WDist.TryParse(parts[2], out rz)) + if (WDist.TryParse(parts[0], out var rx) && WDist.TryParse(parts[1], out var ry) && WDist.TryParse(parts[2], out var rz)) return new WVec(rx, ry, rz); } } @@ -282,8 +270,7 @@ for (var i = 0; i < vecs.Length; ++i) { - WDist rx, ry, rz; - if (WDist.TryParse(parts[3 * i], out rx) && WDist.TryParse(parts[3 * i + 1], out ry) && WDist.TryParse(parts[3 * i + 2], out rz)) + if (WDist.TryParse(parts[3 * i], out var rx) && WDist.TryParse(parts[3 * i + 1], out var ry) && WDist.TryParse(parts[3 * i + 2], out var rz)) vecs[i] = new WVec(rx, ry, rz); } @@ -299,8 +286,7 @@ var parts = value.Split(','); if (parts.Length == 3) { - WDist rx, ry, rz; - if (WDist.TryParse(parts[0], out rx) && WDist.TryParse(parts[1], out ry) && WDist.TryParse(parts[2], out rz)) + if (WDist.TryParse(parts[0], out var rx) && WDist.TryParse(parts[1], out var ry) && WDist.TryParse(parts[2], out var rz)) return new WPos(rx, ry, rz); } } @@ -309,8 +295,7 @@ } else if (fieldType == typeof(WAngle)) { - int res; - if (Exts.TryParseIntegerInvariant(value, out res)) + if (Exts.TryParseIntegerInvariant(value, out var res)) return new WAngle(res); return InvalidValueAction(value, fieldType, fieldName); } @@ -321,8 +306,7 @@ var parts = value.Split(','); if (parts.Length == 3) { - int rr, rp, ry; - if (Exts.TryParseIntegerInvariant(parts[0], out rr) && Exts.TryParseIntegerInvariant(parts[1], out rp) && Exts.TryParseIntegerInvariant(parts[2], out ry)) + if (Exts.TryParseIntegerInvariant(parts[0], out var rr) && Exts.TryParseIntegerInvariant(parts[1], out var rp) && Exts.TryParseIntegerInvariant(parts[2], out var ry)) return new WRot(new WAngle(rr), new WAngle(rp), new WAngle(ry)); } } @@ -361,8 +345,7 @@ var vecs = new CVec[parts.Length / 2]; for (var i = 0; i < vecs.Length; i++) { - int rx, ry; - if (int.TryParse(parts[2 * i], out rx) && int.TryParse(parts[2 * i + 1], out ry)) + if (int.TryParse(parts[2 * i], out var rx) && int.TryParse(parts[2 * i + 1], out var ry)) vecs[i] = new CVec(rx, ry); } @@ -416,8 +399,7 @@ } else if (fieldType == typeof(bool)) { - bool result; - if (bool.TryParse(value.ToLowerInvariant(), out result)) + if (bool.TryParse(value.ToLowerInvariant(), out var result)) return result; return InvalidValueAction(value, fieldType, fieldName); @@ -453,7 +435,7 @@ ret.SetValue(GetValue(fieldName, fieldType.GetElementType(), parts[i].Trim(), field), i); return ret; } - else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(HashSet<>)) + else if (fieldType.IsGenericType && (fieldType.GetGenericTypeDefinition() == typeof(HashSet<>) || fieldType.GetGenericTypeDefinition() == typeof(List<>))) { var set = Activator.CreateInstance(fieldType); if (value == null) @@ -510,8 +492,7 @@ var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); float xx = 0; float yy = 0; - float res; - if (float.TryParse(parts[0].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) + if (float.TryParse(parts[0].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var res)) xx = res * (parts[0].Contains('%') ? 0.01f : 1f); if (float.TryParse(parts[1].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res)) yy = res * (parts[1].Contains('%') ? 0.01f : 1f); @@ -525,13 +506,11 @@ if (value != null) { var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - float x = 0; - float y = 0; - float z = 0; - float.TryParse(parts[0], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out x); - float.TryParse(parts[1], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out y); + float.TryParse(parts[0], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var x); + float.TryParse(parts[1], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var y); // z component is optional for compatibility with older float2 definitions + float z = 0; if (parts.Length > 2) float.TryParse(parts[2], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out z); @@ -567,14 +546,16 @@ } else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable<>)) { + if (string.IsNullOrEmpty(value)) + return null; + var innerType = fieldType.GetGenericArguments().First(); var innerValue = GetValue("Nullable", innerType, value, field); return fieldType.GetConstructor(new[] { innerType }).Invoke(new[] { innerValue }); } else if (fieldType == typeof(DateTime)) { - DateTime dt; - if (DateTime.TryParseExact(value, "yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out dt)) + if (DateTime.TryParseExact(value, "yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var dt)) return dt; return InvalidValueAction(value, fieldType, fieldName); } @@ -724,8 +705,7 @@ if (translations == null) return key; - string value; - if (!translations.TryGetValue(key, out value)) + if (!translations.TryGetValue(key, out var value)) return key; return value; diff -Nru openra-20200503/OpenRA.Game/FieldSaver.cs openra-20210321/OpenRA.Game/FieldSaver.cs --- openra-20200503/OpenRA.Game/FieldSaver.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/FieldSaver.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,6 @@ using System.Globalization; using System.Linq; using System.Reflection; -using OpenRA.Graphics; using OpenRA.Primitives; namespace OpenRA @@ -95,7 +94,7 @@ return ((Array)v).Cast().Select(FormatValue).JoinWith(", "); } - if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(HashSet<>)) + if (t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(HashSet<>) || t.GetGenericTypeDefinition() == typeof(List<>))) { return ((System.Collections.IEnumerable)v).Cast().Select(FormatValue).JoinWith(", "); } diff -Nru openra-20200503/OpenRA.Game/FileSystem/FileSystem.cs openra-20210321/OpenRA.Game/FileSystem/FileSystem.cs --- openra-20200503/OpenRA.Game/FileSystem/FileSystem.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/FileSystem/FileSystem.cs 2021-03-21 11:10:05.000000000 +0000 @@ -63,19 +63,16 @@ { // Raw directories are the easiest and one of the most common cases, so try these first var resolvedPath = Platform.ResolvePath(filename); - if (!filename.Contains("|") && Directory.Exists(resolvedPath)) + if (!resolvedPath.Contains("|") && Directory.Exists(resolvedPath)) return new Folder(resolvedPath); // Children of another package require special handling - IReadOnlyPackage parent; - string subPath = null; - if (TryGetPackageContaining(filename, out parent, out subPath)) + if (TryGetPackageContaining(filename, out var parent, out var subPath)) return parent.OpenPackage(subPath, this); // Try and open it normally - IReadOnlyPackage package; var stream = Open(filename); - if (TryParsePackage(stream, filename, out package)) + if (TryParsePackage(stream, filename, out var package)) return package; // No package loaders took ownership of the stream, so clean it up @@ -97,8 +94,7 @@ { name = name.Substring(1); - Manifest mod; - if (!installedMods.TryGetValue(name, out mod)) + if (!installedMods.TryGetValue(name, out var mod)) throw new InvalidOperationException("Could not load mod '{0}'. Available mods: {1}".F(name, installedMods.Keys.JoinWith(", "))); package = mod.Package; @@ -122,8 +118,7 @@ public void Mount(IReadOnlyPackage package, string explicitName = null) { - var mountCount = 0; - if (mountedPackages.TryGetValue(package, out mountCount)) + if (mountedPackages.TryGetValue(package, out var mountCount)) { // Package is already mounted // Increment the mount count and bump up the file loading priority @@ -149,8 +144,7 @@ public bool Unmount(IReadOnlyPackage package) { - var mountCount = 0; - if (!mountedPackages.TryGetValue(package, out mountCount)) + if (!mountedPackages.TryGetValue(package, out var mountCount)) return false; if (--mountCount <= 0) @@ -203,16 +197,12 @@ var package = fileIndex[filename] .LastOrDefault(x => x.Contains(filename)); - if (package != null) - return package.GetStream(filename); - - return null; + return package?.GetStream(filename); } public Stream Open(string filename) { - Stream s; - if (!TryOpen(filename, out s)) + if (!TryOpen(filename, out var s)) throw new FileNotFoundException("File not found: {0}".F(filename), filename); return s; @@ -238,8 +228,7 @@ var explicitSplit = filename.IndexOf('|'); if (explicitSplit > 0) { - IReadOnlyPackage explicitPackage; - if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out explicitPackage)) + if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage)) { s = explicitPackage.GetStream(filename.Substring(explicitSplit + 1)); if (s != null) @@ -274,12 +263,9 @@ { var explicitSplit = filename.IndexOf('|'); if (explicitSplit > 0) - { - IReadOnlyPackage explicitPackage; - if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out explicitPackage)) + if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage)) if (explicitPackage.Contains(filename.Substring(explicitSplit + 1))) return true; - } return fileIndex.ContainsKey(filename); } @@ -293,8 +279,7 @@ if (explicitSplit < 0) return false; - IReadOnlyPackage explicitPackage; - if (!explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out explicitPackage)) + if (!explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage)) return false; if (installedMods[modID].Package == explicitPackage) @@ -310,7 +295,7 @@ public static string ResolveAssemblyPath(string path, Manifest manifest, InstalledMods installedMods) { var explicitSplit = path.IndexOf('|'); - if (explicitSplit > 0) + if (explicitSplit > 0 && !path.StartsWith("^")) { var parent = path.Substring(0, explicitSplit); var filename = path.Substring(explicitSplit + 1); @@ -321,8 +306,7 @@ if (parentPath.StartsWith("$", StringComparison.Ordinal)) { - Manifest mod; - if (!installedMods.TryGetValue(parentPath.Substring(1), out mod)) + if (!installedMods.TryGetValue(parentPath.Substring(1), out var mod)) return null; if (!(mod.Package is Folder)) diff -Nru openra-20200503/OpenRA.Game/FileSystem/Folder.cs openra-20210321/OpenRA.Game/FileSystem/Folder.cs --- openra-20200503/OpenRA.Game/FileSystem/Folder.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/FileSystem/Folder.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; namespace OpenRA.FileSystem { @@ -32,10 +33,11 @@ { get { - foreach (var filename in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly)) - yield return Path.GetFileName(filename); - foreach (var filename in Directory.GetDirectories(path)) - yield return Path.GetFileName(filename); + // Order may vary on different file systems and it matters for hashing. + return Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly) + .Concat(Directory.GetDirectories(path)) + .Select(Path.GetFileName) + .OrderBy(f => f); } } @@ -58,17 +60,15 @@ return new Folder(resolvedPath); // Zip files loaded from Folders (and *only* from Folders) can be read-write - IReadWritePackage readWritePackage; - if (ZipFileLoader.TryParseReadWritePackage(resolvedPath, out readWritePackage)) + if (ZipFileLoader.TryParseReadWritePackage(resolvedPath, out var readWritePackage)) return readWritePackage; // Other package types can be loaded normally - IReadOnlyPackage package; var s = GetStream(filename); if (s == null) return null; - if (context.TryParsePackage(s, filename, out package)) + if (context.TryParsePackage(s, filename, out var package)) return package; s.Dispose(); diff -Nru openra-20200503/OpenRA.Game/FileSystem/ZipFile.cs openra-20210321/OpenRA.Game/FileSystem/ZipFile.cs --- openra-20200503/OpenRA.Game/FileSystem/ZipFile.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/FileSystem/ZipFile.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,6 @@ using System.IO; using System.Linq; using ICSharpCode.SharpZipLib.Zip; -using OpenRA.Primitives; namespace OpenRA.FileSystem { @@ -67,8 +66,7 @@ public void Dispose() { - if (pkg != null) - pkg.Close(); + pkg?.Close(); } public IReadOnlyPackage OpenPackage(string filename, FileSystem context) @@ -82,12 +80,11 @@ return new ZipFolder(this, filename); // Other package types can be loaded normally - IReadOnlyPackage package; var s = GetStream(filename); if (s == null) return null; - if (context.TryParsePackage(s, filename, out package)) + if (context.TryParsePackage(s, filename, out var package)) return package; s.Dispose(); diff -Nru openra-20200503/OpenRA.Game/Game.cs openra-20210321/OpenRA.Game/Game.cs --- openra-20200503/OpenRA.Game/Game.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Game.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,6 +17,7 @@ using System.Linq; using System.Net; using System.Reflection; +using System.Runtime; using System.Threading; using System.Threading.Tasks; using OpenRA.Graphics; @@ -51,7 +52,6 @@ public static Renderer Renderer; public static Sound Sound; - public static bool HasInputFocus = false; public static string EngineVersion { get; private set; } public static LocalPlayerProfile LocalPlayerProfile; @@ -62,26 +62,26 @@ public static event Action OnShellmapLoaded = () => { }; - public static OrderManager JoinServer(string host, int port, string password, bool recordReplay = true) + public static OrderManager JoinServer(ConnectionTarget endpoint, string password, bool recordReplay = true) { - var connection = new NetworkConnection(host, port); + var connection = new NetworkConnection(endpoint); if (recordReplay) connection.StartRecording(() => { return TimestampedFilename(); }); - var om = new OrderManager(host, port, password, connection); + var om = new OrderManager(endpoint, password, connection); JoinInner(om); return om; } - static string TimestampedFilename(bool includemilliseconds = false) + public static string TimestampedFilename(bool includemilliseconds = false, string extra = "") { var format = includemilliseconds ? "yyyy-MM-ddTHHmmssfffZ" : "yyyy-MM-ddTHHmmssZ"; - return "OpenRA-" + DateTime.UtcNow.ToString(format, CultureInfo.InvariantCulture); + return ModData.Manifest.Id + extra + "-" + DateTime.UtcNow.ToString(format, CultureInfo.InvariantCulture); } static void JoinInner(OrderManager om) { - if (OrderManager != null) OrderManager.Dispose(); + OrderManager?.Dispose(); OrderManager = om; lastConnectionState = ConnectionState.PreConnecting; ConnectionStateChanged(OrderManager); @@ -89,12 +89,12 @@ public static void JoinReplay(string replayFile) { - JoinInner(new OrderManager("", -1, "", new ReplayConnection(replayFile))); + JoinInner(new OrderManager(new ConnectionTarget(), "", new ReplayConnection(replayFile))); } static void JoinLocal() { - JoinInner(new OrderManager("", -1, "", new EchoConnection())); + JoinInner(new OrderManager(new ConnectionTarget(), "", new EchoConnection())); } // More accurate replacement for Environment.TickCount @@ -105,14 +105,14 @@ public static int NetFrameNumber { get { return OrderManager.NetFrameNumber; } } public static int LocalTick { get { return OrderManager.LocalFrameNumber; } } - public static event Action OnRemoteDirectConnect = (a, b) => { }; + public static event Action OnRemoteDirectConnect = _ => { }; public static event Action ConnectionStateChanged = _ => { }; static ConnectionState lastConnectionState = ConnectionState.PreConnecting; public static int LocalClientId { get { return OrderManager.Connection.LocalClientId; } } - public static void RemoteDirectConnect(string host, int port) + public static void RemoteDirectConnect(ConnectionTarget endpoint) { - OnRemoteDirectConnect(host, port); + OnRemoteDirectConnect(endpoint); } // Hacky workaround for orderManager visibility @@ -155,8 +155,7 @@ internal static void StartGame(string mapUID, WorldType type) { // Dispose of the old world before creating a new one. - if (worldRenderer != null) - worldRenderer.Dispose(); + worldRenderer?.Dispose(); Cursor.SetCursor(null); BeforeGameStart(); @@ -172,11 +171,13 @@ worldRenderer = new WorldRenderer(ModData, OrderManager.World); + // Proactively collect memory during loading to reduce peak memory. GC.Collect(); using (new PerfTimer("LoadComplete")) OrderManager.World.LoadComplete(worldRenderer); + // Proactively collect memory during loading to reduce peak memory. GC.Collect(); if (OrderManager.GameStarted) @@ -191,6 +192,14 @@ worldRenderer.RefreshPalette(); Cursor.SetCursor("default"); + // Now loading is completed, now is the ideal time to run a GC and compact the LOH. + // - All the temporary garbage created during loading can be collected. + // - Live objects are likely to live for the length of the game or longer, + // thus promoting them into a higher generation is not an issue. + // - We can remove any fragmentation in the LOH caused by temporary loading garbage. + // - A loading screen is visible, so a delay won't matter to the user. + // Much better to clean up now then to drop frames during gameplay for GC pauses. + GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(); } @@ -234,7 +243,7 @@ LobbyInfoChanged += lobbyReady; - om = JoinServer(IPAddress.Loopback.ToString(), CreateLocalServer(mapUID), ""); + om = JoinServer(CreateLocalServer(mapUID), ""); } public static bool IsHost @@ -253,18 +262,24 @@ public static void InitializeSettings(Arguments args) { - Settings = new Settings(Platform.ResolvePath(Path.Combine(Platform.SupportDirPrefix, "settings.yaml")), args); + Settings = new Settings(Path.Combine(Platform.SupportDir, "settings.yaml"), args); } public static RunStatus InitializeAndRun(string[] args) { Initialize(new Arguments(args)); + + // Proactively collect memory during loading to reduce peak memory. GC.Collect(); return Run(); } static void Initialize(Arguments args) { + var engineDirArg = args.GetValue("Engine.EngineDir", null); + if (!string.IsNullOrEmpty(engineDirArg)) + Platform.OverrideEngineDir(engineDirArg); + var supportDirArg = args.GetValue("Engine.SupportDir", null); if (!string.IsNullOrEmpty(supportDirArg)) Platform.OverrideSupportDir(supportDirArg); @@ -274,7 +289,7 @@ // Load the engine version as early as possible so it can be written to exception logs try { - EngineVersion = File.ReadAllText(Platform.ResolvePath(Path.Combine(".", "VERSION"))).Trim(); + EngineVersion = File.ReadAllText(Path.Combine(Platform.EngineDir, "VERSION")).Trim(); } catch { } @@ -302,6 +317,7 @@ Log.AddChannel("graphics", "graphics.log"); Log.AddChannel("geoip", "geoip.log"); Log.AddChannel("nat", "nat.log"); + Log.AddChannel("client", "client.log"); var platforms = new[] { Settings.Game.Platform, "Default", null }; foreach (var p in platforms) @@ -312,7 +328,7 @@ Settings.Game.Platform = p; try { - var rendererPath = Platform.ResolvePath(Path.Combine(".", "OpenRA.Platforms." + p + ".dll")); + var rendererPath = Path.Combine(Platform.BinDir, "OpenRA.Platforms." + p + ".dll"); var assembly = Assembly.LoadFile(rendererPath); var platformType = assembly.GetTypes().SingleOrDefault(t => typeof(IPlatform).IsAssignableFrom(t)); @@ -330,11 +346,9 @@ Log.Write("graphics", "{0}", e); Console.WriteLine("Renderer initialization failed. Check graphics.log for details."); - if (Renderer != null) - Renderer.Dispose(); + Renderer?.Dispose(); - if (Sound != null) - Sound.Dispose(); + Sound?.Dispose(); } } @@ -344,7 +358,7 @@ var modSearchArg = args.GetValue("Engine.ModSearchPaths", null); var modSearchPaths = modSearchArg != null ? FieldLoader.GetValue("Engine.ModsPath", modSearchArg) : - new[] { Path.Combine(".", "mods") }; + new[] { Path.Combine(Platform.EngineDir, "mods") }; Mods = new InstalledMods(modSearchPaths, explicitModPaths); Console.WriteLine("Internal mods:"); @@ -355,20 +369,28 @@ ExternalMods = new ExternalMods(); - Manifest currentMod; - if (modID != null && Mods.TryGetValue(modID, out currentMod)) + if (modID != null && Mods.TryGetValue(modID, out _)) { - var launchPath = args.GetValue("Engine.LaunchPath", Assembly.GetEntryAssembly().Location); + var launchPath = args.GetValue("Engine.LaunchPath", null); + var launchArgs = new List(); // Sanitize input from platform-specific launchers // Process.Start requires paths to not be quoted, even if they contain spaces - if (launchPath.First() == '"' && launchPath.Last() == '"') + if (launchPath != null && launchPath.First() == '"' && launchPath.Last() == '"') launchPath = launchPath.Substring(1, launchPath.Length - 2); - ExternalMods.Register(Mods[modID], launchPath, ModRegistration.User); + if (launchPath == null) + { + // When launching the assembly directly we must propagate the Engine.EngineDir argument if defined + // Platform-specific launchers are expected to manage this internally. + launchPath = Assembly.GetEntryAssembly().Location; + if (!string.IsNullOrEmpty(engineDirArg)) + launchArgs.Add("Engine.EngineDir=\"" + engineDirArg + "\""); + } + + ExternalMods.Register(Mods[modID], launchPath, launchArgs, ModRegistration.User); - ExternalMod activeMod; - if (ExternalMods.TryGetValue(ExternalMod.MakeKey(Mods[modID]), out activeMod)) + if (ExternalMods.TryGetValue(ExternalMod.MakeKey(Mods[modID]), out var activeMod)) ExternalMods.ClearInvalidRegistrations(activeMod, ModRegistration.User); } @@ -385,18 +407,15 @@ LobbyInfoChanged = () => { }; ConnectionStateChanged = om => { }; BeforeGameStart = () => { }; - OnRemoteDirectConnect = (a, b) => { }; + OnRemoteDirectConnect = endpoint => { }; delayedActions = new ActionQueue(); Ui.ResetAll(); - if (worldRenderer != null) - worldRenderer.Dispose(); + worldRenderer?.Dispose(); worldRenderer = null; - if (server != null) - server.Shutdown(); - if (OrderManager != null) - OrderManager.Dispose(); + server?.Shutdown(); + OrderManager?.Dispose(); if (ModData != null) { @@ -418,7 +437,7 @@ ModData = new ModData(Mods[mod], Mods, true); - LocalPlayerProfile = new LocalPlayerProfile(Platform.ResolvePath(Path.Combine("^", Settings.Game.AuthProfile)), ModData.Manifest.Get()); + LocalPlayerProfile = new LocalPlayerProfile(Path.Combine(Platform.SupportDir, Settings.Game.AuthProfile), ModData.Manifest.Get()); if (!ModData.LoadScreen.BeforeLoad()) return; @@ -432,8 +451,7 @@ var grid = ModData.Manifest.Contains() ? ModData.Manifest.Get() : null; Renderer.InitializeDepthBuffer(grid); - if (Cursor != null) - Cursor.Dispose(); + Cursor?.Dispose(); Cursor = new CursorManager(ModData.CursorProvider); @@ -442,13 +460,13 @@ PerfHistory.Items["render_world"].HasNormalTick = false; PerfHistory.Items["render_widgets"].HasNormalTick = false; PerfHistory.Items["render_flip"].HasNormalTick = false; + PerfHistory.Items["terrain_lighting"].HasNormalTick = false; JoinLocal(); try { - if (discoverNat != null) - discoverNat.Wait(); + discoverNat?.Wait(); } catch (Exception e) { @@ -535,7 +553,7 @@ using (new PerfTimer("Renderer.SaveScreenshot")) { var mod = ModData.Manifest.Metadata; - var directory = Platform.ResolvePath(Platform.SupportDirPrefix, "Screenshots", ModData.Manifest.Id, mod.Version); + var directory = Path.Combine(Platform.SupportDir, "Screenshots", ModData.Manifest.Id, mod.Version); Directory.CreateDirectory(directory); var filename = TimestampedFilename(true); @@ -611,8 +629,7 @@ Sync.RunUnsynced(Settings.Debug.SyncCheckUnsyncedCode, world, () => world.TickRender(worldRenderer)); } - if (benchmark != null) - benchmark.Tick(LocalTick); + benchmark?.Tick(LocalTick); } } @@ -710,6 +727,7 @@ PerfHistory.Items["render_world"].Tick(); PerfHistory.Items["render_widgets"].Tick(); PerfHistory.Items["render_flip"].Tick(); + PerfHistory.Items["terrain_lighting"].Tick(); } static void Loop() @@ -836,12 +854,10 @@ finally { // Ensure that the active replay is properly saved - if (OrderManager != null) - OrderManager.Dispose(); + OrderManager?.Dispose(); } - if (worldRenderer != null) - worldRenderer.Dispose(); + worldRenderer?.Dispose(); ModData.Dispose(); ChromeProvider.Deinitialize(); @@ -880,8 +896,7 @@ public static void Disconnect() { - if (OrderManager.World != null) - OrderManager.World.TraitDict.PrintReport(); + OrderManager.World?.TraitDict.PrintReport(); OrderManager.Dispose(); CloseServer(); @@ -890,8 +905,7 @@ public static void CloseServer() { - if (server != null) - server.Shutdown(); + server?.Shutdown(); } public static T CreateObject(string name) @@ -899,12 +913,19 @@ return ModData.ObjectCreator.CreateObject(name); } - public static void CreateServer(ServerSettings settings) + public static ConnectionTarget CreateServer(ServerSettings settings) { - server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, ModData, ServerType.Multiplayer); + var endpoints = new List + { + new IPEndPoint(IPAddress.IPv6Any, settings.ListenPort), + new IPEndPoint(IPAddress.Any, settings.ListenPort) + }; + server = new Server.Server(endpoints, settings, ModData, ServerType.Multiplayer); + + return server.GetEndpointForLocalConnection(); } - public static int CreateLocalServer(string map) + public static ConnectionTarget CreateLocalServer(string map) { var settings = new ServerSettings() { @@ -913,9 +934,16 @@ AdvertiseOnline = false }; - server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, ModData, ServerType.Local); + // Always connect to local games using the same loopback connection + // Exposing multiple endpoints introduces a race condition on the client's PlayerIndex (sometimes 0, sometimes 1) + // This would break the Restart button, which relies on the PlayerIndex always being the same for local servers + var endpoints = new List + { + new IPEndPoint(IPAddress.Loopback, 0) + }; + server = new Server.Server(endpoints, settings, ModData, ServerType.Local); - return server.Port; + return server.GetEndpointForLocalConnection(); } public static bool IsCurrentWorld(World world) diff -Nru openra-20200503/OpenRA.Game/GameInformation.cs openra-20210321/OpenRA.Game/GameInformation.cs --- openra-20200503/OpenRA.Game/GameInformation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/GameInformation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -35,6 +35,7 @@ /// Gets the game's duration, from the time the game started until the replay recording stopped. public TimeSpan Duration { get { return EndTimeUtc > StartTimeUtc ? EndTimeUtc - StartTimeUtc : TimeSpan.Zero; } } public IList Players { get; private set; } + public HashSet DisabledSpawnPoints = new HashSet(); public MapPreview MapPreview { get { return Game.ModData.MapCache[MapUid]; } } public IEnumerable HumanPlayers { get { return Players.Where(p => p.IsHuman); } } public bool IsSinglePlayer { get { return HumanPlayers.Count() == 1; } } @@ -118,11 +119,14 @@ IsBot = runtimePlayer.IsBot, FactionName = runtimePlayer.Faction.Name, FactionId = runtimePlayer.Faction.InternalName, + DisplayFactionName = runtimePlayer.DisplayFaction.Name, + DisplayFactionId = runtimePlayer.DisplayFaction.InternalName, Color = runtimePlayer.Color, Team = client.Team, + Handicap = client.Handicap, SpawnPoint = runtimePlayer.SpawnPoint, IsRandomFaction = runtimePlayer.Faction.InternalName != client.Faction, - IsRandomSpawnPoint = runtimePlayer.SpawnPoint != client.SpawnPoint, + IsRandomSpawnPoint = runtimePlayer.DisplaySpawnPoint == 0, Fingerprint = client.Fingerprint }; @@ -133,9 +137,7 @@ /// Gets the player information for the specified runtime player instance. public Player GetPlayer(OpenRA.Player runtimePlayer) { - Player player; - - playersByRuntime.TryGetValue(runtimePlayer, out player); + playersByRuntime.TryGetValue(runtimePlayer, out var player); return player; } @@ -158,9 +160,14 @@ public string FactionId; public Color Color; + /// The faction (including Random, etc.) that was selected in the lobby. + public string DisplayFactionName; + public string DisplayFactionId; + /// The team ID on start-up, or 0 if the player is not part of a team. public int Team; public int SpawnPoint; + public int Handicap; /// True if the faction was chosen at random; otherwise, false. public bool IsRandomFaction; @@ -181,6 +188,9 @@ /// The time when this player won or lost the game. public DateTime OutcomeTimestampUtc; + /// The frame at which this player disconnected. + public int DisconnectFrame; + #endregion } } diff -Nru openra-20200503/OpenRA.Game/GameRules/ActorInfo.cs openra-20210321/OpenRA.Game/GameRules/ActorInfo.cs --- openra-20200503/OpenRA.Game/GameRules/ActorInfo.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/GameRules/ActorInfo.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,6 +23,7 @@ public class ActorInfo { public const string AbstractActorPrefix = "^"; + public const char TraitInstanceSeparator = '@'; /// /// The actor name can be anything, but the sprites used in the Render*: traits default to this one. @@ -32,7 +33,7 @@ /// public readonly string Name; readonly TypeDictionary traits = new TypeDictionary(); - List constructOrderCache = null; + List constructOrderCache = null; public ActorInfo(ObjectCreator creator, string name, MiniYaml node) { @@ -46,7 +47,7 @@ { // HACK: The linter does not want to crash when a trait doesn't exist but only print an error instead // LoadTraitInfo will only return null to signal us to abort here if the linter is running - var trait = LoadTraitInfo(creator, t.Key.Split('@')[0], t.Value); + var trait = LoadTraitInfo(creator, t.Key, t.Value); if (trait != null) traits.Add(trait); } @@ -64,7 +65,7 @@ } } - public ActorInfo(string name, params ITraitInfo[] traitInfos) + public ActorInfo(string name, params TraitInfo[] traitInfos) { Name = name; foreach (var t in traitInfos) @@ -72,7 +73,7 @@ traits.TrimExcess(); } - static ITraitInfo LoadTraitInfo(ObjectCreator creator, string traitName, MiniYaml my) + static TraitInfo LoadTraitInfo(ObjectCreator creator, string traitName, MiniYaml my) { if (!string.IsNullOrEmpty(my.Value)) throw new YamlException("Junk value `{0}` on trait node {1}" @@ -80,12 +81,16 @@ // HACK: The linter does not want to crash when a trait doesn't exist but only print an error instead // ObjectCreator will only return null to signal us to abort here if the linter is running - var info = creator.CreateObject(traitName + "Info"); + var traitInstance = traitName.Split(TraitInstanceSeparator); + var info = creator.CreateObject(traitInstance[0] + "Info"); if (info == null) return null; try { + if (traitInstance.Length > 1) + info.GetType().GetField("InstanceName").SetValue(info, traitInstance[1]); + FieldLoader.Load(info, my); } catch (FieldLoader.MissingFieldsException e) @@ -97,12 +102,12 @@ return info; } - public IEnumerable TraitsInConstructOrder() + public IEnumerable TraitsInConstructOrder() { if (constructOrderCache != null) return constructOrderCache; - var source = traits.WithInterface().Select(i => new + var source = traits.WithInterface().Select(i => new { Trait = i, Type = i.GetType(), @@ -148,7 +153,7 @@ return constructOrderCache; } - public static IEnumerable PrerequisitesOf(ITraitInfo info) + public static IEnumerable PrerequisitesOf(TraitInfo info) { return info .GetType() diff -Nru openra-20200503/OpenRA.Game/GameRules/MusicInfo.cs openra-20210321/OpenRA.Game/GameRules/MusicInfo.cs --- openra-20200503/OpenRA.Game/GameRules/MusicInfo.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/GameRules/MusicInfo.cs 2021-03-21 11:10:05.000000000 +0000 @@ -41,8 +41,7 @@ public void Load(IReadOnlyFileSystem fileSystem) { - Stream stream; - if (!fileSystem.TryOpen(Filename, out stream)) + if (!fileSystem.TryOpen(Filename, out var stream)) return; try @@ -50,8 +49,7 @@ Exists = true; foreach (var loader in Game.ModData.SoundLoaders) { - ISoundFormat soundFormat; - if (loader.TryParseSound(stream, out soundFormat)) + if (loader.TryParseSound(stream, out var soundFormat)) { Length = (int)soundFormat.LengthInSeconds; soundFormat.Dispose(); diff -Nru openra-20200503/OpenRA.Game/GameRules/Ruleset.cs openra-20210321/OpenRA.Game/GameRules/Ruleset.cs --- openra-20200503/OpenRA.Game/GameRules/Ruleset.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/GameRules/Ruleset.cs 2021-03-21 11:10:05.000000000 +0000 @@ -208,7 +208,7 @@ // TODO: Top-level dictionary should be moved into the Ruleset instead of in its own object var sequences = mapSequences == null ? modData.DefaultSequences[tileSet] : - new SequenceProvider(fileSystem, modData, ts, mapSequences); + new SequenceProvider(fileSystem, modData, tileSet, mapSequences); var modelSequences = dr.ModelSequences; if (mapModelSequences != null) diff -Nru openra-20200503/OpenRA.Game/GameRules/WeaponInfo.cs openra-20210321/OpenRA.Game/GameRules/WeaponInfo.cs --- openra-20200503/OpenRA.Game/GameRules/WeaponInfo.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/GameRules/WeaponInfo.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,8 +24,8 @@ public int[] DamageModifiers; public int[] InaccuracyModifiers; public int[] RangeModifiers; - public int Facing; - public Func CurrentMuzzleFacing; + public WAngle Facing; + public Func CurrentMuzzleFacing; public WPos Source; public Func CurrentSource; public Actor SourceActor; @@ -38,6 +38,8 @@ public WeaponInfo Weapon; public int[] DamageModifiers = { }; public WPos? Source; + public WRot ImpactOrientation; + public WPos ImpactPosition; public Actor SourceActor; public Target WeaponTarget; @@ -45,11 +47,22 @@ { Weapon = args.Weapon; DamageModifiers = args.DamageModifiers; + ImpactPosition = args.PassiveTarget; Source = args.Source; SourceActor = args.SourceActor; WeaponTarget = args.GuidedTarget; } + // For places that only want to update some of the fields (usually DamageModifiers) + public WarheadArgs(WarheadArgs args) + { + Weapon = args.Weapon; + DamageModifiers = args.DamageModifiers; + Source = args.Source; + SourceActor = args.SourceActor; + WeaponTarget = args.WeaponTarget; + } + // Default empty constructor for callers that want to initialize fields themselves public WarheadArgs() { } } @@ -92,6 +105,12 @@ [Desc("What types of targets are unaffected.", "Overrules ValidTargets.")] public readonly BitSet InvalidTargets; + static readonly BitSet TargetTypeAir = new BitSet("Air"); + + [Desc("If weapon is not directly targeting an actor and targeted position is above this altitude,", + "the weapon will ignore terrain target types and only check TargetTypeAir for validity.")] + public readonly WDist AirThreshold = new WDist(128); + [Desc("Delay in ticks between firing shots from the same ammo magazine. If one entry, it will be used for all bursts.", "If multiple entries, their number needs to match Burst - 1.")] public readonly int[] BurstDelays = { 5 }; @@ -118,8 +137,7 @@ static object LoadProjectile(MiniYaml yaml) { - MiniYaml proj; - if (!yaml.ToDictionary().TryGetValue("Projectile", out proj)) + if (!yaml.ToDictionary().TryGetValue("Projectile", out var proj)) return null; var ret = Game.CreateObject(proj.Value + "Info"); FieldLoader.Load(ret, proj); @@ -145,7 +163,7 @@ } /// Checks if the weapon is valid against (can target) the target. - public bool IsValidAgainst(Target target, World world, Actor firedBy) + public bool IsValidAgainst(in Target target, World world, Actor firedBy) { if (target.Type == TargetType.Actor) return IsValidAgainst(target.Actor, firedBy); @@ -155,6 +173,10 @@ if (target.Type == TargetType.Terrain) { + var dat = world.Map.DistanceAboveTerrain(target.CenterPosition); + if (dat > AirThreshold) + return IsValidTarget(TargetTypeAir); + var cell = world.Map.CellContaining(target.CenterPosition); if (!world.Map.Contains(cell)) return false; @@ -198,20 +220,24 @@ } /// Applies all the weapon's warheads to the target. - public void Impact(Target target, WarheadArgs args) + public void Impact(in Target target, WarheadArgs args) { var world = args.SourceActor.World; foreach (var warhead in Warheads) { if (warhead.Delay > 0) - world.AddFrameEndTask(w => w.Add(new DelayedImpact(warhead.Delay, warhead, target, args))); + { + // Lambdas can't use 'in' variables, so capture a copy for later + var delayedTarget = target; + world.AddFrameEndTask(w => w.Add(new DelayedImpact(warhead.Delay, warhead, delayedTarget, args))); + } else warhead.DoImpact(target, args); } } /// Applies all the weapon's warheads to the target. Only use for projectile-less, special-case impacts. - public void Impact(Target target, Actor firedBy) + public void Impact(in Target target, Actor firedBy) { // The impact will happen immediately at target.CenterPosition. var args = new WarheadArgs diff -Nru openra-20200503/OpenRA.Game/Graphics/Animation.cs openra-20210321/OpenRA.Game/Graphics/Animation.cs --- openra-20200503/OpenRA.Game/Graphics/Animation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/Animation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,7 +23,7 @@ public bool IsDecoration { get; set; } readonly SequenceProvider sequenceProvider; - readonly Func facingFunc; + readonly Func facingFunc; readonly Func paused; int frame; @@ -33,15 +33,15 @@ Action tickFunc = () => { }; public Animation(World world, string name) - : this(world, name, () => 0) { } + : this(world, name, () => WAngle.Zero) { } - public Animation(World world, string name, Func facingFunc) + public Animation(World world, string name, Func facingFunc) : this(world, name, facingFunc, null) { } public Animation(World world, string name, Func paused) - : this(world, name, () => 0, paused) { } + : this(world, name, () => WAngle.Zero, paused) { } - public Animation(World world, string name, Func facingFunc, Func paused) + public Animation(World world, string name, Func facingFunc, Func paused) { sequenceProvider = world.Map.Rules.Sequences; Name = name.ToLowerInvariant(); @@ -54,12 +54,12 @@ public IRenderable[] Render(WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale) { - var imageRenderable = new SpriteRenderable(Image, pos, offset, CurrentSequence.ZOffset + zOffset, palette, scale, IsDecoration); + var imageRenderable = new SpriteRenderable(Image, pos, offset, CurrentSequence.ZOffset + zOffset, palette, scale, IsDecoration, CurrentSequence.IgnoreWorldTint); if (CurrentSequence.ShadowStart >= 0) { var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc()); - var shadowRenderable = new SpriteRenderable(shadow, pos, offset, CurrentSequence.ShadowZOffset + zOffset, palette, scale, true); + var shadowRenderable = new SpriteRenderable(shadow, pos, offset, CurrentSequence.ShadowZOffset + zOffset, palette, scale, true, CurrentSequence.IgnoreWorldTint); return new IRenderable[] { shadowRenderable, imageRenderable }; } @@ -156,7 +156,7 @@ { frame = CurrentSequence.Length - 1; tickFunc = () => { }; - if (after != null) after(); + after?.Invoke(); } }; } diff -Nru openra-20200503/OpenRA.Game/Graphics/ChromeProvider.cs openra-20210321/OpenRA.Game/Graphics/ChromeProvider.cs --- openra-20200503/OpenRA.Game/Graphics/ChromeProvider.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/ChromeProvider.cs 2021-03-21 11:10:05.000000000 +0000 @@ -54,10 +54,10 @@ public static IReadOnlyDictionary Collections { get; private set; } static Dictionary collections; - static Dictionary> cachedSheets; + static Dictionary cachedSheets; static Dictionary> cachedSprites; static Dictionary cachedPanelSprites; - static Dictionary> cachedCollectionSheets; + static Dictionary cachedCollectionSheets; static IReadOnlyFileSystem fileSystem; static float dpiScale = 1; @@ -72,10 +72,10 @@ fileSystem = modData.DefaultFileSystem; collections = new Dictionary(); - cachedSheets = new Dictionary>(); + cachedSheets = new Dictionary(); cachedSprites = new Dictionary>(); cachedPanelSprites = new Dictionary(); - cachedCollectionSheets = new Dictionary>(); + cachedCollectionSheets = new Dictionary(); Collections = new ReadOnlyDictionary(collections); @@ -91,7 +91,7 @@ { if (cachedSheets != null) foreach (var sheet in cachedSheets.Values) - sheet.First.Dispose(); + sheet.Sheet.Dispose(); collections = null; cachedSheets = null; @@ -108,12 +108,10 @@ collections.Add(name, FieldLoader.Load(yaml)); } - static Pair SheetForCollection(Collection c) + static (Sheet Sheet, int Density) SheetForCollection(Collection c) { - Pair sheetDensity; - // Outer cache avoids recalculating image names - if (!cachedCollectionSheets.TryGetValue(c, out sheetDensity)) + if (!cachedCollectionSheets.TryGetValue(c, out (Sheet, int) sheetDensity)) { var image = c.Image; var density = 1; @@ -137,7 +135,7 @@ sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear; - sheetDensity = Pair.New(sheet, density); + sheetDensity = (sheet, density); cachedSheets.Add(image, sheetDensity); } @@ -153,20 +151,16 @@ return null; // Cached sprite - Dictionary cachedCollection; - Sprite sprite; - if (cachedSprites.TryGetValue(collectionName, out cachedCollection) && cachedCollection.TryGetValue(imageName, out sprite)) + if (cachedSprites.TryGetValue(collectionName, out var cachedCollection) && cachedCollection.TryGetValue(imageName, out var sprite)) return sprite; - Collection collection; - if (!collections.TryGetValue(collectionName, out collection)) + if (!collections.TryGetValue(collectionName, out var collection)) { Log.Write("debug", "Could not find collection '{0}'", collectionName); return null; } - Rectangle mi; - if (!collection.Regions.TryGetValue(imageName, out mi)) + if (!collection.Regions.TryGetValue(imageName, out var mi)) return null; // Cache the sprite @@ -177,7 +171,7 @@ cachedSprites.Add(collectionName, cachedCollection); } - var image = new Sprite(sheetDensity.First, sheetDensity.Second * mi, TextureChannel.RGBA, 1f / sheetDensity.Second); + var image = new Sprite(sheetDensity.Sheet, sheetDensity.Density * mi, TextureChannel.RGBA, 1f / sheetDensity.Density); cachedCollection.Add(imageName, image); return image; @@ -189,12 +183,10 @@ return null; // Cached sprite - Sprite[] cachedSprites; - if (cachedPanelSprites.TryGetValue(collectionName, out cachedSprites)) + if (cachedPanelSprites.TryGetValue(collectionName, out var cachedSprites)) return cachedSprites; - Collection collection; - if (!collections.TryGetValue(collectionName, out collection)) + if (!collections.TryGetValue(collectionName, out var collection)) { Log.Write("debug", "Could not find collection '{0}'", collectionName); return null; @@ -214,20 +206,20 @@ var pr = collection.PanelRegion; var ps = collection.PanelSides; - var sides = new[] + var sides = new (PanelSides PanelSides, Rectangle Bounds)[] { - Pair.New(PanelSides.Top | PanelSides.Left, new Rectangle(pr[0], pr[1], pr[2], pr[3])), - Pair.New(PanelSides.Top, new Rectangle(pr[0] + pr[2], pr[1], pr[4], pr[3])), - Pair.New(PanelSides.Top | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1], pr[6], pr[3])), - Pair.New(PanelSides.Left, new Rectangle(pr[0], pr[1] + pr[3], pr[2], pr[5])), - Pair.New(PanelSides.Center, new Rectangle(pr[0] + pr[2], pr[1] + pr[3], pr[4], pr[5])), - Pair.New(PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3], pr[6], pr[5])), - Pair.New(PanelSides.Bottom | PanelSides.Left, new Rectangle(pr[0], pr[1] + pr[3] + pr[5], pr[2], pr[7])), - Pair.New(PanelSides.Bottom, new Rectangle(pr[0] + pr[2], pr[1] + pr[3] + pr[5], pr[4], pr[7])), - Pair.New(PanelSides.Bottom | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3] + pr[5], pr[6], pr[7])) + (PanelSides.Top | PanelSides.Left, new Rectangle(pr[0], pr[1], pr[2], pr[3])), + (PanelSides.Top, new Rectangle(pr[0] + pr[2], pr[1], pr[4], pr[3])), + (PanelSides.Top | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1], pr[6], pr[3])), + (PanelSides.Left, new Rectangle(pr[0], pr[1] + pr[3], pr[2], pr[5])), + (PanelSides.Center, new Rectangle(pr[0] + pr[2], pr[1] + pr[3], pr[4], pr[5])), + (PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3], pr[6], pr[5])), + (PanelSides.Bottom | PanelSides.Left, new Rectangle(pr[0], pr[1] + pr[3] + pr[5], pr[2], pr[7])), + (PanelSides.Bottom, new Rectangle(pr[0] + pr[2], pr[1] + pr[3] + pr[5], pr[4], pr[7])), + (PanelSides.Bottom | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3] + pr[5], pr[6], pr[7])) }; - sprites = sides.Select(x => ps.HasSide(x.First) ? new Sprite(sheetDensity.First, sheetDensity.Second * x.Second, TextureChannel.RGBA, 1f / sheetDensity.Second) : null) + sprites = sides.Select(x => ps.HasSide(x.PanelSides) ? new Sprite(sheetDensity.Sheet, sheetDensity.Density * x.Bounds, TextureChannel.RGBA, 1f / sheetDensity.Density) : null) .ToArray(); } else @@ -256,8 +248,7 @@ if (string.IsNullOrEmpty(collectionName)) return new Size(0, 0); - Collection collection; - if (!collections.TryGetValue(collectionName, out collection)) + if (!collections.TryGetValue(collectionName, out var collection)) { Log.Write("debug", "Could not find collection '{0}'", collectionName); return new Size(0, 0); diff -Nru openra-20200503/OpenRA.Game/Graphics/CursorManager.cs openra-20210321/OpenRA.Game/Graphics/CursorManager.cs --- openra-20200503/OpenRA.Game/Graphics/CursorManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/CursorManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -236,15 +236,14 @@ { for (var i = 0; i < width; i++) { - var bytes = BitConverter.GetBytes(palette[frame.Data[j * width + i]]); - var c = palette[frame.Data[j * width + i]]; + var rgba = palette[frame.Data[j * width + i]]; var k = 4 * (j * width + i); // Convert RGBA to BGRA - data[k] = bytes[2]; - data[k + 1] = bytes[1]; - data[k + 2] = bytes[0]; - data[k + 3] = bytes[3]; + data[k] = (byte)(rgba >> 16); + data[k + 1] = (byte)(rgba >> 8); + data[k + 2] = (byte)(rgba >> 0); + data[k + 3] = (byte)(rgba >> 24); } } diff -Nru openra-20200503/OpenRA.Game/Graphics/CursorSequence.cs openra-20210321/OpenRA.Game/Graphics/CursorSequence.cs --- openra-20200503/OpenRA.Game/Graphics/CursorSequence.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/CursorSequence.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,8 +31,10 @@ Palette = palette; Name = name; + Frames = cache[cursorSrc].Skip(Start).ToArray(); + if ((d.ContainsKey("Length") && d["Length"].Value == "*") || (d.ContainsKey("End") && d["End"].Value == "*")) - Length = Frames.Length - Start; + Length = Frames.Length; else if (d.ContainsKey("Length")) Length = Exts.ParseIntegerInvariant(d["Length"].Value); else if (d.ContainsKey("End")) @@ -40,22 +42,17 @@ else Length = 1; - Frames = cache[cursorSrc] - .Skip(Start) - .Take(Length) - .ToArray(); + Frames = Frames.Take(Length).ToArray(); if (d.ContainsKey("X")) { - int x; - Exts.TryParseIntegerInvariant(d["X"].Value, out x); + Exts.TryParseIntegerInvariant(d["X"].Value, out var x); Hotspot = Hotspot.WithX(x); } if (d.ContainsKey("Y")) { - int y; - Exts.TryParseIntegerInvariant(d["Y"].Value, out y); + Exts.TryParseIntegerInvariant(d["Y"].Value, out var y); Hotspot = Hotspot.WithY(y); } } diff -Nru openra-20200503/OpenRA.Game/Graphics/HardwarePalette.cs openra-20210321/OpenRA.Game/Graphics/HardwarePalette.cs --- openra-20200503/OpenRA.Game/Graphics/HardwarePalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/HardwarePalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -38,19 +38,16 @@ public IPalette GetPalette(string name) { - MutablePalette mutable; - if (modifiablePalettes.TryGetValue(name, out mutable)) + if (modifiablePalettes.TryGetValue(name, out var mutable)) return mutable.AsReadOnly(); - ImmutablePalette immutable; - if (palettes.TryGetValue(name, out immutable)) + if (palettes.TryGetValue(name, out var immutable)) return immutable; throw new InvalidOperationException("Palette `{0}` does not exist".F(name)); } public int GetPaletteIndex(string name) { - int ret; - if (!indices.TryGetValue(name, out ret)) + if (!indices.TryGetValue(name, out var ret)) throw new InvalidOperationException("Palette `{0}` does not exist".F(name)); return ret; } diff -Nru openra-20200503/OpenRA.Game/Graphics/ModelAnimation.cs openra-20210321/OpenRA.Game/Graphics/ModelAnimation.cs --- openra-20200503/OpenRA.Game/Graphics/ModelAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/ModelAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System; -using System.Collections.Generic; using OpenRA.Primitives; namespace OpenRA.Graphics @@ -19,12 +18,12 @@ { public readonly IModel Model; public readonly Func OffsetFunc; - public readonly Func> RotationFunc; + public readonly Func RotationFunc; public readonly Func DisableFunc; public readonly Func FrameFunc; public readonly bool ShowShadow; - public ModelAnimation(IModel model, Func offset, Func> rotation, Func disable, Func frame, bool showshadow) + public ModelAnimation(IModel model, Func offset, Func rotation, Func disable, Func frame, bool showshadow) { Model = model; OffsetFunc = offset; diff -Nru openra-20200503/OpenRA.Game/Graphics/ModelRenderer.cs openra-20210321/OpenRA.Game/Graphics/ModelRenderer.cs --- openra-20200503/OpenRA.Game/Graphics/ModelRenderer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/ModelRenderer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -48,7 +48,7 @@ readonly Dictionary mappedBuffers = new Dictionary(); readonly Stack> unmappedBuffers = new Stack>(); - readonly List> doRender = new List>(); + readonly List<(Sheet Sheet, Action Func)> doRender = new List<(Sheet, Action)>(); SheetBuilder sheetBuilderForFrame; bool isInFrame; @@ -79,8 +79,8 @@ } public ModelRenderProxy RenderAsync( - WorldRenderer wr, IEnumerable models, WRot camera, float scale, - float[] groundNormal, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, + WorldRenderer wr, IEnumerable models, in WRot camera, float scale, + float[] groundNormal, in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, PaletteReference color, PaletteReference normals, PaletteReference shadowPalette) { if (!isInFrame) @@ -114,8 +114,7 @@ var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); - var worldTransform = m.RotationFunc().Aggregate(Util.IdentityMatrix(), - (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); + var worldTransform = Util.MakeFloatMatrix(m.RotationFunc().AsMatrix()); worldTransform = Util.MatrixMultiply(scaleTransform, worldTransform); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); @@ -161,10 +160,8 @@ } // Shadows are rendered at twice the resolution to reduce artifacts - Size spriteSize, shadowSpriteSize; - int2 spriteOffset, shadowSpriteOffset; - CalculateSpriteGeometry(tl, br, 1, out spriteSize, out spriteOffset); - CalculateSpriteGeometry(stl, sbr, 2, out shadowSpriteSize, out shadowSpriteOffset); + CalculateSpriteGeometry(tl, br, 1, out var spriteSize, out var spriteOffset); + CalculateSpriteGeometry(stl, sbr, 2, out var shadowSpriteSize, out var shadowSpriteOffset); if (sheetBuilderForFrame == null) sheetBuilderForFrame = new SheetBuilder(SheetType.BGRA, AllocateSheet); @@ -181,7 +178,7 @@ var correctionTransform = Util.MatrixMultiply(translateMtx, FlipMtx); var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, ShadowScaleFlipMtx); - doRender.Add(Pair.New(sprite.Sheet, () => + doRender.Add((sprite.Sheet, () => { foreach (var m in models) { @@ -189,8 +186,7 @@ var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); - var rotations = m.RotationFunc().Aggregate(Util.IdentityMatrix(), - (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); + var rotations = Util.MakeFloatMatrix(m.RotationFunc().AsMatrix()); var worldTransform = Util.MatrixMultiply(scaleTransform, rotations); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); @@ -326,16 +322,16 @@ foreach (var v in doRender) { // Change sheet - if (v.First != currentSheet) + if (v.Sheet != currentSheet) { if (fbo != null) DisableFrameBuffer(fbo); - currentSheet = v.First; + currentSheet = v.Sheet; fbo = EnableFrameBuffer(currentSheet); } - v.Second(); + v.Func(); } if (fbo != null) diff -Nru openra-20200503/OpenRA.Game/Graphics/PlatformInterfaces.cs openra-20210321/OpenRA.Game/Graphics/PlatformInterfaces.cs --- openra-20200503/OpenRA.Game/Graphics/PlatformInterfaces.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/PlatformInterfaces.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,6 +17,8 @@ { public enum GLProfile { + Automatic, + ANGLE, Modern, Embedded, Legacy @@ -24,7 +26,7 @@ public interface IPlatform { - IPlatformWindow CreateWindow(Size size, WindowMode windowMode, float scaleModifier, int batchSize, int videoDisplay, GLProfile profile); + IPlatformWindow CreateWindow(Size size, WindowMode windowMode, float scaleModifier, int batchSize, int videoDisplay, GLProfile profile, bool enableLegacyGL); ISoundEngine CreateSound(string device); IFont CreateFont(byte[] data); } @@ -39,7 +41,10 @@ Subtractive, Multiply, Multiplicative, - DoubleMultiplicative + DoubleMultiplicative, + LowAdditive, + Screen, + Translucent } public interface IPlatformWindow : IDisposable @@ -53,6 +58,7 @@ Size SurfaceSize { get; } int DisplayCount { get; } int CurrentDisplay { get; } + bool HasInputFocus { get; } event Action OnWindowScaleChanged; @@ -97,8 +103,7 @@ { void Bind(); void SetData(T[] vertices, int length); - void SetData(T[] vertices, int start, int length); - void SetData(IntPtr data, int start, int length); + void SetData(T[] vertices, int offset, int start, int length); } public interface IShader diff -Nru openra-20200503/OpenRA.Game/Graphics/PlayerColorRemap.cs openra-20210321/OpenRA.Game/Graphics/PlayerColorRemap.cs --- openra-20200503/OpenRA.Game/Graphics/PlayerColorRemap.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/PlayerColorRemap.cs 2021-03-21 11:10:05.000000000 +0000 @@ -47,14 +47,13 @@ remapRamp = ramp.Select(r => r - ramp[rampMaxIndex]); } - remapColors = remapRamp.Select((x, i) => Pair.New(baseIndex + i, Exts.ColorLerp(x / (float)ramp.Length, c1, c2))) - .ToDictionary(u => u.First, u => u.Second); + remapColors = remapRamp.Select((x, i) => (baseIndex + i, Exts.ColorLerp(x / (float)ramp.Length, c1, c2))) + .ToDictionary(u => u.Item1, u => u.Item2); } public Color GetRemappedColor(Color original, int index) { - Color c; - return remapColors.TryGetValue(index, out c) + return remapColors.TryGetValue(index, out var c) ? c : original; } } diff -Nru openra-20200503/OpenRA.Game/Graphics/Renderable.cs openra-20210321/OpenRA.Game/Graphics/Renderable.cs --- openra-20200503/OpenRA.Game/Graphics/Renderable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/Renderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,6 +28,11 @@ IFinalizedRenderable PrepareRender(WorldRenderer wr); } + public interface ITintableRenderable + { + IRenderable WithTint(in float3 newTint); + } + public interface IFinalizedRenderable { void Render(WorldRenderer wr); diff -Nru openra-20200503/OpenRA.Game/Graphics/RgbaColorRenderer.cs openra-20210321/OpenRA.Game/Graphics/RgbaColorRenderer.cs --- openra-20200503/OpenRA.Game/Graphics/RgbaColorRenderer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/RgbaColorRenderer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,7 +28,7 @@ this.parent = parent; } - public void DrawLine(float3 start, float3 end, float width, Color startColor, Color endColor) + public void DrawLine(in float3 start, in float3 end, float width, Color startColor, Color endColor) { var delta = (end - start) / (end - start).XY.Length; var corner = width / 2 * new float3(-delta.Y, delta.X, delta.Z); @@ -55,7 +55,7 @@ parent.DrawRGBAVertices(vertices); } - public void DrawLine(float3 start, float3 end, float width, Color color) + public void DrawLine(in float3 start, in float3 end, float width, Color color) { var delta = (end - start) / (end - start).XY.Length; var corner = width / 2 * new float2(-delta.Y, delta.X); @@ -80,7 +80,7 @@ /// Will behave badly if the lines are parallel. /// Z position is the average of a and b (ignores actual intersection point if it exists) /// - float3 IntersectionOf(float3 a, float3 da, float3 b, float3 db) + float3 IntersectionOf(in float3 a, in float3 da, in float3 b, in float3 db) { var crossA = a.X * (a.Y + da.Y) - a.Y * (a.X + da.X); var crossB = b.X * (b.Y + db.Y) - b.Y * (b.X + db.X); @@ -193,14 +193,14 @@ DrawConnectedLine(vertices.Select(v => new float3(v, 0)).ToArray(), width, color, true); } - public void DrawRect(float3 tl, float3 br, float width, Color color) + public void DrawRect(in float3 tl, in float3 br, float width, Color color) { var tr = new float3(br.X, tl.Y, tl.Z); var bl = new float3(tl.X, br.Y, br.Z); DrawPolygon(new[] { tl, tr, br, bl }, width, color); } - public void FillTriangle(float3 a, float3 b, float3 c, Color color) + public void FillTriangle(in float3 a, in float3 b, in float3 c, Color color) { color = Util.PremultiplyAlpha(color); var cr = color.R / 255.0f; @@ -214,14 +214,14 @@ parent.DrawRGBAVertices(vertices); } - public void FillRect(float3 tl, float3 br, Color color) + public void FillRect(in float3 tl, in float3 br, Color color) { var tr = new float3(br.X, tl.Y, tl.Z); var bl = new float3(tl.X, br.Y, br.Z); FillRect(tl, tr, br, bl, color); } - public void FillRect(float3 a, float3 b, float3 c, float3 d, Color color) + public void FillRect(in float3 a, in float3 b, in float3 c, in float3 d, Color color) { color = Util.PremultiplyAlpha(color); var cr = color.R / 255.0f; @@ -238,7 +238,7 @@ parent.DrawRGBAVertices(vertices); } - public void FillRect(float3 a, float3 b, float3 c, float3 d, Color topLeftColor, Color topRightColor, Color bottomRightColor, Color bottomLeftColor) + public void FillRect(in float3 a, in float3 b, in float3 c, in float3 d, Color topLeftColor, Color topRightColor, Color bottomRightColor, Color bottomLeftColor) { vertices[0] = VertexWithColor(a + Offset, topLeftColor); vertices[1] = VertexWithColor(b + Offset, topRightColor); @@ -250,7 +250,7 @@ parent.DrawRGBAVertices(vertices); } - static Vertex VertexWithColor(float3 xyz, Color color) + static Vertex VertexWithColor(in float3 xyz, Color color) { color = Util.PremultiplyAlpha(color); var cr = color.R / 255.0f; @@ -261,7 +261,7 @@ return new Vertex(xyz, cr, cg, cb, ca, 0, 0); } - public void FillEllipse(float3 tl, float3 br, Color color, int vertices = 32) + public void FillEllipse(in float3 tl, in float3 br, Color color, int vertices = 32) { // TODO: Create an ellipse polygon instead var a = (br.X - tl.X) / 2; diff -Nru openra-20200503/OpenRA.Game/Graphics/RgbaSpriteRenderer.cs openra-20210321/OpenRA.Game/Graphics/RgbaSpriteRenderer.cs --- openra-20200503/OpenRA.Game/Graphics/RgbaSpriteRenderer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/RgbaSpriteRenderer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,7 +22,7 @@ this.parent = parent; } - public void DrawSprite(Sprite s, float3 location, float3 size) + public void DrawSprite(Sprite s, in float3 location, in float3 size) { if (s.Channel != TextureChannel.RGBA) throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite."); @@ -30,7 +30,7 @@ parent.DrawSprite(s, location, 0, size); } - public void DrawSprite(Sprite s, float3 location) + public void DrawSprite(Sprite s, in float3 location) { if (s.Channel != TextureChannel.RGBA) throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite."); @@ -38,12 +38,28 @@ parent.DrawSprite(s, location, 0, s.Size); } - public void DrawSprite(Sprite s, float3 a, float3 b, float3 c, float3 d) + public void DrawSprite(Sprite s, in float3 a, in float3 b, in float3 c, in float3 d) { if (s.Channel != TextureChannel.RGBA) throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite."); parent.DrawSprite(s, a, b, c, d); } + + public void DrawSpriteWithTint(Sprite s, in float3 location, in float3 size, in float3 tint) + { + if (s.Channel != TextureChannel.RGBA) + throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite."); + + parent.DrawSpriteWithTint(s, location, 0, size, tint); + } + + public void DrawSpriteWithTint(Sprite s, in float3 a, in float3 b, in float3 c, in float3 d, in float3 tint) + { + if (s.Channel != TextureChannel.RGBA) + throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite."); + + parent.DrawSpriteWithTint(s, a, b, c, d, tint); + } } } diff -Nru openra-20200503/OpenRA.Game/Graphics/SequenceProvider.cs openra-20210321/OpenRA.Game/Graphics/SequenceProvider.cs --- openra-20200503/OpenRA.Game/Graphics/SequenceProvider.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/SequenceProvider.cs 2021-03-21 11:10:05.000000000 +0000 @@ -32,29 +32,29 @@ int ShadowZOffset { get; } int[] Frames { get; } Rectangle Bounds { get; } + bool IgnoreWorldTint { get; } Sprite GetSprite(int frame); - Sprite GetSprite(int frame, int facing); - Sprite GetShadow(int frame, int facing); + Sprite GetSprite(int frame, WAngle facing); + Sprite GetShadow(int frame, WAngle facing); } public interface ISpriteSequenceLoader { - Action OnMissingSpriteError { get; set; } - IReadOnlyDictionary ParseSequences(ModData modData, TileSet tileSet, SpriteCache cache, MiniYamlNode node); + IReadOnlyDictionary ParseSequences(ModData modData, string tileSet, SpriteCache cache, MiniYamlNode node); } public class SequenceProvider : IDisposable { readonly ModData modData; - readonly TileSet tileSet; + readonly string tileSet; readonly Lazy sequences; readonly Lazy spriteCache; public SpriteCache SpriteCache { get { return spriteCache.Value; } } readonly Dictionary sequenceCache = new Dictionary(); - public SequenceProvider(IReadOnlyFileSystem fileSystem, ModData modData, TileSet tileSet, MiniYaml additionalSequences) + public SequenceProvider(IReadOnlyFileSystem fileSystem, ModData modData, string tileSet, MiniYaml additionalSequences) { this.modData = modData; this.tileSet = tileSet; @@ -69,17 +69,17 @@ public ISpriteSequence GetSequence(string unitName, string sequenceName) { - UnitSequences unitSeq; - if (!sequences.Value.TryGetValue(unitName, out unitSeq)) + if (!sequences.Value.TryGetValue(unitName, out var unitSeq)) throw new InvalidOperationException("Unit `{0}` does not have any sequences defined.".F(unitName)); - ISpriteSequence seq; - if (!unitSeq.Value.TryGetValue(sequenceName, out seq)) + if (!unitSeq.Value.TryGetValue(sequenceName, out var seq)) throw new InvalidOperationException("Unit `{0}` does not have a sequence named `{1}`".F(unitName, sequenceName)); return seq; } + public IEnumerable Images { get { return sequences.Value.Keys; } } + public bool HasSequence(string unitName) { return sequences.Value.ContainsKey(unitName); @@ -87,8 +87,7 @@ public bool HasSequence(string unitName, string sequenceName) { - UnitSequences unitSeq; - if (!sequences.Value.TryGetValue(unitName, out unitSeq)) + if (!sequences.Value.TryGetValue(unitName, out var unitSeq)) throw new InvalidOperationException("Unit `{0}` does not have any sequences defined.".F(unitName)); return unitSeq.Value.ContainsKey(sequenceName); @@ -96,8 +95,7 @@ public IEnumerable Sequences(string unitName) { - UnitSequences unitSeq; - if (!sequences.Value.TryGetValue(unitName, out unitSeq)) + if (!sequences.Value.TryGetValue(unitName, out var unitSeq)) throw new InvalidOperationException("Unit `{0}` does not have any sequences defined.".F(unitName)); return unitSeq.Value.Keys; @@ -107,15 +105,15 @@ { var nodes = MiniYaml.Load(fileSystem, modData.Manifest.Sequences, additionalSequences); var items = new Dictionary(); - foreach (var n in nodes) + foreach (var node in nodes) { - // Work around the loop closure issue in older versions of C# - var node = n; + // Nodes starting with ^ are inheritable but never loaded directly + if (node.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal)) + continue; var key = node.Value.ToLines(node.Key).JoinWith("|"); - UnitSequences t; - if (sequenceCache.TryGetValue(key, out t)) + if (sequenceCache.TryGetValue(key, out var t)) items.Add(node.Key, t); else { diff -Nru openra-20200503/OpenRA.Game/Graphics/SheetBuilder.cs openra-20210321/OpenRA.Game/Graphics/SheetBuilder.cs --- openra-20200503/OpenRA.Game/Graphics/SheetBuilder.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/SheetBuilder.cs 2021-03-21 11:10:05.000000000 +0000 @@ -76,7 +76,7 @@ public Sprite Add(ISpriteFrame frame) { return Add(frame.Data, frame.Size, 0, frame.Offset); } public Sprite Add(byte[] src, Size size) { return Add(src, size, 0, float3.Zero); } - public Sprite Add(byte[] src, Size size, float zRamp, float3 spriteOffset) + public Sprite Add(byte[] src, Size size, float zRamp, in float3 spriteOffset) { // Don't bother allocating empty sprites if (size.Width == 0 || size.Height == 0) @@ -115,7 +115,7 @@ } public Sprite Allocate(Size imageSize, float scale = 1f) { return Allocate(imageSize, 0, float3.Zero, scale); } - public Sprite Allocate(Size imageSize, float zRamp, float3 spriteOffset, float scale = 1f) + public Sprite Allocate(Size imageSize, float zRamp, in float3 spriteOffset, float scale = 1f) { if (imageSize.Width + p.X + margin > current.Size.Width) { diff -Nru openra-20200503/OpenRA.Game/Graphics/Sheet.cs openra-20210321/OpenRA.Game/Graphics/Sheet.cs --- openra-20200503/OpenRA.Game/Graphics/Sheet.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/Sheet.cs 2021-03-21 11:10:05.000000000 +0000 @@ -146,8 +146,7 @@ public void Dispose() { - if (texture != null) - texture.Dispose(); + texture?.Dispose(); } } } diff -Nru openra-20200503/OpenRA.Game/Graphics/Sprite.cs openra-20210321/OpenRA.Game/Graphics/Sprite.cs --- openra-20200503/OpenRA.Game/Graphics/Sprite.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/Sprite.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,7 +29,7 @@ public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel, float scale = 1) : this(sheet, bounds, 0, float2.Zero, channel, BlendMode.Alpha, scale) { } - public Sprite(Sheet sheet, Rectangle bounds, float zRamp, float3 offset, TextureChannel channel, BlendMode blendMode = BlendMode.Alpha, float scale = 1f) + public Sprite(Sheet sheet, Rectangle bounds, float zRamp, in float3 offset, TextureChannel channel, BlendMode blendMode = BlendMode.Alpha, float scale = 1f) { Sheet = sheet; Bounds = bounds; diff -Nru openra-20200503/OpenRA.Game/Graphics/SpriteFont.cs openra-20210321/OpenRA.Game/Graphics/SpriteFont.cs --- openra-20200503/OpenRA.Game/Graphics/SpriteFont.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/SpriteFont.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,8 +23,8 @@ readonly SheetBuilder builder; readonly Func lineWidth; readonly IFont font; - readonly Cache, GlyphInfo> glyphs; - readonly Cache, Sprite> contrastGlyphs; + readonly Cache glyphs; + readonly Cache<(char C, int Radius), Sprite> contrastGlyphs; readonly Cache dilationElements; float deviceScale; @@ -39,17 +39,20 @@ this.builder = builder; font = Game.Renderer.CreateFont(data); - - glyphs = new Cache, GlyphInfo>(CreateGlyph, Pair.EqualityComparer); - contrastGlyphs = new Cache, Sprite>(CreateContrastGlyph); + glyphs = new Cache(CreateGlyph); + contrastGlyphs = new Cache<(char, int), Sprite>(CreateContrastGlyph); dilationElements = new Cache(CreateCircularWeightMap); // PERF: Cache these delegates for Measure calls. - Func characterWidth = character => glyphs[Pair.New(character, Color.White)].Advance; + Func characterWidth = character => glyphs[character].Advance; lineWidth = line => line.Sum(characterWidth) / deviceScale; + // Pre-cache small font sizes so glyphs are immediately available when we need them if (size <= 24) - PrecacheColor(Color.White, name); + using (new PerfTimer("Precache {0} {1}px".F(name, size))) + for (var n = (char)0x20; n < (char)0x7f; n++) + if (glyphs[n] == null) + throw new InvalidOperationException(); TopOffset = size - ascender; } @@ -61,14 +64,6 @@ contrastGlyphs.Clear(); } - void PrecacheColor(Color c, string name) - { - using (new PerfTimer("PrecacheColor {0} {1}px {2}".F(name, size, c))) - for (var n = (char)0x20; n < (char)0x7f; n++) - if (glyphs[Pair.New(n, c)] == null) - throw new InvalidOperationException(); - } - void DrawTextContrast(string text, float2 location, Color contrastColor, int contrastOffset) { // Offset from the baseline position to the top-left of the glyph for rendering @@ -78,6 +73,7 @@ var screenContrast = (int)(contrastOffset * deviceScale); var screen = new int2((int)(location.X * deviceScale + 0.5f), (int)(location.Y * deviceScale + 0.5f)); var contrastVector = new float2(screenContrast, screenContrast); + var tint = new float3(contrastColor.R / 255f, contrastColor.G / 255f, contrastColor.B / 255f); foreach (var s in text) { if (s == '\n') @@ -87,15 +83,16 @@ continue; } - var g = glyphs[Pair.New(s, Color.Black)]; + var g = glyphs[s]; // Convert screen coordinates back to UI coordinates for drawing if (g.Sprite != null) { - var contrastSprite = contrastGlyphs[Tuple.Create(s, contrastColor, screenContrast)]; - Game.Renderer.RgbaSpriteRenderer.DrawSprite(contrastSprite, + var contrastSprite = contrastGlyphs[(s, screenContrast)]; + Game.Renderer.RgbaSpriteRenderer.DrawSpriteWithTint(contrastSprite, (screen + g.Offset - contrastVector) / deviceScale, - contrastSprite.Size / deviceScale); + contrastSprite.Size / deviceScale, + tint); } screen += new int2((int)(g.Advance + 0.5f), 0); @@ -109,6 +106,7 @@ // Calculate positions in screen pixel coordinates var screen = new int2((int)(location.X * deviceScale + 0.5f), (int)(location.Y * deviceScale + 0.5f)); + var tint = new float3(c.R / 255f, c.G / 255f, c.B / 255f); foreach (var s in text) { if (s == '\n') @@ -118,13 +116,14 @@ continue; } - var g = glyphs[Pair.New(s, c)]; + var g = glyphs[s]; // Convert screen coordinates back to UI coordinates for drawing if (g.Sprite != null) - Game.Renderer.RgbaSpriteRenderer.DrawSprite(g.Sprite, + Game.Renderer.RgbaSpriteRenderer.DrawSpriteWithTint(g.Sprite, (screen + g.Offset).ToFloat2() / deviceScale, - g.Sprite.Size / deviceScale); + g.Sprite.Size / deviceScale, + tint); screen += new int2((int)(g.Advance + 0.5f), 0); } @@ -144,6 +143,7 @@ var offset = new float2(0, size); var cosa = (float)Math.Cos(-angle); var sina = (float)Math.Sin(-angle); + var tint = new float3(c.R / 255f, c.G / 255f, c.B / 255f); var p = offset; foreach (var s in text) @@ -155,7 +155,7 @@ continue; } - var g = glyphs[Pair.New(s, c)]; + var g = glyphs[s]; if (g.Sprite != null) { var tl = new float2( @@ -172,11 +172,12 @@ // Offset rotated glyph to align the top-left corner with the screen pixel grid var screenOffset = new float2((int)(ra.X * deviceScale + 0.5f), (int)(ra.Y * deviceScale + 0.5f)) / deviceScale - ra; - Game.Renderer.RgbaSpriteRenderer.DrawSprite(g.Sprite, + Game.Renderer.RgbaSpriteRenderer.DrawSpriteWithTint(g.Sprite, ra + screenOffset, rb + screenOffset, rc + screenOffset, - rd + screenOffset); + rd + screenOffset, + tint); } p += new float2(g.Advance / deviceScale, 0); @@ -238,13 +239,20 @@ return new int2(0, size); var lines = text.Split('\n'); - return new int2((int)Math.Ceiling(lines.Max(lineWidth)), lines.Length * size); + return new int2((int)Math.Ceiling(MaxLineWidth(lines, lineWidth)), lines.Length * size); } - GlyphInfo CreateGlyph(Pair c) + static float MaxLineWidth(string[] lines, Func lineWidth) { - var glyph = font.CreateGlyph(c.First, size, deviceScale); + var maxWidth = 0f; + foreach (var line in lines) + maxWidth = Math.Max(maxWidth, lineWidth(line)); + return maxWidth; + } + GlyphInfo CreateGlyph(char c) + { + var glyph = font.CreateGlyph(c, size, deviceScale); if (glyph.Data == null) { return new GlyphInfo @@ -274,12 +282,10 @@ if (p != 0) { var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left); - var pmc = Util.PremultiplyAlpha(Color.FromArgb(p, c.Second)); - - dest[q] = pmc.B; - dest[q + 1] = pmc.G; - dest[q + 2] = pmc.R; - dest[q + 3] = pmc.A; + dest[q] = p; + dest[q + 1] = p; + dest[q + 2] = p; + dest[q + 3] = p; } } } @@ -347,16 +353,12 @@ return elem; } - Sprite CreateContrastGlyph(Tuple c) + Sprite CreateContrastGlyph((char C, int Radius) c) { - // Source glyph color doesn't matter, so use black - var glyph = glyphs[Pair.New(c.Item1, Color.Black)]; - var color = c.Item2; - var r = c.Item3; - - var size = new Size(glyph.Sprite.Bounds.Width + 2 * r, glyph.Sprite.Bounds.Height + 2 * r); + var glyph = glyphs[c.C]; + var r = c.Radius; - var s = builder.Allocate(size); + var s = builder.Allocate(new Size(glyph.Sprite.Bounds.Width + 2 * r, glyph.Sprite.Bounds.Height + 2 * r)); var dest = s.Sheet.GetData(); var destStride = s.Sheet.Size.Width * 4; @@ -398,11 +400,10 @@ if (alpha > 0) { var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left); - var pmc = Util.PremultiplyAlpha(Color.FromArgb(alpha, color)); - dest[q] = pmc.B; - dest[q + 1] = pmc.G; - dest[q + 2] = pmc.R; - dest[q + 3] = pmc.A; + dest[q] = alpha; + dest[q + 1] = alpha; + dest[q + 2] = alpha; + dest[q + 3] = alpha; } } } diff -Nru openra-20200503/OpenRA.Game/Graphics/SpriteLoader.cs openra-20210321/OpenRA.Game/Graphics/SpriteLoader.cs --- openra-20200503/OpenRA.Game/Graphics/SpriteLoader.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/SpriteLoader.cs 2021-03-21 11:10:05.000000000 +0000 @@ -76,8 +76,7 @@ var allSprites = sprites.GetOrAdd(filename); var sprite = allSprites.FirstOrDefault(); - ISpriteFrame[] unloaded; - if (!unloadedFrames.TryGetValue(filename, out unloaded)) + if (!unloadedFrames.TryGetValue(filename, out var unloaded)) unloaded = null; // This is the first time that the file has been requested @@ -85,8 +84,7 @@ // the loaded cache (initially empty) if (sprite == null) { - TypeDictionary fileMetadata = null; - unloaded = FrameLoader.GetFrames(fileSystem, filename, loaders, out fileMetadata); + unloaded = FrameLoader.GetFrames(fileSystem, filename, loaders, out var fileMetadata); unloadedFrames[filename] = unloaded; metadata[filename] = fileMetadata; @@ -125,8 +123,7 @@ /// public TypeDictionary FrameMetadata(string filename) { - TypeDictionary fileMetadata; - if (!metadata.TryGetValue(filename, out fileMetadata)) + if (!metadata.TryGetValue(filename, out var fileMetadata)) { FrameLoader.GetFrames(fileSystem, filename, loaders, out fileMetadata); metadata[filename] = fileMetadata; @@ -142,8 +139,7 @@ public FrameCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders) { - TypeDictionary metadata; - frames = new Cache(filename => FrameLoader.GetFrames(fileSystem, filename, loaders, out metadata)); + frames = new Cache(filename => FrameLoader.GetFrames(fileSystem, filename, loaders, out _)); } public ISpriteFrame[] this[string filename] { get { return frames[filename]; } } @@ -165,11 +161,10 @@ public static ISpriteFrame[] GetFrames(Stream stream, ISpriteLoader[] loaders, out TypeDictionary metadata) { - ISpriteFrame[] frames; metadata = null; foreach (var loader in loaders) - if (loader.TryParseSprite(stream, out frames, out metadata)) + if (loader.TryParseSprite(stream, out var frames, out metadata)) return frames; return null; diff -Nru openra-20200503/OpenRA.Game/Graphics/SpriteRenderable.cs openra-20210321/OpenRA.Game/Graphics/SpriteRenderable.cs --- openra-20200503/OpenRA.Game/Graphics/SpriteRenderable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/SpriteRenderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Graphics { - public struct SpriteRenderable : IRenderable, IFinalizedRenderable + public struct SpriteRenderable : IRenderable, ITintableRenderable, IFinalizedRenderable { public static readonly IEnumerable None = new IRenderable[0]; @@ -24,9 +24,17 @@ readonly int zOffset; readonly PaletteReference palette; readonly float scale; + readonly float3 tint; readonly bool isDecoration; + readonly bool ignoreWorldTint; public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, bool isDecoration) + : this(sprite, pos, offset, zOffset, palette, scale, float3.Ones, isDecoration, false) { } + + public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, bool isDecoration, bool ignoreWorldTint) + : this(sprite, pos, offset, zOffset, palette, scale, float3.Ones, isDecoration, ignoreWorldTint) { } + + public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, float3 tint, bool isDecoration, bool ignoreWorldTint) { this.sprite = sprite; this.pos = pos; @@ -34,7 +42,9 @@ this.zOffset = zOffset; this.palette = palette; this.scale = scale; + this.tint = tint; this.isDecoration = isDecoration; + this.ignoreWorldTint = ignoreWorldTint; } public WPos Pos { get { return pos + offset; } } @@ -43,10 +53,12 @@ public int ZOffset { get { return zOffset; } } public bool IsDecoration { get { return isDecoration; } } - public IRenderable WithPalette(PaletteReference newPalette) { return new SpriteRenderable(sprite, pos, offset, zOffset, newPalette, scale, isDecoration); } - public IRenderable WithZOffset(int newOffset) { return new SpriteRenderable(sprite, pos, offset, newOffset, palette, scale, isDecoration); } - public IRenderable OffsetBy(WVec vec) { return new SpriteRenderable(sprite, pos + vec, offset, zOffset, palette, scale, isDecoration); } - public IRenderable AsDecoration() { return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, true); } + public IRenderable WithPalette(PaletteReference newPalette) { return new SpriteRenderable(sprite, pos, offset, zOffset, newPalette, scale, tint, isDecoration, ignoreWorldTint); } + public IRenderable WithZOffset(int newOffset) { return new SpriteRenderable(sprite, pos, offset, newOffset, palette, scale, tint, isDecoration, ignoreWorldTint); } + public IRenderable OffsetBy(WVec vec) { return new SpriteRenderable(sprite, pos + vec, offset, zOffset, palette, scale, tint, isDecoration, ignoreWorldTint); } + public IRenderable AsDecoration() { return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, tint, true, ignoreWorldTint); } + + public IRenderable WithTint(in float3 newTint) { return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, newTint, isDecoration, ignoreWorldTint); } float3 ScreenPosition(WorldRenderer wr) { @@ -59,7 +71,17 @@ public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { - Game.Renderer.WorldSpriteRenderer.DrawSprite(sprite, ScreenPosition(wr), palette, scale * sprite.Size); + var wsr = Game.Renderer.WorldSpriteRenderer; + if (ignoreWorldTint) + wsr.DrawSprite(sprite, ScreenPosition(wr), palette, scale * sprite.Size); + else + { + var t = tint; + if (wr.TerrainLighting != null) + t *= wr.TerrainLighting.TintAt(pos); + + wsr.DrawSpriteWithTint(sprite, ScreenPosition(wr), palette, scale * sprite.Size, t); + } } public void RenderDebugGeometry(WorldRenderer wr) diff -Nru openra-20200503/OpenRA.Game/Graphics/SpriteRenderer.cs openra-20210321/OpenRA.Game/Graphics/SpriteRenderer.cs --- openra-20200503/OpenRA.Game/Graphics/SpriteRenderer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/SpriteRenderer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,17 +10,21 @@ #endregion using System; +using System.Linq; using OpenRA.Primitives; namespace OpenRA.Graphics { public class SpriteRenderer : Renderer.IBatchRenderer { + const int SheetCount = 7; + static readonly string[] SheetIndexToTextureName = Exts.MakeArray(SheetCount, i => "Texture{0}".F(i)); + readonly Renderer renderer; readonly IShader shader; readonly Vertex[] vertices; - readonly Sheet[] sheets = new Sheet[7]; + readonly Sheet[] sheets = new Sheet[SheetCount]; BlendMode currentBlend = BlendMode.Alpha; int nv = 0; @@ -39,7 +43,7 @@ { for (var i = 0; i < ns; i++) { - shader.SetTexture("Texture{0}".F(i), sheets[i].GetTexture()); + shader.SetTexture(SheetIndexToTextureName[i], sheets[i].GetTexture()); sheets[i] = null; } @@ -104,27 +108,46 @@ return new int2(sheetIndex, secondarySheetIndex); } - internal void DrawSprite(Sprite s, float3 location, float paletteTextureIndex, float3 size) + internal void DrawSprite(Sprite s, in float3 location, float paletteTextureIndex, in float3 size) { var samplers = SetRenderStateForSprite(s); - Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, samplers, paletteTextureIndex, nv, size); + Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, samplers, paletteTextureIndex, nv, size, float3.Ones); nv += 6; } - public void DrawSprite(Sprite s, float3 location, PaletteReference pal) + public void DrawSprite(Sprite s, in float3 location, PaletteReference pal) { DrawSprite(s, location, pal.TextureIndex, s.Size); } - public void DrawSprite(Sprite s, float3 location, PaletteReference pal, float3 size) + public void DrawSprite(Sprite s, in float3 location, PaletteReference pal, float3 size) { DrawSprite(s, location, pal.TextureIndex, size); } - public void DrawSprite(Sprite s, float3 a, float3 b, float3 c, float3 d) + public void DrawSprite(Sprite s, in float3 a, in float3 b, in float3 c, in float3 d) + { + var samplers = SetRenderStateForSprite(s); + Util.FastCreateQuad(vertices, a, b, c, d, s, samplers, 0, float3.Ones, nv); + nv += 6; + } + + internal void DrawSpriteWithTint(Sprite s, in float3 location, float paletteTextureIndex, in float3 size, in float3 tint) + { + var samplers = SetRenderStateForSprite(s); + Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, samplers, paletteTextureIndex, nv, size, tint); + nv += 6; + } + + public void DrawSpriteWithTint(Sprite s, in float3 location, PaletteReference pal, in float3 size, in float3 tint) + { + DrawSpriteWithTint(s, location, pal.TextureIndex, size, tint); + } + + public void DrawSpriteWithTint(Sprite s, in float3 a, in float3 b, in float3 c, in float3 d, in float3 tint) { var samplers = SetRenderStateForSprite(s); - Util.FastCreateQuad(vertices, a, b, c, d, s, samplers, 0, nv); + Util.FastCreateQuad(vertices, a, b, c, d, s, samplers, 0, tint, nv); nv += 6; } diff -Nru openra-20200503/OpenRA.Game/Graphics/TerrainSpriteLayer.cs openra-20210321/OpenRA.Game/Graphics/TerrainSpriteLayer.cs --- openra-20200503/OpenRA.Game/Graphics/TerrainSpriteLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/TerrainSpriteLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,6 +18,8 @@ { public sealed class TerrainSpriteLayer : IDisposable { + static readonly int[] CornerVertexMap = { 0, 1, 2, 2, 3, 0 }; + public readonly Sheet Sheet; public readonly BlendMode BlendMode; @@ -25,6 +27,7 @@ readonly IVertexBuffer vertexBuffer; readonly Vertex[] vertices; + readonly bool[] ignoreTint; readonly HashSet dirtyRows = new HashSet(); readonly int rowStride; readonly bool restrictToBounds; @@ -50,6 +53,12 @@ emptySprite = new Sprite(sheet, Rectangle.Empty, TextureChannel.Alpha); wr.PaletteInvalidated += UpdatePaletteIndices; + + if (wr.TerrainLighting != null) + { + ignoreTint = new bool[rowStride * map.MapSize.Y]; + wr.TerrainLighting.CellChanged += UpdateTint; + } } void UpdatePaletteIndices() @@ -59,22 +68,76 @@ for (var i = 0; i < vertices.Length; i++) { var v = vertices[i]; - vertices[i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C); + vertices[i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, v.R, v.G, v.B); } for (var row = 0; row < map.MapSize.Y; row++) dirtyRows.Add(row); } - public void Update(CPos cell, Sprite sprite) + public void Clear(CPos cell) + { + Update(cell, null, true); + } + + public void Update(CPos cell, ISpriteSequence sequence, int frame) + { + Update(cell, sequence.GetSprite(frame), sequence.IgnoreWorldTint); + } + + public void Update(CPos cell, Sprite sprite, bool ignoreTint) { - var xyz = sprite == null ? float3.Zero : - worldRenderer.Screen3DPosition(map.CenterOfCell(cell)) + sprite.Offset - 0.5f * sprite.Size; + var xyz = float3.Zero; + if (sprite != null) + { + var cellOrigin = map.CenterOfCell(cell) - new WVec(0, 0, map.Grid.Ramps[map.Ramp[cell]].CenterHeightOffset); + xyz = worldRenderer.Screen3DPosition(cellOrigin) + sprite.Offset - 0.5f * sprite.Size; + } + + Update(cell.ToMPos(map.Grid.Type), sprite, xyz, ignoreTint); + } + + void UpdateTint(MPos uv) + { + var offset = rowStride * uv.V + 6 * uv.U; + if (ignoreTint[offset]) + { + var noTint = float3.Ones; + for (var i = 0; i < 6; i++) + { + var v = vertices[offset + i]; + vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, noTint); + } + + return; + } + + // Allow the terrain tint to vary linearly across the cell to smooth out the staircase effect + // This is done by sampling the lighting the corners of the sprite, even though those pixels are + // transparent for isometric tiles + var tl = worldRenderer.TerrainLighting; + var pos = map.CenterOfCell(uv.ToCPos(map)); + var step = map.Grid.Type == MapGridType.RectangularIsometric ? 724 : 512; + var weights = new[] + { + tl.TintAt(pos + new WVec(-step, -step, 0)), + tl.TintAt(pos + new WVec(step, -step, 0)), + tl.TintAt(pos + new WVec(step, step, 0)), + tl.TintAt(pos + new WVec(-step, step, 0)) + }; + + // Apply tint directly to the underlying vertices + // This saves us from having to re-query the sprite information, which has not changed + for (var i = 0; i < 6; i++) + { + var v = vertices[offset + i]; + vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, weights[CornerVertexMap[i]]); + } - Update(cell.ToMPos(map.Grid.Type), sprite, xyz); + dirtyRows.Add(uv.V); } - public void Update(MPos uv, Sprite sprite, float3 pos) + public void Update(MPos uv, Sprite sprite, in float3 pos, bool ignoreTint) { if (sprite != null) { @@ -92,7 +155,13 @@ return; var offset = rowStride * uv.V + 6 * uv.U; - Util.FastCreateQuad(vertices, pos, sprite, int2.Zero, palette.TextureIndex, offset, sprite.Size); + Util.FastCreateQuad(vertices, pos, sprite, int2.Zero, palette.TextureIndex, offset, sprite.Size, float3.Ones); + + if (worldRenderer.TerrainLighting != null) + { + this.ignoreTint[offset] = ignoreTint; + UpdateTint(uv); + } dirtyRows.Add(uv.V); } @@ -114,15 +183,7 @@ continue; var rowOffset = rowStride * row; - - unsafe - { - // The compiler / language spec won't let us calculate a pointer to - // an offset inside a generic array T[], and so we are forced to - // calculate the start-of-row pointer here to pass in to SetData. - fixed (Vertex* vPtr = &vertices[0]) - vertexBuffer.SetData((IntPtr)(vPtr + rowOffset), rowOffset, rowStride); - } + vertexBuffer.SetData(vertices, rowOffset, rowOffset, rowStride); } Game.Renderer.WorldSpriteRenderer.DrawVertexBuffer( @@ -135,6 +196,9 @@ public void Dispose() { worldRenderer.PaletteInvalidated -= UpdatePaletteIndices; + if (worldRenderer.TerrainLighting != null) + worldRenderer.TerrainLighting.CellChanged -= UpdateTint; + vertexBuffer.Dispose(); } } diff -Nru openra-20200503/OpenRA.Game/Graphics/Theater.cs openra-20210321/OpenRA.Game/Graphics/Theater.cs --- openra-20200503/OpenRA.Game/Graphics/Theater.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/Theater.cs 2021-03-21 11:10:05.000000000 +0000 @@ -40,7 +40,7 @@ readonly MersenneTwister random; TileSet tileset; - public Theater(TileSet tileset) + public Theater(TileSet tileset, Action onMissingImage = null) { this.tileset = tileset; var allocated = false; @@ -63,9 +63,31 @@ foreach (var i in t.Value.Images) { - var allFrames = frameCache[i]; + ISpriteFrame[] allFrames; + if (onMissingImage != null) + { + try + { + allFrames = frameCache[i]; + } + catch (FileNotFoundException) + { + onMissingImage(t.Key, i); + continue; + } + } + else + allFrames = frameCache[i]; + var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length; - var indices = t.Value.Frames != null ? t.Value.Frames : Enumerable.Range(0, frameCount); + var indices = t.Value.Frames != null ? t.Value.Frames : Exts.MakeArray(t.Value.TilesCount, j => j); + + var start = indices.Min(); + var end = indices.Max(); + if (start < 0 || end >= frameCount) + throw new YamlException("Template `{0}` uses frames [{1}..{2}] of {3}, but only [0..{4}] actually exist" + .F(t.Key, start, end, i, frameCount - 1)); + variants.Add(indices.Select(j => { var f = allFrames[j]; @@ -82,7 +104,7 @@ if (sheetBuilder == null) sheetBuilder = new SheetBuilder(SheetBuilder.FrameTypeToSheetType(f.Type), allocate); else if (type != sheetBuilder.Type) - throw new InvalidDataException("Sprite type mismatch. Terrain sprites must all be either Indexed or RGBA."); + throw new YamlException("Sprite type mismatch. Terrain sprites must all be either Indexed or RGBA."); var s = sheetBuilder.Allocate(f.Size, zRamp, offset); Util.FastCopyIntoChannel(s, f.Data); @@ -107,6 +129,9 @@ if (tileset.IgnoreTileSpriteOffsets) allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode)); + if (onMissingImage != null && !variants.Any()) + continue; + templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } @@ -116,10 +141,14 @@ Sheet.ReleaseBuffer(); } + public bool HasTileSprite(TerrainTile r, int? variant = null) + { + return TileSprite(r, variant) != missingTile; + } + public Sprite TileSprite(TerrainTile r, int? variant = null) { - TheaterTemplate template; - if (!templates.TryGetValue(r.Type, out template)) + if (!templates.TryGetValue(r.Type, out var template)) return missingTile; if (r.Index >= template.Stride) diff -Nru openra-20200503/OpenRA.Game/Graphics/Util.cs openra-20210321/OpenRA.Game/Graphics/Util.cs --- openra-20200503/OpenRA.Game/Graphics/Util.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/Util.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,15 +20,18 @@ // yes, our channel order is nuts. static readonly int[] ChannelMasks = { 2, 1, 0, 3 }; - public static void FastCreateQuad(Vertex[] vertices, float3 o, Sprite r, int2 samplers, float paletteTextureIndex, int nv, float3 size) + public static void FastCreateQuad(Vertex[] vertices, in float3 o, Sprite r, int2 samplers, float paletteTextureIndex, int nv, in float3 size, in float3 tint) { var b = new float3(o.X + size.X, o.Y, o.Z); var c = new float3(o.X + size.X, o.Y + size.Y, o.Z + size.Z); var d = new float3(o.X, o.Y + size.Y, o.Z + size.Z); - FastCreateQuad(vertices, o, b, c, d, r, samplers, paletteTextureIndex, nv); + FastCreateQuad(vertices, o, b, c, d, r, samplers, paletteTextureIndex, tint, nv); } - public static void FastCreateQuad(Vertex[] vertices, float3 a, float3 b, float3 c, float3 d, Sprite r, int2 samplers, float paletteTextureIndex, int nv) + public static void FastCreateQuad(Vertex[] vertices, + in float3 a, in float3 b, in float3 c, in float3 d, + Sprite r, int2 samplers, float paletteTextureIndex, + in float3 tint, int nv) { float sl = 0; float st = 0; @@ -51,12 +54,12 @@ } var fAttribC = (float)attribC; - vertices[nv] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC); - vertices[nv + 1] = new Vertex(b, r.Right, r.Top, sr, st, paletteTextureIndex, fAttribC); - vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC); - vertices[nv + 3] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC); - vertices[nv + 4] = new Vertex(d, r.Left, r.Bottom, sl, sb, paletteTextureIndex, fAttribC); - vertices[nv + 5] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC); + vertices[nv] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC, tint); + vertices[nv + 1] = new Vertex(b, r.Right, r.Top, sr, st, paletteTextureIndex, fAttribC, tint); + vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC, tint); + vertices[nv + 3] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC, tint); + vertices[nv + 4] = new Vertex(d, r.Left, r.Bottom, sl, sb, paletteTextureIndex, fAttribC, tint); + vertices[nv + 5] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC, tint); } public static void FastCopyIntoChannel(Sprite dest, byte[] src) diff -Nru openra-20200503/OpenRA.Game/Graphics/Vertex.cs openra-20210321/OpenRA.Game/Graphics/Vertex.cs --- openra-20200503/OpenRA.Game/Graphics/Vertex.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/Vertex.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,17 +16,34 @@ [StructLayout(LayoutKind.Sequential)] public struct Vertex { - public readonly float X, Y, Z, S, T, U, V, P, C; + // 3d position + public readonly float X, Y, Z; - public Vertex(float3 xyz, float s, float t, float u, float v, float p, float c) - : this(xyz.X, xyz.Y, xyz.Z, s, t, u, v, p, c) { } + // Primary and secondary texture coordinates or RGBA color + public readonly float S, T, U, V; - public Vertex(float x, float y, float z, float s, float t, float u, float v, float p, float c) + // Palette and channel flags + public readonly float P, C; + + // Color tint + public readonly float R, G, B; + + public Vertex(in float3 xyz, float s, float t, float u, float v, float p, float c) + : this(xyz.X, xyz.Y, xyz.Z, s, t, u, v, p, c, float3.Ones) { } + + public Vertex(in float3 xyz, float s, float t, float u, float v, float p, float c, in float3 tint) + : this(xyz.X, xyz.Y, xyz.Z, s, t, u, v, p, c, tint.X, tint.Y, tint.Z) { } + + public Vertex(float x, float y, float z, float s, float t, float u, float v, float p, float c, in float3 tint) + : this(x, y, z, s, t, u, v, p, c, tint.X, tint.Y, tint.Z) { } + + public Vertex(float x, float y, float z, float s, float t, float u, float v, float p, float c, float r, float g, float b) { X = x; Y = y; Z = z; S = s; T = t; U = u; V = v; P = p; C = c; + R = r; G = g; B = b; } } } diff -Nru openra-20200503/OpenRA.Game/Graphics/Viewport.cs openra-20210321/OpenRA.Game/Graphics/Viewport.cs --- openra-20200503/OpenRA.Game/Graphics/Viewport.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/Viewport.cs 2021-03-21 11:10:05.000000000 +0000 @@ -89,12 +89,22 @@ } } + public float MinZoom { get { return minZoom; } } + public void AdjustZoom(float dz) { // Exponential ensures that equal positive and negative steps have the same effect Zoom = (zoom * (float)Math.Exp(dz)).Clamp(unlockMinZoom ? unlockedMinZoom : minZoom, maxZoom); } + public void AdjustZoom(float dz, int2 center) + { + var oldCenter = worldRenderer.Viewport.ViewToWorldPx(center); + AdjustZoom(dz); + var newCenter = worldRenderer.Viewport.ViewToWorldPx(center); + CenterLocation += oldCenter - newCenter; + } + public void ToggleZoom() { // Unlocked zooms always reset to the default zoom @@ -252,7 +262,6 @@ var world = worldRenderer.Viewport.ViewToWorldPx(view); var map = worldRenderer.World.Map; var candidates = CandidateMouseoverCells(world).ToList(); - var tileSet = worldRenderer.World.Map.Rules.TileSet; foreach (var uv in candidates) { @@ -261,18 +270,9 @@ var s = worldRenderer.ScreenPxPosition(p); if (Math.Abs(s.X - world.X) <= tileSize.Width && Math.Abs(s.Y - world.Y) <= tileSize.Height) { - var ramp = 0; - if (map.Contains(uv)) - { - var ti = tileSet.GetTileInfo(map.Tiles[uv]); - if (ti != null) - ramp = ti.RampType; - } - - var corners = map.Grid.CellCorners[ramp]; - var pos = map.CenterOfCell(uv.ToCPos(map)); - var screen = corners.Select(c => worldRenderer.ScreenPxPosition(pos + c)).ToArray(); - + var ramp = map.Grid.Ramps[map.Ramp.Contains(uv) ? map.Ramp[uv] : 0]; + var pos = map.CenterOfCell(uv.ToCPos(map)) - new WVec(0, 0, ramp.CenterHeightOffset); + var screen = ramp.Corners.Select(c => worldRenderer.ScreenPxPosition(pos + c)).ToArray(); if (screen.PolygonContains(world)) return uv.ToCPos(map); } @@ -282,7 +282,7 @@ // Try and find the closest cell if (candidates.Count > 0) { - return candidates.OrderBy(uv => + return candidates.MinBy(uv => { var p = map.CenterOfCell(uv.ToCPos(map.Grid.Type)); var s = worldRenderer.ScreenPxPosition(p); @@ -290,7 +290,7 @@ var dy = Math.Abs(s.Y - world.Y); return dx * dx + dy * dy; - }).First().ToCPos(map); + }).ToCPos(map); } // Something is very wrong, but lets return something that isn't completely bogus and hope the caller can recover @@ -314,7 +314,7 @@ public int2 ViewToWorldPx(int2 view) { return (graphicSettings.UIScale / Zoom * view.ToFloat2()).ToInt2() + TopLeft; } public int2 WorldToViewPx(int2 world) { return ((Zoom / graphicSettings.UIScale) * (world - TopLeft).ToFloat2()).ToInt2(); } - public int2 WorldToViewPx(float3 world) { return ((Zoom / graphicSettings.UIScale) * (world - TopLeft).XY).ToInt2(); } + public int2 WorldToViewPx(in float3 world) { return ((Zoom / graphicSettings.UIScale) * (world - TopLeft).XY).ToInt2(); } public void Center(IEnumerable actors) { diff -Nru openra-20200503/OpenRA.Game/Graphics/WorldRenderer.cs openra-20210321/OpenRA.Game/Graphics/WorldRenderer.cs --- openra-20200503/OpenRA.Game/Graphics/WorldRenderer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Graphics/WorldRenderer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,7 +20,7 @@ { public sealed class WorldRenderer : IDisposable { - public static readonly Func RenderableScreenZPositionComparisonKey = + public static readonly Func RenderableZPositionComparisonKey = r => ZPosition(r.Pos, r.ZOffset); public readonly Size TileSize; @@ -28,6 +28,7 @@ public readonly World World; public readonly Theater Theater; public Viewport Viewport { get; private set; } + public readonly ITerrainLighting TerrainLighting; public event Action PaletteInvalidated = null; @@ -43,6 +44,8 @@ readonly List preparedOverlayRenderables = new List(); readonly List preparedAnnotationRenderables = new List(); + readonly List renderablesBuffer = new List(); + bool lastDepthPreviewEnabled; internal WorldRenderer(ModData modData, World world) @@ -66,6 +69,7 @@ palette.Initialize(); Theater = new Theater(world.Map.Rules.TileSet); + TerrainLighting = world.WorldActor.TraitOrDefault(); terrainRenderer = world.WorldActor.TraitOrDefault(); debugVis = Exts.Lazy(() => world.WorldActor.TraitOrDefault()); @@ -93,8 +97,8 @@ var oldHeight = palette.Height; palette.AddPalette(name, pal, allowModifiers); - if (oldHeight != palette.Height && PaletteInvalidated != null) - PaletteInvalidated(); + if (oldHeight != palette.Height) + PaletteInvalidated?.Invoke(); } } @@ -107,78 +111,118 @@ palettes[name].Palette = pal; } - IEnumerable GenerateRenderables() + // PERF: Avoid LINQ. + void GenerateRenderables() { - var actors = onScreenActors.Append(World.WorldActor); + foreach (var actor in onScreenActors) + renderablesBuffer.AddRange(actor.Render(this)); + + renderablesBuffer.AddRange(World.WorldActor.Render(this)); + if (World.RenderPlayer != null) - actors = actors.Append(World.RenderPlayer.PlayerActor); + renderablesBuffer.AddRange(World.RenderPlayer.PlayerActor.Render(this)); - var worldRenderables = actors.SelectMany(a => a.Render(this)); if (World.OrderGenerator != null) - worldRenderables = worldRenderables.Concat(World.OrderGenerator.Render(this, World)); + renderablesBuffer.AddRange(World.OrderGenerator.Render(this, World)); // Unpartitioned effects - worldRenderables = worldRenderables.Concat(World.UnpartitionedEffects.SelectMany(e => e.Render(this))); + foreach (var e in World.UnpartitionedEffects) + renderablesBuffer.AddRange(e.Render(this)); // Partitioned, currently on-screen effects - var effectRenderables = World.ScreenMap.RenderableEffectsInBox(Viewport.TopLeft, Viewport.BottomRight); - worldRenderables = worldRenderables.Concat(effectRenderables.SelectMany(e => e.Render(this))); + foreach (var e in World.ScreenMap.RenderableEffectsInBox(Viewport.TopLeft, Viewport.BottomRight)) + renderablesBuffer.AddRange(e.Render(this)); - worldRenderables = worldRenderables.OrderBy(RenderableScreenZPositionComparisonKey); + // Renderables must be ordered using a stable sorting algorithm to avoid flickering artefacts + foreach (var renderable in renderablesBuffer.OrderBy(RenderableZPositionComparisonKey)) + preparedRenderables.Add(renderable.PrepareRender(this)); - return worldRenderables.Select(r => r.PrepareRender(this)); + // PERF: Reuse collection to avoid allocations. + renderablesBuffer.Clear(); } - IEnumerable GenerateOverlayRenderables() + // PERF: Avoid LINQ. + void GenerateOverlayRenderables() { - var actors = World.ActorsWithTrait() - .Where(a => a.Actor.IsInWorld && !a.Actor.Disposed && (!a.Trait.SpatiallyPartitionable || onScreenActors.Contains(a.Actor))) - .SelectMany(a => a.Trait.RenderAboveShroud(a.Actor, this)); - - var selected = World.Selection.Actors.Where(a => a.IsInWorld && !a.Disposed) - .SelectMany(a => a.TraitsImplementing() - .Where(t => !t.SpatiallyPartitionable || onScreenActors.Contains(a)) - .SelectMany(t => t.RenderAboveShroud(a, this))); - - var effects = World.Effects.Select(e => e as IEffectAboveShroud) - .Where(e => e != null) - .SelectMany(e => e.RenderAboveShroud(this)); + foreach (var a in World.ActorsWithTrait()) + { + if (!a.Actor.IsInWorld || a.Actor.Disposed || (a.Trait.SpatiallyPartitionable && !onScreenActors.Contains(a.Actor))) + continue; - var orderGenerator = SpriteRenderable.None; - if (World.OrderGenerator != null) - orderGenerator = World.OrderGenerator.RenderAboveShroud(this, World); + foreach (var renderable in a.Trait.RenderAboveShroud(a.Actor, this)) + preparedOverlayRenderables.Add(renderable.PrepareRender(this)); + } + + foreach (var a in World.Selection.Actors) + { + if (!a.IsInWorld || a.Disposed) + continue; + + foreach (var t in a.TraitsImplementing()) + { + if (t.SpatiallyPartitionable && !onScreenActors.Contains(a)) + continue; + + foreach (var renderable in t.RenderAboveShroud(a, this)) + preparedOverlayRenderables.Add(renderable.PrepareRender(this)); + } + } + + foreach (var e in World.Effects) + { + var ea = e as IEffectAboveShroud; + if (ea == null) + continue; + + foreach (var renderable in ea.RenderAboveShroud(this)) + preparedOverlayRenderables.Add(renderable.PrepareRender(this)); + } - return actors - .Concat(selected) - .Concat(effects) - .Concat(orderGenerator) - .Select(r => r.PrepareRender(this)); + if (World.OrderGenerator != null) + foreach (var renderable in World.OrderGenerator.RenderAboveShroud(this, World)) + preparedOverlayRenderables.Add(renderable.PrepareRender(this)); } - IEnumerable GenerateAnnotationRenderables() + // PERF: Avoid LINQ. + void GenerateAnnotationRenderables() { - var actors = World.ActorsWithTrait() - .Where(a => a.Actor.IsInWorld && !a.Actor.Disposed && (!a.Trait.SpatiallyPartitionable || onScreenActors.Contains(a.Actor))) - .SelectMany(a => a.Trait.RenderAnnotations(a.Actor, this)); - - var selected = World.Selection.Actors.Where(a => a.IsInWorld && !a.Disposed) - .SelectMany(a => a.TraitsImplementing() - .Where(t => !t.SpatiallyPartitionable || onScreenActors.Contains(a)) - .SelectMany(t => t.RenderAnnotations(a, this))); - - var effects = World.Effects.Select(e => e as IEffectAnnotation) - .Where(e => e != null) - .SelectMany(e => e.RenderAnnotation(this)); + foreach (var a in World.ActorsWithTrait()) + { + if (!a.Actor.IsInWorld || a.Actor.Disposed || (a.Trait.SpatiallyPartitionable && !onScreenActors.Contains(a.Actor))) + continue; - var orderGenerator = SpriteRenderable.None; - if (World.OrderGenerator != null) - orderGenerator = World.OrderGenerator.RenderAnnotations(this, World); + foreach (var renderAnnotation in a.Trait.RenderAnnotations(a.Actor, this)) + preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this)); + } + + foreach (var a in World.Selection.Actors) + { + if (!a.IsInWorld || a.Disposed) + continue; + + foreach (var t in a.TraitsImplementing()) + { + if (t.SpatiallyPartitionable && !onScreenActors.Contains(a)) + continue; - return actors - .Concat(selected) - .Concat(effects) - .Concat(orderGenerator) - .Select(r => r.PrepareRender(this)); + foreach (var renderAnnotation in t.RenderAnnotations(a, this)) + preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this)); + } + } + + foreach (var e in World.Effects) + { + var ea = e as IEffectAnnotation; + if (ea == null) + continue; + + foreach (var renderAnnotation in ea.RenderAnnotation(this)) + preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this)); + } + + if (World.OrderGenerator != null) + foreach (var renderAnnotation in World.OrderGenerator.RenderAnnotations(this, World)) + preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this)); } public void PrepareRenderables() @@ -190,9 +234,11 @@ // PERF: Reuse collection to avoid allocations. onScreenActors.UnionWith(World.ScreenMap.RenderableActorsInBox(Viewport.TopLeft, Viewport.BottomRight)); - preparedRenderables.AddRange(GenerateRenderables()); - preparedOverlayRenderables.AddRange(GenerateOverlayRenderables()); - preparedAnnotationRenderables.AddRange(GenerateAnnotationRenderables()); + + GenerateRenderables(); + GenerateOverlayRenderables(); + GenerateAnnotationRenderables(); + onScreenActors.Clear(); } @@ -213,8 +259,7 @@ if (enableDepthBuffer) Game.Renderer.Context.EnableDepthBuffer(); - if (terrainRenderer != null) - terrainRenderer.RenderTerrain(this, Viewport); + terrainRenderer?.RenderTerrain(this, Viewport); Game.Renderer.Flush(); @@ -277,11 +322,16 @@ Game.Renderer.RgbaColorRenderer.DrawRect(tl, br, 1, Color.MediumSpringGreen); } - foreach (var r in World.ScreenMap.MouseBounds(World.RenderPlayer)) + foreach (var b in World.ScreenMap.MouseBounds(World.RenderPlayer)) { - var tl = Viewport.WorldToViewPx(new float2(r.Left, r.Top)); - var br = Viewport.WorldToViewPx(new float2(r.Right, r.Bottom)); - Game.Renderer.RgbaColorRenderer.DrawRect(tl, br, 1, Color.OrangeRed); + var points = new float2[b.Vertices.Length]; + for (var index = 0; index < b.Vertices.Length; index++) + { + var vertex = b.Vertices[index]; + points[index] = Viewport.WorldToViewPx(vertex).ToFloat2(); + } + + Game.Renderer.RgbaColorRenderer.DrawPolygon(points, 1, Color.OrangeRed); } } diff -Nru openra-20200503/OpenRA.Game/HotkeyManager.cs openra-20210321/OpenRA.Game/HotkeyManager.cs --- openra-20200503/OpenRA.Game/HotkeyManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/HotkeyManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -50,8 +50,7 @@ return () => keys[name]; // Try and parse as a hardcoded definition - Hotkey key; - if (!Hotkey.TryParse(name, out key)) + if (!Hotkey.TryParse(name, out var key)) key = Hotkey.Invalid; return () => key; @@ -59,8 +58,7 @@ public void Set(string name, Hotkey value) { - HotkeyDefinition definition; - if (!definitions.TryGetValue(name, out definition)) + if (!definitions.TryGetValue(name, out var definition)) return; keys[name] = value; diff -Nru openra-20200503/OpenRA.Game/Input/Hotkey.cs openra-20210321/OpenRA.Game/Input/Hotkey.cs --- openra-20200503/OpenRA.Game/Input/Hotkey.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Input/Hotkey.cs 2021-03-21 11:10:05.000000000 +0000 @@ -32,11 +32,9 @@ var parts = s.Split(' '); - Keycode key; - if (!Enum.TryParse(parts[0], true, out key)) + if (!Enum.TryParse(parts[0], true, out var key)) { - int c; - if (!int.TryParse(parts[0], out c)) + if (!int.TryParse(parts[0], out var c)) return false; key = (Keycode)c; } diff -Nru openra-20200503/OpenRA.Game/Input/Keycode.cs openra-20210321/OpenRA.Game/Input/Keycode.cs --- openra-20200503/OpenRA.Game/Input/Keycode.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Input/Keycode.cs 2021-03-21 11:10:05.000000000 +0000 @@ -498,8 +498,7 @@ public static string DisplayString(Keycode k) { - string ret; - if (!KeyNames.TryGetValue(k, out ret)) + if (!KeyNames.TryGetValue(k, out var ret)) return k.ToString(); return ret; diff -Nru openra-20200503/OpenRA.Game/InstalledMods.cs openra-20210321/OpenRA.Game/InstalledMods.cs --- openra-20200503/OpenRA.Game/InstalledMods.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/InstalledMods.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using OpenRA.FileFormats; using OpenRA.FileSystem; using OpenRA.Graphics; using OpenRA.Primitives; @@ -35,9 +34,9 @@ mods = GetInstalledMods(searchPaths, explicitPaths); } - static IEnumerable> GetCandidateMods(IEnumerable searchPaths) + static IEnumerable<(string Id, string Path)> GetCandidateMods(IEnumerable searchPaths) { - var mods = new List>(); + var mods = new List<(string, string)>(); foreach (var path in searchPaths) { try @@ -48,7 +47,7 @@ var directory = new DirectoryInfo(resolved); foreach (var subdir in directory.EnumerateDirectories()) - mods.Add(Pair.New(subdir.Name, subdir.FullName)); + mods.Add((subdir.Name, subdir.FullName)); } catch (Exception e) { @@ -79,8 +78,7 @@ Log.Write("debug", "Load mod '{0}': {1}".F(path, e)); } - if (package != null) - package.Dispose(); + package?.Dispose(); return null; } @@ -89,13 +87,13 @@ { var ret = new Dictionary(); var candidates = GetCandidateMods(searchPaths) - .Concat(explicitPaths.Select(p => Pair.New(Path.GetFileNameWithoutExtension(p), p))); + .Concat(explicitPaths.Select(p => (Id: Path.GetFileNameWithoutExtension(p), Path: p))); foreach (var pair in candidates) { - var mod = LoadMod(pair.First, pair.Second); + var mod = LoadMod(pair.Id, pair.Path); if (mod != null) - ret[pair.First] = mod; + ret[pair.Id] = mod; } return ret; diff -Nru openra-20200503/OpenRA.Game/LocalPlayerProfile.cs openra-20210321/OpenRA.Game/LocalPlayerProfile.cs --- openra-20200503/OpenRA.Game/LocalPlayerProfile.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/LocalPlayerProfile.cs 2021-03-21 11:10:05.000000000 +0000 @@ -80,8 +80,6 @@ { try { - innerState = LinkState.Unlinked; - if (i.Error != null) { innerState = LinkState.ConnectionFailed; @@ -100,6 +98,8 @@ else innerState = LinkState.Linked; } + else + innerState = LinkState.Unlinked; } catch (Exception e) { @@ -108,8 +108,7 @@ } finally { - if (onComplete != null) - onComplete(); + onComplete?.Invoke(); } }; diff -Nru openra-20200503/OpenRA.Game/Manifest.cs openra-20210321/OpenRA.Game/Manifest.cs --- openra-20200503/OpenRA.Game/Manifest.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Manifest.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,7 +52,7 @@ } /// Describes what is to be loaded in order to run a mod. - public class Manifest + public class Manifest : IDisposable { public readonly string Id; public readonly IReadOnlyPackage Package; @@ -73,7 +73,7 @@ readonly string[] reservedModuleNames = { - "Metadata", "Folders", "MapFolders", "Packages", "Rules", + "Include", "Metadata", "Folders", "MapFolders", "Packages", "Rules", "Sequences", "ModelSequences", "Cursors", "Chrome", "Assemblies", "ChromeLayout", "Weapons", "Voices", "Notifications", "Music", "Translations", "TileSets", "ChromeMetrics", "Missions", "Hotkeys", "ServerTraits", "LoadScreen", "SupportsMapsFrom", "SoundFormats", "SpriteFormats", @@ -89,15 +89,32 @@ { Id = modId; Package = package; - yaml = new MiniYaml(null, MiniYaml.FromStream(package.GetStream("mod.yaml"), "mod.yaml")).ToDictionary(); + + var nodes = MiniYaml.FromStream(package.GetStream("mod.yaml"), "mod.yaml"); + for (var i = nodes.Count - 1; i >= 0; i--) + { + if (nodes[i].Key != "Include") + continue; + + // Replace `Includes: filename.yaml` with the contents of filename.yaml + var filename = nodes[i].Value.Value; + var contents = package.GetStream(filename); + if (contents == null) + throw new YamlException("{0}: File `{1}` not found.".F(nodes[i].Location, filename)); + + nodes.RemoveAt(i); + nodes.InsertRange(i, MiniYaml.FromStream(contents, filename)); + } + + // Merge inherited overrides + yaml = new MiniYaml(null, MiniYaml.Merge(new[] { nodes })).ToDictionary(); Metadata = FieldLoader.Load(yaml["Metadata"]); // TODO: Use fieldloader MapFolders = YamlDictionary(yaml, "MapFolders"); - MiniYaml packages; - if (yaml.TryGetValue("Packages", out packages)) + if (yaml.TryGetValue("Packages", out var packages)) Packages = packages.ToDictionary(x => x.Value).AsReadOnly(); Rules = YamlList(yaml, "Rules"); @@ -217,9 +234,8 @@ /// public T Get(ObjectCreator oc) where T : IGlobalModData { - MiniYaml data; var t = typeof(T); - if (!yaml.TryGetValue(t.Name, out data)) + if (!yaml.TryGetValue(t.Name, out var data)) { // Lazily create the default values if not explicitly defined. return (T)oc.CreateBasic(t); @@ -241,5 +257,14 @@ return (T)module; } + + public void Dispose() + { + foreach (var module in modules) + { + var disposableModule = module as IDisposable; + disposableModule?.Dispose(); + } + } } } diff -Nru openra-20200503/OpenRA.Game/Map/ActorInitializer.cs openra-20210321/OpenRA.Game/Map/ActorInitializer.cs --- openra-20200503/OpenRA.Game/Map/ActorInitializer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/ActorInitializer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,17 +9,29 @@ */ #endregion +using System; +using System.Collections.Generic; using System.Linq; +using System.Reflection; using OpenRA.Primitives; +using OpenRA.Traits; namespace OpenRA { public interface IActorInitializer { World World { get; } - T Get() where T : IActorInit; - U Get() where T : IActorInit; - bool Contains() where T : IActorInit; + T GetOrDefault(TraitInfo info) where T : ActorInit; + T Get(TraitInfo info) where T : ActorInit; + U GetValue(TraitInfo info) where T : ValueActorInit; + U GetValue(TraitInfo info, U fallback) where T : ValueActorInit; + bool Contains(TraitInfo info) where T : ActorInit; + + T GetOrDefault() where T : ActorInit, ISingleInstanceInit; + T Get() where T : ActorInit, ISingleInstanceInit; + U GetValue() where T : ValueActorInit, ISingleInstanceInit; + U GetValue(U fallback) where T : ValueActorInit, ISingleInstanceInit; + bool Contains() where T : ActorInit, ISingleInstanceInit; } public class ActorInitializer : IActorInitializer @@ -35,50 +47,228 @@ Dict = dict; } - public T Get() where T : IActorInit { return Dict.Get(); } - public U Get() where T : IActorInit { return Dict.Get().Value(World); } - public bool Contains() where T : IActorInit { return Dict.Contains(); } + public T GetOrDefault(TraitInfo info) where T : ActorInit + { + var inits = Dict.WithInterface(); + + // Traits tagged with an instance name prefer inits with the same name. + // If a more specific init is not available, fall back to an unnamed init. + // If duplicate inits are defined, take the last to match standard yaml override expectations + if (info != null && !string.IsNullOrEmpty(info.InstanceName)) + return inits.LastOrDefault(i => i.InstanceName == info.InstanceName) ?? + inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName)); + + // Untagged traits will only use untagged inits + return inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName)); + } + + public T Get(TraitInfo info) where T : ActorInit + { + var init = GetOrDefault(info); + if (init == null) + throw new InvalidOperationException("TypeDictionary does not contain instance of type `{0}`".F(typeof(T))); + + return init; + } + + public U GetValue(TraitInfo info) where T : ValueActorInit + { + return Get(info).Value; + } + + public U GetValue(TraitInfo info, U fallback) where T : ValueActorInit + { + var init = GetOrDefault(info); + return init != null ? init.Value : fallback; + } + + public bool Contains(TraitInfo info) where T : ActorInit { return GetOrDefault(info) != null; } + + public T GetOrDefault() where T : ActorInit, ISingleInstanceInit + { + return Dict.GetOrDefault(); + } + + public T Get() where T : ActorInit, ISingleInstanceInit + { + return Dict.Get(); + } + + public U GetValue() where T : ValueActorInit, ISingleInstanceInit + { + return Get().Value; + } + + public U GetValue(U fallback) where T : ValueActorInit, ISingleInstanceInit + { + var init = GetOrDefault(); + return init != null ? init.Value : fallback; + } + + public bool Contains() where T : ActorInit, ISingleInstanceInit { return GetOrDefault() != null; } + } + + /* + * Things to be aware of when writing ActorInits: + * + * - ActorReference and ActorGlobal can dynamically create objects without calling a constructor. + * The object will be allocated directly then the best matching Initialize() method will be called to set valid state. + * - ActorReference will always attempt to call Initialize(MiniYaml). ActorGlobal will use whichever one it first + * finds with an argument type that matches the given LuaValue. + * - Most ActorInits will want to inherit either ValueActorInit or CompositeActorInit which hide the low-level plumbing. + * - Inits that reference actors should use ActorInitActorReference which allows actors to be referenced by name in map.yaml + * - Inits that should only have a single instance defined on an actor should implement ISingleInstanceInit to allow + * direct queries and runtime enforcement. + * - Inits that aren't ISingleInstanceInit should expose a ctor that accepts a TraitInfo to allow per-trait targeting. + */ + public abstract class ActorInit + { + [FieldLoader.Ignore] + public readonly string InstanceName; + + protected ActorInit(string instanceName) + { + InstanceName = instanceName; + } + + protected ActorInit() { } + + public abstract MiniYaml Save(); } - public interface IActorInit { } + public interface ISingleInstanceInit { } - public interface IActorInit : IActorInit + public abstract class ValueActorInit : ActorInit { - T Value(World world); + protected readonly T value; + + protected ValueActorInit(TraitInfo info, T value) + : base(info.InstanceName) { this.value = value; } + + protected ValueActorInit(string instanceName, T value) + : base(instanceName) { this.value = value; } + + protected ValueActorInit(T value) { this.value = value; } + + public virtual T Value { get { return value; } } + + public virtual void Initialize(MiniYaml yaml) + { + Initialize((T)FieldLoader.GetValue("value", typeof(T), yaml.Value)); + } + + public virtual void Initialize(T value) + { + var field = GetType().GetField("value", BindingFlags.NonPublic | BindingFlags.Instance); + if (field != null) + field.SetValue(this, value); + } + + public override MiniYaml Save() + { + return new MiniYaml(FieldSaver.FormatValue(value)); + } } - public class LocationInit : IActorInit + public abstract class CompositeActorInit : ActorInit { - [FieldFromYamlKey] - readonly CPos value = CPos.Zero; + protected CompositeActorInit(TraitInfo info) + : base(info.InstanceName) { } + + protected CompositeActorInit() + : base() { } + + public virtual void Initialize(MiniYaml yaml) + { + FieldLoader.Load(this, yaml); + } + + public virtual void Initialize(Dictionary values) + { + foreach (var field in GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) + { + var sa = field.GetCustomAttributes(false).DefaultIfEmpty(FieldLoader.SerializeAttribute.Default).First(); + if (!sa.Serialize) + continue; + + if (values.TryGetValue(field.Name, out var value)) + field.SetValue(this, value); + } + } + + public virtual Dictionary InitializeArgs() + { + var dict = new Dictionary(); + foreach (var field in GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) + { + var sa = field.GetCustomAttributes(false).DefaultIfEmpty(FieldLoader.SerializeAttribute.Default).First(); + if (!sa.Serialize) + continue; + + dict[field.Name] = field.FieldType; + } + + return dict; + } - public LocationInit() { } - public LocationInit(CPos init) { value = init; } - public CPos Value(World world) { return value; } + public override MiniYaml Save() + { + return FieldSaver.Save(this); + } } - public class OwnerInit : IActorInit + public class LocationInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - public readonly string PlayerName = "Neutral"; + public LocationInit(CPos value) + : base(value) { } + } - Player player; + public class OwnerInit : ActorInit, ISingleInstanceInit + { + public readonly string InternalName; + protected readonly Player value; - public OwnerInit() { } - public OwnerInit(string playerName) { PlayerName = playerName; } + public OwnerInit(Player value) + { + this.value = value; + InternalName = value.InternalName; + } - public OwnerInit(Player player) + public OwnerInit(string value) { - this.player = player; - PlayerName = player.InternalName; + InternalName = value; } public Player Value(World world) { - if (player != null) - return player; + return value ?? world.Players.First(x => x.InternalName == InternalName); + } + + public void Initialize(MiniYaml yaml) + { + var field = GetType().GetField("InternalName", BindingFlags.Public | BindingFlags.Instance); + if (field != null) + field.SetValue(this, yaml.Value); + } + + public void Initialize(Player player) + { + var field = GetType().GetField("value", BindingFlags.NonPublic | BindingFlags.Instance); + if (field != null) + field.SetValue(this, player); + } + + public override MiniYaml Save() + { + return new MiniYaml(InternalName); + } + } - return world.Players.First(x => x.InternalName == PlayerName); + public abstract class RuntimeFlagInit : ActorInit, ISuppressInitExport + { + public override MiniYaml Save() + { + throw new NotImplementedException("RuntimeFlagInit cannot be saved"); } } } diff -Nru openra-20200503/OpenRA.Game/Map/ActorReference.cs openra-20210321/OpenRA.Game/Map/ActorReference.cs --- openra-20200503/OpenRA.Game/Map/ActorReference.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/ActorReference.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,11 @@ using System; using System.Collections; using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; using OpenRA.Primitives; +using OpenRA.Traits; namespace OpenRA { @@ -21,13 +25,10 @@ public class ActorReference : IEnumerable { public string Type; - public TypeDictionary InitDict - { - get { return initDict.Value; } - } - Lazy initDict; + internal TypeDictionary InitDict { get { return initDict.Value; } } + public ActorReference(string type) : this(type, new Dictionary()) { } @@ -38,47 +39,168 @@ { var dict = new TypeDictionary(); foreach (var i in inits) - dict.Add(LoadInit(i.Key, i.Value)); + { + var init = LoadInit(i.Key, i.Value); + if (init is ISingleInstanceInit && dict.Contains(init.GetType())) + throw new InvalidDataException("Duplicate initializer '{0}'".F(init.GetType().Name)); + + dict.Add(init); + } + + return dict; + }); + } + + public ActorReference(string type, TypeDictionary inits) + { + Type = type; + initDict = new Lazy(() => + { + var dict = new TypeDictionary(); + foreach (var i in inits) + dict.Add(i); return dict; }); } - static IActorInit LoadInit(string traitName, MiniYaml my) + static ActorInit LoadInit(string initName, MiniYaml initYaml) { - var info = Game.CreateObject(traitName + "Init"); - FieldLoader.Load(info, my); - return info; + var initInstance = initName.Split(ActorInfo.TraitInstanceSeparator); + var type = Game.ModData.ObjectCreator.FindType(initInstance[0] + "Init"); + if (type == null) + throw new InvalidDataException("Unknown initializer type '{0}Init'".F(initInstance[0])); + + var init = (ActorInit)FormatterServices.GetUninitializedObject(type); + if (initInstance.Length > 1) + type.GetField("InstanceName").SetValue(init, initInstance[1]); + + var loader = type.GetMethod("Initialize", new[] { typeof(MiniYaml) }); + if (loader == null) + throw new InvalidDataException("{0}Init does not define a yaml-assignable type.".F(initInstance[0])); + + loader.Invoke(init, new[] { initYaml }); + return init; } - public MiniYaml Save(Func initFilter = null) + public MiniYaml Save(Func initFilter = null) { var ret = new MiniYaml(Type); - foreach (var init in InitDict) + foreach (var o in initDict.Value) { - if (init is ISuppressInitExport) + var init = o as ActorInit; + if (init == null || o is ISuppressInitExport) continue; if (initFilter != null && !initFilter(init)) continue; - var initName = init.GetType().Name; - ret.Nodes.Add(new MiniYamlNode(initName.Substring(0, initName.Length - 4), FieldSaver.Save(init))); + var initTypeName = init.GetType().Name; + var initName = initTypeName.Substring(0, initTypeName.Length - 4); + if (!string.IsNullOrEmpty(init.InstanceName)) + initName += ActorInfo.TraitInstanceSeparator + init.InstanceName; + + ret.Nodes.Add(new MiniYamlNode(initName, init.Save())); } return ret; } - // for initialization syntax - public void Add(object o) { InitDict.Add(o); } - public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); } + public IEnumerator GetEnumerator() { return initDict.Value.GetEnumerator(); } public ActorReference Clone() { var clone = new ActorReference(Type); - foreach (var init in InitDict) - clone.InitDict.Add(init); + foreach (var init in initDict.Value) + clone.initDict.Value.Add(init); return clone; } + + public void Add(ActorInit init) + { + if (init is ISingleInstanceInit && InitDict.Contains(init.GetType())) + throw new InvalidDataException("Duplicate initializer '{0}'".F(init.GetType().Name)); + + InitDict.Add(init); + } + + public void Remove(ActorInit o) { initDict.Value.Remove(o); } + + public int RemoveAll() where T : ActorInit + { + var removed = 0; + foreach (var o in initDict.Value.WithInterface().ToList()) + { + removed++; + initDict.Value.Remove(o); + } + + return removed; + } + + public IEnumerable GetAll() where T : ActorInit + { + return initDict.Value.WithInterface(); + } + + public T GetOrDefault(TraitInfo info) where T : ActorInit + { + var inits = initDict.Value.WithInterface(); + + // Traits tagged with an instance name prefer inits with the same name. + // If a more specific init is not available, fall back to an unnamed init. + // If duplicate inits are defined, take the last to match standard yaml override expectations + if (info != null && !string.IsNullOrEmpty(info.InstanceName)) + return inits.LastOrDefault(i => i.InstanceName == info.InstanceName) ?? + inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName)); + + // Untagged traits will only use untagged inits + return inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName)); + } + + public T Get(TraitInfo info) where T : ActorInit + { + var init = GetOrDefault(info); + if (init == null) + throw new InvalidOperationException("TypeDictionary does not contain instance of type `{0}`".F(typeof(T))); + + return init; + } + + public U GetValue(TraitInfo info) where T : ValueActorInit + { + return Get(info).Value; + } + + public U GetValue(TraitInfo info, U fallback) where T : ValueActorInit + { + var init = GetOrDefault(info); + return init != null ? init.Value : fallback; + } + + public bool Contains(TraitInfo info) where T : ActorInit { return GetOrDefault(info) != null; } + + public T GetOrDefault() where T : ActorInit, ISingleInstanceInit + { + return initDict.Value.GetOrDefault(); + } + + public T Get() where T : ActorInit, ISingleInstanceInit + { + return initDict.Value.Get(); + } + + public U GetValue() where T : ValueActorInit, ISingleInstanceInit + { + return Get().Value; + } + + public U GetValue(U fallback) where T : ValueActorInit, ISingleInstanceInit + { + var init = GetOrDefault(); + return init != null ? init.Value : fallback; + } + + public bool Contains() where T : ActorInit, ISingleInstanceInit { return GetOrDefault() != null; } } } diff -Nru openra-20200503/OpenRA.Game/Map/CellLayerBase.cs openra-20210321/OpenRA.Game/Map/CellLayerBase.cs --- openra-20200503/OpenRA.Game/Map/CellLayerBase.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/CellLayerBase.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,63 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using OpenRA.Primitives; + +namespace OpenRA +{ + public abstract class CellLayerBase : IEnumerable + { + public readonly Size Size; + public readonly MapGridType GridType; + + protected readonly T[] entries; + protected readonly Rectangle bounds; + + public CellLayerBase(Map map) + : this(map.Grid.Type, new Size(map.MapSize.X, map.MapSize.Y)) { } + + public CellLayerBase(MapGridType gridType, Size size) + { + Size = size; + bounds = new Rectangle(0, 0, Size.Width, Size.Height); + GridType = gridType; + entries = new T[size.Width * size.Height]; + } + + public virtual void CopyValuesFrom(CellLayerBase anotherLayer) + { + if (Size != anotherLayer.Size || GridType != anotherLayer.GridType) + throw new ArgumentException("Layers must have a matching size and shape (grid type).", "anotherLayer"); + + Array.Copy(anotherLayer.entries, entries, entries.Length); + } + + /// Clears the layer contents with a known value + public void Clear(T clearValue) + { + for (var i = 0; i < entries.Length; i++) + entries[i] = clearValue; + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)entries).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff -Nru openra-20200503/OpenRA.Game/Map/CellLayer.cs openra-20210321/OpenRA.Game/Map/CellLayer.cs --- openra-20200503/OpenRA.Game/Map/CellLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/CellLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,42 +10,28 @@ #endregion using System; -using System.Collections; -using System.Collections.Generic; using OpenRA.Primitives; namespace OpenRA { // Represents a layer of "something" that covers the map - public class CellLayer : IEnumerable + public sealed class CellLayer : CellLayerBase { - public readonly Size Size; - readonly Rectangle bounds; - public readonly MapGridType GridType; public event Action CellEntryChanged = null; - readonly T[] entries; - public CellLayer(Map map) - : this(map.Grid.Type, new Size(map.MapSize.X, map.MapSize.Y)) { } + : base(map) { } public CellLayer(MapGridType gridType, Size size) - { - Size = size; - bounds = new Rectangle(0, 0, Size.Width, Size.Height); - GridType = gridType; - entries = new T[size.Width * size.Height]; - } + : base(gridType, size) { } - public void CopyValuesFrom(CellLayer anotherLayer) + public override void CopyValuesFrom(CellLayerBase anotherLayer) { - if (Size != anotherLayer.Size || GridType != anotherLayer.GridType) - throw new ArgumentException( - "layers must have a matching size and shape (grid type).", "anotherLayer"); if (CellEntryChanged != null) throw new InvalidOperationException( "Cannot copy values when there are listeners attached to the CellEntryChanged event."); - Array.Copy(anotherLayer.entries, entries, entries.Length); + + base.CopyValuesFrom(anotherLayer); } public static CellLayer CreateInstance(Func initialCellValueFactory, Size size, MapGridType mapGridType) @@ -87,8 +73,7 @@ { entries[Index(cell)] = value; - if (CellEntryChanged != null) - CellEntryChanged(cell); + CellEntryChanged?.Invoke(cell); } } @@ -104,28 +89,10 @@ { entries[Index(uv)] = value; - if (CellEntryChanged != null) - CellEntryChanged(uv.ToCPos(GridType)); + CellEntryChanged?.Invoke(uv.ToCPos(GridType)); } } - /// Clears the layer contents with a known value - public void Clear(T clearValue) - { - for (var i = 0; i < entries.Length; i++) - entries[i] = clearValue; - } - - public IEnumerator GetEnumerator() - { - return ((IEnumerable)entries).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - public bool Contains(CPos cell) { // .ToMPos() returns the same result if the X and Y coordinates diff -Nru openra-20200503/OpenRA.Game/Map/CellRegion.cs openra-20210321/OpenRA.Game/Map/CellRegion.cs --- openra-20200503/OpenRA.Game/Map/CellRegion.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/CellRegion.cs 2021-03-21 11:10:05.000000000 +0000 @@ -117,7 +117,7 @@ return GetEnumerator(); } - public sealed class CellRegionEnumerator : IEnumerator + public struct CellRegionEnumerator : IEnumerator { readonly CellRegion r; @@ -128,9 +128,11 @@ CPos current; public CellRegionEnumerator(CellRegion region) + : this() { r = region; Reset(); + current = new MPos(u, v).ToCPos(r.gridType); } public bool MoveNext() diff -Nru openra-20200503/OpenRA.Game/Map/MapCache.cs openra-20210321/OpenRA.Game/Map/MapCache.cs --- openra-20200503/OpenRA.Game/Map/MapCache.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/MapCache.cs 2021-03-21 11:10:05.000000000 +0000 @@ -38,6 +38,8 @@ object syncRoot = new object(); Queue generateMinimap = new Queue(); + public Dictionary StringPool { get; } = new Dictionary(); + public MapCache(ModData modData) { this.modData = modData; @@ -70,13 +72,10 @@ try { // HACK: If the path is inside the the support directory then we may need to create it - if (Platform.IsPathRelativeToSupportDirectory(name)) - { - // Assume that the path is a directory if there is not an existing file with the same name - var resolved = Platform.ResolvePath(name); - if (!File.Exists(resolved)) - Directory.CreateDirectory(resolved); - } + // Assume that the path is a directory if there is not an existing file with the same name + var resolved = Platform.ResolvePath(name); + if (resolved.StartsWith(Platform.SupportDir) && !File.Exists(resolved)) + Directory.CreateDirectory(resolved); package = modData.ModFiles.OpenPackage(name); } @@ -111,8 +110,7 @@ } catch (Exception e) { - if (mapPackage != null) - mapPackage.Dispose(); + mapPackage?.Dispose(); Console.WriteLine("Failed to load map: {0}", map); Console.WriteLine("Details: {0}", e); Log.Write("debug", "Failed to load map: {0}", map); @@ -131,8 +129,7 @@ // Enumerate map directories foreach (var kv in modData.Manifest.MapFolders) { - MapClassification packageClassification; - if (!Enum.TryParse(kv.Value, out packageClassification)) + if (!Enum.TryParse(kv.Value, out MapClassification packageClassification)) continue; if (!classification.HasFlag(packageClassification)) @@ -144,12 +141,9 @@ name = name.Substring(1); // Don't try to open the map directory in the support directory if it doesn't exist - if (Platform.IsPathRelativeToSupportDirectory(name)) - { - var resolved = Platform.ResolvePath(name); - if (!Directory.Exists(resolved) || !File.Exists(resolved)) - continue; - } + var resolved = Platform.ResolvePath(name); + if (resolved.StartsWith(Platform.SupportDir) && (!Directory.Exists(resolved) || !File.Exists(resolved))) + continue; using (var package = (IReadWritePackage)modData.ModFiles.OpenPackage(name)) { @@ -172,6 +166,7 @@ public void QueryRemoteMapDetails(string repositoryUrl, IEnumerable uids, Action mapDetailsReceived = null, Action queryFailed = null) { var maps = uids.Distinct() + .Where(uid => uid != null) .Select(uid => previews[uid]) .Where(p => p.Status == MapStatus.Unavailable) .ToDictionary(p => p.Uid, p => p); @@ -193,8 +188,7 @@ foreach (var p in maps.Values) p.UpdateRemoteSearch(MapStatus.Unavailable, null); - if (queryFailed != null) - queryFailed(); + queryFailed?.Invoke(); return; } @@ -214,8 +208,7 @@ { Log.Write("debug", "Can't parse remote map search data:\n{0}", data); Log.Write("debug", "Exception: {0}", e); - if (queryFailed != null) - queryFailed(); + queryFailed?.Invoke(); } }; @@ -299,8 +292,7 @@ Game.RunAfterTick(() => { // Wait for any existing thread to exit before starting a new one. - if (previewLoaderThread != null) - previewLoaderThread.Join(); + previewLoaderThread?.Join(); previewLoaderThread = new Thread(LoadAsyncInternal) { diff -Nru openra-20200503/OpenRA.Game/Map/Map.cs openra-20210321/OpenRA.Game/Map/Map.cs --- openra-20200503/OpenRA.Game/Map/Map.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/Map.cs 2021-03-21 11:10:05.000000000 +0000 @@ -230,9 +230,10 @@ public CellLayer Tiles { get; private set; } public CellLayer Resources { get; private set; } public CellLayer Height { get; private set; } + public CellLayer Ramp { get; private set; } public CellLayer CustomTerrain { get; private set; } - public ProjectedCellRegion ProjectedCellBounds { get; private set; } + public PPos[] ProjectedCells { get; private set; } public CellRegion AllCells { get; private set; } public List AllEdgeCells { get; private set; } @@ -301,10 +302,12 @@ Tiles = new CellLayer(Grid.Type, size); Resources = new CellLayer(Grid.Type, size); Height = new CellLayer(Grid.Type, size); + Ramp = new CellLayer(Grid.Type, size); if (Grid.MaximumTerrainHeight > 0) { Height.CellEntryChanged += UpdateProjection; Tiles.CellEntryChanged += UpdateProjection; + Tiles.CellEntryChanged += UpdateRamp; } Tiles.Clear(tileRef); @@ -328,6 +331,9 @@ throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, package.Name)); PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players"); + if (PlayerDefinitions.Count > 64) + throw new InvalidDataException("Maps must not define more than 64 players.\n File: {0}".F(package.Name)); + ActorDefinitions = MiniYaml.NodesOrEmpty(yaml, "Actors"); Grid = modData.Manifest.Get(); @@ -336,6 +342,7 @@ Tiles = new CellLayer(Grid.Type, size); Resources = new CellLayer(Grid.Type, size); Height = new CellLayer(Grid.Type, size); + Ramp = new CellLayer(Grid.Type, size); using (var s = Package.GetStream("map.bin")) { @@ -384,6 +391,7 @@ if (Grid.MaximumTerrainHeight > 0) { + Tiles.CellEntryChanged += UpdateRamp; Tiles.CellEntryChanged += UpdateProjection; Height.CellEntryChanged += UpdateProjection; } @@ -422,9 +430,23 @@ foreach (var uv in AllCells.MapCoords) CustomTerrain[uv] = byte.MaxValue; + // Cache initial ramp state + var tileset = Rules.TileSet; + foreach (var uv in AllCells) + { + var tile = tileset.GetTileInfo(Tiles[uv]); + Ramp[uv] = tile != null ? tile.RampType : (byte)0; + } + AllEdgeCells = UpdateEdgeCells(); } + void UpdateRamp(CPos cell) + { + var tile = Rules.TileSet.GetTileInfo(Tiles[cell]); + Ramp[cell] = tile != null ? tile.RampType : (byte)0; + } + void InitializeCellProjection() { if (initializedCellProjection) @@ -531,12 +553,8 @@ return new[] { (PPos)uv }; // Odd-height ramps get bumped up a level to the next even height layer - if ((height & 1) == 1) - { - var ti = Rules.TileSet.GetTileInfo(Tiles[uv]); - if (ti != null && ti.RampType != 0) - height += 1; - } + if ((height & 1) == 1 && Ramp[uv] != 0) + height += 1; var candidates = new List(); @@ -647,12 +665,40 @@ return dataStream.ToArray(); } + public (Color Left, Color Right) GetTerrainColorPair(MPos uv) + { + Color left, right; + var tileset = Rules.TileSet; + var type = tileset.GetTileInfo(Tiles[uv]); + if (type != null) + { + if (type.MinColor != type.MaxColor) + { + left = Exts.ColorLerp(Game.CosmeticRandom.NextFloat(), type.MinColor, type.MaxColor); + right = Exts.ColorLerp(Game.CosmeticRandom.NextFloat(), type.MinColor, type.MaxColor); + } + else + left = right = type.MinColor; + + if (tileset.MinHeightColorBrightness != 1.0f || tileset.MaxHeightColorBrightness != 1.0f) + { + var scale = float2.Lerp(tileset.MinHeightColorBrightness, tileset.MaxHeightColorBrightness, Height[uv] * 1f / Grid.MaximumTerrainHeight); + left = Color.FromArgb((int)(scale * left.R).Clamp(0, 255), (int)(scale * left.G).Clamp(0, 255), (int)(scale * left.B).Clamp(0, 255)); + right = Color.FromArgb((int)(scale * right.R).Clamp(0, 255), (int)(scale * right.G).Clamp(0, 255), (int)(scale * right.B).Clamp(0, 255)); + } + } + else + left = right = Color.Black; + + return (left, right); + } + public byte[] SavePreview() { var tileset = Rules.TileSet; var actorTypes = Rules.Actors.Values.Where(a => a.HasTraitInfo()); var actors = ActorDefinitions.Where(a => actorTypes.Where(ai => ai.Name == a.Value.Value).Any()); - var positions = new List>(); + var positions = new List<(MPos Position, Color Color)>(); foreach (var actor in actors) { var s = new ActorReference(actor.Value.Value, actor.Value.ToDictionary()); @@ -686,24 +732,18 @@ var stride = bitmapWidth * 4; var pxStride = 4; var minimapData = new byte[stride * height]; - Color leftColor, rightColor; + (Color Left, Color Right) terrainColor = default((Color, Color)); + for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var uv = new MPos(x + Bounds.Left, y + Bounds.Top); - var actorsThere = positions.Where(ap => ap.First == uv); - if (actorsThere.Any()) - { - leftColor = rightColor = actorsThere.First().Second; - } - else - { - // Cell contains terrain - var type = tileset.GetTileInfo(Tiles[uv]); - leftColor = type != null ? type.LeftColor : Color.Black; - rightColor = type != null ? type.RightColor : Color.Black; - } + + // FirstOrDefault will return a (MPos.Zero, Color.Transparent) if positions is empty + var actorColor = positions.FirstOrDefault(ap => ap.Position == uv).Color; + if (actorColor.A == 0) + terrainColor = GetTerrainColorPair(uv); if (isRectangularIsometric) { @@ -713,28 +753,31 @@ if (x + dx > 0) { var z = y * stride + xOffset - pxStride; - minimapData[z++] = leftColor.R; - minimapData[z++] = leftColor.G; - minimapData[z++] = leftColor.B; - minimapData[z++] = leftColor.A; + var c = actorColor.A == 0 ? terrainColor.Left : actorColor; + minimapData[z++] = c.R; + minimapData[z++] = c.G; + minimapData[z++] = c.B; + minimapData[z] = c.A; } if (xOffset < stride) { var z = y * stride + xOffset; - minimapData[z++] = rightColor.R; - minimapData[z++] = rightColor.G; - minimapData[z++] = rightColor.B; - minimapData[z++] = rightColor.A; + var c = actorColor.A == 0 ? terrainColor.Right : actorColor; + minimapData[z++] = c.R; + minimapData[z++] = c.G; + minimapData[z++] = c.B; + minimapData[z] = c.A; } } else { var z = y * stride + pxStride * x; - minimapData[z++] = leftColor.R; - minimapData[z++] = leftColor.G; - minimapData[z++] = leftColor.B; - minimapData[z++] = leftColor.A; + var c = actorColor.A == 0 ? terrainColor.Left : actorColor; + minimapData[z++] = c.R; + minimapData[z++] = c.G; + minimapData[z++] = c.B; + minimapData[z] = c.A; } } } @@ -770,8 +813,9 @@ bool ContainsAllProjectedCellsCovering(MPos uv) { + // PERF: Checking the bounds directly here is the same as calling Contains((PPos)uv) but saves an allocation if (Grid.MaximumTerrainHeight == 0) - return Contains((PPos)uv); + return Bounds.Contains(uv.U, uv.V); // If the cell has no valid projection, then we're off the map. var projectedCells = ProjectedCellsCovering(uv); @@ -781,6 +825,7 @@ foreach (var puv in projectedCells) if (!Contains(puv)) return false; + return true; } @@ -805,7 +850,7 @@ // (c) u, v coordinates run diagonally to the cell axes, and we define // 1024 as the length projected onto the primary cell axis // - 512 * sqrt(2) = 724 - var z = Height.Contains(cell) ? 724 * Height[cell] : 0; + var z = Height.Contains(cell) ? 724 * Height[cell] + Grid.Ramps[Ramp[cell]].CenterHeightOffset : 0; return new WPos(724 * (cell.X - cell.Y + 1), 724 * (cell.X + cell.Y + 1), z); } @@ -813,15 +858,42 @@ { var index = (int)subCell; if (index >= 0 && index < Grid.SubCellOffsets.Length) - return CenterOfCell(cell) + Grid.SubCellOffsets[index]; + { + var center = CenterOfCell(cell); + var offset = Grid.SubCellOffsets[index]; + var ramp = Ramp.Contains(cell) ? Ramp[cell] : 0; + if (ramp != 0) + { + var r = Grid.Ramps[ramp]; + offset += new WVec(0, 0, r.HeightOffset(offset.X, offset.Y) - r.CenterHeightOffset); + } + + return center + offset; + } + return CenterOfCell(cell); } public WDist DistanceAboveTerrain(WPos pos) { + if (Grid.Type == MapGridType.Rectangular) + return new WDist(pos.Z); + + // Apply ramp offset var cell = CellContaining(pos); - var delta = pos - CenterOfCell(cell); - return new WDist(delta.Z); + var offset = pos - CenterOfCell(cell); + + if (!Ramp.Contains(cell)) + return new WDist(offset.Z); + + var ramp = Ramp[cell]; + if (ramp != 0) + { + var r = Grid.Ramps[ramp]; + return new WDist(offset.Z + r.CenterHeightOffset - r.HeightOffset(offset.X, offset.Y)); + } + + return new WDist(offset.Z); } public WVec Offset(CVec delta, int dz) @@ -899,13 +971,13 @@ return projectedHeight[(MPos)puv]; } - public int FacingBetween(CPos cell, CPos towards, int fallbackfacing) + public WAngle FacingBetween(CPos cell, CPos towards, WAngle fallbackfacing) { var delta = CenterOfCell(towards) - CenterOfCell(cell); if (delta.HorizontalLengthSquared == 0) return fallbackfacing; - return delta.Yaw.Facing; + return delta.Yaw; } public void Resize(int width, int height) @@ -913,11 +985,13 @@ var oldMapTiles = Tiles; var oldMapResources = Resources; var oldMapHeight = Height; + var oldMapRamp = Ramp; var newSize = new Size(width, height); Tiles = CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[MPos.Zero]); Resources = CellLayer.Resize(oldMapResources, newSize, oldMapResources[MPos.Zero]); Height = CellLayer.Resize(oldMapHeight, newSize, oldMapHeight[MPos.Zero]); + Ramp = CellLayer.Resize(oldMapRamp, newSize, oldMapRamp[MPos.Zero]); MapSize = new int2(newSize); var tl = new MPos(0, 0); @@ -947,7 +1021,8 @@ ProjectedBottomRight = new WPos(br.U * 1024 - 1, (br.V + 1) * 1024 - 1, 0); } - ProjectedCellBounds = new ProjectedCellRegion(this, tl, br); + // PERF: This enumeration isn't going to change during the game + ProjectedCells = new ProjectedCellRegion(this, tl, br).ToArray(); } public void FixOpenAreas() @@ -1210,16 +1285,12 @@ throw new ArgumentOutOfRangeException("maxRange", "The requested range ({0}) cannot exceed the value of MaximumTileSearchRange ({1})".F(maxRange, Grid.MaximumTileSearchRange)); - Func valid = Contains; - if (allowOutsideBounds) - valid = Tiles.Contains; - for (var i = minRange; i <= maxRange; i++) { foreach (var offset in Grid.TilesByDistance[i]) { var t = offset + center; - if (valid(t)) + if (allowOutsideBounds ? Tiles.Contains(t) : Contains(t)) yield return t; } } diff -Nru openra-20200503/OpenRA.Game/Map/MapGrid.cs openra-20210321/OpenRA.Game/Map/MapGrid.cs --- openra-20200503/OpenRA.Game/Map/MapGrid.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/MapGrid.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -20,6 +19,85 @@ { public enum MapGridType { Rectangular, RectangularIsometric } + public enum RampSplit { Flat, X, Y } + public enum RampCornerHeight { Low = 0, Half = 1, Full = 2 } + + public struct CellRamp + { + public readonly int CenterHeightOffset; + public readonly WVec[] Corners; + public readonly WVec[][] Polygons; + + public CellRamp(MapGridType type, RampCornerHeight tl = RampCornerHeight.Low, RampCornerHeight tr = RampCornerHeight.Low, RampCornerHeight br = RampCornerHeight.Low, RampCornerHeight bl = RampCornerHeight.Low, RampSplit split = RampSplit.Flat) + { + if (type == MapGridType.RectangularIsometric) + { + Corners = new[] + { + new WVec(0, -724, 724 * (int)tl), + new WVec(724, 0, 724 * (int)tr), + new WVec(0, 724, 724 * (int)br), + new WVec(-724, 0, 724 * (int)bl), + }; + } + else + { + Corners = new[] + { + new WVec(-512, -512, 512 * (int)tl), + new WVec(512, -512, 512 * (int)tr), + new WVec(512, 512, 512 * (int)br), + new WVec(-512, 512, 512 * (int)bl) + }; + } + + if (split == RampSplit.X) + { + Polygons = new[] + { + new[] { Corners[0], Corners[1], Corners[3] }, + new[] { Corners[1], Corners[2], Corners[3] } + }; + } + else if (split == RampSplit.Y) + { + Polygons = new[] + { + new[] { Corners[0], Corners[1], Corners[2] }, + new[] { Corners[0], Corners[2], Corners[3] } + }; + } + else + Polygons = new[] { Corners }; + + // Initial value must be asigned before HeightOffset can be called + CenterHeightOffset = 0; + CenterHeightOffset = HeightOffset(0, 0); + } + + public int HeightOffset(int dX, int dY) + { + // Enumerate over the polygons, assuming that they are triangles + // If the ramp is not split we will take the first three vertices of the corners as a valid triangle + WVec[] p = null; + var u = 0; + var v = 0; + for (var i = 0; i < Polygons.Length; i++) + { + p = Polygons[i]; + u = ((p[1].Y - p[2].Y) * (dX - p[2].X) - (p[1].X - p[2].X) * (dY - p[2].Y)) / 1024; + v = ((p[0].X - p[2].X) * (dY - p[2].Y) - (p[0].Y - p[2].Y) * (dX - p[2].X)) / 1024; + + // Point is within the triangle if 0 <= u,v <= 1024 + if (u >= 0 && u <= 1024 && v >= 0 && v <= 1024) + break; + } + + // Calculate w from u,v and interpolate height + return (u * p[0].Z + v * p[1].Z + (1024 - u - v) * p[2].Z) / 1024; + } + } + public class MapGrid : IGlobalModData { public readonly MapGridType Type = MapGridType.Rectangular; @@ -41,43 +119,7 @@ new WVec(256, 256, 0), // bottom right - index 5 }; - public WVec[][] CellCorners { get; private set; } - - readonly int[][] cellCornerHalfHeights = new int[][] - { - // Flat - new[] { 0, 0, 0, 0 }, - - // Slopes (two corners high) - new[] { 0, 0, 1, 1 }, - new[] { 1, 0, 0, 1 }, - new[] { 1, 1, 0, 0 }, - new[] { 0, 1, 1, 0 }, - - // Slopes (one corner high) - new[] { 0, 0, 0, 1 }, - new[] { 1, 0, 0, 0 }, - new[] { 0, 1, 0, 0 }, - new[] { 0, 0, 1, 0 }, - - // Slopes (three corners high) - new[] { 1, 0, 1, 1 }, - new[] { 1, 1, 0, 1 }, - new[] { 1, 1, 1, 0 }, - new[] { 0, 1, 1, 1 }, - - // Slopes (two corners high, one corner double high) - new[] { 1, 0, 1, 2 }, - new[] { 2, 1, 0, 1 }, - new[] { 1, 2, 1, 0 }, - new[] { 0, 1, 2, 1 }, - - // Slopes (two corners high, alternating) - new[] { 1, 0, 1, 0 }, - new[] { 0, 1, 0, 1 }, - new[] { 1, 0, 1, 0 }, - new[] { 0, 1, 0, 1 } - }; + public CellRamp[] Ramps { get; private set; } internal readonly CVec[][] TilesByDistance; @@ -96,32 +138,44 @@ throw new InvalidDataException("Subcell default index must be a valid index into the offset triples and must be greater than 0 for mods with subcells"); } - var makeCorners = Type == MapGridType.RectangularIsometric ? - (Func)IsometricCellCorners : RectangularCellCorners; - CellCorners = cellCornerHalfHeights.Select(makeCorners).ToArray(); - TilesByDistance = CreateTilesByDistance(); - } - - static WVec[] IsometricCellCorners(int[] cornerHeight) - { - return new WVec[] + // Slope types are hardcoded following the convention from the TS and RA2 map format + Ramps = new[] { - new WVec(-724, 0, 724 * cornerHeight[0]), - new WVec(0, -724, 724 * cornerHeight[1]), - new WVec(724, 0, 724 * cornerHeight[2]), - new WVec(0, 724, 724 * cornerHeight[3]) - }; - } + // Flat + new CellRamp(Type), - static WVec[] RectangularCellCorners(int[] cornerHeight) - { - return new WVec[] - { - new WVec(-512, -512, 512 * cornerHeight[0]), - new WVec(512, -512, 512 * cornerHeight[1]), - new WVec(512, 512, 512 * cornerHeight[2]), - new WVec(-512, 512, 512 * cornerHeight[3]) + // Two adjacent corners raised by half a cell + new CellRamp(Type, tr: RampCornerHeight.Half, br: RampCornerHeight.Half), + new CellRamp(Type, br: RampCornerHeight.Half, bl: RampCornerHeight.Half), + new CellRamp(Type, tl: RampCornerHeight.Half, bl: RampCornerHeight.Half), + new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Half), + + // One corner raised by half a cell + new CellRamp(Type, br: RampCornerHeight.Half, split: RampSplit.X), + new CellRamp(Type, bl: RampCornerHeight.Half, split: RampSplit.Y), + new CellRamp(Type, tl: RampCornerHeight.Half, split: RampSplit.X), + new CellRamp(Type, tr: RampCornerHeight.Half, split: RampSplit.Y), + + // Three corners raised by half a cell + new CellRamp(Type, tr: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X), + new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y), + new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X), + new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y), + + // Full tile sloped (mid corners raised by half cell, far corner by full cell) + new CellRamp(Type, tr: RampCornerHeight.Half, br: RampCornerHeight.Full, bl: RampCornerHeight.Half), + new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Full), + new CellRamp(Type, tl: RampCornerHeight.Full, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half), + new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Full, br: RampCornerHeight.Half), + + // Two opposite corners raised by half a cell + new CellRamp(Type, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y), + new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y), + new CellRamp(Type, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X), + new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.X), }; + + TilesByDistance = CreateTilesByDistance(); } CVec[][] CreateTilesByDistance() diff -Nru openra-20200503/OpenRA.Game/Map/MapPreview.cs openra-20210321/OpenRA.Game/Map/MapPreview.cs --- openra-20200503/OpenRA.Game/Map/MapPreview.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/MapPreview.cs 2021-03-21 11:10:05.000000000 +0000 @@ -89,7 +89,7 @@ public bool DefinesUnsafeCustomRules { get; private set; } public bool RulesLoaded { get; private set; } - public void SetRulesetGenerator(ModData modData, Func> generator) + public void SetRulesetGenerator(ModData modData, Func<(Ruleset Ruleset, bool DefinesUnsafeCustomRules)> generator) { InvalidCustomRules = false; RulesLoaded = false; @@ -106,8 +106,8 @@ try { var ret = generator(); - DefinesUnsafeCustomRules = ret.Second; - return ret.First; + DefinesUnsafeCustomRules = ret.DefinesUnsafeCustomRules; + return ret.Ruleset; } catch (Exception e) { @@ -223,7 +223,7 @@ if (yamlStream == null) throw new FileNotFoundException("Required file map.yaml not present in this map"); - yaml = new MiniYaml(null, MiniYaml.FromStream(yamlStream, "map.yaml")).ToDictionary(); + yaml = new MiniYaml(null, MiniYaml.FromStream(yamlStream, "map.yaml", stringPool: cache.StringPool)).ToDictionary(); } Package = p; @@ -233,8 +233,7 @@ newData.GridType = gridType; newData.Class = classification; - MiniYaml temp; - if (yaml.TryGetValue("MapFormat", out temp)) + if (yaml.TryGetValue("MapFormat", out var temp)) { var format = FieldLoader.GetValue("MapFormat", temp.Value); if (format != Map.SupportedMapFormat) @@ -269,14 +268,13 @@ try { // Actor definitions may change if the map format changes - MiniYaml actorDefinitions; - if (yaml.TryGetValue("Actors", out actorDefinitions)) + if (yaml.TryGetValue("Actors", out var actorDefinitions)) { var spawns = new List(); foreach (var kv in actorDefinitions.Nodes.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); - spawns.Add(s.InitDict.Get().Value(null)); + spawns.Add(s.Get().Value); } newData.SpawnPoints = spawns.ToArray(); @@ -293,8 +291,7 @@ try { // Player definitions may change if the map format changes - MiniYaml playerDefinitions; - if (yaml.TryGetValue("Players", out playerDefinitions)) + if (yaml.TryGetValue("Players", out var playerDefinitions)) { newData.Players = new MapPlayers(playerDefinitions.Nodes); newData.PlayerCount = newData.Players.Players.Count(x => x.Value.Playable); @@ -318,7 +315,7 @@ voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions, modelSequenceDefinitions); var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions); - return Pair.New(rules, flagged); + return (rules, flagged); }); if (p.Contains("map.png")) @@ -331,8 +328,7 @@ MiniYaml LoadRuleSection(Dictionary yaml, string section) { - MiniYaml node; - if (!yaml.TryGetValue(section, out node)) + if (!yaml.TryGetValue(section, out var node)) return null; return node; @@ -402,7 +398,7 @@ voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions, modelSequenceDefinitions); var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions); - return Pair.New(rules, flagged); + return (rules, flagged); }); } catch (Exception e) @@ -416,8 +412,7 @@ if (innerData.Preview != null) cache.CacheMinimap(this); - if (parseMetadata != null) - parseMetadata(this); + parseMetadata?.Invoke(this); } // Update the status and class unconditionally @@ -526,9 +521,7 @@ public void Delete() { Invalidate(); - var deleteFromPackage = parentPackage as IReadWritePackage; - if (deleteFromPackage != null) - deleteFromPackage.Delete(Package.Name); + (parentPackage as IReadWritePackage)?.Delete(Package.Name); } Stream IReadOnlyFileSystem.Open(string filename) diff -Nru openra-20200503/OpenRA.Game/Map/PlayerReference.cs openra-20210321/OpenRA.Game/Map/PlayerReference.cs --- openra-20200503/OpenRA.Game/Map/PlayerReference.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/PlayerReference.cs 2021-03-21 11:10:05.000000000 +0000 @@ -30,14 +30,29 @@ public string Faction; public bool LockColor = false; - public Color Color = Color.FromAhsl(0, 0, 238); + public Color Color = Game.ModData.Manifest.Get().Color; + + /// + /// Sets the "Home" location, which can be used by traits and scripts to e.g. set the initial camera + /// location or choose the map edge for reinforcements. + /// This will usually be overridden for client (lobby slot) players with a location based on the Spawn index + /// + public CPos HomeLocation = CPos.Zero; public bool LockSpawn = false; + + /// + /// Sets the initial spawn point index that is used to override the "Home" location for client (lobby slot) players. + /// Map players always ignore this and use HomeLocation directly. + /// public int Spawn = 0; public bool LockTeam = false; public int Team = 0; + public bool LockHandicap = false; + public int Handicap = 0; + public string[] Allies = { }; public string[] Enemies = { }; diff -Nru openra-20200503/OpenRA.Game/Map/ProjectedCellLayer.cs openra-20210321/OpenRA.Game/Map/ProjectedCellLayer.cs --- openra-20200503/OpenRA.Game/Map/ProjectedCellLayer.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/ProjectedCellLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,62 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Primitives; + +namespace OpenRA +{ + public sealed class ProjectedCellLayer : CellLayerBase + { + public ProjectedCellLayer(Map map) + : base(map) { } + + public ProjectedCellLayer(MapGridType gridType, Size size) + : base(gridType, size) { } + + // Resolve an array index from map coordinates. + public int Index(PPos uv) + { + return uv.V * Size.Width + uv.U; + } + + public T this[int index] + { + get + { + return entries[index]; + } + + set + { + entries[index] = value; + } + } + + /// Gets or sets the layer contents using projected map coordinates. + public T this[PPos uv] + { + get + { + return entries[Index(uv)]; + } + + set + { + entries[Index(uv)] = value; + } + } + + public bool Contains(PPos uv) + { + return bounds.Contains(uv.U, uv.V); + } + } +} diff -Nru openra-20200503/OpenRA.Game/Map/ProjectedCellRegion.cs openra-20210321/OpenRA.Game/Map/ProjectedCellRegion.cs --- openra-20200503/OpenRA.Game/Map/ProjectedCellRegion.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/ProjectedCellRegion.cs 2021-03-21 11:10:05.000000000 +0000 @@ -76,7 +76,7 @@ return GetEnumerator(); } - public sealed class ProjectedCellRegionEnumerator : IEnumerator + public struct ProjectedCellRegionEnumerator : IEnumerator { readonly ProjectedCellRegion r; @@ -86,9 +86,11 @@ PPos current; public ProjectedCellRegionEnumerator(ProjectedCellRegion region) + : this() { r = region; Reset(); + current = new PPos(u, v); } public bool MoveNext() diff -Nru openra-20200503/OpenRA.Game/Map/TileSet.cs openra-20210321/OpenRA.Game/Map/TileSet.cs --- openra-20200503/OpenRA.Game/Map/TileSet.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Map/TileSet.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,9 +24,8 @@ public readonly byte TerrainType = byte.MaxValue; public readonly byte Height; public readonly byte RampType; - public readonly Color LeftColor; - public readonly Color RightColor; - + public readonly Color MinColor; + public readonly Color MaxColor; public readonly float ZOffset = 0.0f; public readonly float ZRamp = 1.0f; } @@ -55,13 +54,6 @@ readonly TerrainTileInfo[] tileInfo; - public TerrainTemplateInfo(ushort id, string[] images, int2 size, byte[] tiles) - { - Id = id; - Images = images; - Size = size; - } - public TerrainTemplateInfo(TileSet tileSet, MiniYaml my) { FieldLoader.Load(this, my); @@ -73,9 +65,11 @@ tileInfo = new TerrainTileInfo[Size.X * Size.Y]; foreach (var node in nodes) { - int key; - if (!int.TryParse(node.Key, out key) || key < 0 || key >= tileInfo.Length) - throw new InvalidDataException("Invalid tile key '{0}' on template '{1}' of tileset '{2}'.".F(node.Key, Id, tileSet.Id)); + if (!int.TryParse(node.Key, out var key)) + throw new YamlException("Tileset `{0}` template `{1}` defines a frame `{2}` that is not a valid integer.".F(tileSet.Id, Id, node.Key)); + + if (key < 0 || key >= tileInfo.Length) + throw new YamlException("Tileset `{0}` template `{1}` references frame {2}, but only [0..{3}] are valid for a {4}x{5} Size template.".F(tileSet.Id, Id, key, tileInfo.Length - 1, Size.X, Size.Y)); tileInfo[key] = LoadTileInfo(tileSet, node.Value); } @@ -87,9 +81,11 @@ var i = 0; foreach (var node in nodes) { - int key; - if (!int.TryParse(node.Key, out key) || key != i++) - throw new InvalidDataException("Invalid tile key '{0}' on template '{1}' of tileset '{2}'.".F(node.Key, Id, tileSet.Id)); + if (!int.TryParse(node.Key, out var key)) + throw new YamlException("Tileset `{0}` template `{1}` defines a frame `{2}` that is not a valid integer.".F(tileSet.Id, Id, node.Key)); + + if (key != i++) + throw new YamlException("Tileset `{0}` template `{1}` is missing a definition for frame {2}.".F(tileSet.Id, Id, i - 1)); tileInfo[key] = LoadTileInfo(tileSet, node.Value); } @@ -106,11 +102,11 @@ // Fall back to the terrain-type color if necessary var overrideColor = tileSet.TerrainInfo[tile.TerrainType].Color; - if (tile.LeftColor == default(Color)) - tile.GetType().GetField("LeftColor").SetValue(tile, overrideColor); + if (tile.MinColor == default(Color)) + tile.GetType().GetField("MinColor").SetValue(tile, overrideColor); - if (tile.RightColor == default(Color)) - tile.GetType().GetField("RightColor").SetValue(tile, overrideColor); + if (tile.MaxColor == default(Color)) + tile.GetType().GetField("MaxColor").SetValue(tile, overrideColor); return tile; } @@ -139,6 +135,8 @@ public readonly string[] EditorTemplateOrder; public readonly bool IgnoreTileSpriteOffsets; public readonly bool EnableDepth = false; + public readonly float MinHeightColorBrightness = 1.0f; + public readonly float MaxHeightColorBrightness = 1.0f; [FieldLoader.Ignore] public readonly IReadOnlyDictionary Templates; @@ -163,14 +161,14 @@ .ToArray(); if (TerrainInfo.Length >= byte.MaxValue) - throw new InvalidDataException("Too many terrain types."); + throw new YamlException("Too many terrain types."); for (byte i = 0; i < TerrainInfo.Length; i++) { var tt = TerrainInfo[i].Type; if (terrainIndexByType.ContainsKey(tt)) - throw new InvalidDataException("Duplicate terrain type '{0}' in '{1}'.".F(tt, filepath)); + throw new YamlException("Duplicate terrain type '{0}' in '{1}'.".F(tt, filepath)); terrainIndexByType.Add(tt, i); } @@ -215,8 +213,7 @@ public byte GetTerrainIndex(string type) { - byte index; - if (terrainIndexByType.TryGetValue(type, out index)) + if (terrainIndexByType.TryGetValue(type, out var index)) return index; throw new InvalidDataException("Tileset '{0}' lacks terrain type '{1}'".F(Id, type)); @@ -224,8 +221,7 @@ public byte GetTerrainIndex(TerrainTile r) { - TerrainTemplateInfo tpl; - if (!Templates.TryGetValue(r.Type, out tpl)) + if (!Templates.TryGetValue(r.Type, out var tpl)) return defaultWalkableTerrainIndex; if (tpl.Contains(r.Index)) @@ -240,8 +236,7 @@ public TerrainTileInfo GetTileInfo(TerrainTile r) { - TerrainTemplateInfo tpl; - if (!Templates.TryGetValue(r.Type, out tpl)) + if (!Templates.TryGetValue(r.Type, out var tpl)) return null; return tpl.Contains(r.Index) ? tpl[r.Index] : null; diff -Nru openra-20200503/OpenRA.Game/MiniYaml.cs openra-20210321/OpenRA.Game/MiniYaml.cs --- openra-20200503/OpenRA.Game/MiniYaml.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/MiniYaml.cs 2021-03-21 11:10:05.000000000 +0000 @@ -99,7 +99,10 @@ public MiniYaml Clone() { - return new MiniYaml(Value, Nodes.Select(n => n.Clone()).ToList()); + var clonedNodes = new MiniYamlNodes(Nodes.Count); + foreach (var node in Nodes) + clonedNodes.Add(node.Clone()); + return new MiniYaml(Value, clonedNodes); } public Dictionary ToDictionary() @@ -148,8 +151,11 @@ return nd.ContainsKey(s) ? nd[s].Nodes : new List(); } - static List FromLines(IEnumerable lines, string filename, bool discardCommentsAndWhitespace) + static List FromLines(IEnumerable lines, string filename, bool discardCommentsAndWhitespace, Dictionary stringPool) { + if (stringPool == null) + stringPool = new Dictionary(); + var levels = new List>(); levels.Add(new List()); @@ -263,6 +269,10 @@ if (key != null || !discardCommentsAndWhitespace) { + key = key == null ? null : stringPool.GetOrAdd(key, key); + value = value == null ? null : stringPool.GetOrAdd(value, value); + comment = comment == null ? null : stringPool.GetOrAdd(comment, comment); + var nodes = new List(); levels[level].Add(new MiniYamlNode(key, value, comment, nodes, location)); @@ -270,23 +280,33 @@ } } + foreach (var nodes in levels) + nodes.TrimExcess(); + return levels[0]; } - public static List FromFile(string path, bool discardCommentsAndWhitespace = true) + public static List FromFile(string path, bool discardCommentsAndWhitespace = true, Dictionary stringPool = null) { - return FromLines(File.ReadAllLines(path), path, discardCommentsAndWhitespace); + return FromLines(File.ReadAllLines(path), path, discardCommentsAndWhitespace, stringPool); } - public static List FromStream(Stream s, string fileName = "", bool discardCommentsAndWhitespace = true) + public static List FromStream(Stream s, string fileName = "", bool discardCommentsAndWhitespace = true, Dictionary stringPool = null) { + IEnumerable Lines(StreamReader reader) + { + string line; + while ((line = reader.ReadLine()) != null) + yield return line; + } + using (var reader = new StreamReader(s)) - return FromString(reader.ReadToEnd(), fileName, discardCommentsAndWhitespace); + return FromLines(Lines(reader), fileName, discardCommentsAndWhitespace, stringPool); } - public static List FromString(string text, string fileName = "", bool discardCommentsAndWhitespace = true) + public static List FromString(string text, string fileName = "", bool discardCommentsAndWhitespace = true, Dictionary stringPool = null) { - return FromLines(text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None), fileName, discardCommentsAndWhitespace); + return FromLines(text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None), fileName, discardCommentsAndWhitespace, stringPool); } public static List Merge(IEnumerable> sources) @@ -330,7 +350,7 @@ static List ResolveInherits(string key, MiniYaml node, Dictionary tree, Dictionary inherited) { - var resolved = new List(); + var resolved = new List(node.Nodes.Count); // Inheritance is tracked from parent->child, but not from child->parentsiblings. inherited = new Dictionary(inherited); @@ -339,8 +359,7 @@ { if (n.Key == "Inherits" || n.Key.StartsWith("Inherits@", StringComparison.Ordinal)) { - MiniYaml parent; - if (!tree.TryGetValue(n.Value.Value, out parent)) + if (!tree.TryGetValue(n.Value.Value, out var parent)) throw new YamlException( "{0}: Parent type `{1}` not found".F(n.Location, n.Value.Value)); @@ -362,6 +381,7 @@ MergeIntoResolved(n, resolved, tree, inherited); } + resolved.TrimExcess(); return resolved; } @@ -398,6 +418,7 @@ } } + ret.TrimExcess(); return ret; } @@ -428,9 +449,8 @@ foreach (var key in allKeys) { - MiniYamlNode existingNode, overrideNode; - existingDict.TryGetValue(key, out existingNode); - overrideDict.TryGetValue(key, out overrideNode); + existingDict.TryGetValue(key, out var existingNode); + overrideDict.TryGetValue(key, out var overrideNode); var loc = overrideNode == null ? default(MiniYamlNode.SourceLocation) : overrideNode.Location; var comment = (overrideNode ?? existingNode).Comment; @@ -439,6 +459,7 @@ ret.Add(merged); } + ret.TrimExcess(); return ret; } diff -Nru openra-20200503/OpenRA.Game/ModData.cs openra-20210321/OpenRA.Game/ModData.cs --- openra-20200503/OpenRA.Game/ModData.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/ModData.cs 2021-03-21 11:10:05.000000000 +0000 @@ -79,7 +79,6 @@ throw new InvalidOperationException("Unable to find a sequence loader for type '{0}'.".F(sequenceFormat.Type)); SpriteSequenceLoader = (ISpriteSequenceLoader)sequenceCtor.Invoke(new[] { this }); - SpriteSequenceLoader.OnMissingSpriteError = s => Log.Write("debug", s); var modelFormat = Manifest.Get(); var modelLoader = ObjectCreator.FindType(modelFormat.Type + "Loader"); @@ -108,7 +107,7 @@ defaultSequences = Exts.Lazy(() => { - var items = DefaultTileSets.ToDictionary(t => t.Key, t => new SequenceProvider(DefaultFileSystem, this, t.Value, null)); + var items = DefaultTileSets.ToDictionary(t => t.Key, t => new SequenceProvider(DefaultFileSystem, this, t.Key, null)); return (IReadOnlyDictionary)(new ReadOnlyDictionary(items)); }); @@ -177,8 +176,7 @@ public Map PrepareMap(string uid) { - if (LoadScreen != null) - LoadScreen.Display(); + LoadScreen?.Display(); if (MapCache[uid].Status != MapStatus.Available) throw new InvalidDataException("Invalid map uid: {0}".F(uid)); @@ -202,12 +200,12 @@ public void Dispose() { - if (LoadScreen != null) - LoadScreen.Dispose(); + LoadScreen?.Dispose(); MapCache.Dispose(); - if (ObjectCreator != null) - ObjectCreator.Dispose(); + ObjectCreator?.Dispose(); + + Manifest.Dispose(); } } diff -Nru openra-20200503/OpenRA.Game/Network/Connection.cs openra-20210321/OpenRA.Game/Network/Connection.cs --- openra-20200503/OpenRA.Game/Network/Connection.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/Connection.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,8 +10,11 @@ #endregion using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Net; using System.Net.Sockets; using System.Threading; using OpenRA.Server; @@ -30,12 +33,63 @@ { int LocalClientId { get; } ConnectionState ConnectionState { get; } + IPEndPoint EndPoint { get; } + string ErrorMessage { get; } void Send(int frame, List orders); void SendImmediate(IEnumerable orders); void SendSync(int frame, byte[] syncData); void Receive(Action packetFn); } + public class ConnectionTarget + { + readonly DnsEndPoint[] endpoints; + + public ConnectionTarget() + { + endpoints = new[] { new DnsEndPoint("invalid", 0) }; + } + + public ConnectionTarget(string host, int port) + { + endpoints = new[] { new DnsEndPoint(host, port) }; + } + + public ConnectionTarget(IEnumerable endpoints) + { + this.endpoints = endpoints.ToArray(); + if (this.endpoints.Length == 0) + { + throw new ArgumentException("ConnectionTarget must have at least one address."); + } + } + + public IEnumerable GetConnectEndPoints() + { + return endpoints + .SelectMany(e => + { + try + { + return Dns.GetHostAddresses(e.Host) + .Select(a => new IPEndPoint(a, e.Port)); + } + catch (Exception) + { + return Enumerable.Empty(); + } + }) + .ToList(); + } + + public override string ToString() + { + return endpoints + .Select(e => "{0}:{1}".F(e.Host, e.Port)) + .JoinWith("/"); + } + } + class EchoConnection : IConnection { protected struct ReceivedPacket @@ -57,6 +111,16 @@ get { return ConnectionState.PreConnecting; } } + public virtual IPEndPoint EndPoint + { + get { throw new NotSupportedException("An echo connection doesn't have an endpoint"); } + } + + public virtual string ErrorMessage + { + get { return null; } + } + public virtual void Send(int frame, List orders) { var ms = new MemoryStream(); @@ -110,23 +174,21 @@ foreach (var p in packets) { packetFn(p.FromClient, p.Data); - if (Recorder != null) - Recorder.Receive(p.FromClient, p.Data); + Recorder?.Receive(p.FromClient, p.Data); } } public void StartRecording(Func chooseFilename) { // If we have a previous recording then save/dispose it and start a new one. - if (Recorder != null) - Recorder.Dispose(); + Recorder?.Dispose(); Recorder = new ReplayRecorder(chooseFilename); } protected virtual void Dispose(bool disposing) { - if (disposing && Recorder != null) - Recorder.Dispose(); + if (disposing) + Recorder?.Dispose(); } public void Dispose() @@ -138,35 +200,100 @@ sealed class NetworkConnection : EchoConnection { - readonly TcpClient tcp; + readonly ConnectionTarget target; + TcpClient tcp; + IPEndPoint endpoint; readonly List queuedSyncPackets = new List(); volatile ConnectionState connectionState = ConnectionState.Connecting; volatile int clientId; bool disposed; + string errorMessage; + + public override IPEndPoint EndPoint { get { return endpoint; } } + + public override string ErrorMessage { get { return errorMessage; } } - public NetworkConnection(string host, int port) + public NetworkConnection(ConnectionTarget target) { - try + this.target = target; + new Thread(NetworkConnectionConnect) + { + Name = "{0} (connect to {1})".F(GetType().Name, target), + IsBackground = true + }.Start(); + } + + void NetworkConnectionConnect() + { + var queue = new BlockingCollection(); + + var atLeastOneEndpoint = false; + foreach (var endpoint in target.GetConnectEndPoints()) { - tcp = new TcpClient(host, port) { NoDelay = true }; + atLeastOneEndpoint = true; + new Thread(() => + { + try + { + var client = new TcpClient(endpoint.AddressFamily) { NoDelay = true }; + client.Connect(endpoint.Address, endpoint.Port); + + try + { + queue.Add(client); + } + catch (InvalidOperationException) + { + // Another connection was faster, close this one. + client.Close(); + } + } + catch (Exception ex) + { + errorMessage = "Failed to connect"; + Log.Write("client", "Failed to connect to {0}: {1}".F(endpoint, ex.Message)); + } + }) + { + Name = "{0} (connect to {1})".F(GetType().Name, endpoint), + IsBackground = true + }.Start(); + } + + if (!atLeastOneEndpoint) + { + errorMessage = "Failed to resolve address"; + connectionState = ConnectionState.NotConnected; + } + + // Wait up to 5s for a successful connection. This should hopefully be enough because such high latency makes the game unplayable anyway. + else if (queue.TryTake(out tcp, 5000)) + { + // Copy endpoint here to have it even after getting disconnected. + endpoint = (IPEndPoint)tcp.Client.RemoteEndPoint; + new Thread(NetworkConnectionReceive) { - Name = GetType().Name + " " + host + ":" + port, + Name = "{0} (receive from {1})".F(GetType().Name, tcp.Client.RemoteEndPoint), IsBackground = true - }.Start(tcp.GetStream()); + }.Start(); } - catch + else { connectionState = ConnectionState.NotConnected; } + + // Close all unneeded connections in the queue and make sure new ones are closed on the connect thread. + queue.CompleteAdding(); + foreach (var client in queue) + client.Close(); } - void NetworkConnectionReceive(object networkStreamObject) + void NetworkConnectionReceive() { try { - var networkStream = (NetworkStream)networkStreamObject; - var reader = new BinaryReader(networkStream); + var reader = new BinaryReader(tcp.GetStream()); var handshakeProtocol = reader.ReadInt32(); if (handshakeProtocol != ProtocolVersion.Handshake) @@ -187,7 +314,11 @@ AddPacket(new ReceivedPacket { FromClient = client, Data = buf }); } } - catch { } + catch (Exception ex) + { + errorMessage = "Connection failed"; + Log.Write("client", "Connection to {0} failed: {1}".F(endpoint, ex.Message)); + } finally { connectionState = ConnectionState.NotConnected; @@ -239,8 +370,7 @@ // Closing the stream will cause any reads on the receiving thread to throw. // This will mark the connection as no longer connected and the thread will terminate cleanly. - if (tcp != null) - tcp.Close(); + tcp?.Close(); base.Dispose(disposing); } diff -Nru openra-20200503/OpenRA.Game/Network/FrameData.cs openra-20210321/OpenRA.Game/Network/FrameData.cs --- openra-20200503/OpenRA.Game/Network/FrameData.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/FrameData.cs 2021-03-21 11:10:05.000000000 +0000 @@ -43,7 +43,7 @@ if (lastClientFrame == -1) lastClientFrame = framePackets .Where(x => x.Value.ContainsKey(clientId)) - .Select(x => x.Key).OrderBy(x => x).LastOrDefault(); + .Select(x => x.Key).MaxByOrDefault(x => x); clientQuitTimes[clientId] = lastClientFrame; } diff -Nru openra-20200503/OpenRA.Game/Network/GameSave.cs openra-20210321/OpenRA.Game/Network/GameSave.cs --- openra-20200503/OpenRA.Game/Network/GameSave.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/GameSave.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,6 +25,7 @@ public readonly string Faction; public readonly int SpawnPoint; public readonly int Team; + public readonly int Handicap; public readonly string Slot; public readonly string Bot; public readonly bool IsAdmin; @@ -39,6 +40,7 @@ Faction = client.Faction; SpawnPoint = client.SpawnPoint; Team = client.Team; + Handicap = client.Handicap; Slot = client.Slot; Bot = client.Bot; IsAdmin = client.IsAdmin; @@ -53,6 +55,7 @@ client.Faction = Faction; client.SpawnPoint = SpawnPoint; client.Team = Team; + client.Handicap = Handicap; client.Slot = Slot; client.Bot = Bot; client.IsAdmin = IsAdmin; @@ -117,7 +120,7 @@ LastOrdersFrame = rs.ReadInt32(); LastSyncFrame = rs.ReadInt32(); - lastSyncPacket = rs.ReadBytes(5); + lastSyncPacket = rs.ReadBytes(Order.SyncHashOrderLength); var globalSettings = MiniYaml.FromString(rs.ReadString(Encoding.UTF8, Connection.MaxOrderLength)); GlobalSettings = Session.Global.Deserialize(globalSettings[0].Value); @@ -190,6 +193,12 @@ // Sync packet - we only care about the last value if (data.Length > 0 && data[0] == (byte)OrderType.SyncHash && frame > LastSyncFrame) { + if (data.Length != Order.SyncHashOrderLength) + { + Log.Write("debug", "Dropped sync order with length {0}. Expected length {1}.".F(data.Length, Order.SyncHashOrderLength)); + return; + } + LastSyncFrame = frame; lastSyncPacket = data; } @@ -282,7 +291,7 @@ file.Write(BitConverter.GetBytes(MetadataMarker), 0, 4); file.Write(BitConverter.GetBytes(LastOrdersFrame), 0, 4); file.Write(BitConverter.GetBytes(LastSyncFrame), 0, 4); - file.Write(lastSyncPacket, 0, 5); + file.Write(lastSyncPacket, 0, Order.SyncHashOrderLength); var globalSettingsNodes = new List() { GlobalSettings.Serialize() }; file.WriteString(Encoding.UTF8, globalSettingsNodes.WriteToString()); diff -Nru openra-20200503/OpenRA.Game/Network/GameServer.cs openra-20210321/OpenRA.Game/Network/GameServer.cs --- openra-20200503/OpenRA.Game/Network/GameServer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/GameServer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -56,7 +56,7 @@ "Mod", "Version", "ModTitle", "ModWebsite", "ModIcon32", // Current server state - "Map", "State", "MaxPlayers", "Protected", "Authentication" + "Map", "State", "MaxPlayers", "Protected", "Authentication", "DisabledSpawnPoints" }; public const int ProtocolVersion = 2; @@ -132,6 +132,9 @@ [FieldLoader.LoadUsing("LoadClients")] public readonly GameClient[] Clients; + /// The list of spawnpoints that are disabled for this game + public readonly int[] DisabledSpawnPoints = { }; + public string ModLabel { get { return "{0} ({1})".F(ModTitle, Version); } } static object LoadClients(MiniYaml yaml) @@ -167,28 +170,22 @@ // Games advertised using the old API calculated the play time locally if (State == 2 && PlayTime < 0) - { - DateTime startTime; - if (DateTime.TryParse(Started, out startTime)) + if (DateTime.TryParse(Started, out var startTime)) PlayTime = (int)(DateTime.UtcNow - startTime).TotalSeconds; - } - ExternalMod external; var externalKey = ExternalMod.MakeKey(Mod, Version); - if (Game.ExternalMods.TryGetValue(externalKey, out external) && external.Version == Version) + if (Game.ExternalMods.TryGetValue(externalKey, out var external) && external.Version == Version) IsCompatible = true; // Games advertised using the old API used local mod metadata if (string.IsNullOrEmpty(ModTitle)) { - Manifest mod; - if (external != null && external.Version == Version) { // Use external mod registration to populate the section header ModTitle = external.Title; } - else if (Game.Mods.TryGetValue(Mod, out mod)) + else if (Game.Mods.TryGetValue(Mod, out var mod)) { // Use internal mod data to populate the section header, but // on-connect switching must use the external mod plumbing. @@ -232,6 +229,7 @@ Protected = !string.IsNullOrEmpty(server.Settings.Password); Authentication = server.Settings.RequireAuthentication || server.Settings.ProfileIDWhitelist.Any(); Clients = server.LobbyInfo.Clients.Select(c => new GameClient(c)).ToArray(); + DisabledSpawnPoints = server.LobbyInfo.DisabledSpawnPoints?.ToArray() ?? Array.Empty(); } public string ToPOSTData(bool lanGame) diff -Nru openra-20200503/OpenRA.Game/Network/Order.cs openra-20210321/OpenRA.Game/Network/Order.cs --- openra-20200503/OpenRA.Game/Network/Order.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/Order.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,7 @@ } [Flags] - enum OrderFields : byte + enum OrderFields : short { None = 0x0, Target = 0x01, @@ -35,7 +35,8 @@ ExtraLocation = 0x10, ExtraData = 0x20, TargetIsCell = 0x40, - Subject = 0x80 + Subject = 0x80, + Grouped = 0x100 } static class OrderFieldsExts @@ -48,10 +49,15 @@ public sealed class Order { + // Length of orders with type OrderType.SyncHash + public const int SyncHashOrderLength = 13; + public readonly string OrderString; public readonly Actor Subject; public readonly bool Queued; - public readonly Target Target; + public ref readonly Target Target => ref target; + public readonly Actor[] GroupedActors; + public string TargetString; public CPos ExtraLocation; public Actor[] ExtraActors; @@ -60,20 +66,24 @@ public OrderType Type = OrderType.Fields; public bool SuppressVisualFeedback; - public Target VisualFeedbackTarget; + public ref readonly Target VisualFeedbackTarget => ref visualFeedbackTarget; public Player Player { get { return Subject != null ? Subject.Owner : null; } } - Order(string orderString, Actor subject, Target target, string targetString, bool queued, Actor[] extraActors, CPos extraLocation, uint extraData) + readonly Target target; + readonly Target visualFeedbackTarget; + + Order(string orderString, Actor subject, in Target target, string targetString, bool queued, Actor[] extraActors, CPos extraLocation, uint extraData, Actor[] groupedActors = null) { OrderString = orderString ?? ""; Subject = subject; - Target = target; + this.target = target; TargetString = targetString; Queued = queued; ExtraActors = extraActors; ExtraLocation = extraLocation; ExtraData = extraData; + GroupedActors = groupedActors; } public static Order Deserialize(World world, BinaryReader r) @@ -86,7 +96,7 @@ case OrderType.Fields: { var order = r.ReadString(); - var flags = (OrderFields)r.ReadByte(); + var flags = (OrderFields)r.ReadInt16(); Actor subject = null; if (flags.HasField(OrderFields.Subject)) @@ -103,8 +113,7 @@ { case TargetType.Actor: { - Actor targetActor; - if (world != null && TryGetActorFromUInt(world, r.ReadUInt32(), out targetActor)) + if (world != null && TryGetActorFromUInt(world, r.ReadUInt32(), out var targetActor)) target = Target.FromActor(targetActor); break; } @@ -114,8 +123,7 @@ var playerActorID = r.ReadUInt32(); var frozenActorID = r.ReadUInt32(); - Actor playerActor; - if (world == null || !TryGetActorFromUInt(world, playerActorID, out playerActor)) + if (world == null || !TryGetActorFromUInt(world, playerActorID, out var playerActor)) break; if (playerActor.Owner.FrozenActorLayer == null) @@ -164,13 +172,23 @@ var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? new CPos(r.ReadInt32()) : CPos.Zero; var extraData = flags.HasField(OrderFields.ExtraData) ? r.ReadUInt32() : 0; + Actor[] groupedActors = null; + if (flags.HasField(OrderFields.Grouped)) + { + var count = r.ReadInt32(); + if (world != null) + groupedActors = Exts.MakeArray(count, _ => world.GetActorById(r.ReadUInt32())); + else + r.ReadBytes(4 * count); + } + if (world == null) - return new Order(order, null, target, targetString, queued, extraActors, extraLocation, extraData); + return new Order(order, null, target, targetString, queued, extraActors, extraLocation, extraData, groupedActors); if (subject == null && flags.HasField(OrderFields.Subject)) return null; - return new Order(order, subject, target, targetString, queued, extraActors, extraLocation, extraData); + return new Order(order, subject, target, targetString, queued, extraActors, extraLocation, extraData, groupedActors); } case OrderType.Handshake: @@ -231,6 +249,11 @@ return new Order(order, null, false) { IsImmediate = isImmediate, TargetString = targetString }; } + public static Order FromGroupedOrder(Order grouped, Actor subject) + { + return new Order(grouped.OrderString, subject, grouped.Target, grouped.TargetString, grouped.Queued, grouped.ExtraActors, grouped.ExtraLocation, grouped.ExtraData); + } + public static Order Command(string text) { return new Order("Command", null, false) { IsImmediate = true, TargetString = text }; @@ -255,11 +278,17 @@ public Order() : this(null, null, Target.Invalid, null, false, null, CPos.Zero, 0) { } - public Order(string orderString, Actor subject, bool queued, Actor[] extraActors = null) - : this(orderString, subject, Target.Invalid, null, queued, extraActors, CPos.Zero, 0) { } + public Order(string orderString, Actor subject, bool queued, Actor[] extraActors = null, Actor[] groupedActors = null) + : this(orderString, subject, Target.Invalid, null, queued, extraActors, CPos.Zero, 0, groupedActors) { } + + public Order(string orderString, Actor subject, in Target target, bool queued, Actor[] extraActors = null, Actor[] groupedActors = null) + : this(orderString, subject, target, null, queued, extraActors, CPos.Zero, 0, groupedActors) { } - public Order(string orderString, Actor subject, Target target, bool queued, Actor[] extraActors = null) - : this(orderString, subject, target, null, queued, extraActors, CPos.Zero, 0) { } + public Order(string orderString, Actor subject, Target target, Target visualFeedbackTarget, bool queued) + : this(orderString, subject, target, null, queued, null, CPos.Zero, 0, null) + { + this.visualFeedbackTarget = visualFeedbackTarget; + } public byte[] Serialize() { @@ -267,7 +296,7 @@ if (Type == OrderType.Handshake) minLength += TargetString.Length + 1; else if (Type == OrderType.Fields) - minLength += 4 + 1 + 13 + (TargetString != null ? TargetString.Length + 1 : 0) + 4 + 4 + 4; + minLength += 4 + 2 + 13 + (TargetString != null ? TargetString.Length + 1 : 0) + 4 + 4 + 4; if (ExtraActors != null) minLength += ExtraActors.Length * 4; @@ -308,6 +337,9 @@ if (Queued) fields |= OrderFields.Queued; + if (GroupedActors != null) + fields |= OrderFields.Grouped; + if (ExtraActors != null) fields |= OrderFields.ExtraActors; @@ -317,7 +349,7 @@ if (Target.SerializableCell != null) fields |= OrderFields.TargetIsCell; - w.Write((byte)fields); + w.Write((short)fields); if (fields.HasField(OrderFields.Subject)) w.Write(UIntFromActor(Subject)); @@ -362,6 +394,13 @@ if (fields.HasField(OrderFields.ExtraData)) w.Write(ExtraData); + if (fields.HasField(OrderFields.Grouped)) + { + w.Write(GroupedActors.Length); + foreach (var a in GroupedActors) + w.Write(UIntFromActor(a)); + } + break; } diff -Nru openra-20200503/OpenRA.Game/Network/OrderIO.cs openra-20210321/OpenRA.Game/Network/OrderIO.cs --- openra-20200503/OpenRA.Game/Network/OrderIO.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/OrderIO.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,13 +31,14 @@ return ret; } - public static byte[] SerializeSync(int sync) + public static byte[] SerializeSync(int sync, ulong defeatState) { - var ms = new MemoryStream(1 + 4); + var ms = new MemoryStream(Order.SyncHashOrderLength); using (var writer = new BinaryWriter(ms)) { writer.Write((byte)OrderType.SyncHash); writer.Write(sync); + writer.Write(defeatState); } return ms.GetBuffer(); diff -Nru openra-20200503/OpenRA.Game/Network/OrderManager.cs openra-20210321/OpenRA.Game/Network/OrderManager.cs --- openra-20200503/OpenRA.Game/Network/OrderManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/OrderManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,11 +28,10 @@ public Session.Client LocalClient { get { return LobbyInfo.ClientWithIndex(Connection.LocalClientId); } } public World World; - public readonly string Host; - public readonly int Port; + public readonly ConnectionTarget Endpoint; public readonly string Password = ""; - public string ServerError = "Server is not responding"; + public string ServerError = null; public bool AuthenticationFailed = false; public ExternalMod ServerExternalMod = null; @@ -48,10 +47,10 @@ internal int GameSaveLastFrame = -1; internal int GameSaveLastSyncFrame = -1; - List localOrders = new List(); - List localImmediateOrders = new List(); + readonly List localOrders = new List(); + readonly List localImmediateOrders = new List(); - List chatCache = new List(); + readonly List chatCache = new List(); public readonly ReadOnlyList ChatCache; @@ -80,10 +79,9 @@ Connection.Send(i, new List()); } - public OrderManager(string host, int port, string password, IConnection conn) + public OrderManager(ConnectionTarget endpoint, string password, IConnection conn) { - Host = host; - Port = port; + Endpoint = endpoint; Password = password; Connection = conn; syncReport = new SyncReport(this); @@ -117,7 +115,7 @@ Connection.SendImmediate(localImmediateOrders.Select(o => o.Serialize())); localImmediateOrders.Clear(); - var immediatePackets = new List>(); + var immediatePackets = new List<(int ClientId, byte[] Packet)>(); Connection.Receive( (clientId, packet) => @@ -125,19 +123,27 @@ var frame = BitConverter.ToInt32(packet, 0); if (packet.Length == 5 && packet[4] == (byte)OrderType.Disconnect) frameData.ClientQuit(clientId, frame); - else if (packet.Length >= 5 && packet[4] == (byte)OrderType.SyncHash) + else if (packet.Length > 4 && packet[4] == (byte)OrderType.SyncHash) + { + if (packet.Length != 4 + Order.SyncHashOrderLength) + { + Log.Write("debug", "Dropped sync order with length {0}. Expected length {1}.".F(packet.Length, 4 + Order.SyncHashOrderLength)); + return; + } + CheckSync(packet); + } else if (frame == 0) - immediatePackets.Add(Pair.New(clientId, packet)); + immediatePackets.Add((clientId, packet)); else frameData.AddFrameOrders(clientId, frame, packet); }); foreach (var p in immediatePackets) { - foreach (var o in p.Second.ToOrderList(World)) + foreach (var o in p.Packet.ToOrderList(World)) { - UnitOrders.ProcessOrder(this, World, p.First, o); + UnitOrders.ProcessOrder(this, World, p.ClientId, o); // A mod switch or other event has pulled the ground from beneath us if (disposed) @@ -151,8 +157,7 @@ void CheckSync(byte[] packet) { var frame = BitConverter.ToInt32(packet, 0); - byte[] existingSync; - if (syncForFrame.TryGetValue(frame, out existingSync)) + if (syncForFrame.TryGetValue(frame, out var existingSync)) { if (packet.Length != existingSync.Length) OutOfSync(frame); @@ -167,14 +172,14 @@ public bool IsReadyForNextFrame { - get { return NetFrameNumber >= 1 && frameData.IsReadyForFrame(NetFrameNumber); } + get { return GameStarted && frameData.IsReadyForFrame(NetFrameNumber); } } public IEnumerable GetClientsNotReadyForNextFrame { get { - return NetFrameNumber >= 1 + return GameStarted ? frameData.ClientsNotReadyForFrame(NetFrameNumber) .Select(a => LobbyInfo.ClientWithIndex(a)) : NoClients; @@ -195,9 +200,16 @@ UnitOrders.ProcessOrder(this, World, order.Client, order.Order); if (NetFrameNumber + FramesAhead >= GameSaveLastSyncFrame) - Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(World.SyncHash())); + { + var defeatState = 0UL; + for (var i = 0; i < World.Players.Length; i++) + if (World.Players[i].WinState == WinState.Lost) + defeatState |= 1UL << i; + + Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(World.SyncHash(), defeatState)); + } else - Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(0)); + Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(0, 0)); if (generateSyncReport) using (new PerfSample("sync_report")) @@ -209,8 +221,7 @@ public void Dispose() { disposed = true; - if (Connection != null) - Connection.Dispose(); + Connection?.Dispose(); } } diff -Nru openra-20200503/OpenRA.Game/Network/ReplayConnection.cs openra-20210321/OpenRA.Game/Network/ReplayConnection.cs --- openra-20200503/OpenRA.Game/Network/ReplayConnection.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/ReplayConnection.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,8 +12,8 @@ using System; using System.Collections.Generic; using System.IO; +using System.Net; using OpenRA.FileFormats; -using OpenRA.Primitives; namespace OpenRA.Network { @@ -22,7 +22,7 @@ class Chunk { public int Frame; - public Pair[] Packets; + public (int ClientId, byte[] Packet)[] Packets; } Queue chunks = new Queue(); @@ -32,6 +32,13 @@ public int LocalClientId { get { return -1; } } public ConnectionState ConnectionState { get { return ConnectionState.Connected; } } + public IPEndPoint EndPoint + { + get { throw new NotSupportedException("A replay connection doesn't have an endpoint"); } + } + + public string ErrorMessage { get { return null; } } + public readonly int TickCount; public readonly int FinalGameTick; public readonly bool IsValid; @@ -47,29 +54,26 @@ // to avoid issues with all immediate orders being resolved on the first tick. using (var rs = File.OpenRead(replayFilename)) { - var packets = new List>(); - + var packets = new List<(int ClientId, byte[] Packet)>(); var chunk = new Chunk(); - while (rs.Position < rs.Length) { var client = rs.ReadInt32(); if (client == ReplayMetadata.MetaStartMarker) break; + var packetLen = rs.ReadInt32(); var packet = rs.ReadBytes(packetLen); var frame = BitConverter.ToInt32(packet, 0); - packets.Add(Pair.New(client, packet)); + packets.Add((client, packet)); - if (frame != int.MaxValue && - (!lastClientsFrame.ContainsKey(client) || frame > lastClientsFrame[client])) + if (frame != int.MaxValue && (!lastClientsFrame.ContainsKey(client) || frame > lastClientsFrame[client])) lastClientsFrame[client] = frame; - if (packet.Length == 5 && packet[4] == (byte)OrderType.Disconnect) - continue; // disconnect - else if (packet.Length >= 5 && packet[4] == (byte)OrderType.SyncHash) - continue; // sync - else if (frame == 0) + if (packet.Length > 4 && (packet[4] == (byte)OrderType.Disconnect || packet[4] == (byte)OrderType.SyncHash)) + continue; + + if (frame == 0) { // Parse replay metadata from orders stream var orders = packet.ToOrderList(null); @@ -103,13 +107,13 @@ { foreach (var tmpPacketPair in tmpChunk.Packets) { - var client = tmpPacketPair.First; + var client = tmpPacketPair.ClientId; // Don't replace the final disconnection packet - we still want this to end the replay. if (client == lastClientToDisconnect) continue; - var packet = tmpPacketPair.Second; + var packet = tmpPacketPair.Packet; if (packet.Length == 5 && packet[4] == (byte)OrderType.Disconnect) { var lastClientFrame = lastClientsFrame[client]; @@ -148,7 +152,7 @@ while (chunks.Count != 0 && chunks.Peek().Frame <= ordersFrame) foreach (var o in chunks.Dequeue().Packets) - packetFn(o.First, o.Second); + packetFn(o.ClientId, o.Packet); } public void Dispose() { } diff -Nru openra-20200503/OpenRA.Game/Network/ReplayRecorder.cs openra-20210321/OpenRA.Game/Network/ReplayRecorder.cs --- openra-20200503/OpenRA.Game/Network/ReplayRecorder.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/ReplayRecorder.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,6 +10,7 @@ #endregion using System; +using System.Collections.Generic; using System.IO; using System.Linq; using OpenRA.FileFormats; @@ -25,9 +26,7 @@ static bool IsGameStart(byte[] data) { - if (data.Length == 5 && data[4] == (byte)OrderType.Disconnect) - return false; - if (data.Length >= 5 && data[4] == (byte)OrderType.SyncHash) + if (data.Length > 4 && (data[4] == (byte)OrderType.Disconnect || data[4] == (byte)OrderType.SyncHash)) return false; var frame = BitConverter.ToInt32(data, 0); @@ -45,7 +44,7 @@ { var filename = chooseFilename(); var mod = Game.ModData.Manifest; - var dir = Platform.ResolvePath(Platform.SupportDirPrefix, "Replays", mod.Id, mod.Metadata.Version); + var dir = Path.Combine(Platform.SupportDir, "Replays", mod.Id, mod.Metadata.Version); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); @@ -85,6 +84,14 @@ writer.Write(data); } + public void ReceiveFrame(int clientID, int frame, byte[] data) + { + var ms = new MemoryStream(4 + data.Length); + ms.WriteArray(BitConverter.GetBytes(frame)); + ms.WriteArray(data); + Receive(clientID, ms.GetBuffer()); + } + bool disposed; public void Dispose() @@ -100,8 +107,7 @@ Metadata.Write(writer); } - if (preStartBuffer != null) - preStartBuffer.Dispose(); + preStartBuffer?.Dispose(); writer.Close(); } } diff -Nru openra-20200503/OpenRA.Game/Network/Session.cs openra-20210321/OpenRA.Game/Network/Session.cs --- openra-20200503/OpenRA.Game/Network/Session.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/Session.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,6 +26,8 @@ // Keyed by the PlayerReference id that the slot corresponds to public Dictionary Slots = new Dictionary(); + public HashSet DisabledSpawnPoints = new HashSet(); + public Global GlobalSettings = new Global(); public static string AnonymizeIP(IPAddress ip) @@ -69,6 +71,9 @@ var s = Slot.Deserialize(node.Value); session.Slots.Add(s.PlayerReference, s); break; + case "DisabledSpawnPoints": + session.DisabledSpawnPoints = FieldLoader.GetValue>("DisabledSpawnPoints", node.Value.Value); + break; } } @@ -139,6 +144,7 @@ public ClientState State = ClientState.Invalid; public int Team; + public int Handicap; public string Slot; // Slot ID, or null for observer public string Bot; // Bot type, null for real clients public int BotControllerClientIndex; // who added the bot to the slot @@ -188,6 +194,7 @@ public bool LockFaction; public bool LockColor; public bool LockTeam; + public bool LockHandicap; public bool LockSpawn; public bool Required; @@ -250,8 +257,7 @@ public bool OptionOrDefault(string id, bool def) { - LobbyOptionState option; - if (LobbyOptions.TryGetValue(id, out option)) + if (LobbyOptions.TryGetValue(id, out var option)) return option.IsEnabled; return def; @@ -259,8 +265,7 @@ public string OptionOrDefault(string id, string def) { - LobbyOptionState option; - if (LobbyOptions.TryGetValue(id, out option)) + if (LobbyOptions.TryGetValue(id, out var option)) return option.Value; return def; @@ -269,7 +274,10 @@ public string Serialize() { - var sessionData = new List(); + var sessionData = new List() + { + new MiniYamlNode("DisabledSpawnPoints", FieldSaver.FormatValue(DisabledSpawnPoints)) + }; foreach (var client in Clients) sessionData.Add(client.Serialize()); diff -Nru openra-20200503/OpenRA.Game/Network/SyncReport.cs openra-20210321/OpenRA.Game/Network/SyncReport.cs --- openra-20200503/OpenRA.Game/Network/SyncReport.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/SyncReport.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,7 +29,7 @@ readonly Report[] syncReports = new Report[NumSyncReports]; int curIndex = 0; - static Pair DumpSyncTrait(ISync sync) + static (string[] Names, Values Values) DumpSyncTrait(ISync sync) { var type = sync.GetType(); TypeInfo typeInfo; @@ -41,7 +41,7 @@ foreach (var func in typeInfo.SerializableCopyOfMemberFunctions) values[index++] = func(sync); - return Pair.New(typeInfo.Names, values); + return (typeInfo.Names, values); } public SyncReport(OrderManager orderManager) @@ -120,9 +120,9 @@ Log.Write("sync", "\t {0} {1} {2} {3} ({4})".F(a.ActorID, a.Type, a.Owner, a.Trait, a.Hash)); var nvp = a.NamesValues; - for (int i = 0; i < nvp.First.Length; i++) - if (nvp.Second[i] != null) - Log.Write("sync", "\t\t {0}: {1}".F(nvp.First[i], nvp.Second[i])); + for (int i = 0; i < nvp.Names.Length; i++) + if (nvp.Values[i] != null) + Log.Write("sync", "\t\t {0}: {1}".F(nvp.Names[i], nvp.Values[i])); } Log.Write("sync", "Synced Effects:"); @@ -131,9 +131,9 @@ Log.Write("sync", "\t {0} ({1})", e.Name, e.Hash); var nvp = e.NamesValues; - for (int i = 0; i < nvp.First.Length; i++) - if (nvp.Second[i] != null) - Log.Write("sync", "\t\t {0}: {1}".F(nvp.First[i], nvp.Second[i])); + for (int i = 0; i < nvp.Names.Length; i++) + if (nvp.Values[i] != null) + Log.Write("sync", "\t\t {0}: {1}".F(nvp.Names[i], nvp.Values[i])); } Log.Write("sync", "Orders Issued:"); @@ -163,14 +163,14 @@ public string Owner; public string Trait; public int Hash; - public Pair NamesValues; + public (string[] Names, Values Values) NamesValues; } struct EffectReport { public string Name; public int Hash; - public Pair NamesValues; + public (string[] Names, Values Values) NamesValues; } struct TypeInfo diff -Nru openra-20200503/OpenRA.Game/Network/UnitOrders.cs openra-20210321/OpenRA.Game/Network/UnitOrders.cs --- openra-20200503/OpenRA.Game/Network/UnitOrders.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Network/UnitOrders.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,10 +9,8 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Primitives; using OpenRA.Server; using OpenRA.Traits; @@ -29,13 +27,6 @@ internal static void ProcessOrder(OrderManager orderManager, World world, int clientId, Order order) { - if (world != null) - { - if (!world.WorldActor.TraitsImplementing().All(vo => - vo.OrderValidation(orderManager, world, clientId, order))) - return; - } - switch (order.OrderString) { // Server message @@ -48,7 +39,13 @@ { var client = orderManager.LobbyInfo.ClientWithIndex(clientId); if (client != null) + { client.State = Session.ClientState.Disconnected; + var player = world?.FindPlayerByClient(client); + if (player != null) + world.OnPlayerDisconnected(player); + } + break; } @@ -147,8 +144,7 @@ var data = MiniYaml.FromString(order.TargetString)[0]; var traitIndex = int.Parse(data.Key); - if (world != null) - world.AddGameSaveTraitData(traitIndex, data.Value); + world?.AddGameSaveTraitData(traitIndex, data.Value); break; } @@ -192,9 +188,8 @@ var request = HandshakeRequest.Deserialize(order.TargetString); var externalKey = ExternalMod.MakeKey(request.Mod, request.Version); - ExternalMod external; - if ((request.Mod != mod.Id || request.Version != mod.Metadata.Version) - && Game.ExternalMods.TryGetValue(externalKey, out external)) + if ((request.Mod != mod.Id || request.Version != mod.Metadata.Version) && + Game.ExternalMods.TryGetValue(externalKey, out var external)) { // The ConnectionFailedLogic will prompt the user to switch mods orderManager.ServerExternalMod = external; @@ -337,17 +332,27 @@ default: { - ResolveOrder(order); + if (world == null) + break; + + if (order.GroupedActors == null) + ResolveOrder(order, world, orderManager, clientId); + else + foreach (var subject in order.GroupedActors) + ResolveOrder(Order.FromGroupedOrder(order, subject), world, orderManager, clientId); + break; } } } - static void ResolveOrder(Order order) + static void ResolveOrder(Order order, World world, OrderManager orderManager, int clientId) { - if (order.Subject != null && !order.Subject.IsDead) - foreach (var t in order.Subject.TraitsImplementing()) - t.ResolveOrder(order.Subject, order); + if (order.Subject == null || order.Subject.IsDead) + return; + + if (world.OrderValidators.All(vo => vo.OrderValidation(orderManager, world, clientId, order))) + order.Subject.ResolveOrder(order); } static void SetOrderLag(OrderManager o) diff -Nru openra-20200503/OpenRA.Game/ObjectCreator.cs openra-20210321/OpenRA.Game/ObjectCreator.cs --- openra-20200503/OpenRA.Game/ObjectCreator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/ObjectCreator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,7 +26,7 @@ readonly Cache typeCache; readonly Cache ctorCache; - readonly Pair[] assemblies; + readonly (Assembly Assembly, string Namespace)[] assemblies; public ObjectCreator(Manifest manifest, InstalledMods mods) { @@ -48,8 +48,7 @@ // We can't check the internal name of the assembly, so we'll work off the data instead var hash = CryptoUtil.SHA1Hash(File.ReadAllBytes(resolvedPath)); - Assembly assembly; - if (!ResolvedAssemblies.TryGetValue(hash, out assembly)) + if (!ResolvedAssemblies.TryGetValue(hash, out var assembly)) { assembly = Assembly.LoadFile(resolvedPath); ResolvedAssemblies.Add(hash, assembly); @@ -59,7 +58,7 @@ } AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; - assemblies = assemblyList.SelectMany(asm => asm.GetNamespaces().Select(ns => Pair.New(asm, ns))).ToArray(); + assemblies = assemblyList.SelectMany(asm => asm.GetNamespaces().Select(ns => (asm, ns))).ToArray(); } Assembly ResolveAssembly(object sender, ResolveEventArgs e) @@ -68,10 +67,7 @@ if (a.FullName == e.Name) return a; - if (assemblies == null) - return null; - - return assemblies.Select(a => a.First).FirstOrDefault(a => a.FullName == e.Name); + return assemblies?.Select(a => a.Assembly).FirstOrDefault(a => a.FullName == e.Name); } // Only used by the linter to prevent exceptions from being thrown during a lint run @@ -106,7 +102,7 @@ public Type FindType(string className) { return assemblies - .Select(pair => pair.First.GetType(pair.Second + "." + className, false)) + .Select(pair => pair.Assembly.GetType(pair.Namespace + "." + className, false)) .FirstOrDefault(t => t != null); } @@ -146,7 +142,7 @@ public IEnumerable GetTypes() { - return assemblies.Select(ma => ma.First).Distinct() + return assemblies.Select(ma => ma.Assembly).Distinct() .SelectMany(ma => ma.GetTypes()); } diff -Nru openra-20200503/OpenRA.Game/OpenRA.Game.csproj openra-20210321/OpenRA.Game/OpenRA.Game.csproj --- openra-20200503/OpenRA.Game/OpenRA.Game.csproj 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/OpenRA.Game.csproj 2021-03-21 11:10:05.000000000 +0000 @@ -1,23 +1,27 @@  - Exe - net461 + Library + net472 true true false - 5 + 7.3 true true false OpenRA - .. + ../bin false AnyCPU false false ..\OpenRA.ruleset - Release;Debug;Release-x86 - mono + Release;Debug + + + win-x64 + linux-x64 + osx-x64 @@ -27,44 +31,13 @@ DEBUG;TRACE false - - true - - - Project - Game.Mod=ra - - - Project - Game.Mod=d2k - - - Project - Game.Mod=cnc - - - Project - Game.Mod=ts - - - ..\thirdparty\download\Open.Nat.dll - - - ..\thirdparty\download\Eluant.dll - False - - - ..\thirdparty\download\ICSharpCode.SharpZipLib.dll - False - - - false - - - + + + + + - @@ -72,8 +45,4 @@ - - - - diff -Nru openra-20200503/OpenRA.Game/Orders/GenericSelectTarget.cs openra-20210321/OpenRA.Game/Orders/GenericSelectTarget.cs --- openra-20200503/OpenRA.Game/Orders/GenericSelectTarget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Orders/GenericSelectTarget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,7 @@ #endregion using System.Collections.Generic; -using OpenRA.Graphics; +using System.Linq; using OpenRA.Traits; namespace OpenRA.Orders @@ -18,13 +18,14 @@ public class GenericSelectTarget : UnitOrderGenerator { public readonly string OrderName; - protected readonly IEnumerable Subjects; protected readonly string Cursor; protected readonly MouseButton ExpectedButton; + protected IEnumerable subjects; + public GenericSelectTarget(IEnumerable subjects, string order, string cursor, MouseButton button) { - Subjects = subjects; + this.subjects = subjects; OrderName = order; Cursor = cursor; ExpectedButton = button; @@ -53,8 +54,7 @@ world.CancelInputMode(); var queued = mi.Modifiers.HasModifier(Modifiers.Shift); - foreach (var subject in Subjects) - yield return new Order(OrderName, subject, Target.FromCell(world, cell), queued); + yield return new Order(OrderName, null, Target.FromCell(world, cell), queued, null, subjects.ToArray()); } } @@ -69,6 +69,11 @@ return true; } + public override void SelectionChanged(World world, IEnumerable selected) + { + subjects = selected; + } + public override bool ClearSelectionOnLeftClick { get { return false; } } } } diff -Nru openra-20200503/OpenRA.Game/Orders/IOrderGenerator.cs openra-20210321/OpenRA.Game/Orders/IOrderGenerator.cs --- openra-20200503/OpenRA.Game/Orders/IOrderGenerator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Orders/IOrderGenerator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,5 +24,6 @@ string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi); void Deactivate(); bool HandleKeyPress(KeyInput e); + void SelectionChanged(World world, IEnumerable selected); } } diff -Nru openra-20200503/OpenRA.Game/Orders/UnitOrderGenerator.cs openra-20210321/OpenRA.Game/Orders/UnitOrderGenerator.cs --- openra-20200503/OpenRA.Game/Orders/UnitOrderGenerator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Orders/UnitOrderGenerator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -70,7 +70,7 @@ bool useSelect; if (Game.Settings.Game.UseClassicMouseStyle && !InputOverridesSelection(world, worldPixel, mi)) - useSelect = target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo(); + useSelect = target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo(); else { var ordersWithCursor = world.Selection.Actors @@ -81,7 +81,7 @@ if (cursorOrder != null) return cursorOrder.Cursor; - useSelect = target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo() && + useSelect = target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo() && (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()); } @@ -96,7 +96,7 @@ public virtual bool InputOverridesSelection(World world, int2 xy, MouseInput mi) { var actor = world.ScreenMap.ActorsAtMouse(xy) - .Where(a => !a.Actor.IsDead && a.Actor.Info.HasTraitInfo() && (a.Actor.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(a.Actor))) + .Where(a => !a.Actor.IsDead && a.Actor.Info.HasTraitInfo() && (a.Actor.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(a.Actor))) .WithHighestSelectionPriority(xy, mi.Modifiers); if (actor == null) @@ -124,6 +124,8 @@ return false; } + public virtual void SelectionChanged(World world, IEnumerable selected) { } + /// /// Returns the most appropriate order for a given actor and target. /// First priority is given to orders that interact with the given actors. @@ -194,15 +196,17 @@ public readonly IOrderTargeter Order; public readonly IIssueOrder Trait; public readonly string Cursor; - public readonly Target Target; + public ref readonly Target Target => ref target; + + readonly Target target; - public UnitOrderResult(Actor actor, IOrderTargeter order, IIssueOrder trait, string cursor, Target target) + public UnitOrderResult(Actor actor, IOrderTargeter order, IIssueOrder trait, string cursor, in Target target) { Actor = actor; Order = order; Trait = trait; Cursor = cursor; - Target = target; + this.target = target; } } diff -Nru openra-20200503/OpenRA.Game/Platform.cs openra-20210321/OpenRA.Game/Platform.cs --- openra-20200503/OpenRA.Game/Platform.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Platform.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,12 +22,14 @@ public static class Platform { - public const string SupportDirPrefix = "^"; public static PlatformType CurrentPlatform { get { return currentPlatform.Value; } } public static readonly Guid SessionGUID = Guid.NewGuid(); static Lazy currentPlatform = Exts.Lazy(GetCurrentPlatform); + static bool engineDirAccessed; + static string engineDir; + static bool supportDirInitialized; static string systemSupportPath; static string legacyUserSupportPath; @@ -137,7 +139,7 @@ } // Use a local directory in the game root if it exists (shared with the system support dir) - var localSupportDir = Path.Combine(GameDir, "Support"); + var localSupportDir = Path.Combine(EngineDir, "Support"); if (Directory.Exists(localSupportDir)) userSupportPath = systemSupportPath = localSupportDir + Path.DirectorySeparatorChar; @@ -170,7 +172,45 @@ userSupportPath = path; } - public static string GameDir + public static string EngineDir + { + get + { + // Engine directory defaults to the location of the binaries, + // unless OverrideGameDir is called during startup. + if (!engineDirAccessed) + engineDir = BinDir; + + engineDirAccessed = true; + return engineDir; + } + } + + /// + /// Specify a custom engine directory that already exists on the filesystem. + /// Cannot be called after Platform.EngineDir has been accessed. + /// + public static void OverrideEngineDir(string path) + { + if (engineDirAccessed) + throw new InvalidOperationException("Attempted to override engine directory after it has already been accessed."); + + // Note: Relative paths are interpreted as being relative to BinDir, not the current working dir. + if (!Path.IsPathRooted(path)) + path = Path.Combine(BinDir, path); + + if (!Directory.Exists(path)) + throw new DirectoryNotFoundException(path); + + if (!path.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) && + !path.EndsWith(Path.AltDirectorySeparatorChar.ToString(), StringComparison.Ordinal)) + path += Path.DirectorySeparatorChar; + + engineDirAccessed = true; + engineDir = path; + } + + public static string BinDir { get { @@ -189,50 +229,25 @@ { path = path.TrimEnd(' ', '\t'); - // Paths starting with ^ are relative to the support dir - if (IsPathRelativeToSupportDirectory(path)) - path = SupportDir + path.Substring(1); - - // Paths starting with . are relative to the game dir - if (path == ".") - return GameDir; - - if (path.StartsWith("./", StringComparison.Ordinal) || path.StartsWith(".\\", StringComparison.Ordinal)) - path = GameDir + path.Substring(2); + if (path == "^SupportDir") + return SupportDir; - return path; - } + if (path == "^EngineDir") + return EngineDir; - /// Replace special character prefixes with full paths. - public static string ResolvePath(params string[] path) - { - return ResolvePath(Path.Combine(path)); - } + if (path == "^BinDir") + return BinDir; - /// - /// Replace the full path prefix with the special notation characters ^ or . - /// and transforms \ path separators to / on Windows - /// - public static string UnresolvePath(string path) - { - // Use a case insensitive comparison on windows to avoid problems - // with inconsistent drive letter case - var compare = CurrentPlatform == PlatformType.Windows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; - if (path.StartsWith(SupportDir, compare)) - path = SupportDirPrefix + path.Substring(SupportDir.Length); + if (path.StartsWith("^SupportDir|", StringComparison.Ordinal)) + path = SupportDir + path.Substring(12); - if (path.StartsWith(GameDir, compare)) - path = "./" + path.Substring(GameDir.Length); + if (path.StartsWith("^EngineDir|", StringComparison.Ordinal)) + path = EngineDir + path.Substring(11); - if (CurrentPlatform == PlatformType.Windows) - path = path.Replace('\\', '/'); + if (path.StartsWith("^BinDir|", StringComparison.Ordinal)) + path = BinDir + path.Substring(8); return path; } - - public static bool IsPathRelativeToSupportDirectory(string path) - { - return path.StartsWith(SupportDirPrefix, StringComparison.Ordinal); - } } } diff -Nru openra-20200503/OpenRA.Game/Player.cs openra-20210321/OpenRA.Game/Player.cs --- openra-20200503/OpenRA.Game/Player.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Player.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,10 +14,10 @@ using System.Linq; using Eluant; using Eluant.ObjectBinding; -using OpenRA.Graphics; using OpenRA.Network; using OpenRA.Primitives; using OpenRA.Scripting; +using OpenRA.Support; using OpenRA.Traits; using OpenRA.Widgets; @@ -37,6 +37,9 @@ public class Player : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding { + public const string PlayerActorType = "Player"; + public const string EditorPlayerActorType = "EditorPlayer"; + struct StanceColors { public Color Self; @@ -54,23 +57,39 @@ public readonly bool NonCombatant = false; public readonly bool Playable = true; public readonly int ClientIndex; + public readonly CPos HomeLocation; + public readonly int Handicap; public readonly PlayerReference PlayerReference; public readonly bool IsBot; public readonly string BotType; public readonly Shroud Shroud; public readonly FrozenActorLayer FrozenActorLayer; - /// The faction (including Random, etc) that was selected in the lobby. + /// The faction (including Random, etc.) that was selected in the lobby. public readonly FactionInfo DisplayFaction; + /// The spawn point index that was assigned for client-based players. + public readonly int SpawnPoint; + + /// The spawn point index (including 0 for Random) that was selected in the lobby for client-based players. + public readonly int DisplaySpawnPoint; + public WinState WinState = WinState.Undefined; - public int SpawnPoint; public bool HasObjectives = false; - public bool Spectating; + + public bool Spectating + { + get + { + // Players in mission maps must not leave the player view + return !inMissionMap && (spectating || WinState != WinState.Undefined); + } + } public World World { get; private set; } readonly bool inMissionMap; + readonly bool spectating; readonly IUnlocksRenderPlayer[] unlockRenderPlayer; // Each player is identified with a unique bit in the set @@ -92,19 +111,19 @@ readonly StanceColors stanceColors; - static FactionInfo ChooseFaction(World world, string name, bool requireSelectable = true) + public static FactionInfo ResolveFaction(string factionName, IEnumerable factionInfos, MersenneTwister playerRandom, bool requireSelectable = true) { - var selectableFactions = world.Map.Rules.Actors["world"].TraitInfos() + var selectableFactions = factionInfos .Where(f => !requireSelectable || f.Selectable) .ToList(); - var selected = selectableFactions.FirstOrDefault(f => f.InternalName == name) - ?? selectableFactions.Random(world.SharedRandom); + var selected = selectableFactions.FirstOrDefault(f => f.InternalName == factionName) + ?? selectableFactions.Random(playerRandom); // Don't loop infinite for (var i = 0; i <= 10 && selected.RandomFactionMembers.Any(); i++) { - var faction = selected.RandomFactionMembers.Random(world.SharedRandom); + var faction = selected.RandomFactionMembers.Random(playerRandom); selected = selectableFactions.FirstOrDefault(f => f.InternalName == faction); if (selected == null) @@ -114,14 +133,32 @@ return selected; } - static FactionInfo ChooseDisplayFaction(World world, string factionName) + static FactionInfo ResolveFaction(World world, string factionName, MersenneTwister playerRandom, bool requireSelectable) + { + var factionInfos = world.Map.Rules.Actors["world"].TraitInfos(); + return ResolveFaction(factionName, factionInfos, playerRandom, requireSelectable); + } + + static FactionInfo ResolveDisplayFaction(World world, string factionName) { var factions = world.Map.Rules.Actors["world"].TraitInfos().ToArray(); return factions.FirstOrDefault(f => f.InternalName == factionName) ?? factions.First(); } - public Player(World world, Session.Client client, PlayerReference pr) + public static string ResolvePlayerName(Session.Client client, IEnumerable clients, IEnumerable botInfos) + { + if (client.Bot != null) + { + var botInfo = botInfos.First(b => b.Type == client.Bot); + var botsOfSameType = clients.Where(c => c.Bot == client.Bot).ToArray(); + return botsOfSameType.Length == 1 ? botInfo.Name : "{0} {1}".F(botInfo.Name, botsOfSameType.IndexOf(client) + 1); + } + + return client.Name; + } + + public Player(World world, Session.Client client, PlayerReference pr, MersenneTwister playerRandom) { World = world; InternalName = pr.Name; @@ -134,18 +171,18 @@ { ClientIndex = client.Index; Color = client.Color; - if (client.Bot != null) - { - var botInfo = world.Map.Rules.Actors["player"].TraitInfos().First(b => b.Type == client.Bot); - var botsOfSameType = world.LobbyInfo.Clients.Where(c => c.Bot == client.Bot).ToArray(); - PlayerName = botsOfSameType.Length == 1 ? botInfo.Name : "{0} {1}".F(botInfo.Name, botsOfSameType.IndexOf(client) + 1); - } - else - PlayerName = client.Name; + PlayerName = ResolvePlayerName(client, world.LobbyInfo.Clients, world.Map.Rules.Actors["player"].TraitInfos()); BotType = client.Bot; - Faction = ChooseFaction(world, client.Faction, !pr.LockFaction); - DisplayFaction = ChooseDisplayFaction(world, client.Faction); + Faction = ResolveFaction(world, client.Faction, playerRandom, !pr.LockFaction); + DisplayFaction = ResolveDisplayFaction(world, client.Faction); + + var assignSpawnPoints = world.WorldActor.TraitOrDefault(); + HomeLocation = assignSpawnPoints?.AssignHomeLocation(world, client, playerRandom) ?? pr.HomeLocation; + SpawnPoint = assignSpawnPoints?.SpawnPointForPlayer(this) ?? client.SpawnPoint; + DisplaySpawnPoint = client.SpawnPoint; + + Handicap = client.Handicap; } else { @@ -155,22 +192,34 @@ PlayerName = pr.Name; NonCombatant = pr.NonCombatant; Playable = pr.Playable; - Spectating = pr.Spectating; + spectating = pr.Spectating; BotType = pr.Bot; - Faction = ChooseFaction(world, pr.Faction, false); - DisplayFaction = ChooseDisplayFaction(world, pr.Faction); + Faction = ResolveFaction(world, pr.Faction, playerRandom, false); + DisplayFaction = ResolveDisplayFaction(world, pr.Faction); + HomeLocation = pr.HomeLocation; + SpawnPoint = DisplaySpawnPoint = 0; + Handicap = pr.Handicap; } - if (!Spectating) + if (!spectating) PlayerMask = new LongBitSet(InternalName); - var playerActorType = world.Type == WorldType.Editor ? "EditorPlayer" : "Player"; - PlayerActor = world.CreateActor(playerActorType, new TypeDictionary { new OwnerInit(this) }); + // Set this property before running any Created callbacks on the player actor + IsBot = BotType != null; + + // Special case handling is required for the Player actor: + // Since Actor.Created would be called before PlayerActor is assigned here + // querying player traits in INotifyCreated.Created would crash. + // Therefore assign the uninitialized actor and run the Created callbacks + // by calling Initialize ourselves. + var playerActorType = world.Type == WorldType.Editor ? EditorPlayerActorType : PlayerActorType; + PlayerActor = new Actor(world, playerActorType, new TypeDictionary { new OwnerInit(this) }); + PlayerActor.Initialize(true); + Shroud = PlayerActor.Trait(); FrozenActorLayer = PlayerActor.TraitOrDefault(); // Enable the bot logic on the host - IsBot = BotType != null; if (IsBot && Game.IsHost) { var logic = PlayerActor.TraitsImplementing().FirstOrDefault(b => b.Info.Type == BotType); @@ -193,11 +242,27 @@ return "{0} ({1})".F(PlayerName, ClientIndex); } - public Dictionary Stances = new Dictionary(); - public bool IsAlliedWith(Player p) + public PlayerRelationship RelationshipWith(Player other) { + if (this == other) + return PlayerRelationship.Ally; + // Observers are considered allies to active combatants - return p == null || Stances[p] == Stance.Ally || (p.Spectating && !NonCombatant); + if (other == null || other.Spectating) + return NonCombatant ? PlayerRelationship.Neutral : PlayerRelationship.Ally; + + if (AlliedPlayersMask.Overlaps(other.PlayerMask)) + return PlayerRelationship.Ally; + + if (EnemyPlayersMask.Overlaps(other.PlayerMask)) + return PlayerRelationship.Enemy; + + return PlayerRelationship.Neutral; + } + + public bool IsAlliedWith(Player p) + { + return RelationshipWith(p) == PlayerRelationship.Ally; } public Color PlayerStanceColor(Actor a) @@ -242,8 +307,7 @@ public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right) { - Player a, b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out Player a) || !right.TryGetClrValue(out Player b)) return false; return a == b; diff -Nru openra-20200503/OpenRA.Game/PlayerDatabase.cs openra-20210321/OpenRA.Game/PlayerDatabase.cs --- openra-20200503/OpenRA.Game/PlayerDatabase.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/PlayerDatabase.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; @@ -33,7 +32,7 @@ SheetBuilder sheetBuilder; [FieldLoader.Ignore] - Cache, Sprite> iconCache; + Cache<(PlayerBadge, int), Sprite> iconCache; Sprite LoadSprite(string url, int density) { @@ -84,15 +83,15 @@ { sheetBuilder = new SheetBuilder(SheetType.BGRA, CreateSheet); - iconCache = new Cache, Sprite>(p => + iconCache = new Cache<(PlayerBadge Badge, int Density), Sprite>(p => { - if (p.Second > 2 && !string.IsNullOrEmpty(p.First.Icon3x)) - return LoadSprite(p.First.Icon3x, 3); + if (p.Density > 2 && !string.IsNullOrEmpty(p.Badge.Icon3x)) + return LoadSprite(p.Badge.Icon3x, 3); - if (p.Second > 1 && !string.IsNullOrEmpty(p.First.Icon2x)) - return LoadSprite(p.First.Icon2x, 2); + if (p.Density > 1 && !string.IsNullOrEmpty(p.Badge.Icon2x)) + return LoadSprite(p.Badge.Icon2x, 2); - return LoadSprite(p.First.Icon, 1); + return LoadSprite(p.Badge.Icon, 1); }); } @@ -114,7 +113,7 @@ { var ws = Game.Renderer.WindowScale; var density = ws > 2 ? 3 : ws > 1 ? 2 : 1; - return iconCache[Pair.New(badge, density)]; + return iconCache[(badge, density)]; } } } diff -Nru openra-20200503/OpenRA.Game/Primitives/BitSet.cs openra-20210321/OpenRA.Game/Primitives/BitSet.cs --- openra-20200503/OpenRA.Game/Primitives/BitSet.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/BitSet.cs 2021-03-21 11:10:05.000000000 +0000 @@ -47,14 +47,9 @@ BitSetIndex bits = 0; lock (Bits) - { foreach (var value in values) - { - BitSetIndex valueBit; - if (Bits.TryGetValue(value, out valueBit)) + if (Bits.TryGetValue(value, out var valueBit)) bits |= valueBit; - } - } return bits; } diff -Nru openra-20200503/OpenRA.Game/Primitives/Color.cs openra-20210321/OpenRA.Game/Primitives/Color.cs --- openra-20200503/OpenRA.Game/Primitives/Color.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/Color.cs 2021-03-21 11:10:05.000000000 +0000 @@ -124,10 +124,10 @@ if (value.Length != 6 && value.Length != 8) return false; - byte red, green, blue, alpha = 255; - if (!byte.TryParse(value.Substring(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out red) - || !byte.TryParse(value.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out green) - || !byte.TryParse(value.Substring(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out blue)) + byte alpha = 255; + if (!byte.TryParse(value.Substring(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var red) + || !byte.TryParse(value.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var green) + || !byte.TryParse(value.Substring(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var blue)) return false; if (value.Length == 8 diff -Nru openra-20200503/OpenRA.Game/Primitives/float3.cs openra-20210321/OpenRA.Game/Primitives/float3.cs --- openra-20200503/OpenRA.Game/Primitives/float3.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/float3.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ { [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter", Justification = "Mimic a built-in type alias.")] [StructLayout(LayoutKind.Sequential)] - public struct float3 : IEquatable + public readonly struct float3 : IEquatable { public readonly float X, Y, Z; public float2 XY { get { return new float2(X, Y); } } @@ -28,13 +28,13 @@ public static implicit operator float3(int2 src) { return new float3(src.X, src.Y, 0); } public static implicit operator float3(float2 src) { return new float3(src.X, src.Y, 0); } - public static float3 operator +(float3 a, float3 b) { return new float3(a.X + b.X, a.Y + b.Y, a.Z + b.Z); } - public static float3 operator -(float3 a, float3 b) { return new float3(a.X - b.X, a.Y - b.Y, a.Z - b.Z); } - public static float3 operator -(float3 a) { return new float3(-a.X, -a.Y, -a.Z); } - public static float3 operator *(float3 a, float3 b) { return new float3(a.X * b.X, a.Y * b.Y, a.Z * b.Z); } - public static float3 operator *(float a, float3 b) { return new float3(a * b.X, a * b.Y, a * b.Z); } - public static float3 operator /(float3 a, float3 b) { return new float3(a.X / b.X, a.Y / b.Y, a.Z / b.Z); } - public static float3 operator /(float3 a, float b) { return new float3(a.X / b, a.Y / b, a.Z / b); } + public static float3 operator +(in float3 a, in float3 b) { return new float3(a.X + b.X, a.Y + b.Y, a.Z + b.Z); } + public static float3 operator -(in float3 a, in float3 b) { return new float3(a.X - b.X, a.Y - b.Y, a.Z - b.Z); } + public static float3 operator -(in float3 a) { return new float3(-a.X, -a.Y, -a.Z); } + public static float3 operator *(in float3 a, in float3 b) { return new float3(a.X * b.X, a.Y * b.Y, a.Z * b.Z); } + public static float3 operator *(float a, in float3 b) { return new float3(a * b.X, a * b.Y, a * b.Z); } + public static float3 operator /(in float3 a, in float3 b) { return new float3(a.X / b.X, a.Y / b.Y, a.Z / b.Z); } + public static float3 operator /(in float3 a, float b) { return new float3(a.X / b, a.Y / b, a.Z / b); } public static float3 Lerp(float3 a, float3 b, float t) { @@ -44,8 +44,8 @@ float2.Lerp(a.Z, b.Z, t)); } - public static bool operator ==(float3 me, float3 other) { return me.X == other.X && me.Y == other.Y && me.Z == other.Z; } - public static bool operator !=(float3 me, float3 other) { return !(me == other); } + public static bool operator ==(in float3 me, in float3 other) { return me.X == other.X && me.Y == other.Y && me.Z == other.Z; } + public static bool operator !=(in float3 me, in float3 other) { return !(me == other); } public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); } public bool Equals(float3 other) @@ -62,5 +62,6 @@ public override string ToString() { return "{0},{1},{2}".F(X, Y, Z); } public static readonly float3 Zero = new float3(0, 0, 0); + public static readonly float3 Ones = new float3(1, 1, 1); } } diff -Nru openra-20200503/OpenRA.Game/Primitives/LongBitSet.cs openra-20210321/OpenRA.Game/Primitives/LongBitSet.cs --- openra-20200503/OpenRA.Game/Primitives/LongBitSet.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/LongBitSet.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,6 +18,7 @@ static class LongBitSetAllocator where T : class { static readonly Cache Bits = new Cache(Allocate); + static long allBits = 1; static long nextBits = 1; static long Allocate(string value) @@ -25,6 +26,7 @@ lock (Bits) { var bits = nextBits; + allBits |= bits; nextBits <<= 1; if (nextBits == 0) @@ -50,14 +52,9 @@ long bits = 0; lock (Bits) - { foreach (var value in values) - { - long valueBit; - if (Bits.TryGetValue(value, out valueBit)) + if (Bits.TryGetValue(value, out var valueBit)) bits |= valueBit; - } - } return bits; } @@ -90,6 +87,8 @@ nextBits = 1; } } + + public static long Mask { get { return allBits; } } } // Opitmized BitSet to be used only when guaranteed to be no more than 64 values. @@ -119,6 +118,7 @@ public static bool operator ==(LongBitSet me, LongBitSet other) { return me.bits == other.bits; } public static bool operator !=(LongBitSet me, LongBitSet other) { return !(me == other); } + public static LongBitSet operator ~(LongBitSet me) { return new LongBitSet(me.bits ^ LongBitSetAllocator.Mask); } public bool Equals(LongBitSet other) { return other == this; } public override bool Equals(object obj) { return obj is LongBitSet && Equals((LongBitSet)obj); } diff -Nru openra-20200503/OpenRA.Game/Primitives/MergedStream.cs openra-20210321/OpenRA.Game/Primitives/MergedStream.cs --- openra-20200503/OpenRA.Game/Primitives/MergedStream.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/MergedStream.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,6 +9,7 @@ */ #endregion +using System; using System.IO; namespace OpenRA.Primitives @@ -18,7 +19,7 @@ public Stream Stream1 { get; set; } public Stream Stream2 { get; set; } - long VirtualLength { get; set; } + long VirtualLength { get; } long position; public MergedStream(Stream stream1, Stream stream2) @@ -61,7 +62,21 @@ public override void SetLength(long value) { - VirtualLength = value; + throw new NotSupportedException(); + } + + public override int ReadByte() + { + int value; + + if (position >= Stream1.Length) + value = Stream2.ReadByte(); + else + value = Stream1.ReadByte(); + + position++; + + return value; } public override int Read(byte[] buffer, int offset, int count) @@ -83,12 +98,14 @@ return bytesRead; } + public override void WriteByte(byte value) + { + throw new NotSupportedException(); + } + public override void Write(byte[] buffer, int offset, int count) { - if (position >= Stream1.Length) - Stream2.Write(buffer, offset - (int)Stream1.Length, count); - else - Stream1.Write(buffer, offset, count); + throw new NotSupportedException(); } public override bool CanRead @@ -103,7 +120,7 @@ public override bool CanWrite { - get { return Stream1.CanWrite && Stream2.CanWrite; } + get { return false; } } public override long Length diff -Nru openra-20200503/OpenRA.Game/Primitives/Pair.cs openra-20210321/OpenRA.Game/Primitives/Pair.cs --- openra-20200503/OpenRA.Game/Primitives/Pair.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/Pair.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; - -namespace OpenRA.Primitives -{ - public struct Pair : IEquatable> - { - public T First; - public U Second; - - public Pair(T first, U second) - { - First = first; - Second = second; - } - - internal static IEqualityComparer Tcomparer = EqualityComparer.Default; - internal static IEqualityComparer Ucomparer = EqualityComparer.Default; - - public static bool operator ==(Pair a, Pair b) - { - return Tcomparer.Equals(a.First, b.First) && Ucomparer.Equals(a.Second, b.Second); - } - - public static bool operator !=(Pair a, Pair b) - { - return !(a == b); - } - - public override int GetHashCode() { return First.GetHashCode() ^ Second.GetHashCode(); } - - public bool Equals(Pair other) { return this == other; } - public override bool Equals(object obj) { return obj is Pair && Equals((Pair)obj); } - - public Pair WithFirst(T t) { return new Pair(t, Second); } - public Pair WithSecond(U u) { return new Pair(First, u); } - - public static T AsFirst(Pair p) { return p.First; } - public static U AsSecond(Pair p) { return p.Second; } - - public override string ToString() - { - return "({0},{1})".F(First, Second); - } - - class PairEqualityComparer : IEqualityComparer> - { - public bool Equals(Pair x, Pair y) { return x == y; } - public int GetHashCode(Pair obj) { return obj.GetHashCode(); } - } - - public static IEqualityComparer> EqualityComparer { get { return new PairEqualityComparer(); } } - } - - public static class Pair - { - public static Pair New(T t, U u) { return new Pair(t, u); } - } -} diff -Nru openra-20200503/OpenRA.Game/Primitives/Polygon.cs openra-20210321/OpenRA.Game/Primitives/Polygon.cs --- openra-20200503/OpenRA.Game/Primitives/Polygon.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/Polygon.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,114 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Linq; + +namespace OpenRA.Primitives +{ + public struct Polygon + { + public static readonly Polygon Empty = new Polygon(Rectangle.Empty); + + public readonly Rectangle BoundingRect; + public readonly int2[] Vertices; + bool isRectangle; + + public Polygon(Rectangle bounds) + { + BoundingRect = bounds; + Vertices = new[] { bounds.TopLeft, bounds.BottomLeft, bounds.BottomRight, bounds.TopRight }; + isRectangle = true; + } + + public Polygon(int2[] vertices) + { + if (vertices != null && vertices.Length > 0) + { + Vertices = vertices; + var left = int.MaxValue; + var right = int.MinValue; + var top = int.MaxValue; + var bottom = int.MinValue; + foreach (var p in vertices) + { + left = Math.Min(left, p.X); + right = Math.Max(right, p.X); + top = Math.Min(top, p.Y); + bottom = Math.Max(bottom, p.Y); + } + + BoundingRect = Rectangle.FromLTRB(left, top, right, bottom); + isRectangle = false; + } + else + { + isRectangle = true; + BoundingRect = Rectangle.Empty; + Vertices = Exts.MakeArray(4, _ => int2.Zero); + } + } + + public bool IsEmpty { get { return BoundingRect.IsEmpty; } } + public bool Contains(int2 xy) + { + return isRectangle ? BoundingRect.Contains(xy) : Vertices.PolygonContains(xy); + } + + public bool IntersectsWith(Rectangle rect) + { + var intersectsBoundingRect = BoundingRect.Left < rect.Right && BoundingRect.Right > rect.Left && BoundingRect.Top < rect.Bottom && BoundingRect.Bottom > rect.Top; + if (isRectangle) + return intersectsBoundingRect; + + // Easy case 1: Rect and bounding box don't intersect + if (!intersectsBoundingRect) + return false; + + // Easy case 2: Rect and bounding box intersect in a cross shape + if ((rect.Left <= BoundingRect.Left && rect.Right >= BoundingRect.Right) || (rect.Top <= BoundingRect.Top && rect.Bottom >= BoundingRect.Bottom)) + return true; + + // Easy case 3: Corner of rect is inside the polygon + if (Vertices.PolygonContains(rect.TopLeft) || Vertices.PolygonContains(rect.TopRight) || Vertices.PolygonContains(rect.BottomLeft) || Vertices.PolygonContains(rect.BottomRight)) + return true; + + // Easy case 4: Polygon vertex is inside rect + if (Vertices.Any(p => rect.Contains(p))) + return true; + + // Hard case: check intersection of every line segment pair + var rectVertices = new[] + { + rect.TopLeft, + rect.BottomLeft, + rect.BottomRight, + rect.TopRight + }; + + for (var i = 0; i < Vertices.Length; i++) + for (var j = 0; j < 4; j++) + if (Exts.LinesIntersect(Vertices[i], Vertices[(i + 1) % Vertices.Length], rectVertices[j], rectVertices[(j + 1) % 4])) + return true; + + return false; + } + + public override int GetHashCode() + { + var code = BoundingRect.GetHashCode(); + foreach (var v in Vertices) + code = ((code << 5) + code) ^ v.GetHashCode(); + + return code; + } + } +} diff -Nru openra-20200503/OpenRA.Game/Primitives/ReadOnlyAdapterStream.cs openra-20210321/OpenRA.Game/Primitives/ReadOnlyAdapterStream.cs --- openra-20200503/OpenRA.Game/Primitives/ReadOnlyAdapterStream.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/ReadOnlyAdapterStream.cs 2021-03-21 11:10:05.000000000 +0000 @@ -48,9 +48,25 @@ public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public sealed override void SetLength(long value) { throw new NotSupportedException(); } + public sealed override void WriteByte(byte value) { throw new NotSupportedException(); } public sealed override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } public sealed override void Flush() { throw new NotSupportedException(); } + public sealed override int ReadByte() + { + if (data.Count > 0) + return data.Dequeue(); + + while (!baseStreamEmpty) + { + baseStreamEmpty = BufferData(baseStream, data); + if (data.Count > 0) + return data.Dequeue(); + } + + return -1; + } + public sealed override int Read(byte[] buffer, int offset, int count) { var copied = 0; @@ -66,7 +82,8 @@ } /// - /// Reads data into a buffer, which will be used to satisfy calls. + /// Reads data into a buffer, which will be used to satisfy and + /// calls. /// /// The source stream from which bytes should be read. /// The queue where bytes should be enqueued. Do not dequeue from this buffer. diff -Nru openra-20200503/OpenRA.Game/Primitives/Rectangle.cs openra-20210321/OpenRA.Game/Primitives/Rectangle.cs --- openra-20200503/OpenRA.Game/Primitives/Rectangle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/Rectangle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -66,6 +66,11 @@ public int2 Location { get { return new int2(X, Y); } } public Size Size { get { return new Size(Width, Height); } } + public int2 TopLeft { get { return Location; } } + public int2 TopRight { get { return new int2(X + Width, Y); } } + public int2 BottomLeft { get { return new int2(X, Y + Height); } } + public int2 BottomRight { get { return new int2(X + Width, Y + Height); } } + public bool Contains(int x, int y) { return x >= Left && x < Right && y >= Top && y < Bottom; diff -Nru openra-20200503/OpenRA.Game/Primitives/SegmentStream.cs openra-20210321/OpenRA.Game/Primitives/SegmentStream.cs --- openra-20200503/OpenRA.Game/Primitives/SegmentStream.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/SegmentStream.cs 2021-03-21 11:10:05.000000000 +0000 @@ -59,8 +59,35 @@ set { BaseStream.Position = BaseOffset + value; } } - public override int Read(byte[] buffer, int offset, int count) { return BaseStream.Read(buffer, offset, count); } - public override void Write(byte[] buffer, int offset, int count) { BaseStream.Write(buffer, offset, count); } + public override int ReadByte() + { + if (Position < Length) + return BaseStream.ReadByte(); + return -1; + } + + public override int Read(byte[] buffer, int offset, int count) + { + var remaining = Length - Position; + if (remaining <= 0) + return 0; + return BaseStream.Read(buffer, offset, (int)Math.Min(remaining, count)); + } + + public override void WriteByte(byte value) + { + if (Position < Length) + BaseStream.WriteByte(value); + throw new IOException("Attempted to write past the end of the stream."); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (Position + count >= Length) + throw new IOException("Attempted to write past the end of the stream."); + BaseStream.Write(buffer, offset, count); + } + public override void Flush() { BaseStream.Flush(); } public override long Seek(long offset, SeekOrigin origin) { @@ -120,8 +147,7 @@ /// The length of the segment. public static Stream CreateWithoutOwningStream(Stream stream, long offset, int count) { - Stream parentStream; - var nestedOffset = offset + GetOverallNestedOffset(stream, out parentStream); + var nestedOffset = offset + GetOverallNestedOffset(stream, out var parentStream); // Special case FileStream - instead of creating an in-memory copy, // just reference the portion of the on-disk file that we need to save memory. diff -Nru openra-20200503/OpenRA.Game/Primitives/SpatiallyPartitioned.cs openra-20210321/OpenRA.Game/Primitives/SpatiallyPartitioned.cs --- openra-20200503/OpenRA.Game/Primitives/SpatiallyPartitioned.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/SpatiallyPartitioned.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,8 +52,7 @@ public bool Remove(T item) { - Rectangle bounds; - if (!itemBounds.TryGetValue(item, out bounds)) + if (!itemBounds.TryGetValue(item, out var bounds)) return false; MutateBins(item, bounds, removeItem); @@ -91,8 +90,7 @@ void MutateBins(T actor, Rectangle bounds, Action, T, Rectangle> action) { - int minRow, maxRow, minCol, maxCol; - BoundsToBinRowsAndCols(bounds, out minRow, out maxRow, out minCol, out maxCol); + BoundsToBinRowsAndCols(bounds, out var minRow, out var maxRow, out var minCol, out var maxCol); for (var row = minRow; row < maxRow; row++) for (var col = minCol; col < maxCol; col++) @@ -110,8 +108,7 @@ public IEnumerable InBox(Rectangle box) { - int minRow, maxRow, minCol, maxCol; - BoundsToBinRowsAndCols(box, out minRow, out maxRow, out minCol, out maxCol); + BoundsToBinRowsAndCols(box, out var minRow, out var maxRow, out var minCol, out var maxCol); // We want to return any items intersecting the box. // If the box covers multiple bins, we must handle items that are contained in multiple bins and avoid @@ -139,5 +136,7 @@ } public IEnumerable ItemBounds { get { return itemBounds.Values; } } + + public IEnumerable Items { get { return itemBounds.Keys; } } } } diff -Nru openra-20200503/OpenRA.Game/Primitives/TypeDictionary.cs openra-20210321/OpenRA.Game/Primitives/TypeDictionary.cs --- openra-20200503/OpenRA.Game/Primitives/TypeDictionary.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Primitives/TypeDictionary.cs 2021-03-21 11:10:05.000000000 +0000 @@ -41,6 +41,11 @@ return data.ContainsKey(typeof(T)); } + public bool Contains(Type t) + { + return data.ContainsKey(t); + } + public T Get() { return (T)Get(typeof(T), true); @@ -56,8 +61,7 @@ object Get(Type t, bool throwsIfMissing) { - List ret; - if (!data.TryGetValue(t, out ret)) + if (!data.TryGetValue(t, out var ret)) { if (throwsIfMissing) throw new InvalidOperationException("TypeDictionary does not contain instance of type `{0}`".F(t)); @@ -71,8 +75,7 @@ public IEnumerable WithInterface() { - List objs; - if (data.TryGetValue(typeof(T), out objs)) + if (data.TryGetValue(typeof(T), out var objs)) return objs.Cast(); return new T[0]; } @@ -89,8 +92,7 @@ void InnerRemove(Type t, object val) { - List objs; - if (!data.TryGetValue(t, out objs)) + if (!data.TryGetValue(t, out var objs)) return; objs.Remove(val); if (objs.Count == 0) diff -Nru openra-20200503/OpenRA.Game/Properties/launchSettings.json openra-20210321/OpenRA.Game/Properties/launchSettings.json --- openra-20200503/OpenRA.Game/Properties/launchSettings.json 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Properties/launchSettings.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -{ - "profiles": { - "Tiberian Dawn": { - "commandName": "Project", - "commandLineArgs": "Game.Mod=cnc" - }, - "Red Alert": { - "commandName": "Project", - "commandLineArgs": "Game.Mod=ra" - }, - "Dune 2000": { - "commandName": "Project", - "commandLineArgs": "Game.Mod=d2k" - }, - "Tiberian Sun": { - "commandName": "Project", - "commandLineArgs": "Game.Mod=ts" - } - } -} \ No newline at end of file diff -Nru openra-20200503/OpenRA.Game/Renderer.cs openra-20210321/OpenRA.Game/Renderer.cs --- openra-20200503/OpenRA.Game/Renderer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Renderer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,6 +31,15 @@ public RgbaColorRenderer RgbaColorRenderer { get; private set; } public SpriteRenderer SpriteRenderer { get; private set; } public RgbaSpriteRenderer RgbaSpriteRenderer { get; private set; } + + public bool WindowHasInputFocus + { + get + { + return Window.HasInputFocus; + } + } + public IReadOnlyDictionary Fonts; internal IPlatformWindow Window { get; private set; } @@ -68,7 +77,7 @@ Window = platform.CreateWindow(new Size(resolution.Width, resolution.Height), graphicSettings.Mode, graphicSettings.UIScale, graphicSettings.BatchSize, - graphicSettings.VideoDisplay, graphicSettings.GLProfile); + graphicSettings.VideoDisplay, graphicSettings.GLProfile, !graphicSettings.DisableLegacyGL); Context = Window.Context; @@ -106,8 +115,7 @@ font.Dispose(); using (new PerfTimer("SpriteFonts")) { - if (fontSheetBuilder != null) - fontSheetBuilder.Dispose(); + fontSheetBuilder?.Dispose(); fontSheetBuilder = new SheetBuilder(SheetType.BGRA, 512); Fonts = modData.Manifest.Get().FontList.ToDictionary(x => x.Key, x => new SpriteFont(x.Value.Font, modData.DefaultFileSystem.Open(x.Value.Font).ReadAllBytes(), @@ -147,8 +155,7 @@ if (screenSprite == null || screenSprite.Sheet.Size != surfaceBufferSize) { - if (screenBuffer != null) - screenBuffer.Dispose(); + screenBuffer?.Dispose(); // Render the screen into a frame buffer to simplify reading back screenshots screenBuffer = Context.CreateFrameBuffer(surfaceBufferSize, Color.FromArgb(0xFF, 0, 0, 0)); @@ -186,8 +193,7 @@ var worldBufferSize = worldViewport.Size.NextPowerOf2(); if (worldSprite == null || worldSprite.Sheet.Size != worldBufferSize) { - if (worldBuffer != null) - worldBuffer.Dispose(); + worldBuffer?.Dispose(); // Render the world into a framebuffer at 1:1 scaling to allow the depth buffer to match the artwork at all zoom levels worldBuffer = Context.CreateFrameBuffer(worldBufferSize); @@ -320,8 +326,7 @@ { if (currentBatchRenderer == value) return; - if (currentBatchRenderer != null) - currentBatchRenderer.Flush(); + currentBatchRenderer?.Flush(); currentBatchRenderer = value; } } @@ -451,8 +456,7 @@ { WorldModelRenderer.Dispose(); tempBuffer.Dispose(); - if (fontSheetBuilder != null) - fontSheetBuilder.Dispose(); + fontSheetBuilder?.Dispose(); if (Fonts != null) foreach (var font in Fonts.Values) font.Dispose(); diff -Nru openra-20200503/OpenRA.Game/Scripting/ScriptContext.cs openra-20210321/OpenRA.Game/Scripting/ScriptContext.cs --- openra-20200503/OpenRA.Game/Scripting/ScriptContext.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Scripting/ScriptContext.cs 2021-03-21 11:10:05.000000000 +0000 @@ -161,8 +161,8 @@ .ToArray(); PlayerCommands = FilterCommands(world.Map.Rules.Actors["player"], knownPlayerCommands); - runtime.Globals["GameDir"] = Platform.GameDir; - runtime.DoBuffer(File.Open(Platform.ResolvePath(".", "lua", "scriptwrapper.lua"), FileMode.Open, FileAccess.Read).ReadAllText(), "scriptwrapper.lua").Dispose(); + runtime.Globals["EngineDir"] = Platform.EngineDir; + runtime.DoBuffer(File.Open(Path.Combine(Platform.EngineDir, "lua", "scriptwrapper.lua"), FileMode.Open, FileAccess.Read).ReadAllText(), "scriptwrapper.lua").Dispose(); tick = (LuaFunction)runtime.Globals["Tick"]; // Register globals @@ -267,8 +267,7 @@ return; disposed = true; - if (runtime != null) - runtime.Dispose(); + runtime?.Dispose(); } static IEnumerable ExtractRequiredTypes(Type t) diff -Nru openra-20200503/OpenRA.Game/Scripting/ScriptMemberExts.cs openra-20210321/OpenRA.Game/Scripting/ScriptMemberExts.cs --- openra-20200503/OpenRA.Game/Scripting/ScriptMemberExts.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Scripting/ScriptMemberExts.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,8 +28,7 @@ public static string LuaDocString(this Type t) { - string ret; - if (!LuaTypeNameReplacements.TryGetValue(t.Name, out ret)) + if (!LuaTypeNameReplacements.TryGetValue(t.Name, out var ret)) ret = t.Name; return ret; } diff -Nru openra-20200503/OpenRA.Game/Scripting/ScriptMemberWrapper.cs openra-20210321/OpenRA.Game/Scripting/ScriptMemberWrapper.cs --- openra-20200503/OpenRA.Game/Scripting/ScriptMemberWrapper.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Scripting/ScriptMemberWrapper.cs 2021-03-21 11:10:05.000000000 +0000 @@ -86,9 +86,11 @@ { foreach (var arg in clrArgs) { - if (!(arg is LuaValue[])) + var table = arg as LuaValue[]; + if (table == null) continue; - foreach (var value in (LuaValue[])arg) + + foreach (var value in table) value.Dispose(); } } @@ -111,8 +113,7 @@ if (IsSetProperty) { var pi = (PropertyInfo)Member; - object clrValue; - if (!value.TryGetClrValue(pi.PropertyType, out clrValue)) + if (!value.TryGetClrValue(pi.PropertyType, out var clrValue)) throw new LuaException("Unable to convert '{0}' to Clr type '{1}'".F(value.WrappedClrType().Name, pi.PropertyType)); pi.SetValue(Target, clrValue, null); diff -Nru openra-20200503/OpenRA.Game/Scripting/ScriptObjectWrapper.cs openra-20210321/OpenRA.Game/Scripting/ScriptObjectWrapper.cs --- openra-20200503/OpenRA.Game/Scripting/ScriptObjectWrapper.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Scripting/ScriptObjectWrapper.cs 2021-03-21 11:10:05.000000000 +0000 @@ -51,8 +51,7 @@ get { var name = keyValue.ToString(); - ScriptMemberWrapper wrapper; - if (!members.TryGetValue(name, out wrapper)) + if (!members.TryGetValue(name, out var wrapper)) throw new LuaException(MemberNotFoundError(name)); return wrapper.Get(runtime); @@ -61,8 +60,7 @@ set { var name = keyValue.ToString(); - ScriptMemberWrapper wrapper; - if (!members.TryGetValue(name, out wrapper)) + if (!members.TryGetValue(name, out var wrapper)) throw new LuaException(MemberNotFoundError(name)); wrapper.Set(runtime, value); diff -Nru openra-20200503/OpenRA.Game/Scripting/ScriptTypes.cs openra-20210321/OpenRA.Game/Scripting/ScriptTypes.cs --- openra-20200503/OpenRA.Game/Scripting/ScriptTypes.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Scripting/ScriptTypes.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,8 +18,7 @@ { public static Type WrappedClrType(this LuaValue value) { - object inner; - if (value.TryGetClrObject(out inner)) + if (value.TryGetClrObject(out var inner)) return inner.GetType(); return value.GetType(); @@ -27,16 +26,13 @@ public static bool TryGetClrValue(this LuaValue value, out T clrObject) { - object temp; - var ret = value.TryGetClrValue(typeof(T), out temp); + var ret = value.TryGetClrValue(typeof(T), out object temp); clrObject = ret ? (T)temp : default(T); return ret; } public static bool TryGetClrValue(this LuaValue value, Type t, out object clrObject) { - object temp; - // Is t a nullable? // If yes, get the underlying type var nullable = Nullable.GetUnderlyingType(t); @@ -44,7 +40,7 @@ t = nullable; // Value wraps a CLR object - if (value.TryGetClrObject(out temp)) + if (value.TryGetClrObject(out var temp)) { if (temp.GetType() == t) { @@ -172,8 +168,7 @@ { // Object needs additional notification / context var notify = obj as IScriptNotifyBind; - if (notify != null) - notify.OnScriptBind(context); + notify?.OnScriptBind(context); return new LuaCustomClrObject(obj); } diff -Nru openra-20200503/OpenRA.Game/SelectableExts.cs openra-20210321/OpenRA.Game/SelectableExts.cs --- openra-20200503/OpenRA.Game/SelectableExts.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/SelectableExts.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,7 +20,7 @@ { public static int SelectionPriority(this ActorInfo a, Modifiers modifiers) { - var selectableInfo = a.TraitInfoOrDefault(); + var selectableInfo = a.TraitInfoOrDefault(); return selectableInfo != null ? BaseSelectionPriority(selectableInfo, modifiers) : int.MinValue; } @@ -28,7 +28,7 @@ public static int SelectionPriority(this Actor a, Modifiers modifiers) { - var info = a.Info.TraitInfo(); + var info = a.Info.TraitInfo(); var basePriority = BaseSelectionPriority(info, modifiers); var viewer = (a.World.LocalPlayer == null || a.World.LocalPlayer.Spectating) ? a.World.RenderPlayer : a.World.LocalPlayer; @@ -36,18 +36,18 @@ if (a.Owner == viewer || viewer == null) return basePriority; - switch (viewer.Stances[a.Owner]) + switch (viewer.RelationshipWith(a.Owner)) { - case Stance.Ally: return basePriority - PriorityRange; - case Stance.Neutral: return basePriority - 2 * PriorityRange; - case Stance.Enemy: return basePriority - 3 * PriorityRange; + case PlayerRelationship.Ally: return basePriority - PriorityRange; + case PlayerRelationship.Neutral: return basePriority - 2 * PriorityRange; + case PlayerRelationship.Enemy: return basePriority - 3 * PriorityRange; default: throw new InvalidOperationException(); } } - static int BaseSelectionPriority(SelectableInfo info, Modifiers modifiers) + static int BaseSelectionPriority(ISelectableInfo info, Modifiers modifiers) { var priority = info.Priority; @@ -73,14 +73,18 @@ return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Info, a.MouseBounds, selectionPixel, modifiers)); } - static long CalculateActorSelectionPriority(ActorInfo info, Rectangle bounds, int2 selectionPixel, Modifiers modifiers) + static long CalculateActorSelectionPriority(ActorInfo info, Polygon bounds, int2 selectionPixel, Modifiers modifiers) { if (bounds.IsEmpty) return info.SelectionPriority(modifiers); + // Assume that the center of the polygon is the same as the center of the bounding box + // This isn't necessarily true for arbitrary polygons, but is fine for the hexagonal and diamond + // shapes that are currently implemented + var br = bounds.BoundingRect; var centerPixel = new int2( - bounds.Left + bounds.Size.Width / 2, - bounds.Top + bounds.Size.Height / 2); + br.Left + br.Size.Width / 2, + br.Top + br.Size.Height / 2); var pixelDistance = (centerPixel - selectionPixel).Length; return info.SelectionPriority(modifiers) - (long)pixelDistance << 16; diff -Nru openra-20200503/OpenRA.Game/Server/ProtocolVersion.cs openra-20210321/OpenRA.Game/Server/ProtocolVersion.cs --- openra-20200503/OpenRA.Game/Server/ProtocolVersion.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Server/ProtocolVersion.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,6 +25,8 @@ // Order types are: // - 0x65: World sync hash: // - Int32 containing the sync hash value + // - UInt64 containing the current defeat state (a bit set + // to 1 means the corresponding player is defeated) // - 0xBF: Player disconnected // - 0xFE: Handshake (also used for ServerOrders for ProtocolVersion.Orders < 8) // - Length-prefixed string specifying a name or key @@ -66,6 +68,6 @@ // The protocol for server and world orders // This applies after the handshake has completed, and is provided to support // alternative server implementations that wish to support multiple versions in parallel - public const int Orders = 10; + public const int Orders = 11; } } diff -Nru openra-20200503/OpenRA.Game/Server/Server.cs openra-20210321/OpenRA.Game/Server/Server.cs --- openra-20200503/OpenRA.Game/Server/Server.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Server/Server.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,10 +18,11 @@ using System.Net.Sockets; using System.Text; using System.Threading; -using OpenRA.Graphics; +using OpenRA.FileFormats; using OpenRA.Network; using OpenRA.Primitives; using OpenRA.Support; +using OpenRA.Traits; namespace OpenRA.Server { @@ -43,8 +44,6 @@ { public readonly string TwoHumansRequiredText = "This server requires at least two human players to start a match."; - public readonly IPAddress Ip; - public readonly int Port; public readonly MersenneTwister Random = new MersenneTwister(); public readonly ServerType Type; @@ -64,7 +63,7 @@ public GameSave GameSave = null; readonly int randomSeed; - readonly TcpListener listener; + readonly List listeners = new List(); readonly TypeDictionary serverTraits = new TypeDictionary(); readonly PlayerDatabase playerDatabase; @@ -73,6 +72,10 @@ volatile ActionQueue delayedActions = new ActionQueue(); int waitingForAuthenticationCallback = 0; + ReplayRecorder recorder; + GameInformation gameInfo; + readonly List worldPlayers = new List(); + public ServerState State { get { return internalState; } @@ -90,6 +93,8 @@ c.SpawnPoint = pr.Spawn; if (pr.LockTeam) c.Team = pr.Team; + if (pr.LockHandicap) + c.Team = pr.Handicap; c.Color = pr.LockColor ? pr.Color : c.PreferredColor; } @@ -102,8 +107,7 @@ // Non-blocking sends are free to send only part of the data while (start < length) { - SocketError error; - var sent = s.Send(data, start, length - start, SocketFlags.None, out error); + var sent = s.Send(data, start, length - start, SocketFlags.None, out var error); if (error == SocketError.WouldBlock) { Log.Write("server", "Non-blocking send of {0} bytes failed. Falling back to blocking send.", length - start); @@ -127,17 +131,81 @@ { foreach (var t in serverTraits.WithInterface()) t.GameEnded(this); + + recorder?.Dispose(); + recorder = null; } - public Server(IPEndPoint endpoint, ServerSettings settings, ModData modData, ServerType type) + // Craft a fake handshake request/response because that's the + // only way to expose the Version and OrdersProtocol. + public void RecordFakeHandshake() + { + var request = new HandshakeRequest + { + Mod = ModData.Manifest.Id, + Version = ModData.Manifest.Metadata.Version, + }; + + recorder.ReceiveFrame(0, 0, new Order("HandshakeRequest", null, false) + { + Type = OrderType.Handshake, + IsImmediate = true, + TargetString = request.Serialize(), + }.Serialize()); + + var response = new HandshakeResponse() + { + Mod = ModData.Manifest.Id, + Version = ModData.Manifest.Metadata.Version, + OrdersProtocol = ProtocolVersion.Orders, + Client = new Session.Client(), + }; + + recorder.ReceiveFrame(0, 0, new Order("HandshakeResponse", null, false) + { + Type = OrderType.Handshake, + IsImmediate = true, + TargetString = response.Serialize(), + }.Serialize()); + } + + public Server(List endpoints, ServerSettings settings, ModData modData, ServerType type) { Log.AddChannel("server", "server.log", true); - listener = new TcpListener(endpoint); - listener.Start(); - var localEndpoint = (IPEndPoint)listener.LocalEndpoint; - Ip = localEndpoint.Address; - Port = localEndpoint.Port; + SocketException lastException = null; + var checkReadServer = new List(); + foreach (var endpoint in endpoints) + { + var listener = new TcpListener(endpoint); + try + { + try + { + listener.Server.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 1); + } + catch (Exception ex) + { + if (ex is SocketException || ex is ArgumentException) + Log.Write("server", "Failed to set socket option on {0}: {1}", endpoint.ToString(), ex.Message); + else + throw; + } + + listener.Start(); + listeners.Add(listener); + checkReadServer.Add(listener.Server); + } + catch (SocketException ex) + { + lastException = ex; + Log.Write("server", "Failed to listen on {0}: {1}", endpoint.ToString(), ex.Message); + } + } + + if (listeners.Count == 0) + throw lastException; + Type = type; Settings = settings; @@ -152,7 +220,7 @@ if (type != ServerType.Local && settings.EnableGeoIP) GeoIP.Initialize(); - if (UPnP.Status == UPnPStatus.Enabled) + if (type != ServerType.Local && UPnP.Status == UPnPStatus.Enabled) UPnP.ForwardPort(Settings.ListenPort, Settings.ListenPort).Wait(); foreach (var trait in modData.Manifest.ServerTraits) @@ -174,6 +242,15 @@ } }; + if (Settings.RecordReplays && Type == ServerType.Dedicated) + { + recorder = new ReplayRecorder(() => { return Game.TimestampedFilename(extra: "-Server"); }); + + // We only need one handshake to initialize the replay. + // Add it now, then ignore the redundant handshakes from each client + RecordFakeHandshake(); + } + new Thread(_ => { foreach (var t in serverTraits.WithInterface()) @@ -186,7 +263,7 @@ { var checkRead = new List(); if (State == ServerState.WaitingPlayers) - checkRead.Add(listener.Server); + checkRead.AddRange(checkReadServer); checkRead.AddRange(Conns.Select(c => c.Socket)); checkRead.AddRange(PreConns.Select(c => c.Socket)); @@ -205,9 +282,10 @@ foreach (var s in checkRead) { - if (s == listener.Server) + var serverIndex = checkReadServer.IndexOf(s); + if (serverIndex >= 0) { - AcceptConnection(); + AcceptConnection(listeners[serverIndex]); continue; } @@ -219,8 +297,7 @@ } var conn = Conns.SingleOrDefault(c => c.Socket == s); - if (conn != null) - conn.ReadData(this); + conn?.ReadData(this); } delayedActions.PerformActions(0); @@ -235,7 +312,7 @@ if (State == ServerState.ShuttingDown) { EndGame(); - if (UPnP.Status == UPnPStatus.Enabled) + if (type != ServerType.Local && UPnP.Status == UPnPStatus.Enabled) UPnP.RemovePortForward().Wait(); break; } @@ -246,9 +323,14 @@ PreConns.Clear(); Conns.Clear(); - try { listener.Stop(); } - catch { } - }) { IsBackground = true }.Start(); + + foreach (var listener in listeners) + { + try { listener.Stop(); } + catch { } + } + }) + { IsBackground = true }.Start(); } int nextPlayerIndex; @@ -257,7 +339,7 @@ return nextPlayerIndex++; } - void AcceptConnection() + void AcceptConnection(TcpListener listener) { Socket newSocket; @@ -357,6 +439,7 @@ Faction = "Random", SpawnPoint = 0, Team = 0, + Handicap = 0, State = Session.ClientState.Invalid, }; @@ -402,69 +485,72 @@ Action completeConnection = () => { - client.Slot = LobbyInfo.FirstEmptySlot(); - client.IsAdmin = !LobbyInfo.Clients.Any(c1 => c1.IsAdmin); - - if (client.IsObserver && !LobbyInfo.GlobalSettings.AllowSpectators) + lock (LobbyInfo) { - SendOrderTo(newConn, "ServerError", "The game is full"); - DropClient(newConn); - return; - } + client.Slot = LobbyInfo.FirstEmptySlot(); + client.IsAdmin = !LobbyInfo.Clients.Any(c1 => c1.IsAdmin); - if (client.Slot != null) - SyncClientToPlayerReference(client, Map.Players.Players[client.Slot]); - else - client.Color = Color.White; + if (client.IsObserver && !LobbyInfo.GlobalSettings.AllowSpectators) + { + SendOrderTo(newConn, "ServerError", "The game is full"); + DropClient(newConn); + return; + } - // Promote connection to a valid client - PreConns.Remove(newConn); - Conns.Add(newConn); - LobbyInfo.Clients.Add(client); - newConn.Validated = true; + if (client.Slot != null) + SyncClientToPlayerReference(client, Map.Players.Players[client.Slot]); + else + client.Color = Color.White; - var clientPing = new Session.ClientPing { Index = client.Index }; - LobbyInfo.ClientPings.Add(clientPing); + // Promote connection to a valid client + PreConns.Remove(newConn); + Conns.Add(newConn); + LobbyInfo.Clients.Add(client); + newConn.Validated = true; + + var clientPing = new Session.ClientPing { Index = client.Index }; + LobbyInfo.ClientPings.Add(clientPing); + + Log.Write("server", "Client {0}: Accepted connection from {1}.", + newConn.PlayerIndex, newConn.Socket.RemoteEndPoint); + + if (client.Fingerprint != null) + Log.Write("server", "Client {0}: Player fingerprint is {1}.", + newConn.PlayerIndex, client.Fingerprint); - Log.Write("server", "Client {0}: Accepted connection from {1}.", - newConn.PlayerIndex, newConn.Socket.RemoteEndPoint); + foreach (var t in serverTraits.WithInterface()) + t.ClientJoined(this, newConn); - if (client.Fingerprint != null) - Log.Write("server", "Client {0}: Player fingerprint is {1}.", - newConn.PlayerIndex, client.Fingerprint); + SyncLobbyInfo(); - foreach (var t in serverTraits.WithInterface()) - t.ClientJoined(this, newConn); + Log.Write("server", "{0} ({1}) has joined the game.", + client.Name, newConn.Socket.RemoteEndPoint); - SyncLobbyInfo(); + // Report to all other players + SendMessage("{0} has joined the game.".F(client.Name), newConn); - Log.Write("server", "{0} ({1}) has joined the game.", - client.Name, newConn.Socket.RemoteEndPoint); + // Send initial ping + SendOrderTo(newConn, "Ping", Game.RunTime.ToString(CultureInfo.InvariantCulture)); - // Report to all other players - SendMessage("{0} has joined the game.".F(client.Name), newConn); + if (Type == ServerType.Dedicated) + { + var motdFile = Path.Combine(Platform.SupportDir, "motd.txt"); + if (!File.Exists(motdFile)) + File.WriteAllText(motdFile, "Welcome, have fun and good luck!"); + + var motd = File.ReadAllText(motdFile); + if (!string.IsNullOrEmpty(motd)) + SendOrderTo(newConn, "Message", motd); + } - // Send initial ping - SendOrderTo(newConn, "Ping", Game.RunTime.ToString(CultureInfo.InvariantCulture)); + if (Map.DefinesUnsafeCustomRules) + SendOrderTo(newConn, "Message", "This map contains custom rules. Game experience may change."); - if (Type == ServerType.Dedicated) - { - var motdFile = Platform.ResolvePath(Platform.SupportDirPrefix, "motd.txt"); - if (!File.Exists(motdFile)) - File.WriteAllText(motdFile, "Welcome, have fun and good luck!"); - - var motd = File.ReadAllText(motdFile); - if (!string.IsNullOrEmpty(motd)) - SendOrderTo(newConn, "Message", motd); - } - - if (Map.DefinesUnsafeCustomRules) - SendOrderTo(newConn, "Message", "This map contains custom rules. Game experience may change."); - - if (!LobbyInfo.GlobalSettings.EnableSingleplayer) - SendOrderTo(newConn, "Message", TwoHumansRequiredText); - else if (Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots)) - SendOrderTo(newConn, "Message", "Bots have been disabled on this map."); + if (!LobbyInfo.GlobalSettings.EnableSingleplayer) + SendOrderTo(newConn, "Message", TwoHumansRequiredText); + else if (Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots)) + SendOrderTo(newConn, "Message", "Bots have been disabled on this map."); + } }; if (Type == ServerType.Local) @@ -596,11 +682,119 @@ } } + bool AnyUndefinedWinStates() + { + var lastTeam = -1; + var remainingPlayers = gameInfo.Players.Where(p => p.Outcome == WinState.Undefined); + foreach (var player in remainingPlayers) + { + if (lastTeam >= 0 && (player.Team != lastTeam || player.Team == 0)) + return true; + + lastTeam = player.Team; + } + + return false; + } + + void SetPlayerDefeat(int playerIndex) + { + var defeatedPlayer = worldPlayers[playerIndex]; + if (defeatedPlayer == null || defeatedPlayer.Outcome != WinState.Undefined) + return; + + defeatedPlayer.Outcome = WinState.Lost; + defeatedPlayer.OutcomeTimestampUtc = DateTime.UtcNow; + + // Set remaining players as winners if only one side remains + if (!AnyUndefinedWinStates()) + { + var now = DateTime.UtcNow; + var remainingPlayers = gameInfo.Players.Where(p => p.Outcome == WinState.Undefined); + foreach (var winner in remainingPlayers) + { + winner.Outcome = WinState.Won; + winner.OutcomeTimestampUtc = now; + } + } + } + + void OutOfSync(int frame) + { + Log.Write("server", "Out of sync detected at frame {0}, cancel replay recording", frame); + + // Make sure the written file is not valid + // TODO: storing a serverside replay on desync would be extremely useful + recorder.Metadata = null; + + recorder.Dispose(); + + // Stop the recording + recorder = null; + } + + readonly Dictionary syncForFrame = new Dictionary(); + int lastDefeatStateFrame; + ulong lastDefeatState; + + void HandleSyncOrder(int frame, byte[] packet) + { + if (syncForFrame.TryGetValue(frame, out var existingSync)) + { + if (packet.Length != existingSync.Length) + { + OutOfSync(frame); + return; + } + + for (var i = 0; i < packet.Length; i++) + { + if (packet[i] != existingSync[i]) + { + OutOfSync(frame); + return; + } + } + } + else + { + // Update player losses based on the new defeat state. + // Do this once for the first player, the check above + // guarantees a desync if any other player disagrees. + var playerDefeatState = BitConverter.ToUInt64(packet, 1 + 4); + if (frame > lastDefeatStateFrame && lastDefeatState != playerDefeatState) + { + var newDefeats = playerDefeatState & ~lastDefeatState; + for (var i = 0; i < worldPlayers.Count; i++) + if ((newDefeats & (1UL << i)) != 0) + SetPlayerDefeat(i); + + lastDefeatState = playerDefeatState; + lastDefeatStateFrame = frame; + } + + syncForFrame.Add(frame, packet); + } + } + public void DispatchOrdersToClients(Connection conn, int frame, byte[] data) { var from = conn != null ? conn.PlayerIndex : 0; foreach (var c in Conns.Except(conn).ToList()) DispatchOrdersToClient(c, from, frame, data); + + if (recorder != null) + { + recorder.ReceiveFrame(from, frame, data); + + if (data.Length > 0 && data[0] == (byte)OrderType.SyncHash) + { + if (data.Length == Order.SyncHashOrderLength) + HandleSyncOrder(frame, data); + else + Log.Write("server", "Dropped sync order with length {0} from client {1}. Expected length {2}.".F(data.Length, from, Order.SyncHashOrderLength)); + } + } } public void DispatchOrders(Connection conn, int frame, byte[] data) @@ -647,90 +841,119 @@ void InterpretServerOrder(Connection conn, Order o) { - // Only accept handshake responses from unvalidated clients - // Anything else may be an attempt to exploit the server - if (!conn.Validated) + lock (LobbyInfo) { - if (o.OrderString == "HandshakeResponse") - ValidateClient(conn, o.TargetString); - else + // Only accept handshake responses from unvalidated clients + // Anything else may be an attempt to exploit the server + if (!conn.Validated) { - Log.Write("server", "Rejected connection from {0}; Order `{1}` is not a `HandshakeResponse`.", - conn.Socket.RemoteEndPoint, o.OrderString); + if (o.OrderString == "HandshakeResponse") + ValidateClient(conn, o.TargetString); + else + { + Log.Write("server", "Rejected connection from {0}; Order `{1}` is not a `HandshakeResponse`.", + conn.Socket.RemoteEndPoint, o.OrderString); + + DropClient(conn); + } - DropClient(conn); + return; } - return; - } + switch (o.OrderString) + { + case "Command": + { + var handledBy = serverTraits.WithInterface() + .FirstOrDefault(t => t.InterpretCommand(this, conn, GetClient(conn), o.TargetString)); - switch (o.OrderString) - { - case "Command": - { - var handledBy = serverTraits.WithInterface() - .FirstOrDefault(t => t.InterpretCommand(this, conn, GetClient(conn), o.TargetString)); + if (handledBy == null) + { + Log.Write("server", "Unknown server command: {0}", o.TargetString); + SendOrderTo(conn, "Message", "Unknown server command: {0}".F(o.TargetString)); + } - if (handledBy == null) - { - Log.Write("server", "Unknown server command: {0}", o.TargetString); - SendOrderTo(conn, "Message", "Unknown server command: {0}".F(o.TargetString)); + break; } + case "Chat": + DispatchOrdersToClients(conn, 0, o.Serialize()); break; - } - - case "Chat": - DispatchOrdersToClients(conn, 0, o.Serialize()); - break; - case "Pong": - { - long pingSent; - if (!OpenRA.Exts.TryParseInt64Invariant(o.TargetString, out pingSent)) + case "Pong": { - Log.Write("server", "Invalid order pong payload: {0}", o.TargetString); + if (!OpenRA.Exts.TryParseInt64Invariant(o.TargetString, out var pingSent)) + { + Log.Write("server", "Invalid order pong payload: {0}", o.TargetString); + break; + } + + var client = GetClient(conn); + if (client == null) + return; + + var pingFromClient = LobbyInfo.PingFromClient(client); + if (pingFromClient == null) + return; + + var history = pingFromClient.LatencyHistory.ToList(); + history.Add(Game.RunTime - pingSent); + + // Cap ping history at 5 values (25 seconds) + if (history.Count > 5) + history.RemoveRange(0, history.Count - 5); + + pingFromClient.Latency = history.Sum() / history.Count; + pingFromClient.LatencyJitter = (history.Max() - history.Min()) / 2; + pingFromClient.LatencyHistory = history.ToArray(); + + SyncClientPing(); + break; } - var client = GetClient(conn); - if (client == null) - return; - - var pingFromClient = LobbyInfo.PingFromClient(client); - if (pingFromClient == null) - return; + case "GameSaveTraitData": + { + if (GameSave != null) + { + var data = MiniYaml.FromString(o.TargetString)[0]; + GameSave.AddTraitData(int.Parse(data.Key), data.Value); + } - var history = pingFromClient.LatencyHistory.ToList(); - history.Add(Game.RunTime - pingSent); + break; + } - // Cap ping history at 5 values (25 seconds) - if (history.Count > 5) - history.RemoveRange(0, history.Count - 5); - - pingFromClient.Latency = history.Sum() / history.Count; - pingFromClient.LatencyJitter = (history.Max() - history.Min()) / 2; - pingFromClient.LatencyHistory = history.ToArray(); + case "CreateGameSave": + { + if (GameSave != null) + { + // Sanitize potentially malicious input + var filename = o.TargetString; + var invalidIndex = -1; + var invalidChars = Path.GetInvalidFileNameChars(); + while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1) + filename = filename.Remove(invalidIndex, 1); + + var baseSavePath = Path.Combine( + Platform.SupportDir, + "Saves", + ModData.Manifest.Id, + ModData.Manifest.Metadata.Version); - SyncClientPing(); + if (!Directory.Exists(baseSavePath)) + Directory.CreateDirectory(baseSavePath); - break; - } + GameSave.Save(Path.Combine(baseSavePath, filename)); + DispatchOrdersToClients(null, 0, Order.FromTargetString("GameSaved", filename, true).Serialize()); + } - case "GameSaveTraitData": - { - if (GameSave != null) - { - var data = MiniYaml.FromString(o.TargetString)[0]; - GameSave.AddTraitData(int.Parse(data.Key), data.Value); + break; } - break; - } - - case "CreateGameSave": - { - if (GameSave != null) + case "LoadGameSave": { + if (Type == ServerType.Dedicated || State >= ServerState.GameStarted) + break; + // Sanitize potentially malicious input var filename = o.TargetString; var invalidIndex = -1; @@ -738,96 +961,69 @@ while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1) filename = filename.Remove(invalidIndex, 1); - var baseSavePath = Platform.ResolvePath( - Platform.SupportDirPrefix, + var savePath = Path.Combine( + Platform.SupportDir, "Saves", ModData.Manifest.Id, - ModData.Manifest.Metadata.Version); + ModData.Manifest.Metadata.Version, + filename); - if (!Directory.Exists(baseSavePath)) - Directory.CreateDirectory(baseSavePath); + GameSave = new GameSave(savePath); + LobbyInfo.GlobalSettings = GameSave.GlobalSettings; + LobbyInfo.Slots = GameSave.Slots; + + // Reassign clients to slots + // - Bot ordering is preserved + // - Humans are assigned on a first-come-first-serve basis + // - Leftover humans become spectators - GameSave.Save(Path.Combine(baseSavePath, filename)); - DispatchOrdersToClients(null, 0, Order.FromTargetString("GameSaved", filename, true).Serialize()); - } - - break; - } - - case "LoadGameSave": - { - if (Type == ServerType.Dedicated || State >= ServerState.GameStarted) - break; - - // Sanitize potentially malicious input - var filename = o.TargetString; - var invalidIndex = -1; - var invalidChars = Path.GetInvalidFileNameChars(); - while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1) - filename = filename.Remove(invalidIndex, 1); - - var savePath = Platform.ResolvePath( - Platform.SupportDirPrefix, - "Saves", - ModData.Manifest.Id, - ModData.Manifest.Metadata.Version, - filename); - - GameSave = new GameSave(savePath); - LobbyInfo.GlobalSettings = GameSave.GlobalSettings; - LobbyInfo.Slots = GameSave.Slots; - - // Reassign clients to slots - // - Bot ordering is preserved - // - Humans are assigned on a first-come-first-serve basis - // - Leftover humans become spectators - - // Start by removing all bots and assigning all players as spectators - foreach (var c in LobbyInfo.Clients) - { - if (c.Bot != null) + // Start by removing all bots and assigning all players as spectators + foreach (var c in LobbyInfo.Clients) { - LobbyInfo.Clients.Remove(c); - var ping = LobbyInfo.PingFromClient(c); - if (ping != null) - LobbyInfo.ClientPings.Remove(ping); + if (c.Bot != null) + { + LobbyInfo.Clients.Remove(c); + var ping = LobbyInfo.PingFromClient(c); + if (ping != null) + LobbyInfo.ClientPings.Remove(ping); + } + else + c.Slot = null; } - else - c.Slot = null; - } - // Rebuild/remap the saved client state - // TODO: Multiplayer saves should leave all humans as spectators so they can manually pick slots - var adminClientIndex = LobbyInfo.Clients.First(c => c.IsAdmin).Index; - foreach (var kv in GameSave.SlotClients) - { - if (kv.Value.Bot != null) + // Rebuild/remap the saved client state + // TODO: Multiplayer saves should leave all humans as spectators so they can manually pick slots + var adminClientIndex = LobbyInfo.Clients.First(c => c.IsAdmin).Index; + foreach (var kv in GameSave.SlotClients) { - var bot = new Session.Client() + if (kv.Value.Bot != null) { - Index = ChooseFreePlayerIndex(), - State = Session.ClientState.NotReady, - BotControllerClientIndex = adminClientIndex - }; + var bot = new Session.Client() + { + Index = ChooseFreePlayerIndex(), + State = Session.ClientState.NotReady, + BotControllerClientIndex = adminClientIndex + }; - kv.Value.ApplyTo(bot); - LobbyInfo.Clients.Add(bot); - } - else - { - // This will throw if the server doesn't have enough human clients to fill all player slots - // See TODO above - this isn't a problem in practice because MP saves won't use this - var client = LobbyInfo.Clients.First(c => c.Slot == null); - kv.Value.ApplyTo(client); + kv.Value.ApplyTo(bot); + LobbyInfo.Clients.Add(bot); + } + else + { + // This will throw if the server doesn't have enough human clients to fill all player slots + // See TODO above - this isn't a problem in practice because MP saves won't use this + var client = LobbyInfo.Clients.First(c => c.Slot == null); + kv.Value.ApplyTo(client); + } } - } - SyncLobbyInfo(); - SyncLobbyClients(); - SyncClientPing(); + SyncLobbyInfo(); + SyncLobbyClients(); + SyncClientPing(); - break; - } + break; + } + } } } @@ -838,54 +1034,63 @@ public void DropClient(Connection toDrop) { - if (!PreConns.Remove(toDrop)) + lock (LobbyInfo) { - Conns.Remove(toDrop); - - var dropClient = LobbyInfo.Clients.FirstOrDefault(c1 => c1.Index == toDrop.PlayerIndex); - if (dropClient == null) - return; + if (!PreConns.Remove(toDrop)) + { + Conns.Remove(toDrop); - var suffix = ""; - if (State == ServerState.GameStarted) - suffix = dropClient.IsObserver ? " (Spectator)" : dropClient.Team != 0 ? " (Team {0})".F(dropClient.Team) : ""; - SendMessage("{0}{1} has disconnected.".F(dropClient.Name, suffix)); + var dropClient = LobbyInfo.Clients.FirstOrDefault(c1 => c1.Index == toDrop.PlayerIndex); + if (dropClient == null) + return; - // Send disconnected order, even if still in the lobby - DispatchOrdersToClients(toDrop, 0, Order.FromTargetString("Disconnected", "", true).Serialize()); + var suffix = ""; + if (State == ServerState.GameStarted) + suffix = dropClient.IsObserver ? " (Spectator)" : dropClient.Team != 0 ? " (Team {0})".F(dropClient.Team) : ""; + SendMessage("{0}{1} has disconnected.".F(dropClient.Name, suffix)); - LobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex); - LobbyInfo.ClientPings.RemoveAll(p => p.Index == toDrop.PlayerIndex); + // Send disconnected order, even if still in the lobby + DispatchOrdersToClients(toDrop, 0, Order.FromTargetString("Disconnected", "", true).Serialize()); - // Client was the server admin - // TODO: Reassign admin for game in progress via an order - if (Type == ServerType.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers) - { - // Remove any bots controlled by the admin - LobbyInfo.Clients.RemoveAll(c => c.Bot != null && c.BotControllerClientIndex == toDrop.PlayerIndex); + if (gameInfo != null && !dropClient.IsObserver) + { + var disconnectedPlayer = gameInfo.Players.First(p => p.ClientIndex == toDrop.PlayerIndex); + disconnectedPlayer.DisconnectFrame = toDrop.MostRecentFrame; + } - var nextAdmin = LobbyInfo.Clients.Where(c1 => c1.Bot == null) - .MinByOrDefault(c => c.Index); + LobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex); + LobbyInfo.ClientPings.RemoveAll(p => p.Index == toDrop.PlayerIndex); - if (nextAdmin != null) + // Client was the server admin + // TODO: Reassign admin for game in progress via an order + if (Type == ServerType.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers) { - nextAdmin.IsAdmin = true; - SendMessage("{0} is now the admin.".F(nextAdmin.Name)); + // Remove any bots controlled by the admin + LobbyInfo.Clients.RemoveAll(c => c.Bot != null && c.BotControllerClientIndex == toDrop.PlayerIndex); + + var nextAdmin = LobbyInfo.Clients.Where(c1 => c1.Bot == null) + .MinByOrDefault(c => c.Index); + + if (nextAdmin != null) + { + nextAdmin.IsAdmin = true; + SendMessage("{0} is now the admin.".F(nextAdmin.Name)); + } } - } - DispatchOrders(toDrop, toDrop.MostRecentFrame, new[] { (byte)OrderType.Disconnect }); + DispatchOrders(toDrop, toDrop.MostRecentFrame, new[] { (byte)OrderType.Disconnect }); - // All clients have left: clean up - if (!Conns.Any()) - foreach (var t in serverTraits.WithInterface()) - t.ServerEmpty(this); + // All clients have left: clean up + if (!Conns.Any()) + foreach (var t in serverTraits.WithInterface()) + t.ServerEmpty(this); - if (Conns.Any() || Type == ServerType.Dedicated) - SyncLobbyClients(); + if (Conns.Any() || Type == ServerType.Dedicated) + SyncLobbyClients(); - if (Type != ServerType.Dedicated && dropClient.IsAdmin) - Shutdown(); + if (Type != ServerType.Dedicated && dropClient.IsAdmin) + Shutdown(); + } } try @@ -897,11 +1102,14 @@ public void SyncLobbyInfo() { - if (State == ServerState.WaitingPlayers) // Don't do this while the game is running, it breaks things! - DispatchOrders(null, 0, Order.FromTargetString("SyncInfo", LobbyInfo.Serialize(), true).Serialize()); + lock (LobbyInfo) + { + if (State == ServerState.WaitingPlayers) // Don't do this while the game is running, it breaks things! + DispatchOrders(null, 0, Order.FromTargetString("SyncInfo", LobbyInfo.Serialize(), true).Serialize()); - foreach (var t in serverTraits.WithInterface()) - t.LobbyInfoSynced(this); + foreach (var t in serverTraits.WithInterface()) + t.LobbyInfoSynced(this); + } } public void SyncLobbyClients() @@ -909,13 +1117,16 @@ if (State != ServerState.WaitingPlayers) return; - // TODO: Only need to sync the specific client that has changed to avoid conflicts! - var clientData = LobbyInfo.Clients.Select(client => client.Serialize()).ToList(); + lock (LobbyInfo) + { + // TODO: Only need to sync the specific client that has changed to avoid conflicts! + var clientData = LobbyInfo.Clients.Select(client => client.Serialize()).ToList(); - DispatchOrders(null, 0, Order.FromTargetString("SyncLobbyClients", clientData.WriteToString(), true).Serialize()); + DispatchOrders(null, 0, Order.FromTargetString("SyncLobbyClients", clientData.WriteToString(), true).Serialize()); - foreach (var t in serverTraits.WithInterface()) - t.LobbyInfoSynced(this); + foreach (var t in serverTraits.WithInterface()) + t.LobbyInfoSynced(this); + } } public void SyncLobbySlots() @@ -923,13 +1134,16 @@ if (State != ServerState.WaitingPlayers) return; - // TODO: Don't sync all the slots if just one changed! - var slotData = LobbyInfo.Slots.Select(slot => slot.Value.Serialize()).ToList(); + lock (LobbyInfo) + { + // TODO: Don't sync all the slots if just one changed! + var slotData = LobbyInfo.Slots.Select(slot => slot.Value.Serialize()).ToList(); - DispatchOrders(null, 0, Order.FromTargetString("SyncLobbySlots", slotData.WriteToString(), true).Serialize()); + DispatchOrders(null, 0, Order.FromTargetString("SyncLobbySlots", slotData.WriteToString(), true).Serialize()); - foreach (var t in serverTraits.WithInterface()) - t.LobbyInfoSynced(this); + foreach (var t in serverTraits.WithInterface()) + t.LobbyInfoSynced(this); + } } public void SyncLobbyGlobalSettings() @@ -937,86 +1151,146 @@ if (State != ServerState.WaitingPlayers) return; - var sessionData = new List { LobbyInfo.GlobalSettings.Serialize() }; + lock (LobbyInfo) + { + var sessionData = new List { LobbyInfo.GlobalSettings.Serialize() }; - DispatchOrders(null, 0, Order.FromTargetString("SyncLobbyGlobalSettings", sessionData.WriteToString(), true).Serialize()); + DispatchOrders(null, 0, Order.FromTargetString("SyncLobbyGlobalSettings", sessionData.WriteToString(), true).Serialize()); - foreach (var t in serverTraits.WithInterface()) - t.LobbyInfoSynced(this); + foreach (var t in serverTraits.WithInterface()) + t.LobbyInfoSynced(this); + } } public void SyncClientPing() { - // TODO: Split this further into per client ping orders - var clientPings = LobbyInfo.ClientPings.Select(ping => ping.Serialize()).ToList(); + lock (LobbyInfo) + { + // TODO: Split this further into per client ping orders + var clientPings = LobbyInfo.ClientPings.Select(ping => ping.Serialize()).ToList(); - // Note that syncing pings doesn't trigger INotifySyncLobbyInfo - DispatchOrders(null, 0, Order.FromTargetString("SyncClientPings", clientPings.WriteToString(), true).Serialize()); + // Note that syncing pings doesn't trigger INotifySyncLobbyInfo + DispatchOrders(null, 0, Order.FromTargetString("SyncClientPings", clientPings.WriteToString(), true).Serialize()); + } } public void StartGame() { - listener.Stop(); + lock (LobbyInfo) + { + foreach (var listener in listeners) + listener.Stop(); - Console.WriteLine("[{0}] Game started", DateTime.Now.ToString(Settings.TimestampFormat)); + Console.WriteLine("[{0}] Game started", DateTime.Now.ToString(Settings.TimestampFormat)); - // Drop any unvalidated clients - foreach (var c in PreConns.ToArray()) - DropClient(c); + // Drop any unvalidated clients + foreach (var c in PreConns.ToArray()) + DropClient(c); - // Drop any players who are not ready - foreach (var c in Conns.Where(c => GetClient(c).IsInvalid).ToArray()) - { - SendOrderTo(c, "ServerError", "You have been kicked from the server!"); - DropClient(c); - } + // Drop any players who are not ready + foreach (var c in Conns.Where(c => GetClient(c).IsInvalid).ToArray()) + { + SendOrderTo(c, "ServerError", "You have been kicked from the server!"); + DropClient(c); + } - // HACK: Turn down the latency if there is only one real player - if (LobbyInfo.NonBotClients.Count() == 1) - LobbyInfo.GlobalSettings.OrderLatency = 1; + // HACK: Turn down the latency if there is only one real player + if (LobbyInfo.NonBotClients.Count() == 1) + LobbyInfo.GlobalSettings.OrderLatency = 1; + + // Enable game saves for singleplayer missions only + // TODO: Enable for multiplayer (non-dedicated servers only) once the lobby UI has been created + LobbyInfo.GlobalSettings.GameSavesEnabled = Type != ServerType.Dedicated && LobbyInfo.NonBotClients.Count() == 1; + + // Player list for win/loss tracking + // HACK: NonCombatant and non-Playable players are set to null to simplify replay tracking + // The null padding is needed to keep the player indexes in sync with world.Players on the clients + // This will need to change if future code wants to use worldPlayers for other purposes + var playerRandom = new MersenneTwister(LobbyInfo.GlobalSettings.RandomSeed); + foreach (var cmpi in Map.Rules.Actors["world"].TraitInfos()) + cmpi.CreateServerPlayers(Map, LobbyInfo, worldPlayers, playerRandom); - // Enable game saves for singleplayer missions only - // TODO: Enable for multiplayer (non-dedicated servers only) once the lobby UI has been created - LobbyInfo.GlobalSettings.GameSavesEnabled = Type != ServerType.Dedicated && LobbyInfo.NonBotClients.Count() == 1; + if (recorder != null) + { + gameInfo = new GameInformation + { + Mod = Game.ModData.Manifest.Id, + Version = Game.ModData.Manifest.Metadata.Version, + MapUid = Map.Uid, + MapTitle = Map.Title, + StartTimeUtc = DateTime.UtcNow, + }; - SyncLobbyInfo(); - State = ServerState.GameStarted; + // Replay metadata should only include the playable players + foreach (var p in worldPlayers) + if (p != null) + gameInfo.Players.Add(p); - foreach (var c in Conns) - foreach (var d in Conns) - DispatchOrdersToClient(c, d.PlayerIndex, 0x7FFFFFFF, new[] { (byte)OrderType.Disconnect }); + recorder.Metadata = new ReplayMetadata(gameInfo); + } - if (GameSave == null && LobbyInfo.GlobalSettings.GameSavesEnabled) - GameSave = new GameSave(); + SyncLobbyInfo(); + State = ServerState.GameStarted; - var startGameData = ""; - if (GameSave != null) - { - GameSave.StartGame(LobbyInfo, Map); - if (GameSave.LastOrdersFrame >= 0) + var disconnectData = new[] { (byte)OrderType.Disconnect }; + foreach (var c in Conns) { - startGameData = new List() + foreach (var d in Conns) + DispatchOrdersToClient(c, d.PlayerIndex, int.MaxValue, disconnectData); + + if (recorder != null) + recorder.ReceiveFrame(c.PlayerIndex, int.MaxValue, disconnectData); + } + + if (GameSave == null && LobbyInfo.GlobalSettings.GameSavesEnabled) + GameSave = new GameSave(); + + var startGameData = ""; + if (GameSave != null) + { + GameSave.StartGame(LobbyInfo, Map); + if (GameSave.LastOrdersFrame >= 0) { - new MiniYamlNode("SaveLastOrdersFrame", GameSave.LastOrdersFrame.ToString()), - new MiniYamlNode("SaveSyncFrame", GameSave.LastSyncFrame.ToString()) - }.WriteToString(); + startGameData = new List() + { + new MiniYamlNode("SaveLastOrdersFrame", GameSave.LastOrdersFrame.ToString()), + new MiniYamlNode("SaveSyncFrame", GameSave.LastSyncFrame.ToString()) + }.WriteToString(); + } } - } - DispatchOrders(null, 0, - Order.FromTargetString("StartGame", startGameData, true).Serialize()); + DispatchOrders(null, 0, + Order.FromTargetString("StartGame", startGameData, true).Serialize()); - foreach (var t in serverTraits.WithInterface()) - t.GameStarted(this); + foreach (var t in serverTraits.WithInterface()) + t.GameStarted(this); - if (GameSave != null && GameSave.LastOrdersFrame >= 0) - { - GameSave.ParseOrders(LobbyInfo, (frame, client, data) => + if (GameSave != null && GameSave.LastOrdersFrame >= 0) { - foreach (var c in Conns) - DispatchOrdersToClient(c, client, frame, data); - }); + GameSave.ParseOrders(LobbyInfo, (frame, client, data) => + { + foreach (var c in Conns) + DispatchOrdersToClient(c, client, frame, data); + }); + } } } + + public ConnectionTarget GetEndpointForLocalConnection() + { + var endpoints = new List(); + foreach (var listener in listeners) + { + var endpoint = (IPEndPoint)listener.LocalEndpoint; + if (IPAddress.IPv6Any.Equals(endpoint.Address)) + endpoints.Add(new DnsEndPoint(IPAddress.IPv6Loopback.ToString(), endpoint.Port)); + else if (IPAddress.Any.Equals(endpoint.Address)) + endpoints.Add(new DnsEndPoint(IPAddress.Loopback.ToString(), endpoint.Port)); + else + endpoints.Add(new DnsEndPoint(endpoint.Address.ToString(), endpoint.Port)); + } + + return new ConnectionTarget(endpoints); + } } } diff -Nru openra-20200503/OpenRA.Game/Settings.cs openra-20210321/OpenRA.Game/Settings.cs --- openra-20200503/OpenRA.Game/Settings.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Settings.cs 2021-03-21 11:10:05.000000000 +0000 @@ -53,7 +53,7 @@ public bool DiscoverNatDevices = false; [Desc("Time in milliseconds to search for UPnP enabled NAT devices.")] - public int NatDiscoveryTimeout = 1000; + public int NatDiscoveryTimeout = 5000; [Desc("Starts the game with a default map. Input as hash that can be obtained by the utility.")] public string Map = null; @@ -88,6 +88,9 @@ [Desc("Allow clients to see the country of other clients.")] public bool EnableGeoIP = true; + [Desc("For dedicated servers only, save replays for all games played.")] + public bool RecordReplays = false; + public ServerSettings Clone() { return (ServerSettings)MemberwiseClone(); @@ -172,14 +175,18 @@ [Desc("Disable operating-system provided cursor rendering.")] public bool DisableHardwareCursors = false; + [Desc("Disable legacy OpenGL 2.1 support.")] + public bool DisableLegacyGL = true; + [Desc("Display index to use in a multi-monitor fullscreen setup.")] public int VideoDisplay = 0; [Desc("Preferred OpenGL profile to use.", "Modern: OpenGL Core Profile 3.2 or greater.", "Embedded: OpenGL ES 3.0 or greater.", - "Legacy: OpenGL 2.1 with framebuffer_object extension.")] - public GLProfile GLProfile = GLProfile.Modern; + "Legacy: OpenGL 2.1 with framebuffer_object extension (requires DisableLegacyGL: False)", + "Automatic: Use the first supported profile.")] + public GLProfile GLProfile = GLProfile.Automatic; public int BatchSize = 8192; public int SheetSize = 2048; @@ -249,6 +256,8 @@ public int IntroductionPromptVersion = 0; public MPGameFilters MPGameFilters = MPGameFilters.Waiting | MPGameFilters.Empty | MPGameFilters.Protected | MPGameFilters.Started; + + public bool PauseShellmap = false; } public class Settings @@ -295,8 +304,7 @@ yamlCache = MiniYaml.FromFile(settingsFile, false); foreach (var yamlSection in yamlCache) { - object settingsSection; - if (yamlSection.Key != null && Sections.TryGetValue(yamlSection.Key, out settingsSection)) + if (yamlSection.Key != null && Sections.TryGetValue(yamlSection.Key, out var settingsSection)) LoadSectionYaml(yamlSection.Value, settingsSection); } diff -Nru openra-20200503/OpenRA.Game/Sound/Sound.cs openra-20210321/OpenRA.Game/Sound/Sound.cs --- openra-20200503/OpenRA.Game/Sound/Sound.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Sound/Sound.cs 2021-03-21 11:10:05.000000000 +0000 @@ -66,11 +66,10 @@ using (var stream = fileSystem.Open(filename)) { - ISoundFormat soundFormat; foreach (var loader in loaders) { stream.Position = 0; - if (loader.TryParseSound(stream, out soundFormat)) + if (loader.TryParseSound(stream, out var soundFormat)) { var source = loadFormat(soundFormat); soundFormat.Dispose(); @@ -89,8 +88,7 @@ if (sounds != null) foreach (var soundSource in sounds.Values) - if (soundSource != null) - soundSource.Dispose(); + soundSource?.Dispose(); this.loaders = loaders; this.fileSystem = fileSystem; @@ -431,8 +429,8 @@ StopAudio(); if (sounds != null) foreach (var soundSource in sounds.Values) - if (soundSource != null) - soundSource.Dispose(); + soundSource?.Dispose(); + soundEngine.Dispose(); } } diff -Nru openra-20200503/OpenRA.Game/StreamExts.cs openra-20210321/OpenRA.Game/StreamExts.cs --- openra-20200503/OpenRA.Game/StreamExts.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/StreamExts.cs 2021-03-21 11:10:05.000000000 +0000 @@ -61,22 +61,22 @@ public static ushort ReadUInt16(this Stream s) { - return BitConverter.ToUInt16(s.ReadBytes(2), 0); + return (ushort)(s.ReadUInt8() | s.ReadUInt8() << 8); } public static short ReadInt16(this Stream s) { - return BitConverter.ToInt16(s.ReadBytes(2), 0); + return (short)(s.ReadUInt8() | s.ReadUInt8() << 8); } public static uint ReadUInt32(this Stream s) { - return BitConverter.ToUInt32(s.ReadBytes(4), 0); + return (uint)(s.ReadUInt8() | s.ReadUInt8() << 8 | s.ReadUInt8() << 16 | s.ReadUInt8() << 24); } public static int ReadInt32(this Stream s) { - return BitConverter.ToInt32(s.ReadBytes(4), 0); + return s.ReadUInt8() | s.ReadUInt8() << 8 | s.ReadUInt8() << 16 | s.ReadUInt8() << 24; } public static void Write(this Stream s, int value) diff -Nru openra-20200503/OpenRA.Game/Support/LaunchArguments.cs openra-20210321/OpenRA.Game/Support/LaunchArguments.cs --- openra-20200503/OpenRA.Game/Support/LaunchArguments.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Support/LaunchArguments.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,6 +9,9 @@ */ #endregion +using System; +using OpenRA.Network; + namespace OpenRA { public class LaunchArguments @@ -38,17 +41,28 @@ FieldLoader.LoadField(this, f.Name, args.GetValue("Launch" + "." + f.Name, "")); } - public string GetConnectAddress() + public ConnectionTarget GetConnectEndPoint() { - var connect = string.Empty; - - if (!string.IsNullOrEmpty(Connect)) - connect = Connect; - - if (!string.IsNullOrEmpty(URI)) - connect = URI.Substring(URI.IndexOf("://", System.StringComparison.Ordinal) + 3).TrimEnd('/'); - - return connect; + try + { + Uri uri; + if (!string.IsNullOrEmpty(URI)) + uri = new Uri(URI); + else if (!string.IsNullOrEmpty(Connect)) + uri = new Uri("tcp://" + Connect); + else + return null; + + if (uri.IsAbsoluteUri) + return new ConnectionTarget(uri.Host, uri.Port); + else + return null; + } + catch (Exception ex) + { + Log.Write("client", "Failed to parse Launch.URI or Launch.Connect: {0}", ex.Message); + return null; + } } } } diff -Nru openra-20200503/OpenRA.Game/Support/Program.cs openra-20210321/OpenRA.Game/Support/Program.cs --- openra-20200503/OpenRA.Game/Support/Program.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Support/Program.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,26 +21,4 @@ Success = 0, Running = int.MaxValue } - - static class Program - { - [STAThread] - static int Main(string[] args) - { - if (Debugger.IsAttached || args.Contains("--just-die")) - return (int)Game.InitializeAndRun(args); - - AppDomain.CurrentDomain.UnhandledException += (_, e) => ExceptionHandler.HandleFatalError((Exception)e.ExceptionObject); - - try - { - return (int)Game.InitializeAndRun(args); - } - catch (Exception e) - { - ExceptionHandler.HandleFatalError(e); - return (int)RunStatus.Error; - } - } - } } diff -Nru openra-20200503/OpenRA.Game/Support/VariableExpression.cs openra-20210321/OpenRA.Game/Support/VariableExpression.cs --- openra-20200503/OpenRA.Game/Support/VariableExpression.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Support/VariableExpression.cs 2021-03-21 11:10:05.000000000 +0000 @@ -668,8 +668,7 @@ static int ParseSymbol(string symbol, IReadOnlyDictionary symbols) { - int value; - symbols.TryGetValue(symbol, out value); + symbols.TryGetValue(symbol, out var value); return value; } diff -Nru openra-20200503/OpenRA.Game/TraitDictionary.cs openra-20210321/OpenRA.Game/TraitDictionary.cs --- openra-20200503/OpenRA.Game/TraitDictionary.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/TraitDictionary.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,8 +11,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using OpenRA.Primitives; +using OpenRA.Support; namespace OpenRA { @@ -122,6 +124,16 @@ t.Value.RemoveActor(a.ActorID); } + public void ApplyToActorsWithTrait(Action action) + { + InnerGet().ApplyToAll(action); + } + + public void ApplyToActorsWithTraitTimed(Action action, string text) + { + InnerGet().ApplyToAllTimed(action, text); + } + interface ITraitContainer { void Add(Actor actor, object trait); @@ -179,13 +191,14 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } - class MultipleEnumerator : IEnumerator + struct MultipleEnumerator : IEnumerator { readonly List actors; readonly List traits; readonly uint actor; int index; public MultipleEnumerator(TraitContainer container, uint actor) + : this() { actors = container.actors; traits = container.traits; @@ -213,10 +226,11 @@ Actor last = null; for (var i = 0; i < actors.Count; i++) { - if (actors[i] == last) + var current = actors[i]; + if (current == last) continue; - yield return actors[i]; - last = actors[i]; + yield return current; + last = current; } } @@ -227,14 +241,15 @@ for (var i = 0; i < actors.Count; i++) { - if (actors[i] == last || !predicate(traits[i])) + var current = actors[i]; + if (current == last || !predicate(traits[i])) continue; - yield return actors[i]; - last = actors[i]; + yield return current; + last = current; } } - class AllEnumerable : IEnumerable> + struct AllEnumerable : IEnumerable> { readonly TraitContainer container; public AllEnumerable(TraitContainer container) { this.container = container; } @@ -242,12 +257,13 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } - class AllEnumerator : IEnumerator> + struct AllEnumerator : IEnumerator> { readonly List actors; readonly List traits; int index; public AllEnumerator(TraitContainer container) + : this() { actors = container.actors; traits = container.traits; @@ -273,6 +289,32 @@ actors.RemoveRange(startIndex, count); traits.RemoveRange(startIndex, count); } + + public void ApplyToAll(Action action) + { + for (var i = 0; i < actors.Count; i++) + action(actors[i], traits[i]); + } + + public void ApplyToAllTimed(Action action, string text) + { + var longTickThresholdInStopwatchTicks = PerfTimer.LongTickThresholdInStopwatchTicks; + var start = Stopwatch.GetTimestamp(); + for (var i = 0; i < actors.Count; i++) + { + var actor = actors[i]; + var trait = traits[i]; + action(actor, trait); + var current = Stopwatch.GetTimestamp(); + if (current - start > longTickThresholdInStopwatchTicks) + { + PerfTimer.LogLongTick(start, current, text, trait); + start = Stopwatch.GetTimestamp(); + } + else + start = current; + } + } } } } diff -Nru openra-20200503/OpenRA.Game/Traits/ActivityUtils.cs openra-20210321/OpenRA.Game/Traits/ActivityUtils.cs --- openra-20200503/OpenRA.Game/Traits/ActivityUtils.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/ActivityUtils.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Diagnostics; -using System.Linq; using OpenRA.Activities; using OpenRA.Support; diff -Nru openra-20200503/OpenRA.Game/Traits/DebugPauseState.cs openra-20210321/OpenRA.Game/Traits/DebugPauseState.cs --- openra-20200503/OpenRA.Game/Traits/DebugPauseState.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/DebugPauseState.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,9 +12,9 @@ namespace OpenRA.Traits { [Desc("Checks for pause related desyncs. Attach this to the world actor.")] - public class DebugPauseStateInfo : ITraitInfo + public class DebugPauseStateInfo : TraitInfo { - public object Create(ActorInitializer init) { return new DebugPauseState(init.World); } + public override object Create(ActorInitializer init) { return new DebugPauseState(init.World); } } public class DebugPauseState : ISync diff -Nru openra-20200503/OpenRA.Game/Traits/Interactable.cs openra-20210321/OpenRA.Game/Traits/Interactable.cs --- openra-20200503/OpenRA.Game/Traits/Interactable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/Interactable.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Primitives; - -namespace OpenRA.Traits -{ - [Desc("Used to enable mouse interaction on actors that are not Selectable.")] - public class InteractableInfo : ITraitInfo, IMouseBoundsInfo, IDecorationBoundsInfo - { - [Desc("Defines a custom rectangle for mouse interaction with the actor.", - "If null, the engine will guess an appropriate size based on the With*Body trait.", - "The first two numbers define the width and height of the rectangle.", - "The (optional) second two numbers define an x and y offset from the actor center.")] - public readonly int[] Bounds = null; - - [Desc("Defines a custom rectangle for Decorations (e.g. the selection box).", - "If null, Bounds will be used instead")] - public readonly int[] DecorationBounds = null; - - public virtual object Create(ActorInitializer init) { return new Interactable(this); } - } - - public class Interactable : INotifyCreated, IMouseBounds, IDecorationBounds - { - readonly InteractableInfo info; - IAutoMouseBounds[] autoBounds; - - public Interactable(InteractableInfo info) - { - this.info = info; - } - - void INotifyCreated.Created(Actor self) - { - autoBounds = self.TraitsImplementing().ToArray(); - } - - Rectangle AutoBounds(Actor self, WorldRenderer wr) - { - return autoBounds.Select(s => s.AutoMouseoverBounds(self, wr)).FirstOrDefault(r => !r.IsEmpty); - } - - Rectangle Bounds(Actor self, WorldRenderer wr, int[] bounds) - { - if (bounds == null) - return AutoBounds(self, wr); - - var size = new int2(bounds[0], bounds[1]); - - var offset = -size / 2; - if (bounds.Length > 2) - offset += new int2(bounds[2], bounds[3]); - - var xy = wr.ScreenPxPosition(self.CenterPosition) + offset; - return new Rectangle(xy.X, xy.Y, size.X, size.Y); - } - - Rectangle IMouseBounds.MouseoverBounds(Actor self, WorldRenderer wr) - { - return Bounds(self, wr, info.Bounds); - } - - Rectangle IDecorationBounds.DecorationBounds(Actor self, WorldRenderer wr) - { - return Bounds(self, wr, info.DecorationBounds ?? info.Bounds); - } - } -} diff -Nru openra-20200503/OpenRA.Game/Traits/LintAttributes.cs openra-20210321/OpenRA.Game/Traits/LintAttributes.cs --- openra-20200503/OpenRA.Game/Traits/LintAttributes.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/LintAttributes.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,52 +13,53 @@ namespace OpenRA.Traits { - /* attributes used by OpenRA.Lint to understand the rules */ + public enum LintDictionaryReference + { + None = 0, + Keys = 1, + Values = 2 + } [AttributeUsage(AttributeTargets.Field)] public sealed class ActorReferenceAttribute : Attribute { - public Type[] RequiredTraits; - public ActorReferenceAttribute(params Type[] requiredTraits) + public readonly Type[] RequiredTraits; + public readonly LintDictionaryReference DictionaryReference; + + public ActorReferenceAttribute(Type[] requiredTraits, + LintDictionaryReference dictionaryReference = LintDictionaryReference.None) { RequiredTraits = requiredTraits; + DictionaryReference = dictionaryReference; } - } - - [AttributeUsage(AttributeTargets.Field)] - public sealed class WeaponReferenceAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Field)] - public sealed class VoiceSetReferenceAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Field)] - public sealed class VoiceReferenceAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Field)] - public sealed class LocomotorReferenceAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Field)] - public sealed class NotificationReferenceAttribute : Attribute - { - public readonly string NotificationTypeFieldName = null; - public readonly string NotificationType = null; - public NotificationReferenceAttribute(string type = null, string typeFromField = null) + public ActorReferenceAttribute(Type requiredTrait = null, + LintDictionaryReference dictionaryReference = LintDictionaryReference.None) { - NotificationType = type; - NotificationTypeFieldName = typeFromField; + RequiredTraits = requiredTrait != null ? new[] { requiredTrait } : new Type[0]; + DictionaryReference = dictionaryReference; } } [AttributeUsage(AttributeTargets.Field)] + public sealed class WeaponReferenceAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Field)] public sealed class SequenceReferenceAttribute : Attribute { - public readonly string ImageReference; // The field name in the same trait info that contains the image name. + // The field name in the same trait info that contains the image name. + public readonly string ImageReference; public readonly bool Prefix; - public SequenceReferenceAttribute(string imageReference = null, bool prefix = false) + public readonly bool AllowNullImage; + public readonly LintDictionaryReference DictionaryReference; + + public SequenceReferenceAttribute(string imageReference = null, bool prefix = false, bool allowNullImage = false, + LintDictionaryReference dictionaryReference = LintDictionaryReference.None) { ImageReference = imageReference; Prefix = prefix; + AllowNullImage = allowNullImage; + DictionaryReference = dictionaryReference; } } diff -Nru openra-20200503/OpenRA.Game/Traits/Player/FixedColorPalette.cs openra-20210321/OpenRA.Game/Traits/Player/FixedColorPalette.cs --- openra-20200503/OpenRA.Game/Traits/Player/FixedColorPalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/Player/FixedColorPalette.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using OpenRA.Graphics; -using OpenRA.Primitives; - -namespace OpenRA.Traits -{ - [Desc("Add this to the World actor definition.")] - public class FixedColorPaletteInfo : ITraitInfo - { - [PaletteReference] - [Desc("The name of the palette to base off.")] - public readonly string Base = TileSet.TerrainPaletteInternalName; - - [PaletteDefinition] - [Desc("The name of the resulting palette")] - public readonly string Name = "resources"; - - [Desc("Remap these indices to pre-defined colors.")] - public readonly int[] RemapIndex = { }; - - [Desc("The fixed color to remap.")] - public readonly Color Color; - - [Desc("Luminosity range to span.")] - public readonly float Ramp = 0.05f; - - [Desc("Allow palette modifiers to change the palette.")] - public readonly bool AllowModifiers = true; - - public object Create(ActorInitializer init) { return new FixedColorPalette(this); } - } - - public class FixedColorPalette : ILoadsPalettes - { - readonly FixedColorPaletteInfo info; - - public FixedColorPalette(FixedColorPaletteInfo info) - { - this.info = info; - } - - public void LoadPalettes(WorldRenderer wr) - { - var remap = new PlayerColorRemap(info.RemapIndex, info.Color, info.Ramp); - wr.AddPalette(info.Name, new ImmutablePalette(wr.Palette(info.Base).Palette, remap), info.AllowModifiers); - } - } -} diff -Nru openra-20200503/OpenRA.Game/Traits/Player/FrozenActorLayer.cs openra-20210321/OpenRA.Game/Traits/Player/FrozenActorLayer.cs --- openra-20200503/OpenRA.Game/Traits/Player/FrozenActorLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/Player/FrozenActorLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,12 +23,12 @@ } [Desc("Required for FrozenUnderFog to work. Attach this to the player actor.")] - public class FrozenActorLayerInfo : Requires, ITraitInfo + public class FrozenActorLayerInfo : TraitInfo, Requires { [Desc("Size of partition bins (cells)")] public readonly int BinSize = 10; - public object Create(ActorInitializer init) { return new FrozenActorLayer(init.Self, this); } + public override object Create(ActorInitializer init) { return new FrozenActorLayer(init.Self, this); } } public class FrozenActor @@ -39,10 +39,11 @@ readonly ICreatesFrozenActors frozenTrait; readonly Player viewer; readonly Shroud shroud; + readonly List targetablePositions = new List(); public Player Owner { get; private set; } public BitSet TargetTypes { get; private set; } - public WPos[] TargetablePositions { get; private set; } + public IEnumerable TargetablePositions { get { return targetablePositions; } } public ITooltipInfo TooltipInfo { get; private set; } public Player TooltipOwner { get; private set; } @@ -68,8 +69,7 @@ public IRenderable[] Renderables = NoRenderables; public Rectangle[] ScreenBounds = NoBounds; - // TODO: Replace this with an int2[] polygon - public Rectangle MouseBounds = Rectangle.Empty; + public Polygon MouseBounds = Polygon.Empty; static readonly IRenderable[] NoRenderables = new IRenderable[0]; static readonly Rectangle[] NoBounds = new Rectangle[0]; @@ -118,7 +118,8 @@ { Owner = actor.Owner; TargetTypes = actor.GetEnabledTargetTypes(); - TargetablePositions = actor.GetTargetablePositions().ToArray(); + targetablePositions.Clear(); + targetablePositions.AddRange(actor.GetTargetablePositions()); Hidden = !actor.CanBeViewedByPlayer(viewer); if (health != null) @@ -311,8 +312,7 @@ public FrozenActor FromID(uint id) { - FrozenActor fa; - if (!frozenActorsById.TryGetValue(id, out fa)) + if (!frozenActorsById.TryGetValue(id, out var fa)) return null; return fa; diff -Nru openra-20200503/OpenRA.Game/Traits/Player/IndexedPlayerPalette.cs openra-20210321/OpenRA.Game/Traits/Player/IndexedPlayerPalette.cs --- openra-20200503/OpenRA.Game/Traits/Player/IndexedPlayerPalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/Player/IndexedPlayerPalette.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.IO; -using OpenRA.Graphics; -using OpenRA.Primitives; - -namespace OpenRA.Traits -{ - [Desc("Define a player palette by swapping palette indices.")] - public class IndexedPlayerPaletteInfo : ITraitInfo, IRulesetLoaded - { - [PaletteReference] - [Desc("The name of the palette to base off.")] - public readonly string BasePalette = null; - - [PaletteDefinition(true)] - [Desc("The prefix for the resulting player palettes")] - public readonly string BaseName = "player"; - - [Desc("Remap these indices to player colors.")] - public readonly int[] RemapIndex = { }; - - [Desc("Allow palette modifiers to change the palette.")] - public readonly bool AllowModifiers = true; - - public readonly Dictionary PlayerIndex; - - public object Create(ActorInitializer init) { return new IndexedPlayerPalette(this); } - - public void RulesetLoaded(Ruleset rules, ActorInfo ai) - { - foreach (var p in PlayerIndex) - if (p.Value.Length != RemapIndex.Length) - throw new YamlException("PlayerIndex for player `{0}` length does not match RemapIndex!".F(p.Key)); - } - } - - public class IndexedPlayerPalette : ILoadsPlayerPalettes - { - readonly IndexedPlayerPaletteInfo info; - - public IndexedPlayerPalette(IndexedPlayerPaletteInfo info) - { - this.info = info; - } - - public void LoadPlayerPalettes(WorldRenderer wr, string playerName, Color color, bool replaceExisting) - { - var basePalette = wr.Palette(info.BasePalette).Palette; - ImmutablePalette pal; - int[] remap; - - if (info.PlayerIndex.TryGetValue(playerName, out remap)) - pal = new ImmutablePalette(basePalette, new IndexedColorRemap(basePalette, info.RemapIndex, remap)); - else - pal = new ImmutablePalette(basePalette); - - wr.AddPalette(info.BaseName + playerName, pal, info.AllowModifiers, replaceExisting); - } - } - - public class IndexedColorRemap : IPaletteRemap - { - Dictionary replacements = new Dictionary(); - IPalette basePalette; - - public IndexedColorRemap(IPalette basePalette, int[] ramp, int[] remap) - { - this.basePalette = basePalette; - if (ramp.Length != remap.Length) - throw new InvalidDataException("ramp and remap lengths do no match."); - - for (var i = 0; i < ramp.Length; i++) - replacements[ramp[i]] = remap[i]; - } - - public Color GetRemappedColor(Color original, int index) - { - int c; - return replacements.TryGetValue(index, out c) - ? basePalette.GetColor(c) : original; - } - } -} diff -Nru openra-20200503/OpenRA.Game/Traits/Player/PlayerColorPalette.cs openra-20210321/OpenRA.Game/Traits/Player/PlayerColorPalette.cs --- openra-20200503/OpenRA.Game/Traits/Player/PlayerColorPalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/Player/PlayerColorPalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Traits { [Desc("Add this to the Player actor definition.")] - public class PlayerColorPaletteInfo : ITraitInfo + public class PlayerColorPaletteInfo : TraitInfo { [PaletteReference] [Desc("The name of the palette to base off.")] @@ -34,7 +34,7 @@ [Desc("Allow palette modifiers to change the palette.")] public readonly bool AllowModifiers = true; - public object Create(ActorInitializer init) { return new PlayerColorPalette(this); } + public override object Create(ActorInitializer init) { return new PlayerColorPalette(this); } } public class PlayerColorPalette : ILoadsPlayerPalettes diff -Nru openra-20200503/OpenRA.Game/Traits/Player/PlayerHighlightPalette.cs openra-20210321/OpenRA.Game/Traits/Player/PlayerHighlightPalette.cs --- openra-20200503/OpenRA.Game/Traits/Player/PlayerHighlightPalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/Player/PlayerHighlightPalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,13 +16,16 @@ namespace OpenRA.Traits { [Desc("Add this to the Player actor definition.")] - public class PlayerHighlightPaletteInfo : ITraitInfo + public class PlayerHighlightPaletteInfo : TraitInfo { [PaletteDefinition(true)] [Desc("The prefix for the resulting player palettes")] public readonly string BaseName = "highlight"; - public object Create(ActorInitializer init) { return new PlayerHighlightPalette(this); } + [Desc("Index set to be fully transparent/invisible.")] + public readonly int TransparentIndex = 0; + + public override object Create(ActorInitializer init) { return new PlayerHighlightPalette(this); } } public class PlayerHighlightPalette : ILoadsPlayerPalettes @@ -37,7 +40,7 @@ public void LoadPlayerPalettes(WorldRenderer wr, string playerName, Color color, bool replaceExisting) { var argb = (uint)Color.FromArgb(128, color).ToArgb(); - var pal = new ImmutablePalette(Enumerable.Range(0, Palette.Size).Select(i => i == 0 ? 0 : argb)); + var pal = new ImmutablePalette(Enumerable.Range(0, Palette.Size).Select(i => i == info.TransparentIndex ? 0 : argb)); wr.AddPalette(info.BaseName + playerName, pal, false, replaceExisting); } } diff -Nru openra-20200503/OpenRA.Game/Traits/Player/Shroud.cs openra-20210321/OpenRA.Game/Traits/Player/Shroud.cs --- openra-20200503/OpenRA.Game/Traits/Player/Shroud.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/Player/Shroud.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Traits { [Desc("Required for shroud and fog visibility checks. Add this to the player actor.")] - public class ShroudInfo : ITraitInfo, ILobbyOptions + public class ShroudInfo : TraitInfo, ILobbyOptions { [Translate] [Desc("Descriptive label for the fog checkbox in the lobby.")] @@ -65,7 +65,7 @@ FogCheckboxVisible, FogCheckboxDisplayOrder, FogCheckboxEnabled, FogCheckboxLocked); } - public object Create(ActorInitializer init) { return new Shroud(init.Self, this); } + public override object Create(ActorInitializer init) { return new Shroud(init.Self, this); } } public class Shroud : ISync, INotifyCreated, ITick @@ -94,14 +94,15 @@ readonly Dictionary sources = new Dictionary(); // Per-cell count of each source type, used to resolve the final cell type - readonly CellLayer passiveVisibleCount; - readonly CellLayer visibleCount; - readonly CellLayer generatedShroudCount; - readonly CellLayer explored; - readonly CellLayer touched; + readonly ProjectedCellLayer passiveVisibleCount; + readonly ProjectedCellLayer visibleCount; + readonly ProjectedCellLayer generatedShroudCount; + readonly ProjectedCellLayer explored; + readonly ProjectedCellLayer touched; + bool anyCellTouched; // Per-cell cache of the resolved cell type (shroud/fog/visible) - readonly CellLayer resolvedType; + readonly ProjectedCellLayer resolvedType; [Sync] bool disabled; @@ -137,14 +138,15 @@ this.info = info; map = self.World.Map; - passiveVisibleCount = new CellLayer(map); - visibleCount = new CellLayer(map); - generatedShroudCount = new CellLayer(map); - explored = new CellLayer(map); - touched = new CellLayer(map); + passiveVisibleCount = new ProjectedCellLayer(map); + visibleCount = new ProjectedCellLayer(map); + generatedShroudCount = new ProjectedCellLayer(map); + explored = new ProjectedCellLayer(map); + touched = new ProjectedCellLayer(map); + anyCellTouched = true; // Defaults to 0 = Shroud - resolvedType = new CellLayer(map); + resolvedType = new ProjectedCellLayer(map); } void INotifyCreated.Created(Actor self) @@ -159,32 +161,42 @@ void ITick.Tick(Actor self) { + if (!anyCellTouched) + return; + + anyCellTouched = false; + if (OnShroudChanged == null) return; - foreach (var puv in map.ProjectedCellBounds) + foreach (var puv in map.ProjectedCells) { - var uv = (MPos)puv; - if (!touched[uv]) + var index = touched.Index(puv); + if (!touched[index]) continue; - touched[uv] = false; + touched[index] = false; var type = ShroudCellType.Shroud; - if (explored[uv] && (!shroudGenerationEnabled || generatedShroudCount[uv] == 0 || visibleCount[uv] > 0)) + if (explored[index]) { - var count = visibleCount[uv]; - if (passiveVisibilityEnabled) - count += passiveVisibleCount[uv]; + var count = visibleCount[index]; + if (!shroudGenerationEnabled || count > 0 || generatedShroudCount[index] == 0) + { + if (passiveVisibilityEnabled) + count += passiveVisibleCount[index]; - type = count > 0 ? ShroudCellType.Visible : ShroudCellType.Fog; + type = count > 0 ? ShroudCellType.Visible : ShroudCellType.Fog; + } } - var oldResolvedType = resolvedType[uv]; - resolvedType[uv] = type; + var oldResolvedType = resolvedType[index]; if (type != oldResolvedType) - OnShroudChanged((PPos)uv); + { + resolvedType[index] = type; + OnShroudChanged(puv); + } } Hash = Sync.HashPlayer(self.Owner) + self.World.WorldTick; @@ -232,22 +244,23 @@ if (!map.Contains(puv)) continue; - var uv = (MPos)puv; - touched[uv] = true; + var index = touched.Index(puv); + touched[index] = true; + anyCellTouched = true; switch (type) { case SourceType.PassiveVisibility: passiveVisibilityEnabled = true; - passiveVisibleCount[uv]++; - explored[uv] = true; + passiveVisibleCount[index]++; + explored[index] = true; break; case SourceType.Visibility: - visibleCount[uv]++; - explored[uv] = true; + visibleCount[index]++; + explored[index] = true; break; case SourceType.Shroud: shroudGenerationEnabled = true; - generatedShroudCount[uv]++; + generatedShroudCount[index]++; break; } } @@ -255,8 +268,7 @@ public void RemoveSource(object key) { - ShroudSource state; - if (!sources.TryGetValue(key, out state)) + if (!sources.TryGetValue(key, out var state)) return; foreach (var puv in state.ProjectedCells) @@ -264,18 +276,19 @@ // Cells outside the visible bounds don't increment visibleCount if (map.Contains(puv)) { - var uv = (MPos)puv; - touched[uv] = true; + var index = touched.Index(puv); + touched[index] = true; + anyCellTouched = true; switch (state.Type) { case SourceType.PassiveVisibility: - passiveVisibleCount[uv]--; + passiveVisibleCount[index]--; break; case SourceType.Visibility: - visibleCount[uv]--; + visibleCount[index]--; break; case SourceType.Shroud: - generatedShroudCount[uv]--; + generatedShroudCount[index]--; break; } } @@ -288,11 +301,15 @@ { foreach (var puv in cells) { - var uv = (MPos)puv; - if (map.Contains(puv) && !explored[uv]) + if (map.Contains(puv)) { - touched[uv] = true; - explored[uv] = true; + var index = touched.Index(puv); + if (!explored[index]) + { + touched[index] = true; + anyCellTouched = true; + explored[index] = true; + } } } } @@ -302,38 +319,42 @@ if (map.Bounds != s.map.Bounds) throw new ArgumentException("The map bounds of these shrouds do not match.", "s"); - foreach (var puv in map.ProjectedCellBounds) + foreach (var puv in map.ProjectedCells) { - var uv = (MPos)puv; - if (!explored[uv] && s.explored[uv]) + var index = touched.Index(puv); + if (!explored[index] && s.explored[index]) { - touched[uv] = true; - explored[uv] = true; + touched[index] = true; + anyCellTouched = true; + explored[index] = true; } } } public void ExploreAll() { - foreach (var puv in map.ProjectedCellBounds) + foreach (var puv in map.ProjectedCells) { - var uv = (MPos)puv; - if (!explored[uv]) + var index = touched.Index(puv); + if (!explored[index]) { - touched[uv] = true; - explored[uv] = true; + touched[index] = true; + anyCellTouched = true; + explored[index] = true; } } } public void ResetExploration() { - foreach (var puv in map.ProjectedCellBounds) + foreach (var puv in map.ProjectedCells) { - var uv = (MPos)puv; - touched[uv] = true; - explored[uv] = (visibleCount[uv] + passiveVisibleCount[uv]) > 0; + var index = touched.Index(puv); + touched[index] = true; + explored[index] = (visibleCount[index] + passiveVisibleCount[index]) > 0; } + + anyCellTouched = true; } public bool IsExplored(WPos pos) @@ -363,8 +384,7 @@ if (Disabled) return map.Contains(puv); - var uv = (MPos)puv; - return resolvedType.Contains(uv) && resolvedType[uv] > ShroudCellType.Shroud; + return resolvedType.Contains(puv) && resolvedType[puv] > ShroudCellType.Shroud; } public bool IsVisible(WPos pos) @@ -379,9 +399,6 @@ public bool IsVisible(MPos uv) { - if (!resolvedType.Contains(uv)) - return false; - foreach (var puv in map.ProjectedCellsCovering(uv)) if (IsVisible(puv)) return true; @@ -395,15 +412,14 @@ if (!FogEnabled) return map.Contains(puv); - var uv = (MPos)puv; - return resolvedType.Contains(uv) && resolvedType[uv] == ShroudCellType.Visible; + return resolvedType.Contains(puv) && resolvedType[puv] == ShroudCellType.Visible; } public bool Contains(PPos uv) { // Check that uv is inside the map area. There is nothing special // about explored here: any of the CellLayers would have been suitable. - return explored.Contains((MPos)uv); + return explored.Contains(uv); } } } diff -Nru openra-20200503/OpenRA.Game/Traits/Selectable.cs openra-20210321/OpenRA.Game/Traits/Selectable.cs --- openra-20200503/OpenRA.Game/Traits/Selectable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/Selectable.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; - -namespace OpenRA.Traits -{ - [Flags] - public enum SelectionPriorityModifiers - { - None = 0, - Ctrl = 1, - Alt = 2 - } - - [Desc("This actor is selectable. Defines bounds of selectable area, selection class, selection priority and selection priority modifiers.")] - public class SelectableInfo : InteractableInfo - { - public readonly int Priority = 10; - - [Desc("Allow selection priority to be modified using a hotkey.", - "Valid values are None (priority is not affected by modifiers)", - "Ctrl (priority is raised when Ctrl pressed) and", - "Alt (priority is raised when Alt pressed).")] - public readonly SelectionPriorityModifiers PriorityModifiers = SelectionPriorityModifiers.None; - - [Desc("All units having the same selection class specified will be selected with select-by-type commands (e.g. double-click). " - + "Defaults to the actor name when not defined or inherited.")] - public readonly string Class = null; - - [VoiceReference] - public readonly string Voice = "Select"; - - public override object Create(ActorInitializer init) { return new Selectable(init.Self, this); } - } - - public class Selectable : Interactable - { - public readonly string Class = null; - public readonly SelectableInfo Info; - - public Selectable(Actor self, SelectableInfo info) - : base(info) - { - Class = string.IsNullOrEmpty(info.Class) ? self.Info.Name : info.Class; - Info = info; - } - } -} diff -Nru openra-20200503/OpenRA.Game/Traits/Target.cs openra-20210321/OpenRA.Game/Traits/Target.cs --- openra-20200503/OpenRA.Game/Traits/Target.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/Target.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Traits { public enum TargetType : byte { Invalid, Actor, Terrain, FrozenActor } - public struct Target + public readonly struct Target { public static readonly Target[] None = { }; public static readonly Target Invalid = default(Target); @@ -83,7 +83,7 @@ } public static Target FromPos(WPos p) { return new Target(p); } - public static Target FromTargetPositions(Target t) { return new Target(t.CenterPosition, t.Positions.ToArray()); } + public static Target FromTargetPositions(in Target t) { return new Target(t.CenterPosition, t.Positions.ToArray()); } public static Target FromCell(World w, CPos c, SubCell subCell = SubCell.FullCell) { return new Target(w, c, subCell); } public static Target FromActor(Actor a) { return a != null ? new Target(a) : Invalid; } public static Target FromFrozenActor(FrozenActor fa) { return new Target(fa); } diff -Nru openra-20200503/OpenRA.Game/Traits/TraitsInterfaces.cs openra-20210321/OpenRA.Game/Traits/TraitsInterfaces.cs --- openra-20200503/OpenRA.Game/Traits/TraitsInterfaces.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/TraitsInterfaces.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,6 +18,7 @@ using OpenRA.Graphics; using OpenRA.Network; using OpenRA.Primitives; +using OpenRA.Support; namespace OpenRA.Traits { @@ -49,7 +50,7 @@ /// public sealed class DamageType { DamageType() { } } - public interface IHealthInfo : ITraitInfo + public interface IHealthInfo : ITraitInfoInterface { int MaxHP { get; } } @@ -66,11 +67,8 @@ void Kill(Actor self, Actor attacker, BitSet damageTypes); } - // depends on the order of pips in WorldRenderer.cs! - public enum PipType { Transparent, Green, Yellow, Red, Gray, Blue, Ammo, AmmoEmpty } - [Flags] - public enum Stance + public enum PlayerRelationship { None = 0, Enemy = 1, @@ -80,7 +78,7 @@ public static class StanceExts { - public static bool HasStance(this Stance s, Stance stance) + public static bool HasStance(this PlayerRelationship s, PlayerRelationship stance) { // PERF: Enum.HasFlag is slower and requires allocations. return (s & stance) == stance; @@ -123,47 +121,14 @@ IEnumerable ScreenBounds(Actor self, WorldRenderer wr); } - // TODO: Replace Rectangle with an int2[] polygon - public interface IMouseBounds { Rectangle MouseoverBounds(Actor self, WorldRenderer wr); } + public interface IMouseBounds { Polygon MouseoverBounds(Actor self, WorldRenderer wr); } public interface IMouseBoundsInfo : ITraitInfoInterface { } public interface IAutoMouseBounds { Rectangle AutoMouseoverBounds(Actor self, WorldRenderer wr); } - // HACK: This provides a shim for legacy code until it can be rewritten - public interface IDecorationBounds { Rectangle DecorationBounds(Actor self, WorldRenderer wr); } - public interface IDecorationBoundsInfo : ITraitInfoInterface { } - public static class DecorationBoundsExtensions - { - public static Rectangle FirstNonEmptyBounds(this IEnumerable decorationBounds, Actor self, WorldRenderer wr) - { - // PERF: Avoid LINQ. - foreach (var decoration in decorationBounds) - { - var bounds = decoration.DecorationBounds(self, wr); - if (!bounds.IsEmpty) - return bounds; - } - - return Rectangle.Empty; - } - - public static Rectangle FirstNonEmptyBounds(this IDecorationBounds[] decorationBounds, Actor self, WorldRenderer wr) - { - // PERF: Avoid LINQ. - foreach (var decoration in decorationBounds) - { - var bounds = decoration.DecorationBounds(self, wr); - if (!bounds.IsEmpty) - return bounds; - } - - return Rectangle.Empty; - } - } - public interface IIssueOrder { IEnumerable Orders { get; } - Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued); + Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued); } [Flags] @@ -182,9 +147,9 @@ { string OrderID { get; } int OrderPriority { get; } - bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor); + bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor); bool IsQueued { get; } - bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers); + bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers); } public interface IResolveOrder { void ResolveOrder(Actor self, Order order); } @@ -231,7 +196,7 @@ public interface ITooltipInfo : ITraitInfoInterface { - string TooltipForPlayerStance(Stance stance); + string TooltipForPlayerStance(PlayerRelationship stance); bool IsOwnerRowVisible { get; } } @@ -296,16 +261,19 @@ public interface ILoadsPalettes { void LoadPalettes(WorldRenderer wr); } public interface ILoadsPlayerPalettes { void LoadPlayerPalettes(WorldRenderer wr, string playerName, Color playerColor, bool replaceExisting); } public interface IPaletteModifier { void AdjustPalette(IReadOnlyDictionary b); } - public interface IPips { IEnumerable GetPips(Actor self); } [RequireExplicitImplementation] public interface ISelectionBar { float GetValue(); Color GetColor(); bool DisplayWhenEmpty { get; } } - public interface ISelectionDecorations { void DrawRollover(Actor self, WorldRenderer worldRenderer); } + public interface ISelectionDecorations + { + IEnumerable RenderSelectionAnnotations(Actor self, WorldRenderer worldRenderer, Color color); + int2 GetDecorationOrigin(Actor self, WorldRenderer wr, string pos, int2 margin); + } public interface IMapPreviewSignatureInfo : ITraitInfoInterface { - void PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List> destinationBuffer); + void PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer); } public interface IOccupySpaceInfo : ITraitInfoInterface @@ -318,7 +286,7 @@ { WPos CenterPosition { get; } CPos TopLeft { get; } - Pair[] OccupiedCells(); + (CPos Cell, SubCell SubCell)[] OccupiedCells(); } public enum SubCell : byte { Invalid = byte.MaxValue, Any = byte.MaxValue - 1, FullCell = 0, First = 1 } @@ -351,16 +319,29 @@ public interface IFacing { - int TurnSpeed { get; } - int Facing { get; set; } + WAngle TurnSpeed { get; } + WAngle Facing { get; set; } + WRot Orientation { get; } } - public interface IFacingInfo : ITraitInfoInterface { int GetInitialFacing(); } + public interface IFacingInfo : ITraitInfoInterface { WAngle GetInitialFacing(); } public interface ITraitInfoInterface { } - public interface ITraitInfo : ITraitInfoInterface { object Create(ActorInitializer init); } - public class TraitInfo : ITraitInfo where T : new() { public virtual object Create(ActorInitializer init) { return new T(); } } + public abstract class TraitInfo : ITraitInfoInterface + { + // Value is set using reflection during TraitInfo creation + [FieldLoader.Ignore] + public readonly string InstanceName = null; + + public abstract object Create(ActorInitializer init); + } + + public class TraitInfo : TraitInfo where T : new() + { + public override object Create(ActorInitializer init) { return new T(); } + } + public interface ILobbyCustomRulesIgnore { } [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1302:InterfaceNamesMustBeginWithI", Justification = "Not a real interface, but more like a tag.")] @@ -385,7 +366,27 @@ } [RequireExplicitImplementation] - public interface ICreatePlayers { void CreatePlayers(World w); } + public interface ICreatePlayers { void CreatePlayers(World w, MersenneTwister playerRandom); } + + [RequireExplicitImplementation] + public interface ICreatePlayersInfo : ITraitInfoInterface + { + void CreateServerPlayers(MapPreview map, Session lobbyInfo, List players, MersenneTwister playerRandom); + } + + [RequireExplicitImplementation] + public interface IAssignSpawnPoints + { + CPos AssignHomeLocation(World world, Session.Client client, MersenneTwister playerRandom); + int SpawnPointForPlayer(Player player); + } + + [RequireExplicitImplementation] + public interface IAssignSpawnPointsInfo : ITraitInfoInterface + { + object InitializeState(MapPreview map, Session lobbyInfo); + int AssignSpawnPoint(object state, Session lobbyInfo, Session.Client client, MersenneTwister playerRandom); + } public interface IBotInfo : ITraitInfoInterface { @@ -416,6 +417,13 @@ [RequireExplicitImplementation] public interface IRenderTerrain { void RenderTerrain(WorldRenderer wr, Viewport viewport); } + [RequireExplicitImplementation] + public interface ITerrainLighting + { + event Action CellChanged; + float3 TintAt(WPos pos); + } + public interface IRenderAboveShroud { IEnumerable RenderAboveShroud(Actor self, WorldRenderer wr); @@ -440,6 +448,22 @@ bool SpatiallyPartitionable { get; } } + [Flags] + public enum SelectionPriorityModifiers + { + None = 0, + Ctrl = 1, + Alt = 2 + } + + [RequireExplicitImplementation] + public interface ISelectableInfo : ITraitInfoInterface + { + int Priority { get; } + SelectionPriorityModifiers PriorityModifiers { get; } + string Voice { get; } + } + public interface ISelection { int Hash { get; } @@ -450,6 +474,8 @@ bool Contains(Actor a); void Combine(World world, IEnumerable newSelection, bool isCombine, bool isClick); void Clear(); + bool RolloverContains(Actor a); + void SetRollover(IEnumerable actors); void DoControlGroup(World world, WorldRenderer worldRenderer, int group, Modifiers mods, int multiTapCount); void AddToControlGroup(Actor a, int group); void RemoveFromControlGroup(Actor a); @@ -481,7 +507,10 @@ bool AlwaysEnabled { get; } } - public interface IMoveInfo : ITraitInfoInterface { } + public interface IMoveInfo : ITraitInfoInterface + { + Color GetTargetLineColor(); + } [RequireExplicitImplementation] public interface IGameOver { void GameOver(World world); } @@ -491,7 +520,7 @@ int Delay { get; } bool IsValidAgainst(Actor victim, Actor firedBy); bool IsValidAgainst(FrozenActor victim, Actor firedBy); - void DoImpact(Target target, WarheadArgs args); + void DoImpact(in Target target, WarheadArgs args); } public interface IRulesetLoaded { void RulesetLoaded(Ruleset rules, TInfo info); } @@ -537,8 +566,8 @@ { static readonly Dictionary BoolValues = new Dictionary() { - { true.ToString(), "enabled" }, - { false.ToString(), "disabled" } + { true.ToString(), "Enabled" }, + { false.ToString(), "Disabled" } }; public LobbyBooleanOption(string id, string name, string description, bool visible, int displayorder, bool defaultValue, bool locked) @@ -546,7 +575,7 @@ public override string ValueChangedMessage(string playerName, string newValue) { - return playerName + " " + BoolValues[newValue] + " " + Name + "."; + return playerName + " " + BoolValues[newValue].ToLowerInvariant() + " " + Name + "."; } } @@ -555,4 +584,24 @@ [RequireExplicitImplementation] public interface ICreationActivity { Activity GetCreationActivity(); } + + [RequireExplicitImplementation] + public interface IObservesVariablesInfo : ITraitInfoInterface { } + + public delegate void VariableObserverNotifier(Actor self, IReadOnlyDictionary variables); + public struct VariableObserver + { + public VariableObserverNotifier Notifier; + public IEnumerable Variables; + public VariableObserver(VariableObserverNotifier notifier, IEnumerable variables) + { + Notifier = notifier; + Variables = variables; + } + } + + public interface IObservesVariables + { + IEnumerable GetVariableObservers(); + } } diff -Nru openra-20200503/OpenRA.Game/Traits/World/FixedColorPalette.cs openra-20210321/OpenRA.Game/Traits/World/FixedColorPalette.cs --- openra-20200503/OpenRA.Game/Traits/World/FixedColorPalette.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/World/FixedColorPalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,58 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Graphics; +using OpenRA.Primitives; + +namespace OpenRA.Traits +{ + [Desc("Add this to the World actor definition.")] + public class FixedColorPaletteInfo : TraitInfo + { + [PaletteReference] + [Desc("The name of the palette to base off.")] + public readonly string Base = TileSet.TerrainPaletteInternalName; + + [PaletteDefinition] + [Desc("The name of the resulting palette")] + public readonly string Name = "resources"; + + [Desc("Remap these indices to pre-defined colors.")] + public readonly int[] RemapIndex = { }; + + [Desc("The fixed color to remap.")] + public readonly Color Color; + + [Desc("Luminosity range to span.")] + public readonly float Ramp = 0.05f; + + [Desc("Allow palette modifiers to change the palette.")] + public readonly bool AllowModifiers = true; + + public override object Create(ActorInitializer init) { return new FixedColorPalette(this); } + } + + public class FixedColorPalette : ILoadsPalettes + { + readonly FixedColorPaletteInfo info; + + public FixedColorPalette(FixedColorPaletteInfo info) + { + this.info = info; + } + + public void LoadPalettes(WorldRenderer wr) + { + var remap = new PlayerColorRemap(info.RemapIndex, info.Color, info.Ramp); + wr.AddPalette(info.Name, new ImmutablePalette(wr.Palette(info.Base).Palette, remap), info.AllowModifiers); + } + } +} diff -Nru openra-20200503/OpenRA.Game/Traits/World/ScreenMap.cs openra-20210321/OpenRA.Game/Traits/World/ScreenMap.cs --- openra-20200503/OpenRA.Game/Traits/World/ScreenMap.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/World/ScreenMap.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,32 +18,24 @@ namespace OpenRA.Traits { - public struct ActorBoundsPair : IEquatable + public struct ActorBoundsPair { public readonly Actor Actor; + public readonly Polygon Bounds; - // TODO: Replace this with an int2[] polygon - public readonly Rectangle Bounds; - - public ActorBoundsPair(Actor actor, Rectangle bounds) { Actor = actor; Bounds = bounds; } - - public static bool operator ==(ActorBoundsPair me, ActorBoundsPair other) { return me.Actor == other.Actor && Equals(me.Bounds, other.Bounds); } - public static bool operator !=(ActorBoundsPair me, ActorBoundsPair other) { return !(me == other); } + public ActorBoundsPair(Actor actor, Polygon bounds) { Actor = actor; Bounds = bounds; } public override int GetHashCode() { return Actor.GetHashCode() ^ Bounds.GetHashCode(); } - public bool Equals(ActorBoundsPair other) { return this == other; } - public override bool Equals(object obj) { return obj is ActorBoundsPair && Equals((ActorBoundsPair)obj); } - public override string ToString() { return "{0}->{1}".F(Actor.Info.Name, Bounds.GetType().Name); } } - public class ScreenMapInfo : ITraitInfo + public class ScreenMapInfo : TraitInfo { [Desc("Size of partition bins (world pixels)")] public readonly int BinSize = 250; - public object Create(ActorInitializer init) { return new ScreenMap(init.World, this); } + public override object Create(ActorInitializer init) { return new ScreenMap(init.World, this); } } public class ScreenMap : IWorldLoaded @@ -198,7 +190,7 @@ return partitionedMouseActors.InBox(r) .Where(actorIsInWorld) .Select(selectActorAndBounds) - .Where(x => r.IntersectsWith(x.Bounds)); + .Where(x => x.Bounds.IntersectsWith(r)); } public IEnumerable RenderableActorsInBox(int2 a, int2 b) @@ -224,12 +216,12 @@ foreach (var a in addOrUpdateActors) { var mouseBounds = a.MouseBounds(worldRenderer); - if (!mouseBounds.Size.IsEmpty) + if (!mouseBounds.IsEmpty) { if (partitionedMouseActors.Contains(a)) - partitionedMouseActors.Update(a, mouseBounds); + partitionedMouseActors.Update(a, mouseBounds.BoundingRect); else - partitionedMouseActors.Add(a, mouseBounds); + partitionedMouseActors.Add(a, mouseBounds.BoundingRect); partitionedMouseActorBounds[a] = new ActorBoundsPair(a, mouseBounds); } @@ -263,12 +255,12 @@ foreach (var fa in kv.Value) { var mouseBounds = fa.MouseBounds; - if (!mouseBounds.Size.IsEmpty) + if (!mouseBounds.IsEmpty) { if (partitionedMouseFrozenActors[kv.Key].Contains(fa)) - partitionedMouseFrozenActors[kv.Key].Update(fa, mouseBounds); + partitionedMouseFrozenActors[kv.Key].Update(fa, mouseBounds.BoundingRect); else - partitionedMouseFrozenActors[kv.Key].Add(fa, mouseBounds); + partitionedMouseFrozenActors[kv.Key].Add(fa, mouseBounds.BoundingRect); } else partitionedMouseFrozenActors[kv.Key].Remove(fa); @@ -308,11 +300,10 @@ return viewer != null ? bounds.Concat(partitionedRenderableFrozenActors[viewer].ItemBounds) : bounds; } - public IEnumerable MouseBounds(Player viewer) + public IEnumerable MouseBounds(Player viewer) { - var bounds = partitionedMouseActors.ItemBounds; - - return viewer != null ? bounds.Concat(partitionedMouseFrozenActors[viewer].ItemBounds) : bounds; + var bounds = partitionedMouseActorBounds.Values.Select(a => a.Bounds); + return viewer != null ? bounds.Concat(partitionedMouseFrozenActors[viewer].Items.Select(fa => fa.MouseBounds)) : bounds; } } } diff -Nru openra-20200503/OpenRA.Game/Traits/World/ScreenShaker.cs openra-20210321/OpenRA.Game/Traits/World/ScreenShaker.cs --- openra-20200503/OpenRA.Game/Traits/World/ScreenShaker.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Traits/World/ScreenShaker.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,12 +16,12 @@ namespace OpenRA.Traits { - public class ScreenShakerInfo : ITraitInfo + public class ScreenShakerInfo : TraitInfo { public readonly float2 MinMultiplier = new float2(-3, -3); public readonly float2 MaxMultiplier = new float2(3, 3); - public object Create(ActorInitializer init) { return new ScreenShaker(this); } + public override object Create(ActorInitializer init) { return new ScreenShaker(this); } } public class ScreenShaker : ITick, IWorldLoaded diff -Nru openra-20200503/OpenRA.Game/UtilityCommands/RegisterModCommand.cs openra-20210321/OpenRA.Game/UtilityCommands/RegisterModCommand.cs --- openra-20200503/OpenRA.Game/UtilityCommands/RegisterModCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/UtilityCommands/RegisterModCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,7 +31,7 @@ if (args[2] == "user" || args[2] == "both") type |= ModRegistration.User; - new ExternalMods().Register(utility.ModData.Manifest, args[1], type); + new ExternalMods().Register(utility.ModData.Manifest, args[1], Enumerable.Empty(), type); } } } diff -Nru openra-20200503/OpenRA.Game/VoiceExts.cs openra-20210321/OpenRA.Game/VoiceExts.cs --- openra-20200503/OpenRA.Game/VoiceExts.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/VoiceExts.cs 2021-03-21 11:10:05.000000000 +0000 @@ -57,7 +57,13 @@ if (o == null) continue; - if (PlayVoiceForOrder(o)) + if (o.GroupedActors != null) + { + foreach (var subject in o.GroupedActors) + if (PlayVoiceForOrder(Order.FromGroupedOrder(o, subject))) + return; + } + else if (PlayVoiceForOrder(o)) return; } } diff -Nru openra-20200503/OpenRA.Game/WAngle.cs openra-20210321/OpenRA.Game/WAngle.cs --- openra-20200503/OpenRA.Game/WAngle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/WAngle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,13 +10,16 @@ #endregion using System; +using Eluant; +using Eluant.ObjectBinding; +using OpenRA.Scripting; namespace OpenRA { /// /// 1D angle - 1024 units = 360 degrees. /// - public struct WAngle : IEquatable + public struct WAngle : IScriptBindable, ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, IEquatable { public readonly int Angle; public int AngleSquared { get { return (int)Angle * Angle; } } @@ -79,6 +82,50 @@ return new WAngle(aa + (bb - aa) * mul / div); } + public static WAngle ArcSin(int d) + { + if (d < -1024 || d > 1024) + throw new ArgumentException("ArcSin is only valid for values between -1024 and 1024. Received {0}".F(d)); + + var a = ClosestCosineIndex(Math.Abs(d)); + return new WAngle(d < 0 ? 768 + a : 256 - a); + } + + public static WAngle ArcCos(int d) + { + if (d < -1024 || d > 1024) + throw new ArgumentException("ArcCos is only valid for values between -1024 and 1024. Received {0}".F(d)); + + var a = ClosestCosineIndex(Math.Abs(d)); + return new WAngle(d < 0 ? 512 - a : a); + } + + /// + /// Find the index of CosineTable that has the value closest to the given value. + /// The first or last index will be returned for values above or below the valid range + /// + static int ClosestCosineIndex(int value) + { + var aboveIndex = 0; + var belowIndex = 256; + while (aboveIndex != belowIndex - 1) + { + var index = (aboveIndex + belowIndex) / 2; + var val = CosineTable[index]; + + if (val == value) + return index; + + if (val < value) + belowIndex = index; + else + aboveIndex = index; + } + + // Take the index with the smallest error + return CosineTable[aboveIndex] - value > value - CosineTable[belowIndex] ? belowIndex : aboveIndex; + } + public static WAngle ArcTan(int y, int x) { return ArcTan(y, x, 1); } public static WAngle ArcTan(int y, int x, int stride) { @@ -169,5 +216,51 @@ 9233, 9781, 10396, 11094, 11891, 12810, 13882, 15148, 16667, 18524, 20843, 23826, 27801, 33366, 41713, 55622, 83438, 166883, int.MaxValue }; + + #region Scripting interface + + public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right) + { + if (!left.TryGetClrValue(out WAngle a)) + throw new LuaException("Attempted to call WAngle.Add(WAngle, WAngle) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name)); + + if (right.TryGetClrValue(out int c)) + { + Game.Debug("Support for facing calculations mixing Angle with integers is deprecated. Make sure all facing calculations use Angle"); + return new LuaCustomClrObject(a + FromFacing(c)); + } + + if (right.TryGetClrValue(out WAngle b)) + return new LuaCustomClrObject(a + b); + + throw new LuaException("Attempted to call WAngle.Add(WAngle, WAngle) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name)); + } + + public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right) + { + if (!left.TryGetClrValue(out WAngle a)) + throw new LuaException("Attempted to call WAngle.Subtract(WAngle, WAngle) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name)); + + if (right.TryGetClrValue(out int c)) + { + Game.Debug("Support for facing calculations mixing Angle with integers is deprecated. Make sure all facing calculations use Angle"); + return new LuaCustomClrObject(a - FromFacing(c)); + } + + if (right.TryGetClrValue(out WAngle b)) + return new LuaCustomClrObject(a - b); + + throw new LuaException("Attempted to call WAngle.Subtract(WAngle, WAngle) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name)); + } + + public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right) + { + if (!left.TryGetClrValue(out WAngle a) || !right.TryGetClrValue(out WAngle b)) + return false; + + return a == b; + } + + #endregion } } diff -Nru openra-20200503/OpenRA.Game/WDist.cs openra-20210321/OpenRA.Game/WDist.cs --- openra-20200503/OpenRA.Game/WDist.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/WDist.cs 2021-03-21 11:10:05.000000000 +0000 @@ -114,9 +114,7 @@ #region Scripting interface public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right) { - WDist a; - WDist b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out WDist a) || !right.TryGetClrValue(out WDist b)) throw new LuaException("Attempted to call WDist.Add(WDist, WDist) with invalid arguments."); return new LuaCustomClrObject(a + b); @@ -124,9 +122,7 @@ public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right) { - WDist a; - WDist b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out WDist a) || !right.TryGetClrValue(out WDist b)) throw new LuaException("Attempted to call WDist.Subtract(WDist, WDist) with invalid arguments."); return new LuaCustomClrObject(a - b); @@ -134,9 +130,7 @@ public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right) { - WDist a; - WDist b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out WDist a) || !right.TryGetClrValue(out WDist b)) throw new LuaException("Attempted to call WDist.Equals(WDist, WDist) with invalid arguments."); return a == b; diff -Nru openra-20200503/OpenRA.Game/Widgets/ChromeMetrics.cs openra-20210321/OpenRA.Game/Widgets/ChromeMetrics.cs --- openra-20200503/OpenRA.Game/Widgets/ChromeMetrics.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Widgets/ChromeMetrics.cs 2021-03-21 11:10:05.000000000 +0000 @@ -35,8 +35,7 @@ public static bool TryGet(string key, out T result) { - string s; - if (!data.TryGetValue(key, out s)) + if (!data.TryGetValue(key, out var s)) { result = default(T); return false; diff -Nru openra-20200503/OpenRA.Game/Widgets/Widget.cs openra-20210321/OpenRA.Game/Widgets/Widget.cs --- openra-20200503/OpenRA.Game/Widgets/Widget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Widgets/Widget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -113,11 +113,9 @@ if (wasMouseOver != MouseOverWidget) { - if (wasMouseOver != null) - wasMouseOver.MouseExited(); + wasMouseOver?.MouseExited(); - if (MouseOverWidget != null) - MouseOverWidget.MouseEntered(); + MouseOverWidget?.MouseEntered(); } return handled; @@ -279,21 +277,18 @@ public virtual Rectangle EventBounds { get { return RenderBounds; } } - public virtual Rectangle GetEventBounds() + public virtual bool EventBoundsContains(int2 location) { // PERF: Avoid LINQ. - var bounds = EventBounds; + if (EventBounds.Contains(location)) + return true; + foreach (var child in Children) - { if (child.IsVisible()) - { - var childBounds = child.GetEventBounds(); - if (childBounds != Rectangle.Empty) - bounds = Rectangle.Union(bounds, childBounds); - } - } + if (child.EventBoundsContains(location)) + return true; - return bounds; + return false; } public bool HasMouseFocus { get { return Ui.MouseFocusWidget == this; } } @@ -356,7 +351,7 @@ public string GetCursorOuter(int2 pos) { // Is the cursor on top of us? - if (!(IsVisible() && GetEventBounds().Contains(pos))) + if (!(IsVisible() && EventBoundsContains(pos))) return null; // Do any of our children specify a cursor? @@ -381,7 +376,7 @@ public bool HandleMouseInputOuter(MouseInput mi) { // Are we able to handle this event? - if (!(HasMouseFocus || (IsVisible() && GetEventBounds().Contains(mi.Location)))) + if (!(HasMouseFocus || (IsVisible() && EventBoundsContains(mi.Location)))) return false; var oldMouseOver = Ui.MouseOverWidget; diff -Nru openra-20200503/OpenRA.Game/Widgets/WidgetLoader.cs openra-20210321/OpenRA.Game/Widgets/WidgetLoader.cs --- openra-20200503/OpenRA.Game/Widgets/WidgetLoader.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/Widgets/WidgetLoader.cs 2021-03-21 11:10:05.000000000 +0000 @@ -37,8 +37,7 @@ public Widget LoadWidget(WidgetArgs args, Widget parent, string w) { - MiniYamlNode ret; - if (!widgets.TryGetValue(w, out ret)) + if (!widgets.TryGetValue(w, out var ret)) throw new InvalidDataException("Cannot find widget with Id `{0}`".F(w)); return LoadWidget(args, parent, ret); @@ -51,8 +50,7 @@ var widget = NewWidget(node.Key, args); - if (parent != null) - parent.AddChild(widget); + parent?.AddChild(widget); if (node.Key.Contains("@")) FieldLoader.LoadField(widget, "Id", node.Key.Split('@')[1]); diff -Nru openra-20200503/OpenRA.Game/World.cs openra-20210321/OpenRA.Game/World.cs --- openra-20200503/OpenRA.Game/World.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/World.cs 2021-03-21 11:10:05.000000000 +0000 @@ -32,6 +32,7 @@ readonly List effects = new List(); readonly List unpartitionedEffects = new List(); readonly List syncedEffects = new List(); + readonly GameSettings gameSettings; readonly Queue> frameEndActions = new Queue>(); @@ -89,8 +90,7 @@ { renderPlayer = value; - if (RenderPlayerChanged != null) - RenderPlayerChanged(value); + RenderPlayerChanged?.Invoke(value); } } } @@ -143,6 +143,8 @@ public readonly ScreenMap ScreenMap; public readonly WorldType Type; + public readonly IValidateOrder[] OrderValidators; + readonly GameInformation gameInfo; // Hide the OrderManager from mod code @@ -159,8 +161,7 @@ set { Sync.AssertUnsynced("The current order generator may not be changed from synced code"); - if (orderGenerator != null) - orderGenerator.Deactivate(); + orderGenerator?.Deactivate(); orderGenerator = value; } @@ -205,28 +206,14 @@ ActorMap = WorldActor.Trait(); ScreenMap = WorldActor.Trait(); Selection = WorldActor.Trait(); + OrderValidators = WorldActor.TraitsImplementing().ToArray(); - // Reset mask LongBitSet.Reset(); - // Add players + // Create an isolated RNG to simplify synchronization between client and server player faction/spawn assignments + var playerRandom = new MersenneTwister(orderManager.LobbyInfo.GlobalSettings.RandomSeed); foreach (var cmp in WorldActor.TraitsImplementing()) - cmp.CreatePlayers(this); - - // Set defaults for any unset stances - foreach (var p in Players) - { - if (!p.Spectating) - AllPlayersMask = AllPlayersMask.Union(p.PlayerMask); - - foreach (var q in Players) - { - SetUpPlayerMask(p, q); - - if (!p.Stances.ContainsKey(q)) - p.Stances[q] = Stance.Neutral; - } - } + cmp.CreatePlayers(this, playerRandom); Game.Sound.SoundVolumeModifier = 1.0f; @@ -240,25 +227,7 @@ }; RulesContainTemporaryBlocker = map.Rules.Actors.Any(a => a.Value.HasTraitInfo()); - } - - void SetUpPlayerMask(Player p, Player q) - { - if (q.Spectating) - return; - - var bitSet = q.PlayerMask; - - switch (p.Stances[q]) - { - case Stance.Enemy: - case Stance.Neutral: - p.EnemyPlayersMask = p.EnemyPlayersMask.Union(bitSet); - break; - case Stance.Ally: - p.AlliedPlayersMask = p.AlliedPlayersMask.Union(bitSet); - break; - } + gameSettings = Game.Settings.Game; } public void AddToMaps(Actor self, IOccupySpace ios) @@ -317,6 +286,8 @@ foreach (var player in Players) gameInfo.AddPlayer(player, OrderManager.LobbyInfo); + gameInfo.DisabledSpawnPoints = OrderManager.LobbyInfo.DisabledSpawnPoints; + var echo = OrderManager.Connection as EchoConnection; var rc = echo != null ? echo.Recorder : null; @@ -334,13 +305,15 @@ return CreateActor(true, name, initDict); } + public Actor CreateActor(bool addToWorld, ActorReference reference) + { + return CreateActor(addToWorld, reference.Type, reference.InitDict); + } + public Actor CreateActor(bool addToWorld, string name, TypeDictionary initDict) { var a = new Actor(this, name, initDict); - a.Created(); - if (addToWorld) - Add(a); - + a.Initialize(addToWorld); return a; } @@ -453,7 +426,9 @@ wasLoadingGameSave = false; } - if (!Paused) + // Allow users to pause the shellmap via the settings menu + // Some traits initialize important state during the first tick, so we must allow it to tick at least once + if (!Paused && (Type != WorldType.Shellmap || !gameSettings.PauseShellmap || WorldTick == 0)) { WorldTick++; @@ -461,7 +436,7 @@ foreach (var a in actors.Values) a.Tick(); - ActorsWithTrait().DoTimed(x => x.Trait.Tick(x.Actor), "Trait"); + ApplyToActorsWithTraitTimed((Actor actor, ITick trait) => trait.Tick(actor), "Trait"); effects.DoTimed(e => e.Tick(this), "Effect"); } @@ -473,7 +448,7 @@ // For things that want to update their render state once per tick, ignoring pause state public void TickRender(WorldRenderer wr) { - ActorsWithTrait().DoTimed(x => x.Trait.TickRender(wr, x.Actor), "Render"); + ApplyToActorsWithTraitTimed((Actor actor, ITickRender trait) => trait.TickRender(wr, actor), "Render"); ScreenMap.TickRender(); } @@ -484,8 +459,7 @@ public Actor GetActorById(uint actorId) { - Actor a; - if (actors.TryGetValue(actorId, out a)) + if (actors.TryGetValue(actorId, out var a)) return a; return null; } @@ -533,6 +507,11 @@ return TraitDict.ActorsWithTrait(); } + public void ApplyToActorsWithTraitTimed(Action action, string text) + { + TraitDict.ApplyToActorsWithTraitTimed(action, text); + } + public IEnumerable ActorsHavingTrait() { return TraitDict.ActorsHavingTrait(); @@ -553,6 +532,15 @@ } } + public void OnPlayerDisconnected(Player player) + { + var pi = gameInfo.GetPlayer(player); + if (pi == null) + return; + + pi.DisconnectFrame = OrderManager.NetFrameNumber; + } + public void RequestGameSave(string filename) { // Allow traits to save arbitrary data that will be passed back via IGameSaveTraitData.ResolveTraitData @@ -580,8 +568,7 @@ { Disposing = true; - if (OrderGenerator != null) - OrderGenerator.Deactivate(); + OrderGenerator?.Deactivate(); frameEndActions.Clear(); diff -Nru openra-20200503/OpenRA.Game/WorldUtils.cs openra-20210321/OpenRA.Game/WorldUtils.cs --- openra-20200503/OpenRA.Game/WorldUtils.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/WorldUtils.cs 2021-03-21 11:10:05.000000000 +0000 @@ -87,11 +87,5 @@ } } } - - public static bool AreMutualAllies(Player a, Player b) - { - return a.Stances[b] == Stance.Ally && - b.Stances[a] == Stance.Ally; - } } } diff -Nru openra-20200503/OpenRA.Game/WorldViewportSizes.cs openra-20210321/OpenRA.Game/WorldViewportSizes.cs --- openra-20200503/OpenRA.Game/WorldViewportSizes.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/WorldViewportSizes.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Collections.Generic; using OpenRA.Primitives; namespace OpenRA diff -Nru openra-20200503/OpenRA.Game/WPos.cs openra-20210321/OpenRA.Game/WPos.cs --- openra-20200503/OpenRA.Game/WPos.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/WPos.cs 2021-03-21 11:10:05.000000000 +0000 @@ -82,9 +82,7 @@ public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right) { - WPos a; - WVec b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out WPos a) || !right.TryGetClrValue(out WVec b)) throw new LuaException("Attempted to call WPos.Add(WPos, WVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name)); return new LuaCustomClrObject(a + b); @@ -92,21 +90,18 @@ public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right) { - WPos a; var rightType = right.WrappedClrType(); - if (!left.TryGetClrValue(out a)) + if (!left.TryGetClrValue(out WPos a)) throw new LuaException("Attempted to call WPos.Subtract(WPos, (WPos|WVec)) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, rightType.Name)); if (rightType == typeof(WPos)) { - WPos b; - right.TryGetClrValue(out b); + right.TryGetClrValue(out WPos b); return new LuaCustomClrObject(a - b); } else if (rightType == typeof(WVec)) { - WVec b; - right.TryGetClrValue(out b); + right.TryGetClrValue(out WVec b); return new LuaCustomClrObject(a - b); } @@ -115,8 +110,7 @@ public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right) { - WPos a, b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out WPos a) || !right.TryGetClrValue(out WPos b)) return false; return a == b; diff -Nru openra-20200503/OpenRA.Game/WRot.cs openra-20210321/OpenRA.Game/WRot.cs --- openra-20200503/OpenRA.Game/WRot.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/WRot.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,57 +16,119 @@ /// /// 3d World rotation. /// - public struct WRot : IEquatable + public readonly struct WRot : IEquatable { + // The Euler angle representation is a lot more intuitive for public use public readonly WAngle Roll, Pitch, Yaw; - public WRot(WAngle roll, WAngle pitch, WAngle yaw) { Roll = roll; Pitch = pitch; Yaw = yaw; } - public static readonly WRot Zero = new WRot(WAngle.Zero, WAngle.Zero, WAngle.Zero); + // Internal calculations use the quaternion form + readonly int x, y, z, w; + + public WRot(WAngle roll, WAngle pitch, WAngle yaw) + { + Roll = roll; + Pitch = pitch; + Yaw = yaw; + + // Angles increase clockwise + var qr = new WAngle(-Roll.Angle / 2); + var qp = new WAngle(-Pitch.Angle / 2); + var qy = new WAngle(-Yaw.Angle / 2); + var cr = (long)qr.Cos(); + var sr = (long)qr.Sin(); + var cp = (long)qp.Cos(); + var sp = (long)qp.Sin(); + var cy = (long)qy.Cos(); + var sy = (long)qy.Sin(); + + // Normalized to 1024 == 1.0 + x = (int)((sr * cp * cy - cr * sp * sy) / 1048576); + y = (int)((cr * sp * cy + sr * cp * sy) / 1048576); + z = (int)((cr * cp * sy - sr * sp * cy) / 1048576); + w = (int)((cr * cp * cy + sr * sp * sy) / 1048576); + } + + WRot(int x, int y, int z, int w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + // Theoretically 1024 squared, but may differ slightly due to rounding + var lsq = x * x + y * y + z * z + w * w; + + var srcp = 2 * (w * x + y * z); + var crcp = lsq - 2 * (x * x + y * y); + var sp = (w * y - z * x) / 512; + var sycp = 2 * (w * z + x * y); + var cycp = lsq - 2 * (y * y + z * z); + + Roll = -WAngle.ArcTan(srcp, crcp); + Pitch = -(Math.Abs(sp) >= 1024 ? new WAngle(Math.Sign(sp) * 256) : WAngle.ArcSin(sp)); + Yaw = -WAngle.ArcTan(sycp, cycp); + } + + WRot(int x, int y, int z, int w, WAngle roll, WAngle pitch, WAngle yaw) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + Roll = roll; + Pitch = pitch; + Yaw = yaw; + } + + public static readonly WRot None = new WRot(WAngle.Zero, WAngle.Zero, WAngle.Zero); public static WRot FromFacing(int facing) { return new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing)); } public static WRot FromYaw(WAngle yaw) { return new WRot(WAngle.Zero, WAngle.Zero, yaw); } - public static WRot operator +(WRot a, WRot b) { return new WRot(a.Roll + b.Roll, a.Pitch + b.Pitch, a.Yaw + b.Yaw); } - public static WRot operator -(WRot a, WRot b) { return new WRot(a.Roll - b.Roll, a.Pitch - b.Pitch, a.Yaw - b.Yaw); } - public static WRot operator -(WRot a) { return new WRot(-a.Roll, -a.Pitch, -a.Yaw); } + public static WRot operator +(in WRot a, in WRot b) { return new WRot(a.Roll + b.Roll, a.Pitch + b.Pitch, a.Yaw + b.Yaw); } + public static WRot operator -(in WRot a, in WRot b) { return new WRot(a.Roll - b.Roll, a.Pitch - b.Pitch, a.Yaw - b.Yaw); } + public static WRot operator -(in WRot a) { return new WRot(-a.x, -a.y, -a.z, a.w, -a.Roll, -a.Pitch, -a.Yaw); } + + public WRot Rotate(in WRot rot) + { + if (this == None) + return rot; + + if (rot == None) + return this; + + var rx = ((long)rot.w * x + (long)rot.x * w + (long)rot.y * z - (long)rot.z * y) / 1024; + var ry = ((long)rot.w * y - (long)rot.x * z + (long)rot.y * w + (long)rot.z * x) / 1024; + var rz = ((long)rot.w * z + (long)rot.x * y - (long)rot.y * x + (long)rot.z * w) / 1024; + var rw = ((long)rot.w * w - (long)rot.x * x - (long)rot.y * y - (long)rot.z * z) / 1024; - public static bool operator ==(WRot me, WRot other) + return new WRot((int)rx, (int)ry, (int)rz, (int)rw); + } + + public static bool operator ==(in WRot me, in WRot other) { return me.Roll == other.Roll && me.Pitch == other.Pitch && me.Yaw == other.Yaw; } - public static bool operator !=(WRot me, WRot other) { return !(me == other); } + public static bool operator !=(in WRot me, in WRot other) { return !(me == other); } - public WRot WithYaw(WAngle yaw) + public WRot WithRoll(WAngle roll) { - return new WRot(Roll, Pitch, yaw); + return new WRot(roll, Pitch, Yaw); } - void AsQuarternion(out int x, out int y, out int z, out int w) + public WRot WithPitch(WAngle pitch) { - // Angles increase clockwise - var roll = new WAngle(-Roll.Angle / 2); - var pitch = new WAngle(-Pitch.Angle / 2); - var yaw = new WAngle(-Yaw.Angle / 2); - var cr = (long)roll.Cos(); - var sr = (long)roll.Sin(); - var cp = (long)pitch.Cos(); - var sp = (long)pitch.Sin(); - var cy = (long)yaw.Cos(); - var sy = (long)yaw.Sin(); + return new WRot(Roll, pitch, Yaw); + } - // Normalized to 1024 == 1.0 - x = (int)((sr * cp * cy - cr * sp * sy) / 1048576); - y = (int)((cr * sp * cy + sr * cp * sy) / 1048576); - z = (int)((cr * cp * sy - sr * sp * cy) / 1048576); - w = (int)((cr * cp * cy + sr * sp * sy) / 1048576); + public WRot WithYaw(WAngle yaw) + { + return new WRot(Roll, Pitch, yaw); } public void AsMatrix(out Int32Matrix4x4 mtx) { - int x, y, z, w; - AsQuarternion(out x, out y, out z, out w); - - // Theoretically 1024 * * 2, but may differ slightly due to rounding + // Theoretically 1024 squared, but may differ slightly due to rounding var lsq = x * x + y * y + z * z + w * w; // Quaternion components use 10 bits, so there's no risk of overflow @@ -96,8 +158,7 @@ public Int32Matrix4x4 AsMatrix() { - Int32Matrix4x4 mtx; - AsMatrix(out mtx); + AsMatrix(out var mtx); return mtx; } diff -Nru openra-20200503/OpenRA.Game/WVec.cs openra-20210321/OpenRA.Game/WVec.cs --- openra-20200503/OpenRA.Game/WVec.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Game/WVec.cs 2021-03-21 11:10:05.000000000 +0000 @@ -44,10 +44,9 @@ public long VerticalLengthSquared { get { return (long)Z * Z; } } public int VerticalLength { get { return (int)Exts.ISqrt(VerticalLengthSquared); } } - public WVec Rotate(WRot rot) + public WVec Rotate(in WRot rot) { - Int32Matrix4x4 mtx; - rot.AsMatrix(out mtx); + rot.AsMatrix(out var mtx); return Rotate(ref mtx); } @@ -111,8 +110,7 @@ public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right) { - WVec a, b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out WVec a) || !right.TryGetClrValue(out WVec b)) throw new LuaException("Attempted to call WVec.Add(WVec, WVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name)); return new LuaCustomClrObject(a + b); @@ -120,8 +118,7 @@ public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right) { - WVec a, b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out WVec a) || !right.TryGetClrValue(out WVec b)) throw new LuaException("Attempted to call WVec.Subtract(WVec, WVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name)); return new LuaCustomClrObject(a - b); @@ -134,8 +131,7 @@ public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right) { - WVec a, b; - if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b)) + if (!left.TryGetClrValue(out WVec a) || !right.TryGetClrValue(out WVec b)) return false; return a == b; @@ -150,7 +146,7 @@ case "X": return X; case "Y": return Y; case "Z": return Z; - case "Facing": return Yaw.Facing; + case "Facing": return new LuaCustomClrObject(Yaw); default: throw new LuaException("WVec does not define a member '{0}'".F(key)); } } diff -Nru openra-20200503/OpenRA.Launcher/App.config openra-20210321/OpenRA.Launcher/App.config --- openra-20200503/OpenRA.Launcher/App.config 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Launcher/App.config 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,6 @@ + + + + + + diff -Nru openra-20200503/OpenRA.Launcher/OpenRA.Launcher.csproj openra-20210321/OpenRA.Launcher/OpenRA.Launcher.csproj --- openra-20200503/OpenRA.Launcher/OpenRA.Launcher.csproj 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Launcher/OpenRA.Launcher.csproj 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,65 @@ + + + Exe + net472 + true + true + false + 7.3 + true + true + false + ../bin + false + AnyCPU + false + false + ..\OpenRA.ruleset + Release;Debug + OpenRA + + + win-x64 + linux-x64 + osx-x64 + + + + + + + DEBUG;TRACE + false + + + true + + + Project + Engine.EngineDir=".." Game.Mod=ra + + + Project + Engine.EngineDir=".." Game.Mod=d2k + + + Project + Engine.EngineDir=".." Game.Mod=cnc + + + Project + Engine.EngineDir=".." Game.Mod=ts + + + + + + + + + + + + + + diff -Nru openra-20200503/OpenRA.Launcher/Program.cs openra-20210321/OpenRA.Launcher/Program.cs --- openra-20200503/OpenRA.Launcher/Program.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Launcher/Program.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,39 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Diagnostics; +using System.Linq; + +namespace OpenRA.Launcher +{ + static class Program + { + [STAThread] + static int Main(string[] args) + { + if (Debugger.IsAttached || args.Contains("--just-die")) + return (int)Game.InitializeAndRun(args); + + AppDomain.CurrentDomain.UnhandledException += (_, e) => ExceptionHandler.HandleFatalError((Exception)e.ExceptionObject); + + try + { + return (int)Game.InitializeAndRun(args); + } + catch (Exception e) + { + ExceptionHandler.HandleFatalError(e); + return (int)RunStatus.Error; + } + } + } +} diff -Nru openra-20200503/OpenRA.Launcher/Properties/launchSettings.json openra-20210321/OpenRA.Launcher/Properties/launchSettings.json --- openra-20200503/OpenRA.Launcher/Properties/launchSettings.json 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Launcher/Properties/launchSettings.json 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,20 @@ +{ + "profiles": { + "Tiberian Dawn": { + "commandName": "Project", + "commandLineArgs": "Engine.EngineDir=\"..\" Game.Mod=cnc" + }, + "Red Alert": { + "commandName": "Project", + "commandLineArgs": "Engine.EngineDir=\"..\" Game.Mod=ra" + }, + "Dune 2000": { + "commandName": "Project", + "commandLineArgs": "Engine.EngineDir=\"..\" Game.Mod=d2k" + }, + "Tiberian Sun": { + "commandName": "Project", + "commandLineArgs": "Engine.EngineDir=\"..\" Game.Mod=ts" + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Cnc/Activities/Infiltrate.cs openra-20210321/OpenRA.Mods.Cnc/Activities/Infiltrate.cs --- openra-20200503/OpenRA.Mods.Cnc/Activities/Infiltrate.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Activities/Infiltrate.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,14 +24,14 @@ readonly INotifyInfiltration[] notifiers; Actor enterActor; - public Infiltrate(Actor self, Target target, Infiltrates infiltrates) - : base(self, target, Color.Crimson) + public Infiltrate(Actor self, in Target target, Infiltrates infiltrates, Color? targetLineColor) + : base(self, target, targetLineColor) { this.infiltrates = infiltrates; notifiers = self.TraitsImplementing().ToArray(); } - protected override void TickInner(Actor self, Target target, bool targetIsDeadOrHiddenActor) + protected override void TickInner(Actor self, in Target target, bool targetIsDeadOrHiddenActor) { if (infiltrates.IsTraitDisabled) Cancel(self, true); @@ -65,8 +65,7 @@ t.Infiltrated(targetActor, self, infiltrates.Info.Types); var exp = self.Owner.PlayerActor.TraitOrDefault(); - if (exp != null) - exp.GiveExperience(infiltrates.Info.PlayerExperience); + exp?.GiveExperience(infiltrates.Info.PlayerExperience); if (!string.IsNullOrEmpty(infiltrates.Info.Notification)) Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", diff -Nru openra-20200503/OpenRA.Mods.Cnc/Activities/LayMines.cs openra-20210321/OpenRA.Mods.Cnc/Activities/LayMines.cs --- openra-20200503/OpenRA.Mods.Cnc/Activities/LayMines.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Activities/LayMines.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,6 +26,7 @@ readonly Minelayer minelayer; readonly AmmoPool[] ammoPools; readonly IMove movement; + readonly IMoveInfo moveInfo; readonly RearmableInfo rearmableInfo; List minefield; @@ -37,6 +38,7 @@ minelayer = self.Trait(); ammoPools = self.TraitsImplementing().ToArray(); movement = self.Trait(); + moveInfo = self.Info.TraitInfo(); rearmableInfo = self.Info.TraitInfoOrDefault(); this.minefield = minefield; } @@ -69,7 +71,7 @@ if (rearmableInfo != null && ammoPools.Any(p => p.Info.Name == minelayer.Info.AmmoPoolName && !p.HasAmmo)) { // Rearm (and possibly repair) at rearm building, then back out here to refill the minefield some more - rearmTarget = self.World.Actors.Where(a => self.Owner.Stances[a.Owner] == Stance.Ally && rearmableInfo.RearmActors.Contains(a.Info.Name)) + rearmTarget = self.World.Actors.Where(a => self.Owner.RelationshipWith(a.Owner) == PlayerRelationship.Ally && rearmableInfo.RearmActors.Contains(a.Info.Name)) .ClosestTo(self); if (rearmTarget == null) @@ -118,17 +120,17 @@ public override IEnumerable TargetLineNodes(Actor self) { if (returnToBase) - yield return new TargetLineNode(Target.FromActor(rearmTarget), Color.Green); + yield return new TargetLineNode(Target.FromActor(rearmTarget), moveInfo.GetTargetLineColor()); if (minefield == null || minefield.Count == 0) yield break; var nextCell = NextValidCell(self); if (nextCell != null) - yield return new TargetLineNode(Target.FromCell(self.World, nextCell.Value), Color.Crimson); + yield return new TargetLineNode(Target.FromCell(self.World, nextCell.Value), minelayer.Info.TargetLineColor); foreach (var c in minefield) - yield return new TargetLineNode(Target.FromCell(self.World, c), Color.Crimson, tile: minelayer.Tile); + yield return new TargetLineNode(Target.FromCell(self.World, c), minelayer.Info.TargetLineColor, tile: minelayer.Tile); } static bool CanLayMine(Actor self, CPos p) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Activities/LeapAttack.cs openra-20210321/OpenRA.Mods.Cnc/Activities/LeapAttack.cs --- openra-20200503/OpenRA.Mods.Cnc/Activities/LeapAttack.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Activities/LeapAttack.cs 2021-03-21 11:10:05.000000000 +0000 @@ -38,7 +38,7 @@ BitSet lastVisibleTargetTypes; Player lastVisibleOwner; - public LeapAttack(Actor self, Target target, bool allowMovement, bool forceAttack, AttackLeap attack, AttackLeapInfo info, Color? targetLineColor = null) + public LeapAttack(Actor self, in Target target, bool allowMovement, bool forceAttack, AttackLeap attack, AttackLeapInfo info, Color? targetLineColor = null) { this.target = target; this.targetLineColor = targetLineColor; @@ -80,8 +80,7 @@ if (IsCanceling) return true; - bool targetIsHiddenActor; - target = target.Recalculate(self.Owner, out targetIsHiddenActor); + target = target.Recalculate(self.Owner, out var targetIsHiddenActor); if (!targetIsHiddenActor && target.Type == TargetType.Actor) { lastVisibleTarget = Target.FromTargetPositions(target); @@ -132,7 +131,7 @@ var destination = self.World.Map.CenterOfSubCell(target.Actor.Location, targetSubcell); var origin = self.World.Map.CenterOfSubCell(self.Location, mobile.FromSubCell); - var desiredFacing = (destination - origin).Yaw.Facing; + var desiredFacing = (destination - origin).Yaw; if (mobile.Facing != desiredFacing) { QueueChild(new Turn(self, desiredFacing)); diff -Nru openra-20200503/OpenRA.Mods.Cnc/Activities/Leap.cs openra-20210321/OpenRA.Mods.Cnc/Activities/Leap.cs --- openra-20200503/OpenRA.Mods.Cnc/Activities/Leap.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Activities/Leap.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System; using System.Collections.Generic; -using System.Linq; using OpenRA.Activities; using OpenRA.Mods.Cnc.Traits; using OpenRA.Mods.Common.Traits; @@ -37,7 +36,7 @@ int ticks = 0; WPos targetPosition; - public Leap(Actor self, Target target, Mobile mobile, Mobile targetMobile, int speed, AttackLeap attack, EdibleByLeap edible) + public Leap(Actor self, in Target target, Mobile mobile, Mobile targetMobile, int speed, AttackLeap attack, EdibleByLeap edible) { this.mobile = mobile; this.targetMobile = targetMobile; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Activities/Teleport.cs openra-20210321/OpenRA.Mods.Cnc/Activities/Teleport.cs --- openra-20200503/OpenRA.Mods.Cnc/Activities/Teleport.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Activities/Teleport.cs 2021-03-21 11:10:05.000000000 +0000 @@ -97,8 +97,8 @@ } // Consume teleport charges if this wasn't triggered via chronosphere - if (teleporter == self && pc != null) - pc.ResetChargeTime(); + if (teleporter == self) + pc?.ResetChargeTime(); // Trigger screen desaturate effect if (screenFlash) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Activities/VoxelHarvesterDockSequence.cs openra-20210321/OpenRA.Mods.Cnc/Activities/VoxelHarvesterDockSequence.cs --- openra-20200503/OpenRA.Mods.Cnc/Activities/VoxelHarvesterDockSequence.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Activities/VoxelHarvesterDockSequence.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,9 +9,9 @@ */ #endregion -using OpenRA.Activities; using OpenRA.Mods.Cnc.Traits.Render; using OpenRA.Mods.Common.Activities; +using OpenRA.Mods.Common.Traits; namespace OpenRA.Mods.Cnc.Activities { @@ -20,7 +20,7 @@ readonly WithVoxelUnloadBody body; readonly WithDockingOverlay spriteOverlay; - public VoxelHarvesterDockSequence(Actor self, Actor refinery, int dockAngle, bool isDragRequired, WVec dragOffset, int dragLength) + public VoxelHarvesterDockSequence(Actor self, Actor refinery, WAngle dockAngle, bool isDragRequired, WVec dragOffset, int dragLength) : base(self, refinery, dockAngle, isDragRequired, dragOffset, dragLength) { body = self.Trait(); @@ -30,6 +30,10 @@ public override void OnStateDock(Actor self) { body.Docked = true; + foreach (var trait in self.TraitsImplementing()) + trait.Docked(); + foreach (var nd in Refinery.TraitsImplementing()) + nd.Docked(Refinery, self); if (spriteOverlay != null && !spriteOverlay.Visible) { @@ -46,22 +50,38 @@ public override void OnStateUndock(Actor self) { - dockingState = DockingState.Wait; - - if (spriteOverlay != null && !spriteOverlay.Visible) + // If body.Docked wasn't set, we didn't actually dock and have to skip the undock overlay + if (!body.Docked) + dockingState = DockingState.Complete; + else if (Refinery.IsInWorld && !Refinery.IsDead && spriteOverlay != null && !spriteOverlay.Visible) { + dockingState = DockingState.Wait; spriteOverlay.Visible = true; spriteOverlay.WithOffset.Animation.PlayBackwardsThen(spriteOverlay.Info.Sequence, () => { dockingState = DockingState.Complete; body.Docked = false; spriteOverlay.Visible = false; + + foreach (var trait in self.TraitsImplementing()) + trait.Undocked(); + + if (Refinery.IsInWorld && !Refinery.IsDead) + foreach (var nd in Refinery.TraitsImplementing()) + nd.Undocked(Refinery, self); }); } else { dockingState = DockingState.Complete; body.Docked = false; + + foreach (var trait in self.TraitsImplementing()) + trait.Undocked(); + + if (Refinery.IsInWorld && !Refinery.IsDead) + foreach (var nd in Refinery.TraitsImplementing()) + nd.Undocked(Refinery, self); } } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/AudioLoaders/VocLoader.cs openra-20210321/OpenRA.Mods.Cnc/AudioLoaders/VocLoader.cs --- openra-20200503/OpenRA.Mods.Cnc/AudioLoaders/VocLoader.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/AudioLoaders/VocLoader.cs 2021-03-21 11:10:05.000000000 +0000 @@ -98,8 +98,7 @@ this.stream = stream; CheckVocHeader(stream); - int sampleRate; - Preload(stream, out blocks, out totalSamples, out sampleRate); + Preload(stream, out blocks, out totalSamples, out var sampleRate); SampleRate = sampleRate; Rewind(); } diff -Nru openra-20200503/OpenRA.Mods.Cnc/FileFormats/HvaReader.cs openra-20210321/OpenRA.Mods.Cnc/FileFormats/HvaReader.cs --- openra-20200503/OpenRA.Mods.Cnc/FileFormats/HvaReader.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/FileFormats/HvaReader.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System; using System.IO; -using OpenRA.Graphics; namespace OpenRA.Mods.Cnc.FileFormats { @@ -49,7 +48,7 @@ Transforms[c + ids[k]] = s.ReadFloat(); Array.Copy(Transforms, 16 * (LimbCount * j + i), testMatrix, 0, 16); - if (Util.MatrixInverse(testMatrix) == null) + if (OpenRA.Graphics.Util.MatrixInverse(testMatrix) == null) throw new InvalidDataException( "The transformation matrix for HVA file `{0}` section {1} frame {2} is invalid because it is not invertible!" .F(fileName, i, j)); diff -Nru openra-20200503/OpenRA.Mods.Cnc/FileFormats/XccGlobalDatabase.cs openra-20210321/OpenRA.Mods.Cnc/FileFormats/XccGlobalDatabase.cs --- openra-20200503/OpenRA.Mods.Cnc/FileFormats/XccGlobalDatabase.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/FileFormats/XccGlobalDatabase.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Cnc.FileFormats { - public class XccGlobalDatabase : IDisposable + public sealed class XccGlobalDatabase : IDisposable { public readonly string[] Entries; readonly Stream s; @@ -25,22 +25,27 @@ s = stream; var entries = new List(); + var chars = new char[32]; while (s.Peek() > -1) { var count = s.ReadInt32(); - var chars = new List(); + entries.Capacity += count; for (var i = 0; i < count; i++) { - byte c; - // Read filename + byte c; + var charsIndex = 0; while ((c = s.ReadUInt8()) != 0) - chars.Add((char)c); - entries.Add(new string(chars.ToArray())); - chars.Clear(); + { + if (charsIndex >= chars.Length) + Array.Resize(ref chars, chars.Length * 2); + chars[charsIndex++] = (char)c; + } + + entries.Add(new string(chars, 0, charsIndex)); // Skip comment - while ((c = s.ReadUInt8()) != 0) { } + while (s.ReadUInt8() != 0) { } } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/FileSystem/MixFile.cs openra-20210321/OpenRA.Mods.Cnc/FileSystem/MixFile.cs --- openra-20200503/OpenRA.Mods.Cnc/FileSystem/MixFile.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/FileSystem/MixFile.cs 2021-03-21 11:10:05.000000000 +0000 @@ -48,10 +48,7 @@ List entries; if (isEncrypted) - { - long unused; - entries = ParseHeader(DecryptHeader(s, 4, out dataStart), 0, out unused); - } + entries = ParseHeader(DecryptHeader(s, 4, out dataStart), 0, out _); else entries = ParseHeader(s, isCncMix ? 0 : 4, out dataStart); @@ -93,9 +90,8 @@ { var classicHash = PackageEntry.HashFilename(filename, PackageHashType.Classic); var crcHash = PackageEntry.HashFilename(filename, PackageHashType.CRC32); - PackageEntry e; - if (entries.TryGetValue(classicHash, out e)) + if (entries.TryGetValue(classicHash, out var e)) classicIndex.Add(filename, e); if (entries.TryGetValue(crcHash, out e)) @@ -187,8 +183,7 @@ public Stream GetStream(string filename) { - PackageEntry e; - if (!index.TryGetValue(filename, out e)) + if (!index.TryGetValue(filename, out var e)) return null; return GetContent(e); @@ -210,12 +205,11 @@ public IReadOnlyPackage OpenPackage(string filename, FS context) { - IReadOnlyPackage package; var childStream = GetStream(filename); if (childStream == null) return null; - if (context.TryParsePackage(childStream, filename, out package)) + if (context.TryParsePackage(childStream, filename, out var package)) return package; childStream.Dispose(); @@ -237,9 +231,8 @@ } // Load the global mix database - Stream mixDatabase; var allPossibleFilenames = new HashSet(); - if (context.TryOpen("global mix database.dat", out mixDatabase)) + if (context.TryOpen("global mix database.dat", out var mixDatabase)) using (var db = new XccGlobalDatabase(mixDatabase)) foreach (var e in db.Entries) allPossibleFilenames.Add(e); diff -Nru openra-20200503/OpenRA.Mods.Cnc/FileSystem/PackageEntry.cs openra-20210321/OpenRA.Mods.Cnc/FileSystem/PackageEntry.cs --- openra-20200503/OpenRA.Mods.Cnc/FileSystem/PackageEntry.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/FileSystem/PackageEntry.cs 2021-03-21 11:10:05.000000000 +0000 @@ -49,8 +49,7 @@ public override string ToString() { - string filename; - if (names.TryGetValue(Hash, out filename)) + if (names.TryGetValue(Hash, out var filename)) return "{0} - offset 0x{1:x8} - length 0x{2:x8}".F(filename, Offset, Length); else return "0x{0:x8} - offset 0x{1:x8} - length 0x{2:x8}".F(Hash, Offset, Length); @@ -66,16 +65,16 @@ if (name.Length % 4 != 0) name = name.PadRight(name.Length + (4 - name.Length % 4), '\0'); - using (var ms = new MemoryStream(Encoding.ASCII.GetBytes(name))) + var result = 0u; + var data = Encoding.ASCII.GetBytes(name); + var i = 0; + while (i < data.Length) { - var len = name.Length >> 2; - uint result = 0; - - while (len-- != 0) - result = ((result << 1) | (result >> 31)) + ms.ReadUInt32(); - - return result; + var next = (uint)(data[i++] | data[i++] << 8 | data[i++] << 16 | data[i++] << 24); + result = ((result << 1) | (result >> 31)) + next; } + + return result; } case PackageHashType.CRC32: diff -Nru openra-20200503/OpenRA.Mods.Cnc/FileSystem/Pak.cs openra-20210321/OpenRA.Mods.Cnc/FileSystem/Pak.cs --- openra-20200503/OpenRA.Mods.Cnc/FileSystem/Pak.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/FileSystem/Pak.cs 2021-03-21 11:10:05.000000000 +0000 @@ -66,8 +66,7 @@ public Stream GetStream(string filename) { - Entry entry; - if (!index.TryGetValue(filename, out entry)) + if (!index.TryGetValue(filename, out var entry)) return null; return SegmentStream.CreateWithoutOwningStream(stream, entry.Offset, (int)entry.Length); diff -Nru openra-20200503/OpenRA.Mods.Cnc/Graphics/ClassicSpriteSequence.cs openra-20210321/OpenRA.Mods.Cnc/Graphics/ClassicSpriteSequence.cs --- openra-20200503/OpenRA.Mods.Cnc/Graphics/ClassicSpriteSequence.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Graphics/ClassicSpriteSequence.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,50 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; + +namespace OpenRA.Mods.Cnc.Graphics +{ + public class ClassicSpriteSequenceLoader : DefaultSpriteSequenceLoader + { + public ClassicSpriteSequenceLoader(ModData modData) + : base(modData) { } + + public override ISpriteSequence CreateSequence(ModData modData, string tileSet, SpriteCache cache, string sequence, string animation, MiniYaml info) + { + return new ClassicSpriteSequence(modData, tileSet, cache, this, sequence, animation, info); + } + } + + public class ClassicSpriteSequence : DefaultSpriteSequence + { + readonly bool useClassicFacings; + + public ClassicSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info) + : base(modData, tileSet, cache, loader, sequence, animation, info) + { + var d = info.ToDictionary(); + useClassicFacings = LoadField(d, "UseClassicFacings", false); + + if (useClassicFacings && Facings != 32) + throw new InvalidOperationException( + "{0}: Sequence {1}.{2}: UseClassicFacings is only valid for 32 facings" + .F(info.Nodes[0].Location, sequence, animation)); + } + + protected override int GetFacingFrameOffset(WAngle facing) + { + return useClassicFacings ? Util.ClassicIndexFacing(facing, Facings) : Common.Util.IndexFacing(facing, Facings); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Cnc/Graphics/ClassicTilesetSpecificSpriteSequence.cs openra-20210321/OpenRA.Mods.Cnc/Graphics/ClassicTilesetSpecificSpriteSequence.cs --- openra-20200503/OpenRA.Mods.Cnc/Graphics/ClassicTilesetSpecificSpriteSequence.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Graphics/ClassicTilesetSpecificSpriteSequence.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,86 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; + +namespace OpenRA.Mods.Cnc.Graphics +{ + public class ClassicTilesetSpecificSpriteSequenceLoader : ClassicSpriteSequenceLoader + { + public readonly string DefaultSpriteExtension = ".shp"; + public readonly Dictionary TilesetExtensions = new Dictionary(); + public readonly Dictionary TilesetCodes = new Dictionary(); + + public ClassicTilesetSpecificSpriteSequenceLoader(ModData modData) + : base(modData) + { + var metadata = modData.Manifest.Get().Metadata; + if (metadata.TryGetValue("DefaultSpriteExtension", out var yaml)) + DefaultSpriteExtension = yaml.Value; + + if (metadata.TryGetValue("TilesetExtensions", out yaml)) + TilesetExtensions = yaml.ToDictionary(kv => kv.Value); + + if (metadata.TryGetValue("TilesetCodes", out yaml)) + TilesetCodes = yaml.ToDictionary(kv => kv.Value); + } + + public override ISpriteSequence CreateSequence(ModData modData, string tileSet, SpriteCache cache, string sequence, string animation, MiniYaml info) + { + return new ClassicTilesetSpecificSpriteSequence(modData, tileSet, cache, this, sequence, animation, info); + } + } + + public class ClassicTilesetSpecificSpriteSequence : ClassicSpriteSequence + { + public ClassicTilesetSpecificSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info) + : base(modData, tileSet, cache, loader, sequence, animation, info) { } + + string ResolveTilesetId(string tileSet, Dictionary d) + { + if (d.TryGetValue("TilesetOverrides", out var yaml)) + { + var tsNode = yaml.Nodes.FirstOrDefault(n => n.Key == tileSet); + if (tsNode != null) + tileSet = tsNode.Value.Value; + } + + return tileSet; + } + + protected override string GetSpriteSrc(ModData modData, string tileSet, string sequence, string animation, string sprite, Dictionary d) + { + var loader = (ClassicTilesetSpecificSpriteSequenceLoader)Loader; + + var spriteName = sprite ?? sequence; + + if (LoadField(d, "UseTilesetCode", false)) + { + if (loader.TilesetCodes.TryGetValue(ResolveTilesetId(tileSet, d), out var code)) + spriteName = spriteName.Substring(0, 1) + code + spriteName.Substring(2, spriteName.Length - 2); + } + + if (LoadField(d, "AddExtension", true)) + { + var useTilesetExtension = LoadField(d, "UseTilesetExtension", false); + + if (useTilesetExtension && loader.TilesetExtensions.TryGetValue(ResolveTilesetId(tileSet, d), out var tilesetExtension)) + return spriteName + tilesetExtension; + + return spriteName + loader.DefaultSpriteExtension; + } + + return spriteName; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Cnc/Graphics/TeslaZapRenderable.cs openra-20210321/OpenRA.Mods.Cnc/Graphics/TeslaZapRenderable.cs --- openra-20200503/OpenRA.Mods.Cnc/Graphics/TeslaZapRenderable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Graphics/TeslaZapRenderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -148,7 +148,7 @@ .MinBy(t => Math.Abs(float2.Dot(z + new float2(t[0], t[1]), q) + c)); var pos = wr.ProjectedPosition((z + new float2(step[2], step[3])).ToInt2()); - rs.Add(new SpriteRenderable(s.GetSprite(step[4]), pos, WVec.Zero, 0, pal, 1f, true).PrepareRender(wr)); + rs.Add(new SpriteRenderable(s.GetSprite(step[4]), pos, WVec.Zero, 0, pal, 1f, true, s.IgnoreWorldTint).PrepareRender(wr)); z += new float2(step[0], step[1]); if (rs.Count >= 1000) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Graphics/Voxel.cs openra-20210321/OpenRA.Mods.Cnc/Graphics/Voxel.cs --- openra-20200503/OpenRA.Mods.Cnc/Graphics/Voxel.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Graphics/Voxel.cs 2021-03-21 11:10:05.000000000 +0000 @@ -74,8 +74,8 @@ t[14] *= l.Scale * (l.Bounds[5] - l.Bounds[2]) / l.Size[2]; // Center, flip and scale - t = Util.MatrixMultiply(t, Util.TranslationMatrix(l.Bounds[0], l.Bounds[1], l.Bounds[2])); - t = Util.MatrixMultiply(Util.ScaleMatrix(l.Scale, -l.Scale, l.Scale), t); + t = OpenRA.Graphics.Util.MatrixMultiply(t, OpenRA.Graphics.Util.TranslationMatrix(l.Bounds[0], l.Bounds[1], l.Bounds[2])); + t = OpenRA.Graphics.Util.MatrixMultiply(OpenRA.Graphics.Util.ScaleMatrix(l.Scale, -l.Scale, l.Scale), t); return t; } @@ -119,7 +119,7 @@ }; // Calculate limb bounding box - var bb = Util.MatrixAABBMultiply(TransformationMatrix(j, frame), b); + var bb = OpenRA.Graphics.Util.MatrixAABBMultiply(TransformationMatrix(j, frame), b); for (var i = 0; i < 3; i++) { ret[i] = Math.Min(ret[i], bb[i]); diff -Nru openra-20200503/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs openra-20210321/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs --- openra-20200503/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,7 +24,7 @@ static readonly float[] ChannelSelect = { 0.75f, 0.25f, -0.25f, -0.75f }; readonly List vertices = new List(); - readonly Cache, Voxel> voxels; + readonly Cache<(string, string), Voxel> voxels; readonly IReadOnlyFileSystem fileSystem; IVertexBuffer vertexBuffer; int totalVertexCount; @@ -49,7 +49,7 @@ public VoxelLoader(IReadOnlyFileSystem fileSystem) { this.fileSystem = fileSystem; - voxels = new Cache, Voxel>(LoadFile); + voxels = new Cache<(string, string), Voxel>(LoadFile); vertices = new List(); totalVertexCount = 0; cachedVertexCount = 0; @@ -77,8 +77,8 @@ var size = new Size(su, sv); var s = sheetBuilder.Allocate(size); var t = sheetBuilder.Allocate(size); - Util.FastCopyIntoChannel(s, colors); - Util.FastCopyIntoChannel(t, normals); + OpenRA.Graphics.Util.FastCopyIntoChannel(s, colors); + OpenRA.Graphics.Util.FastCopyIntoChannel(t, normals); // s and t are guaranteed to use the same sheet because // of the custom voxel sheet allocation implementation @@ -194,8 +194,7 @@ public void RefreshBuffer() { - if (vertexBuffer != null) - vertexBuffer.Dispose(); + vertexBuffer?.Dispose(); vertexBuffer = Game.Renderer.CreateVertexBuffer(totalVertexCount); vertexBuffer.SetData(vertices.SelectMany(v => v).ToArray(), totalVertexCount); cachedVertexCount = totalVertexCount; @@ -211,20 +210,20 @@ } } - Voxel LoadFile(Pair files) + Voxel LoadFile((string Vxl, string Hva) files) { VxlReader vxl; HvaReader hva; - using (var s = fileSystem.Open(files.First + ".vxl")) + using (var s = fileSystem.Open(files.Vxl + ".vxl")) vxl = new VxlReader(s); - using (var s = fileSystem.Open(files.Second + ".hva")) - hva = new HvaReader(s, files.Second + ".hva"); + using (var s = fileSystem.Open(files.Hva + ".hva")) + hva = new HvaReader(s, files.Hva + ".hva"); return new Voxel(this, vxl, hva); } public Voxel Load(string vxl, string hva) { - return voxels[Pair.New(vxl, hva)]; + return voxels[(vxl, hva)]; } public void Finish() @@ -234,8 +233,7 @@ public void Dispose() { - if (vertexBuffer != null) - vertexBuffer.Dispose(); + vertexBuffer?.Dispose(); sheetBuilder.Dispose(); } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj openra-20210321/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj --- openra-20200503/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj 2021-03-21 11:10:05.000000000 +0000 @@ -1,12 +1,12 @@  - net461 + net472 true true - 5 + 7.3 true true - ../mods/common + ../bin false AnyCPU false @@ -21,10 +21,6 @@ false - - ..\thirdparty\download\Eluant.dll - False - False @@ -32,6 +28,7 @@ False + diff -Nru openra-20200503/OpenRA.Mods.Cnc/Projectiles/DropPodImpact.cs openra-20210321/OpenRA.Mods.Cnc/Projectiles/DropPodImpact.cs --- openra-20200503/OpenRA.Mods.Cnc/Projectiles/DropPodImpact.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Projectiles/DropPodImpact.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,78 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.GameRules; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Cnc.Effects +{ + public class DropPodImpact : IProjectile + { + readonly Target target; + readonly Animation entryAnimation; + readonly Player firedBy; + readonly string entryPalette; + readonly WeaponInfo weapon; + readonly WPos launchPos; + + int weaponDelay; + bool impacted = false; + + public DropPodImpact(Player firedBy, WeaponInfo weapon, World world, WPos launchPos, in Target target, + int delay, string entryEffect, string entrySequence, string entryPalette) + { + this.target = target; + this.firedBy = firedBy; + this.weapon = weapon; + this.entryPalette = entryPalette; + weaponDelay = delay; + this.launchPos = launchPos; + + entryAnimation = new Animation(world, entryEffect); + entryAnimation.PlayThen(entrySequence, () => Finish(world)); + + if (weapon.Report != null && weapon.Report.Any()) + Game.Sound.Play(SoundType.World, weapon.Report, world, launchPos); + } + + public void Tick(World world) + { + entryAnimation.Tick(); + + if (!impacted && weaponDelay-- <= 0) + { + var warheadArgs = new WarheadArgs + { + Weapon = weapon, + Source = target.CenterPosition, + SourceActor = firedBy.PlayerActor, + WeaponTarget = target + }; + + weapon.Impact(target, warheadArgs); + impacted = true; + } + } + + public IEnumerable Render(WorldRenderer wr) + { + return entryAnimation.Render(launchPos, wr.Palette(entryPalette)); + } + + void Finish(World world) + { + world.AddFrameEndTask(w => w.Remove(this)); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Cnc/Projectiles/IonCannon.cs openra-20210321/OpenRA.Mods.Cnc/Projectiles/IonCannon.cs --- openra-20200503/OpenRA.Mods.Cnc/Projectiles/IonCannon.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Projectiles/IonCannon.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,7 +28,7 @@ int weaponDelay; bool impacted = false; - public IonCannon(Player firedBy, WeaponInfo weapon, World world, WPos launchPos, Target target, string effect, string sequence, string palette, int delay) + public IonCannon(Player firedBy, WeaponInfo weapon, World world, WPos launchPos, in Target target, string effect, string sequence, string palette, int delay) { this.target = target; this.firedBy = firedBy; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Projectiles/TeslaZap.cs openra-20210321/OpenRA.Mods.Cnc/Projectiles/TeslaZap.cs --- openra-20200503/OpenRA.Mods.Cnc/Projectiles/TeslaZap.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Projectiles/TeslaZap.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,10 +21,10 @@ { public readonly string Image = "litning"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] public readonly string BrightSequence = "bright"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] public readonly string DimSequence = "dim"; [PaletteReference] diff -Nru openra-20200503/OpenRA.Mods.Cnc/Scripting/Properties/InfiltrateProperties.cs openra-20210321/OpenRA.Mods.Cnc/Scripting/Properties/InfiltrateProperties.cs --- openra-20200503/OpenRA.Mods.Cnc/Scripting/Properties/InfiltrateProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Scripting/Properties/InfiltrateProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -37,7 +37,8 @@ if (infiltrates == null) throw new LuaException("{0} tried to infiltrate invalid target {1}!".F(Self, target)); - Self.QueueActivity(new Infiltrate(Self, Target.FromActor(target), infiltrates)); + // NB: Scripted actions get no visible targetlines. + Self.QueueActivity(new Infiltrate(Self, Target.FromActor(target), infiltrates, null)); } } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/SpriteLoaders/ShpTDLoader.cs openra-20210321/OpenRA.Mods.Cnc/SpriteLoaders/ShpTDLoader.cs --- openra-20200503/OpenRA.Mods.Cnc/SpriteLoaders/ShpTDLoader.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/SpriteLoaders/ShpTDLoader.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,6 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Cnc.FileFormats; -using OpenRA.Mods.Common.FileFormats; using OpenRA.Primitives; namespace OpenRA.Mods.Cnc.SpriteLoaders diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Attack/AttackLeap.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Attack/AttackLeap.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Attack/AttackLeap.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Attack/AttackLeap.cs 2021-03-21 11:10:05.000000000 +0000 @@ -34,8 +34,7 @@ { readonly AttackLeapInfo info; - ConditionManager conditionManager; - int leapToken = ConditionManager.InvalidConditionToken; + int leapToken = Actor.InvalidConditionToken; public AttackLeap(Actor self, AttackLeapInfo info) : base(self, info) @@ -43,13 +42,7 @@ this.info = info; } - protected override void Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - base.Created(self); - } - - protected override bool CanAttack(Actor self, Target target) + protected override bool CanAttack(Actor self, in Target target) { if (target.Type != TargetType.Actor) return false; @@ -62,17 +55,16 @@ public void GrantLeapCondition(Actor self) { - if (conditionManager != null && !string.IsNullOrEmpty(info.LeapCondition)) - leapToken = conditionManager.GrantCondition(self, info.LeapCondition); + leapToken = self.GrantCondition(info.LeapCondition); } public void RevokeLeapCondition(Actor self) { - if (leapToken != ConditionManager.InvalidConditionToken) - leapToken = conditionManager.RevokeCondition(self, leapToken); + if (leapToken != Actor.InvalidConditionToken) + leapToken = self.RevokeCondition(leapToken); } - public override Activity GetAttackActivity(Actor self, AttackSource source, Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor) + public override Activity GetAttackActivity(Actor self, AttackSource source, in Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor) { return new LeapAttack(self, newTarget, allowMove, forceAttack, this, info, targetLineColor); } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Attack/AttackPopupTurreted.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Attack/AttackPopupTurreted.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Attack/AttackPopupTurreted.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Attack/AttackPopupTurreted.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,7 +23,7 @@ [Desc("How many game ticks should pass before closing the actor's turret.")] public readonly int CloseDelay = 125; - public readonly int DefaultFacing = 0; + public readonly WAngle DefaultFacing = WAngle.Zero; [Desc("The percentage of damage that is received while this actor is closed.")] public readonly int ClosedDamageMultiplier = 50; @@ -64,7 +64,7 @@ this.info = info; turret = turrets.FirstOrDefault(); wsb = init.Self.TraitsImplementing().Single(w => w.Info.Name == info.Body); - skippedMakeAnimation = init.Contains(); + skippedMakeAnimation = init.Contains(info); } protected override void Created(Actor self) @@ -76,19 +76,15 @@ { state = PopupState.Closed; wsb.PlayCustomAnimationRepeating(self, info.ClosedIdleSequence); - turret.DesiredFacing = null; + turret.FaceTarget(self, Target.Invalid); } } - protected override bool CanAttack(Actor self, Target target) + protected override bool CanAttack(Actor self, in Target target) { - if (state == PopupState.Transitioning) + if (IsTraitPaused) return false; - if (!base.CanAttack(self, target)) - return false; - - idleTicks = 0; if (state == PopupState.Closed) { state = PopupState.Transitioning; @@ -97,27 +93,36 @@ state = PopupState.Open; wsb.PlayCustomAnimationRepeating(self, wsb.Info.Sequence); }); - return false; + + idleTicks = 0; } + if (state == PopupState.Transitioning || !base.CanAttack(self, target)) + return false; + + idleTicks = 0; return true; } void INotifyIdle.TickIdle(Actor self) { + if (IsTraitDisabled || IsTraitPaused) + return; + if (state == PopupState.Open && idleTicks++ > info.CloseDelay) { - turret.DesiredFacing = info.DefaultFacing; + var facingOffset = new WVec(0, -1024, 0).Rotate(WRot.FromYaw(info.DefaultFacing)); + turret.FaceTarget(self, Target.FromPos(self.CenterPosition + facingOffset)); state = PopupState.Rotating; } - else if (state == PopupState.Rotating && turret.TurretFacing == info.DefaultFacing) + else if (state == PopupState.Rotating && turret.HasAchievedDesiredFacing) { state = PopupState.Transitioning; wsb.PlayCustomAnimation(self, info.ClosingSequence, () => { state = PopupState.Closed; wsb.PlayCustomAnimationRepeating(self, info.ClosedIdleSequence); - turret.DesiredFacing = null; + turret.FaceTarget(self, Target.Invalid); }); } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Attack/AttackTDGunboatTurreted.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Attack/AttackTDGunboatTurreted.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Attack/AttackTDGunboatTurreted.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Attack/AttackTDGunboatTurreted.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; using OpenRA.Activities; @@ -30,7 +29,7 @@ public AttackTDGunboatTurreted(Actor self, AttackTDGunboatTurretedInfo info) : base(self, info) { } - public override Activity GetAttackActivity(Actor self, AttackSource source, Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor) + public override Activity GetAttackActivity(Actor self, AttackSource source, in Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor) { return new AttackTDGunboatTurretedActivity(self, newTarget, allowMove, forceAttack, targetLineColor); } @@ -43,7 +42,7 @@ readonly Color? targetLineColor; bool hasTicked; - public AttackTDGunboatTurretedActivity(Actor self, Target target, bool allowMove, bool forceAttack, Color? targetLineColor = null) + public AttackTDGunboatTurretedActivity(Actor self, in Target target, bool allowMove, bool forceAttack, Color? targetLineColor = null) { attack = self.Trait(); this.target = target; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Attack/AttackTesla.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Attack/AttackTesla.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Attack/AttackTesla.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Attack/AttackTesla.cs 2021-03-21 11:10:05.000000000 +0000 @@ -62,7 +62,7 @@ charges = info.MaxCharges; } - protected override bool CanAttack(Actor self, Target target) + protected override bool CanAttack(Actor self, in Target target) { if (!IsReachableTarget(target, true)) return false; @@ -70,15 +70,15 @@ return base.CanAttack(self, target); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { --charges; timeToRecharge = info.ReloadDelay; } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { } + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { } - public override Activity GetAttackActivity(Actor self, AttackSource source, Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null) + public override Activity GetAttackActivity(Actor self, AttackSource source, in Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null) { return new ChargeAttack(this, newTarget, forceAttack, targetLineColor); } @@ -90,7 +90,7 @@ readonly bool forceAttack; readonly Color? targetLineColor; - public ChargeAttack(AttackTesla attack, Target target, bool forceAttack, Color? targetLineColor = null) + public ChargeAttack(AttackTesla attack, in Target target, bool forceAttack, Color? targetLineColor = null) { this.attack = attack; this.target = target; @@ -149,7 +149,7 @@ readonly AttackTesla attack; readonly Target target; - public ChargeFire(AttackTesla attack, Target target) + public ChargeFire(AttackTesla attack, in Target target) { this.attack = attack; this.target = target; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Buildings/ClonesProducedUnits.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Buildings/ClonesProducedUnits.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Buildings/ClonesProducedUnits.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Buildings/ClonesProducedUnits.cs 2021-03-21 11:10:05.000000000 +0000 @@ -68,7 +68,7 @@ factionInit ?? new FactionInit(BuildableInfo.GetInitialFaction(produced.Info, p.Faction)) }; - if (p.Produce(self, produced.Info, Info.ProductionType, inits)) + if (p.Produce(self, produced.Info, Info.ProductionType, inits, 0)) return; } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Chronoshiftable.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Chronoshiftable.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Chronoshiftable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Chronoshiftable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,6 +10,7 @@ #endregion using OpenRA.Mods.Cnc.Activities; +using OpenRA.Mods.Common; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; @@ -59,17 +60,17 @@ { self = init.Self; - if (init.Contains()) - ReturnTicks = init.Get(); - - if (init.Contains()) - duration = init.Get(); - - if (init.Contains()) - Origin = init.Get(); - - if (init.Contains()) - chronosphere = init.Get(); + var returnInit = init.GetOrDefault(); + if (returnInit != null) + { + ReturnTicks = returnInit.Ticks; + duration = returnInit.Duration; + Origin = returnInit.Origin; + + // Defer to the end of tick as the lazy value may reference an actor that hasn't been created yet + if (returnInit.Chronosphere != null) + init.World.AddFrameEndTask(w => chronosphere = returnInit.Chronosphere.Actor(init.World).Value); + } } void ITick.Tick(Actor self) @@ -93,7 +94,7 @@ typeof(Actor).GetProperty("CurrentActivity").SetValue(self, null); // The actor is killed using Info.DamageTypes if the teleport fails - self.QueueActivity(false, new Teleport(chronosphere, Origin, null, true, killCargo, Info.ChronoshiftSound, + self.QueueActivity(false, new Teleport(chronosphere ?? self, Origin, null, true, killCargo, Info.ChronoshiftSound, false, true, Info.DamageTypes)); } } @@ -168,50 +169,26 @@ if (IsTraitDisabled || !Info.ReturnToOrigin || ReturnTicks <= 0) return; - init.Add(new ChronoshiftOriginInit(Origin)); - init.Add(new ChronoshiftReturnInit(ReturnTicks)); - init.Add(new ChronoshiftDurationInit(duration)); - if (chronosphere != self) - init.Add(new ChronoshiftChronosphereInit(chronosphere)); + init.Add(new ChronoshiftReturnInit(ReturnTicks, duration, Origin, chronosphere)); } void IDeathActorInitModifier.ModifyDeathActorInit(Actor self, TypeDictionary init) { ModifyActorInit(init); } void ITransformActorInitModifier.ModifyTransformActorInit(Actor self, TypeDictionary init) { ModifyActorInit(init); } } - public class ChronoshiftReturnInit : IActorInit - { - [FieldFromYamlKey] - readonly int value = 0; - - public ChronoshiftReturnInit() { } - public ChronoshiftReturnInit(int init) { value = init; } - public int Value(World world) { return value; } - } - - public class ChronoshiftDurationInit : IActorInit + public class ChronoshiftReturnInit : CompositeActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - readonly int value = 0; - - public ChronoshiftDurationInit() { } - public ChronoshiftDurationInit(int init) { value = init; } - public int Value(World world) { return value; } - } - - public class ChronoshiftOriginInit : IActorInit - { - [FieldFromYamlKey] - readonly CPos value; - - public ChronoshiftOriginInit(CPos init) { value = init; } - public CPos Value(World world) { return value; } - } - - public class ChronoshiftChronosphereInit : IActorInit - { - readonly Actor value; - public ChronoshiftChronosphereInit(Actor init) { value = init; } - public Actor Value(World world) { return value; } + public readonly int Ticks; + public readonly int Duration; + public readonly CPos Origin; + public readonly ActorInitActorReference Chronosphere; + + public ChronoshiftReturnInit(int ticks, int duration, CPos origin, Actor chronosphere) + { + Ticks = ticks; + Duration = duration; + Origin = origin; + Chronosphere = chronosphere; + } } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/ClassicFacingBodyOrientation.cs openra-20210321/OpenRA.Mods.Cnc/Traits/ClassicFacingBodyOrientation.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/ClassicFacingBodyOrientation.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/ClassicFacingBodyOrientation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,32 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Mods.Common.Traits; + +namespace OpenRA.Mods.Cnc.Traits +{ + [Desc("Fudge the coordinate system angles like the early games (for sprite sequences that use classic facing fudge).")] + public class ClassicFacingBodyOrientationInfo : BodyOrientationInfo + { + public override WAngle QuantizeFacing(WAngle facing, int facings) + { + return Util.ClassicQuantizeFacing(facing, facings); + } + + public override object Create(ActorInitializer init) { return new ClassicFacingBodyOrientation(init, this); } + } + + public class ClassicFacingBodyOrientation : BodyOrientation + { + public ClassicFacingBodyOrientation(ActorInitializer init, ClassicFacingBodyOrientationInfo info) + : base(init, info) { } + } +} diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/ConyardChronoReturn.cs openra-20210321/OpenRA.Mods.Cnc/Traits/ConyardChronoReturn.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/ConyardChronoReturn.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/ConyardChronoReturn.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,7 +23,7 @@ [Desc("Implements the special case handling for the Chronoshiftable return on a construction yard.", "If ReturnOriginalActorOnCondition evaluates true and the actor is not being sold then OriginalActor will be returned to the origin.", "Otherwise, a vortex animation is played and damage is dealt each tick, ignoring modifiers.")] - public class ConyardChronoReturnInfo : IObservesVariablesInfo, Requires, Requires + public class ConyardChronoReturnInfo : TraitInfo, Requires, Requires, IObservesVariablesInfo { [SequenceReference] [Desc("Sequence name with the baked-in vortex animation")] @@ -51,17 +51,17 @@ public readonly string OriginalActor = "mcv"; [Desc("Facing of the returned actor.")] - public readonly int Facing = 96; + public readonly WAngle Facing = new WAngle(384); public readonly string ChronoshiftSound = "chrono2.aud"; [Desc("The color the bar of the 'return-to-origin' logic has.")] public readonly Color TimeBarColor = Color.White; - public object Create(ActorInitializer init) { return new ConyardChronoReturn(init, this); } + public override object Create(ActorInitializer init) { return new ConyardChronoReturn(init, this); } } - public class ConyardChronoReturn : INotifyCreated, ITick, ISync, IObservesVariables, ISelectionBar, INotifySold, + public class ConyardChronoReturn : ITick, ISync, IObservesVariables, ISelectionBar, INotifySold, IDeathActorInitModifier, ITransformActorInitModifier { readonly ConyardChronoReturnInfo info; @@ -70,8 +70,7 @@ readonly Actor self; readonly string faction; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; Actor chronosphere; int duration; @@ -95,24 +94,19 @@ health = self.Trait(); wsb = self.TraitsImplementing().Single(w => w.Info.Name == info.Body); - faction = init.Contains() ? init.Get() : self.Owner.Faction.InternalName; + faction = init.GetValue(self.Owner.Faction.InternalName); - if (init.Contains()) - returnTicks = init.Get(); - - if (init.Contains()) - duration = init.Get(); - - if (init.Contains()) - origin = init.Get(); - - if (init.Contains()) - chronosphere = init.Get(); - } - - void INotifyCreated.Created(Actor self) - { - conditionManager = self.TraitOrDefault(); + var returnInit = init.GetOrDefault(); + if (returnInit != null) + { + returnTicks = returnInit.Ticks; + duration = returnInit.Duration; + origin = returnInit.Origin; + + // Defer to the end of tick as the lazy value may reference an actor that hasn't been created yet + if (returnInit.Chronosphere != null) + init.World.AddFrameEndTask(w => chronosphere = returnInit.Chronosphere.Actor(init.World).Value); + } } IEnumerable IObservesVariables.GetVariableObservers() @@ -128,8 +122,8 @@ void TriggerVortex() { - if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, info.Condition); + if (conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(info.Condition); triggered = true; @@ -140,8 +134,8 @@ wsb.PlayCustomAnimation(self, info.Sequence, () => { triggered = false; - if (conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); }); } @@ -237,11 +231,7 @@ if (returnTicks <= 0) return; - init.Add(new ChronoshiftOriginInit(origin)); - init.Add(new ChronoshiftReturnInit(returnTicks)); - init.Add(new ChronoshiftDurationInit(duration)); - if (chronosphere != self) - init.Add(new ChronoshiftChronosphereInit(chronosphere)); + init.Add(new ChronoshiftReturnInit(returnTicks, duration, origin, chronosphere)); } void IDeathActorInitModifier.ModifyDeathActorInit(Actor self, TypeDictionary init) { ModifyActorInit(init); } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Disguise.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Disguise.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Disguise.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Disguise.cs 2021-03-21 11:10:05.000000000 +0000 @@ -70,7 +70,7 @@ } [Desc("Provides access to the disguise command, which makes the actor appear to be another player's actor.")] - class DisguiseInfo : ITraitInfo + class DisguiseInfo : TraitInfo { [VoiceReference] public readonly string Voice = "Action"; @@ -79,8 +79,8 @@ [Desc("The condition to grant to self while disguised.")] public readonly string DisguisedCondition = null; - [Desc("What diplomatic stances can this actor disguise as.")] - public readonly Stance ValidStances = Stance.Ally | Stance.Neutral | Stance.Enemy; + [Desc("Player relationships the owner of the disguise target needs.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy; [Desc("Target types of actors that this actor disguise as.")] public readonly BitSet TargetTypes = new BitSet("Disguise"); @@ -89,17 +89,21 @@ "Unload, Infiltrate, Demolish, Move.")] public readonly RevealDisguiseType RevealDisguiseOn = RevealDisguiseType.Attack; + [ActorReference(dictionaryReference: LintDictionaryReference.Keys)] [Desc("Conditions to grant when disguised as specified actor.", "A dictionary of [actor id]: [condition].")] public readonly Dictionary DisguisedAsConditions = new Dictionary(); + [Desc("Cursor to display when hovering over a valid actor to disguise as.")] + public readonly string Cursor = "ability"; + [GrantedConditionReference] public IEnumerable LinterConditions { get { return DisguisedAsConditions.Values; } } - public object Create(ActorInitializer init) { return new Disguise(init.Self, this); } + public override object Create(ActorInitializer init) { return new Disguise(init.Self, this); } } - class Disguise : INotifyCreated, IEffectiveOwner, IIssueOrder, IResolveOrder, IOrderVoice, IRadarColorModifier, INotifyAttack, + class Disguise : IEffectiveOwner, IIssueOrder, IResolveOrder, IOrderVoice, IRadarColorModifier, INotifyAttack, INotifyDamage, INotifyUnload, INotifyDemolition, INotifyInfiltration, ITick { public ActorInfo AsActor { get; private set; } @@ -112,9 +116,8 @@ readonly Actor self; readonly DisguiseInfo info; - ConditionManager conditionManager; - int disguisedToken = ConditionManager.InvalidConditionToken; - int disguisedAsToken = ConditionManager.InvalidConditionToken; + int disguisedToken = Actor.InvalidConditionToken; + int disguisedAsToken = Actor.InvalidConditionToken; CPos? lastPos; public Disguise(Actor self, DisguiseInfo info) @@ -125,11 +128,6 @@ AsActor = self.Info; } - void INotifyCreated.Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - } - IEnumerable IIssueOrder.Orders { get @@ -138,7 +136,7 @@ } } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "Disguise") return new Order(order.OrderID, self, target, queued); @@ -191,7 +189,10 @@ } else { - var tooltip = target.TraitsImplementing().FirstOrDefault(); + var tooltip = target.TraitsImplementing().FirstEnabledTraitOrDefault(); + if (tooltip == null) + throw new ArgumentNullException("tooltip", "Missing tooltip or invalid target."); + AsPlayer = tooltip.Owner; AsActor = target.Info; AsTooltipInfo = tooltip.TooltipInfo; @@ -215,7 +216,7 @@ AsPlayer = newOwner; AsActor = actorInfo; - AsTooltipInfo = actorInfo.TraitInfos().FirstOrDefault(); + AsTooltipInfo = actorInfo.TraitInfos().FirstOrDefault(info => info.EnabledByDefault); HandleDisguise(oldEffectiveActor, oldEffectiveOwner, oldDisguiseSetting); } @@ -225,31 +226,27 @@ foreach (var t in self.TraitsImplementing()) t.OnEffectiveOwnerChanged(self, oldEffectiveOwner, AsPlayer); - if (conditionManager != null) + if (Disguised != oldDisguiseSetting) { - if (Disguised != oldDisguiseSetting) - { - if (Disguised && disguisedToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(info.DisguisedCondition)) - disguisedToken = conditionManager.GrantCondition(self, info.DisguisedCondition); - else if (!Disguised && disguisedToken != ConditionManager.InvalidConditionToken) - disguisedToken = conditionManager.RevokeCondition(self, disguisedToken); - } + if (Disguised && disguisedToken == Actor.InvalidConditionToken) + disguisedToken = self.GrantCondition(info.DisguisedCondition); + else if (!Disguised && disguisedToken != Actor.InvalidConditionToken) + disguisedToken = self.RevokeCondition(disguisedToken); + } - if (AsActor != oldEffectiveActor) - { - if (disguisedAsToken != ConditionManager.InvalidConditionToken) - disguisedAsToken = conditionManager.RevokeCondition(self, disguisedAsToken); + if (AsActor != oldEffectiveActor) + { + if (disguisedAsToken != Actor.InvalidConditionToken) + disguisedAsToken = self.RevokeCondition(disguisedAsToken); - string disguisedAsCondition; - if (info.DisguisedAsConditions.TryGetValue(AsActor.Name, out disguisedAsCondition)) - disguisedAsToken = conditionManager.GrantCondition(self, disguisedAsCondition); - } + if (info.DisguisedAsConditions.TryGetValue(AsActor.Name, out var disguisedAsCondition)) + disguisedAsToken = self.GrantCondition(disguisedAsCondition); } } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { } + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (info.RevealDisguiseOn.HasFlag(RevealDisguiseType.Attack)) DisguiseAs(null); @@ -293,7 +290,7 @@ readonly DisguiseInfo info; public DisguiseOrderTargeter(DisguiseInfo info) - : base("Disguise", 7, "ability", true, true) + : base("Disguise", 7, info.Cursor, true, true) { this.info = info; ForceAttack = false; @@ -301,9 +298,8 @@ public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor) { - var stance = self.Owner.Stances[target.Owner]; - - if (!info.ValidStances.HasStance(stance)) + var stance = self.Owner.RelationshipWith(target.Owner); + if (!info.ValidRelationships.HasStance(stance)) return false; return info.TargetTypes.Overlaps(target.GetAllTargetTypes()); @@ -311,9 +307,8 @@ public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor) { - var stance = self.Owner.Stances[target.Owner]; - - if (!info.ValidStances.HasStance(stance)) + var stance = self.Owner.RelationshipWith(target.Owner); + if (!info.ValidRelationships.HasStance(stance)) return false; return info.TargetTypes.Overlaps(target.Info.GetAllTargetTypes()); diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/DrainPrerequisitePowerOnDamage.cs openra-20210321/OpenRA.Mods.Cnc/Traits/DrainPrerequisitePowerOnDamage.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/DrainPrerequisitePowerOnDamage.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/DrainPrerequisitePowerOnDamage.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,14 +52,8 @@ if (!IsTraitDisabled && damage != null) { var damageSubTicks = (int)(damage.Value * 100L * Info.DamageMultiplier / Info.DamageDivisor); - - SupportPowerInstance spi; - if (spm.Powers.TryGetValue(Info.OrderName, out spi)) - { - var dspi = spi as GrantPrerequisiteChargeDrainPower.DischargeableSupportPowerInstance; - if (dspi != null) - dspi.Discharge(damageSubTicks); - } + if (spm.Powers.TryGetValue(Info.OrderName, out var spi)) + (spi as GrantPrerequisiteChargeDrainPower.DischargeableSupportPowerInstance)?.Discharge(damageSubTicks); } return 100; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/EnergyWall.cs openra-20210321/OpenRA.Mods.Cnc/Traits/EnergyWall.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/EnergyWall.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/EnergyWall.cs 2021-03-21 11:10:05.000000000 +0000 @@ -36,10 +36,8 @@ public void RulesetLoaded(Ruleset rules, ActorInfo ai) { - WeaponInfo weaponInfo; - var weaponToLower = Weapon.ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(weaponToLower, out weaponInfo)) + if (!rules.Weapons.TryGetValue(weaponToLower, out var weaponInfo)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); WeaponInfo = weaponInfo; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/FrozenUnderFogUpdatedByGps.cs openra-20210321/OpenRA.Mods.Cnc/Traits/FrozenUnderFogUpdatedByGps.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/FrozenUnderFogUpdatedByGps.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/FrozenUnderFogUpdatedByGps.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,9 +19,9 @@ using FrozenActorAction = Action; [Desc("Updates frozen actors of actors that change owners, are sold or die whilst having an active GPS power.")] - public class FrozenUnderFogUpdatedByGpsInfo : ITraitInfo, Requires + public class FrozenUnderFogUpdatedByGpsInfo : TraitInfo, Requires { - public object Create(ActorInitializer init) { return new FrozenUnderFogUpdatedByGps(init); } + public override object Create(ActorInitializer init) { return new FrozenUnderFogUpdatedByGps(init); } } public class FrozenUnderFogUpdatedByGps : INotifyOwnerChanged, INotifyActorDisposing, IOnGpsRefreshed diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/GpsDot.cs openra-20210321/OpenRA.Mods.Cnc/Traits/GpsDot.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/GpsDot.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/GpsDot.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,19 +15,19 @@ namespace OpenRA.Mods.Cnc.Traits { [Desc("Show an indicator revealing the actor underneath the fog when a GPSWatcher is activated.")] - class GpsDotInfo : ITraitInfo + class GpsDotInfo : TraitInfo { [Desc("Sprite collection for symbols.")] public readonly string Image = "gpsdot"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] [Desc("Sprite used for this actor.")] public readonly string String = "Infantry"; [PaletteReference(true)] public readonly string IndicatorPalettePrefix = "player"; - public object Create(ActorInitializer init) { return new GpsDot(this); } + public override object Create(ActorInitializer init) { return new GpsDot(this); } } class GpsDot : INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/GpsWatcher.cs openra-20210321/OpenRA.Mods.Cnc/Traits/GpsWatcher.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/GpsWatcher.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/GpsWatcher.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,9 +17,9 @@ namespace OpenRA.Mods.Cnc.Traits { [Desc("Required for `GpsPower`. Attach this to the player actor.")] - class GpsWatcherInfo : ITraitInfo + class GpsWatcherInfo : TraitInfo { - public object Create(ActorInitializer init) { return new GpsWatcher(init.Self.Owner); } + public override object Create(ActorInitializer init) { return new GpsWatcher(init.Self.Owner); } } interface IOnGpsRefreshed { void OnGpsRefresh(Actor self, Player player); } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/HarvesterHuskModifier.cs openra-20210321/OpenRA.Mods.Cnc/Traits/HarvesterHuskModifier.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/HarvesterHuskModifier.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/HarvesterHuskModifier.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,13 +14,13 @@ namespace OpenRA.Mods.Cnc.Traits { - public class HarvesterHuskModifierInfo : ITraitInfo, Requires + public class HarvesterHuskModifierInfo : TraitInfo, Requires { [ActorReference] public readonly string FullHuskActor = null; public readonly int FullnessThreshold = 50; - public object Create(ActorInitializer init) { return new HarvesterHuskModifier(this); } + public override object Create(ActorInitializer init) { return new HarvesterHuskModifier(this); } } public class HarvesterHuskModifier : IHuskModifier diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForCash.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForCash.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForCash.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForCash.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,8 +18,9 @@ namespace OpenRA.Mods.Cnc.Traits { [Desc("Funds are transferred from the owner to the infiltrator.")] - class InfiltrateForCashInfo : ITraitInfo + class InfiltrateForCashInfo : TraitInfo { + [Desc("The `TargetTypes` from `Targetable` that are allowed to enter.")] public readonly BitSet Types = default(BitSet); [Desc("Percentage of the victim's resources that will be stolen.")] @@ -34,12 +35,16 @@ [NotificationReference("Speech")] [Desc("Sound the victim will hear when they get robbed.")] - public readonly string Notification = null; + public readonly string InfiltratedNotification = null; + + [NotificationReference("Speech")] + [Desc("Sound the perpetrator will hear after successful infiltration.")] + public readonly string InfiltrationNotification = null; [Desc("Whether to show the cash tick indicators rising from the actor.")] public readonly bool ShowTicks = true; - public object Create(ActorInitializer init) { return new InfiltrateForCash(this); } + public override object Create(ActorInitializer init) { return new InfiltrateForCash(this); } } class InfiltrateForCash : INotifyInfiltrated @@ -63,8 +68,11 @@ targetResources.TakeCash(toTake); spyResources.GiveCash(toGive); - if (info.Notification != null) - Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.Notification, self.Owner.Faction.InternalName); + if (info.InfiltratedNotification != null) + Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.InfiltratedNotification, self.Owner.Faction.InternalName); + + if (info.InfiltrationNotification != null) + Game.Sound.PlayNotification(self.World.Map.Rules, infiltrator.Owner, "Speech", info.InfiltrationNotification, infiltrator.Owner.Faction.InternalName); if (info.ShowTicks) self.World.AddFrameEndTask(w => w.Add(new FloatingText(self.CenterPosition, infiltrator.Owner.Color, FloatingText.FormatCashTick(toGive), 30))); diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForDecoration.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForDecoration.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForDecoration.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,6 +21,7 @@ [Desc("Reveals a decoration sprite to the indicated players when infiltrated.")] class InfiltrateForDecorationInfo : WithDecorationInfo { + [Desc("The `TargetTypes` from `Targetable` that are allowed to enter.")] public readonly BitSet Types = default(BitSet); public override object Create(ActorInitializer init) { return new InfiltrateForDecoration(init.Self, this); } @@ -47,8 +48,7 @@ protected override bool ShouldRender(Actor self) { - return self.World.RenderPlayer == null || infiltrators.Any(i => - Info.ValidStances.HasStance(i.Stances[self.World.RenderPlayer])); + return infiltrators.Any(i => Info.ValidRelationships.HasStance(i.RelationshipWith(self.World.RenderPlayer))); } } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForExploration.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForExploration.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForExploration.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForExploration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,11 +17,20 @@ namespace OpenRA.Mods.Cnc.Traits { [Desc("Steal and reset the owner's exploration.")] - class InfiltrateForExplorationInfo : ITraitInfo + class InfiltrateForExplorationInfo : TraitInfo { + [Desc("The `TargetTypes` from `Targetable` that are allowed to enter.")] public readonly BitSet Types = default(BitSet); - public object Create(ActorInitializer init) { return new InfiltrateForExploration(init.Self, this); } + [NotificationReference("Speech")] + [Desc("Sound the victim will hear when they get sabotaged.")] + public readonly string InfiltratedNotification = null; + + [NotificationReference("Speech")] + [Desc("Sound the perpetrator will hear after successful infiltration.")] + public readonly string InfiltrationNotification = null; + + public override object Create(ActorInitializer init) { return new InfiltrateForExploration(init.Self, this); } } class InfiltrateForExploration : INotifyInfiltrated @@ -38,6 +47,12 @@ if (!info.Types.Overlaps(types)) return; + if (info.InfiltratedNotification != null) + Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.InfiltratedNotification, self.Owner.Faction.InternalName); + + if (info.InfiltrationNotification != null) + Game.Sound.PlayNotification(self.World.Map.Rules, infiltrator.Owner, "Speech", info.InfiltrationNotification, infiltrator.Owner.Faction.InternalName); + infiltrator.Owner.Shroud.Explore(self.Owner.Shroud); var preventReset = self.Owner.PlayerActor.TraitsImplementing() .Any(p => p.PreventShroudReset(self)); diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForPowerOutage.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForPowerOutage.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForPowerOutage.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForPowerOutage.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,13 +15,23 @@ namespace OpenRA.Mods.Cnc.Traits { - class InfiltrateForPowerOutageInfo : ITraitInfo + class InfiltrateForPowerOutageInfo : TraitInfo { + [Desc("The `TargetTypes` from `Targetable` that are allowed to enter.")] public readonly BitSet Types = default(BitSet); + [Desc("Measured in ticks.")] public readonly int Duration = 25 * 20; - public object Create(ActorInitializer init) { return new InfiltrateForPowerOutage(init.Self, this); } + [NotificationReference("Speech")] + [Desc("Sound the victim will hear when they get sabotaged.")] + public readonly string InfiltratedNotification = null; + + [NotificationReference("Speech")] + [Desc("Sound the perpetrator will hear after successful infiltration.")] + public readonly string InfiltrationNotification = null; + + public override object Create(ActorInitializer init) { return new InfiltrateForPowerOutage(init.Self, this); } } class InfiltrateForPowerOutage : INotifyOwnerChanged, INotifyInfiltrated @@ -40,6 +50,12 @@ if (!info.Types.Overlaps(types)) return; + if (info.InfiltratedNotification != null) + Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.InfiltratedNotification, self.Owner.Faction.InternalName); + + if (info.InfiltrationNotification != null) + Game.Sound.PlayNotification(self.World.Map.Rules, infiltrator.Owner, "Speech", info.InfiltrationNotification, infiltrator.Owner.Faction.InternalName); + playerPower.TriggerPowerOutage(info.Duration); } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForSupportPower.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForSupportPower.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForSupportPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForSupportPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,15 +15,24 @@ namespace OpenRA.Mods.Cnc.Traits { - class InfiltrateForSupportPowerInfo : ITraitInfo + class InfiltrateForSupportPowerInfo : TraitInfo { [ActorReference] [FieldLoader.Require] public readonly string Proxy = null; + [Desc("The `TargetTypes` from `Targetable` that are allowed to enter.")] public readonly BitSet Types = default(BitSet); - public object Create(ActorInitializer init) { return new InfiltrateForSupportPower(this); } + [NotificationReference("Speech")] + [Desc("Sound the victim will hear when technology gets stolen.")] + public readonly string InfiltratedNotification = null; + + [NotificationReference("Speech")] + [Desc("Sound the perpetrator will hear after successful infiltration.")] + public readonly string InfiltrationNotification = null; + + public override object Create(ActorInitializer init) { return new InfiltrateForSupportPower(this); } } class InfiltrateForSupportPower : INotifyInfiltrated @@ -40,6 +49,12 @@ if (!info.Types.Overlaps(types)) return; + if (info.InfiltratedNotification != null) + Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.InfiltratedNotification, self.Owner.Faction.InternalName); + + if (info.InfiltrationNotification != null) + Game.Sound.PlayNotification(self.World.Map.Rules, infiltrator.Owner, "Speech", info.InfiltrationNotification, infiltrator.Owner.Faction.InternalName); + infiltrator.World.AddFrameEndTask(w => w.CreateActor(info.Proxy, new TypeDictionary { new OwnerInit(infiltrator.Owner) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForSupportPowerReset.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForSupportPowerReset.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForSupportPowerReset.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForSupportPowerReset.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,61 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.Common.Traits; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Cnc.Traits +{ + class InfiltrateForSupportPowerResetInfo : TraitInfo + { + [Desc("The `TargetTypes` from `Targetable` that are allowed to enter.")] + public readonly BitSet Types = default(BitSet); + + [NotificationReference("Speech")] + [Desc("Sound the victim will hear when technology gets stolen.")] + public readonly string InfiltratedNotification = null; + + [NotificationReference("Speech")] + [Desc("Sound the perpetrator will hear after successful infiltration.")] + public readonly string InfiltrationNotification = null; + + public override object Create(ActorInitializer init) { return new InfiltrateForSupportPowerReset(this); } + } + + class InfiltrateForSupportPowerReset : INotifyInfiltrated + { + readonly InfiltrateForSupportPowerResetInfo info; + + public InfiltrateForSupportPowerReset(InfiltrateForSupportPowerResetInfo info) + { + this.info = info; + } + + void INotifyInfiltrated.Infiltrated(Actor self, Actor infiltrator, BitSet types) + { + if (!info.Types.Overlaps(types)) + return; + + if (info.InfiltratedNotification != null) + Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.InfiltratedNotification, self.Owner.Faction.InternalName); + + if (info.InfiltrationNotification != null) + Game.Sound.PlayNotification(self.World.Map.Rules, infiltrator.Owner, "Speech", info.InfiltrationNotification, infiltrator.Owner.Faction.InternalName); + + var manager = self.Owner.PlayerActor.Trait(); + var powers = manager.GetPowersForActor(self).Where(sp => !sp.Disabled); + foreach (var power in powers) + power.ResetTimer(); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForTransform.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForTransform.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForTransform.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/InfiltrateForTransform.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using OpenRA.Mods.Common; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Traits; @@ -19,7 +18,7 @@ namespace OpenRA.Mods.Cnc.Traits { [Desc("Transform into a different actor type.")] - class InfiltrateForTransformInfo : ITraitInfo + class InfiltrateForTransformInfo : TraitInfo { [ActorReference] [FieldLoader.Require] @@ -29,9 +28,10 @@ public readonly bool SkipMakeAnims = true; + [Desc("The `TargetTypes` from `Targetable` that are allowed to enter.")] public readonly BitSet Types = default(BitSet); - public object Create(ActorInitializer init) { return new InfiltrateForTransform(init, this); } + public override object Create(ActorInitializer init) { return new InfiltrateForTransform(init, this); } } class InfiltrateForTransform : INotifyInfiltrated @@ -42,7 +42,7 @@ public InfiltrateForTransform(ActorInitializer init, InfiltrateForTransformInfo info) { this.info = info; - faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName; + faction = init.GetValue(init.Self.Owner.Faction.InternalName); } void INotifyInfiltrated.Infiltrated(Actor self, Actor infiltrator, BitSet types) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/Infiltrates.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/Infiltrates.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Infiltration/Infiltrates.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Infiltration/Infiltrates.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Collections.Generic; using OpenRA.Mods.Cnc.Activities; -using OpenRA.Mods.Common; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Traits; @@ -22,13 +21,17 @@ { public class InfiltratesInfo : ConditionalTraitInfo { + [Desc("The `TargetTypes` from `Targetable` that are allowed to enter.")] public readonly BitSet Types = default(BitSet); [VoiceReference] public readonly string Voice = "Action"; - [Desc("What diplomatic stances can be infiltrated by this actor.")] - public readonly Stance ValidStances = Stance.Neutral | Stance.Enemy; + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Crimson; + + [Desc("Player relationships the owner of the infiltration target needs.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy; [Desc("Behaviour when entering the target.", "Possible values are Exit, Suicide, Dispose.")] @@ -41,6 +44,7 @@ [Desc("Experience to grant to the infiltrating player.")] public readonly int PlayerExperience = 0; + [Desc("Cursor to display when able to infiltrate the target actor.")] public readonly string EnterCursor = "enter"; public override object Create(ActorInitializer init) { return new Infiltrates(this); } @@ -62,7 +66,7 @@ } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID != "Infiltrate") return null; @@ -91,16 +95,16 @@ ? Info.Voice : null; } - public bool CanInfiltrateTarget(Actor self, Target target) + public bool CanInfiltrateTarget(Actor self, in Target target) { switch (target.Type) { case TargetType.Actor: return Info.Types.Overlaps(target.Actor.GetEnabledTargetTypes()) && - Info.ValidStances.HasStance(self.Owner.Stances[target.Actor.Owner]); + Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(target.Actor.Owner)); case TargetType.FrozenActor: return target.FrozenActor.IsValid && Info.Types.Overlaps(target.FrozenActor.TargetTypes) && - Info.ValidStances.HasStance(self.Owner.Stances[target.FrozenActor.Owner]); + Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(target.FrozenActor.Owner)); default: return false; } @@ -114,7 +118,7 @@ if (!CanInfiltrateTarget(self, order.Target)) return; - self.QueueActivity(order.Queued, new Infiltrate(self, order.Target, this)); + self.QueueActivity(order.Queued, new Infiltrate(self, order.Target, this, Info.TargetLineColor)); self.ShowTargetLines(); } } @@ -131,9 +135,8 @@ public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor) { - var stance = self.Owner.Stances[target.Owner]; - - if (!info.ValidStances.HasStance(stance)) + var stance = self.Owner.RelationshipWith(target.Owner); + if (!info.ValidRelationships.HasStance(stance)) return false; return info.Types.Overlaps(target.GetAllTargetTypes()); @@ -141,9 +144,8 @@ public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor) { - var stance = self.Owner.Stances[target.Owner]; - - if (!info.ValidStances.HasStance(stance)) + var stance = self.Owner.RelationshipWith(target.Owner); + if (!info.ValidRelationships.HasStance(stance)) return false; return info.Types.Overlaps(target.Info.GetAllTargetTypes()); diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/MadTank.cs openra-20210321/OpenRA.Mods.Cnc/Traits/MadTank.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/MadTank.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/MadTank.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,10 +10,8 @@ #endregion using System.Collections.Generic; -using System.Linq; using OpenRA.Activities; using OpenRA.GameRules; -using OpenRA.Mods.Common; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Traits; @@ -23,7 +21,7 @@ namespace OpenRA.Mods.Cnc.Traits { - class MadTankInfo : ITraitInfo, IRulesetLoaded, Requires, Requires + class MadTankInfo : TraitInfo, IRulesetLoaded, Requires, Requires { [SequenceReference] public readonly string ThumpSequence = "piston"; @@ -63,19 +61,17 @@ [Desc("Types of damage that this trait causes to self while self-destructing. Leave empty for no damage types.")] public readonly BitSet DamageTypes = default(BitSet); - public object Create(ActorInitializer init) { return new MadTank(init.Self, this); } + public override object Create(ActorInitializer init) { return new MadTank(init.Self, this); } public void RulesetLoaded(Ruleset rules, ActorInfo ai) { - WeaponInfo thumpDamageWeapon; - WeaponInfo detonationWeapon; var thumpDamageWeaponToLower = (ThumpDamageWeapon ?? string.Empty).ToLowerInvariant(); var detonationWeaponToLower = (DetonationWeapon ?? string.Empty).ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(thumpDamageWeaponToLower, out thumpDamageWeapon)) + if (!rules.Weapons.TryGetValue(thumpDamageWeaponToLower, out var thumpDamageWeapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(thumpDamageWeaponToLower)); - if (!rules.Weapons.TryGetValue(detonationWeaponToLower, out detonationWeapon)) + if (!rules.Weapons.TryGetValue(detonationWeaponToLower, out var detonationWeapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(detonationWeaponToLower)); ThumpDamageWeaponInfo = thumpDamageWeapon; @@ -83,22 +79,15 @@ } } - class MadTank : INotifyCreated, IIssueOrder, IResolveOrder, IOrderVoice, IIssueDeployOrder + class MadTank : IIssueOrder, IResolveOrder, IOrderVoice, IIssueDeployOrder { readonly MadTankInfo info; - ConditionManager conditionManager; - public MadTank(Actor self, MadTankInfo info) { this.info = info; } - void INotifyCreated.Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - } - public IEnumerable Orders { get @@ -108,7 +97,7 @@ } } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID != "DetonateAttack" && order.OrderID != "Detonate") return null; @@ -161,7 +150,7 @@ assignTargetOnFirstRun = true; } - public DetonationSequence(Actor self, MadTank mad, Target target) + public DetonationSequence(Actor self, MadTank mad, in Target target) { this.self = self; this.mad = mad; @@ -195,8 +184,7 @@ if (target.Type == TargetType.Invalid) return true; - if (mad.conditionManager != null && !string.IsNullOrEmpty(mad.info.DeployedCondition)) - mad.conditionManager.GrantCondition(self, mad.info.DeployedCondition); + self.GrantCondition(mad.info.DeployedCondition); self.World.AddFrameEndTask(w => EjectDriver()); if (mad.info.ThumpSequence != null) @@ -252,9 +240,7 @@ new LocationInit(self.Location), new OwnerInit(self.Owner) }); - var driverMobile = driver.TraitOrDefault(); - if (driverMobile != null) - driverMobile.Nudge(driver); + driver.TraitOrDefault()?.Nudge(driver); } } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Mine.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Mine.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Mine.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Mine.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,14 +15,14 @@ namespace OpenRA.Mods.Cnc.Traits { - class MineInfo : ITraitInfo + class MineInfo : TraitInfo { public readonly BitSet CrushClasses = default(BitSet); public readonly bool AvoidFriendly = true; public readonly bool BlockFriendly = true; public readonly BitSet DetonateClasses = default(BitSet); - public object Create(ActorInitializer init) { return new Mine(this); } + public override object Create(ActorInitializer init) { return new Mine(this); } } class Mine : ICrushable, INotifyCrushed @@ -41,7 +41,7 @@ if (!info.CrushClasses.Overlaps(crushClasses)) return; - if (crusher.Info.HasTraitInfo() || (self.Owner.Stances[crusher.Owner] == Stance.Ally && info.AvoidFriendly)) + if (crusher.Info.HasTraitInfo() || (self.Owner.RelationshipWith(crusher.Owner) == PlayerRelationship.Ally && info.AvoidFriendly)) return; var mobile = crusher.TraitOrDefault(); @@ -53,7 +53,7 @@ bool ICrushable.CrushableBy(Actor self, Actor crusher, BitSet crushClasses) { - if (info.BlockFriendly && !crusher.Info.HasTraitInfo() && self.Owner.Stances[crusher.Owner] == Stance.Ally) + if (info.BlockFriendly && !crusher.Info.HasTraitInfo() && self.Owner.RelationshipWith(crusher.Owner) == PlayerRelationship.Ally) return false; return info.CrushClasses.Overlaps(crushClasses); @@ -65,7 +65,7 @@ return self.World.NoPlayersMask; // Friendly units should move around! - return info.BlockFriendly ? self.Owner.EnemyPlayersMask : self.World.AllPlayersMask; + return info.BlockFriendly ? ~self.Owner.AlliedPlayersMask : self.World.AllPlayersMask; } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Minelayer.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Minelayer.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Minelayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Minelayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; +using OpenRA; using OpenRA.Graphics; using OpenRA.Mods.Cnc.Activities; using OpenRA.Mods.Common.Orders; @@ -21,7 +22,7 @@ namespace OpenRA.Mods.Cnc.Traits { - public class MinelayerInfo : ITraitInfo, Requires + public class MinelayerInfo : TraitInfo, Requires { [ActorReference] public readonly string Mine = "minv"; @@ -34,6 +35,9 @@ [Desc("Voice to use when ordered to lay a minefield.")] public readonly string Voice = "Action"; + [Desc("Color to use for the target line when laying mines.")] + public readonly Color TargetLineColor = Color.Crimson; + [Desc("Sprite overlay to use for valid minefield cells.")] public readonly string TileValidName = "build-valid"; @@ -43,21 +47,33 @@ [Desc("Sprite overlay to use for minefield cells hidden behind fog or shroud.")] public readonly string TileUnknownName = "build-unknown"; - public object Create(ActorInitializer init) { return new Minelayer(init.Self, this); } + [Desc("Only allow laying mines on listed terrain types. Leave empty to allow all terrain types.")] + public readonly HashSet TerrainTypes = new HashSet(); + + [Desc("Cursor to display when able to lay a mine.")] + public readonly string DeployCursor = "deploy"; + + [Desc("Cursor to display when unable to lay a mine.")] + public readonly string DeployBlockedCursor = "deploy-blocked"; + + public override object Create(ActorInitializer init) { return new Minelayer(init.Self, this); } } public class Minelayer : IIssueOrder, IResolveOrder, ISync, IIssueDeployOrder, IOrderVoice, ITick { public readonly MinelayerInfo Info; - public readonly Sprite Tile; + readonly Actor self; + [Sync] CPos minefieldStart; public Minelayer(Actor self, MinelayerInfo info) { Info = info; + this.self = self; + var tileset = self.World.Map.Tileset.ToLowerInvariant(); if (self.World.Map.Rules.Sequences.HasSequence("overlay", "{0}-{1}".F(Info.TileValidName, tileset))) Tile = self.World.Map.Rules.Sequences.GetSequence("overlay", "{0}-{1}".F(Info.TileValidName, tileset)).GetSprite(0); @@ -70,11 +86,11 @@ get { yield return new BeginMinefieldOrderTargeter(); - yield return new DeployOrderTargeter("PlaceMine", 5); + yield return new DeployOrderTargeter("PlaceMine", 5, () => IsCellAcceptable(self, self.Location) ? Info.DeployCursor : Info.DeployBlockedCursor); } } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { switch (order.OrderID) { @@ -98,7 +114,10 @@ return new Order("PlaceMine", self, Target.FromCell(self.World, self.Location), queued); } - bool IIssueDeployOrder.CanIssueDeployOrder(Actor self, bool queued) { return true; } + bool IIssueDeployOrder.CanIssueDeployOrder(Actor self, bool queued) + { + return IsCellAcceptable(self, self.Location); + } void IResolveOrder.ResolveOrder(Actor self, Order order) { @@ -109,13 +128,21 @@ if (order.OrderString == "BeginMinefield") minefieldStart = cell; else if (order.OrderString == "PlaceMine") - self.QueueActivity(order.Queued, new LayMines(self)); + { + if (IsCellAcceptable(self, cell)) + self.QueueActivity(order.Queued, new LayMines(self)); + } else if (order.OrderString == "PlaceMinefield") { + // A different minelayer might have started laying the field without this minelayer knowing the start + minefieldStart = order.ExtraLocation; + var movement = self.Trait(); + var mobile = movement as Mobile; var minefield = GetMinefieldCells(minefieldStart, cell, Info.MinefieldDepth) - .Where(c => movement.CanEnterCell(c, null, BlockedByActor.Immovable) || !self.Owner.Shroud.IsVisible(c)) + .Where(c => IsCellAcceptable(self, c) && self.Owner.Shroud.IsExplored(c) + && movement.CanEnterCell(c, null, BlockedByActor.Immovable) && (mobile != null && mobile.CanStayInCell(c))) .OrderBy(c => (c - minefieldStart).LengthSquared).ToList(); self.QueueActivity(order.Queued, new LayMines(self, minefield)); @@ -157,9 +184,22 @@ yield return new CPos(i, j); } + public bool IsCellAcceptable(Actor self, CPos cell) + { + if (!self.World.Map.Contains(cell)) + return false; + + if (Info.TerrainTypes.Count == 0) + return true; + + var terrainType = self.World.Map.GetTerrainInfo(cell).Type; + return Info.TerrainTypes.Contains(terrainType); + } + class MinefieldOrderGenerator : OrderGenerator { readonly List minelayers; + readonly Minelayer minelayer; readonly Sprite tileOk; readonly Sprite tileUnknown; readonly Sprite tileBlocked; @@ -172,7 +212,7 @@ minefieldStart = xy; this.queued = queued; - var minelayer = a.Trait(); + minelayer = a.Trait(); var tileset = a.World.Map.Tileset.ToLowerInvariant(); if (a.World.Map.Rules.Sequences.HasSequence("overlay", "{0}-{1}".F(minelayer.Info.TileValidName, tileset))) tileOk = a.World.Map.Rules.Sequences.GetSequence("overlay", "{0}-{1}".F(minelayer.Info.TileValidName, tileset)).GetSprite(0); @@ -207,13 +247,14 @@ { minelayers.First().World.CancelInputMode(); foreach (var minelayer in minelayers) - yield return new Order("PlaceMinefield", minelayer, Target.FromCell(world, cell), queued); + yield return new Order("PlaceMinefield", minelayer, Target.FromCell(world, cell), queued) { ExtraLocation = minefieldStart }; } } - protected override void Tick(World world) + protected override void SelectionChanged(World world, IEnumerable selected) { - minelayers.RemoveAll(minelayer => !minelayer.IsInWorld || minelayer.IsDead); + minelayers.Clear(); + minelayers.AddRange(selected.Where(s => !s.IsDead && s.Info.HasTraitInfo())); if (!minelayers.Any()) world.CancelInputMode(); } @@ -236,13 +277,17 @@ foreach (var c in minefield) { var tile = tileOk; - if (world.FogObscures(c)) + if (!world.Map.Contains(c)) + tile = tileBlocked; + else if (world.ShroudObscures(c)) + tile = tileBlocked; + else if (world.FogObscures(c)) tile = tileUnknown; - else if (!movement.CanEnterCell(c, null, BlockedByActor.Immovable) || (mobile != null && !mobile.CanStayInCell(c))) + else if (!this.minelayer.IsCellAcceptable(minelayer, c) + || !movement.CanEnterCell(c, null, BlockedByActor.Immovable) || (mobile != null && !mobile.CanStayInCell(c))) tile = tileBlocked; - yield return new SpriteRenderable(tile, world.Map.CenterOfCell(c), - WVec.Zero, -511, pal, 1f, true); + yield return new SpriteRenderable(tile, world.Map.CenterOfCell(c), WVec.Zero, -511, pal, 1f, true, true); } } @@ -258,9 +303,9 @@ { public string OrderID { get { return "BeginMinefield"; } } public int OrderPriority { get { return 5; } } - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (target.Type != TargetType.Terrain) return false; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/PaletteEffects/ChronoshiftPaletteEffect.cs openra-20210321/OpenRA.Mods.Cnc/Traits/PaletteEffects/ChronoshiftPaletteEffect.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/PaletteEffects/ChronoshiftPaletteEffect.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/PaletteEffects/ChronoshiftPaletteEffect.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,12 +16,12 @@ namespace OpenRA.Mods.Cnc.Traits { [Desc("Apply palette full screen rotations during chronoshifts. Add this to the world actor.")] - public class ChronoshiftPaletteEffectInfo : ITraitInfo + public class ChronoshiftPaletteEffectInfo : TraitInfo { [Desc("Measured in ticks.")] public readonly int ChronoEffectLength = 60; - public object Create(ActorInitializer init) { return new ChronoshiftPaletteEffect(this); } + public override object Create(ActorInitializer init) { return new ChronoshiftPaletteEffect(this); } } public class ChronoshiftPaletteEffect : IPaletteModifier, ITick diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/PaletteEffects/LightPaletteRotator.cs openra-20210321/OpenRA.Mods.Cnc/Traits/PaletteEffects/LightPaletteRotator.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/PaletteEffects/LightPaletteRotator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/PaletteEffects/LightPaletteRotator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Cnc.Traits { [Desc("Palette effect used for blinking \"animations\" on actors.")] - class LightPaletteRotatorInfo : ITraitInfo + class LightPaletteRotatorInfo : TraitInfo { [Desc("Palettes this effect should not apply to.")] public readonly HashSet ExcludePalettes = new HashSet(); @@ -30,7 +30,7 @@ [Desc("Palette indices to rotate through.")] public readonly int[] RotationIndices = { 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 238, 237, 236, 235, 234, 233, 232, 231 }; - public object Create(ActorInitializer init) { return new LightPaletteRotator(this); } + public override object Create(ActorInitializer init) { return new LightPaletteRotator(this); } } class LightPaletteRotator : ITick, IPaletteModifier diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/PortableChrono.cs openra-20210321/OpenRA.Mods.Cnc/Traits/PortableChrono.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/PortableChrono.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/PortableChrono.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,6 +10,7 @@ #endregion using System.Collections.Generic; +using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Cnc.Activities; using OpenRA.Mods.Common.Graphics; @@ -20,7 +21,7 @@ namespace OpenRA.Mods.Cnc.Traits { - class PortableChronoInfo : ITraitInfo, Requires + class PortableChronoInfo : TraitInfo, Requires { [Desc("Cooldown in ticks until the unit can teleport.")] public readonly int ChargeDelay = 500; @@ -55,7 +56,22 @@ [VoiceReference] public readonly string Voice = "Action"; - public object Create(ActorInitializer init) { return new PortableChrono(init.Self, this); } + [Desc("Range circle color.")] + public readonly Color CircleColor = Color.FromArgb(128, Color.LawnGreen); + + [Desc("Range circle line width.")] + public readonly float CircleWidth = 1; + + [Desc("Range circle border color.")] + public readonly Color CircleBorderColor = Color.FromArgb(96, Color.Black); + + [Desc("Range circle border width.")] + public readonly float CircleBorderWidth = 3; + + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.LawnGreen; + + public override object Create(ActorInitializer init) { return new PortableChrono(init.Self, this); } } class PortableChrono : IIssueOrder, IResolveOrder, ITick, ISelectionBar, IOrderVoice, ISync @@ -87,7 +103,7 @@ } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "PortableChronoDeploy") { @@ -115,10 +131,10 @@ var cell = self.World.Map.CellContaining(order.Target.CenterPosition); if (maxDistance != null) - self.QueueActivity(move.MoveWithinRange(order.Target, WDist.FromCells(maxDistance.Value), targetLineColor: Color.LawnGreen)); + self.QueueActivity(move.MoveWithinRange(order.Target, WDist.FromCells(maxDistance.Value), targetLineColor: Info.TargetLineColor)); self.QueueActivity(new Teleport(self, cell, maxDistance, Info.KillCargo, Info.FlashScreen, Info.ChronoshiftSound)); - self.QueueActivity(move.MoveTo(cell, 5, targetLineColor: Color.LawnGreen)); + self.QueueActivity(move.MoveTo(cell, 5, targetLineColor: Info.TargetLineColor)); self.ShowTargetLines(); } } @@ -159,9 +175,9 @@ public string OrderID { get { return "PortableChronoTeleport"; } } public int OrderPriority { get { return 5; } } public bool IsQueued { get; protected set; } - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (modifiers.HasModifier(TargetModifiers.ForceMove)) { @@ -209,9 +225,9 @@ } } - protected override void Tick(World world) + protected override void SelectionChanged(World world, IEnumerable selected) { - if (!self.IsInWorld || self.IsDead) + if (!selected.Contains(self)) world.CancelInputMode(); } @@ -231,8 +247,10 @@ self.CenterPosition, WDist.FromCells(self.Trait().Info.MaxDistance), 0, - Color.FromArgb(128, Color.LawnGreen), - Color.FromArgb(96, Color.Black)); + info.CircleColor, + info.CircleWidth, + info.CircleBorderColor, + info.CircleBorderWidth); } protected override string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/RenderJammerCircle.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/RenderJammerCircle.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/RenderJammerCircle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/RenderJammerCircle.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Graphics; -using OpenRA.Mods.Common.Graphics; -using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; -using OpenRA.Traits; - -namespace OpenRA.Mods.Cnc.Traits -{ - // TODO: remove all the Render*Circle duplication - class RenderJammerCircleInfo : TraitInfo, IPlaceBuildingDecorationInfo - { - public IEnumerable RenderAnnotations(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) - { - var jamsMissiles = ai.TraitInfoOrDefault(); - if (jamsMissiles != null) - { - yield return new RangeCircleAnnotationRenderable( - centerPosition, - jamsMissiles.Range, - 0, - Color.FromArgb(128, Color.Red), - Color.FromArgb(96, Color.Black)); - } - - foreach (var a in w.ActorsWithTrait()) - if (a.Actor.Owner.IsAlliedWith(w.RenderPlayer)) - foreach (var r in a.Trait.RenderAnnotations(a.Actor, wr)) - yield return r; - } - } - - class RenderJammerCircle : IRenderAnnotationsWhenSelected - { - public IEnumerable RenderAnnotations(Actor self, WorldRenderer wr) - { - if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) - yield break; - - var jamsMissiles = self.Info.TraitInfoOrDefault(); - if (jamsMissiles != null) - { - yield return new RangeCircleAnnotationRenderable( - self.CenterPosition, - jamsMissiles.Range, - 0, - Color.FromArgb(128, Color.Red), - Color.FromArgb(96, Color.Black)); - } - } - - bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return false; } } - } -} diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/RenderShroudCircle.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/RenderShroudCircle.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/RenderShroudCircle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/RenderShroudCircle.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.Common.Graphics; -using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; -using OpenRA.Traits; - -namespace OpenRA.Mods.Cnc.Traits -{ - class RenderShroudCircleInfo : ITraitInfo, IPlaceBuildingDecorationInfo - { - [Desc("Color of the circle.")] - public readonly Color Color = Color.FromArgb(128, Color.Cyan); - - [Desc("Contrast color of the circle.")] - public readonly Color ContrastColor = Color.FromArgb(96, Color.Black); - - public IEnumerable RenderAnnotations(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) - { - var localRange = ai.TraitInfos() - .Where(csi => csi.EnabledByDefault) - .Select(csi => csi.Range) - .DefaultIfEmpty(WDist.Zero) - .Max(); - - var localRangeRenderable = new RangeCircleAnnotationRenderable( - centerPosition, - localRange, - 0, - Color, - ContrastColor); - - var otherRangeRenderables = w.ActorsWithTrait() - .SelectMany(a => a.Trait.RangeCircleRenderables(a.Actor, wr)); - - return otherRangeRenderables.Append(localRangeRenderable); - } - - public object Create(ActorInitializer init) { return new RenderShroudCircle(init.Self, this); } - } - - class RenderShroudCircle : INotifyCreated, IRenderAnnotationsWhenSelected - { - readonly RenderShroudCircleInfo info; - WDist range; - - public RenderShroudCircle(Actor self, RenderShroudCircleInfo info) - { - this.info = info; - } - - void INotifyCreated.Created(Actor self) - { - range = self.TraitsImplementing() - .Select(cs => cs.Info.Range) - .DefaultIfEmpty(WDist.Zero) - .Max(); - } - - public IEnumerable RangeCircleRenderables(Actor self, WorldRenderer wr) - { - if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) - yield break; - - yield return new RangeCircleAnnotationRenderable( - self.CenterPosition, - range, - 0, - info.Color, - info.ContrastColor); - } - - IEnumerable IRenderAnnotationsWhenSelected.RenderAnnotations(Actor self, WorldRenderer wr) - { - return RangeCircleRenderables(self, wr); - } - - bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return false; } } - } -} diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithBuildingBib.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithBuildingBib.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithBuildingBib.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithBuildingBib.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Cnc.Traits { - public class WithBuildingBibInfo : ITraitInfo, Requires, IRenderActorPreviewSpritesInfo, IActorPreviewInitInfo, Requires + public class WithBuildingBibInfo : TraitInfo, Requires, IRenderActorPreviewSpritesInfo, IActorPreviewInitInfo, Requires { [SequenceReference] public readonly string Sequence = "bib"; @@ -28,11 +28,11 @@ public readonly bool HasMinibib = false; - public object Create(ActorInitializer init) { return new WithBuildingBib(init.Self, this); } + public override object Create(ActorInitializer init) { return new WithBuildingBib(init.Self, this); } public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { - if (init.Contains() && init.Get()) + if (init.Contains(this)) yield break; if (Palette != null) @@ -45,10 +45,7 @@ var bibOffset = bi.Dimensions.Y - rows; var centerOffset = bi.CenterOffset(init.World); var map = init.World.Map; - var location = CPos.Zero; - - if (init.Contains()) - location = init.Get(); + var location = init.GetValue(CPos.Zero); for (var i = 0; i < rows * width; i++) { @@ -76,7 +73,7 @@ } } - IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) + IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) { yield return new HideBibPreviewInit(); } @@ -136,13 +133,5 @@ } } - class HideBibPreviewInit : IActorInit, ISuppressInitExport - { - [FieldFromYamlKey] - readonly bool value = true; - - public HideBibPreviewInit() { } - public HideBibPreviewInit(bool init) { value = init; } - public bool Value(World world) { return value; } - } + class HideBibPreviewInit : RuntimeFlagInit { } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithCargo.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithCargo.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithCargo.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithCargo.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,7 +21,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render { [Desc("Renders the cargo loaded into the unit.")] - public class WithCargoInfo : ITraitInfo, Requires, Requires + public class WithCargoInfo : TraitInfo, Requires, Requires { [Desc("Cargo position relative to turret or body in (forward, right, up) triples. The default offset should be in the middle of the list.")] public readonly WVec[] LocalOffset = { WVec.Zero }; @@ -29,7 +29,7 @@ [Desc("Passenger CargoType to display.")] public readonly HashSet DisplayTypes = new HashSet(); - public object Create(ActorInitializer init) { return new WithCargo(init.Self, this); } + public override object Create(ActorInitializer init) { return new WithCargo(init.Self, this); } } public class WithCargo : ITick, IRender, INotifyPassengerEntered, INotifyPassengerExited @@ -38,7 +38,7 @@ readonly Cargo cargo; readonly BodyOrientation body; readonly IFacing facing; - int cachedFacing; + WAngle cachedFacing; Dictionary previews = new Dictionary(); diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithDisguisingInfantryBody.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithDisguisingInfantryBody.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithDisguisingInfantryBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithDisguisingInfantryBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -60,7 +60,7 @@ .FirstOrDefault(t => t.EnabledByDefault); if (renderSprites != null && infantryBody != null) { - disguiseImage = renderSprites.GetImage(disguiseActor, self.World.Map.Rules.Sequences, disguisePlayer.InternalName); + disguiseImage = renderSprites.GetImage(disguiseActor, self.World.Map.Rules.Sequences, disguisePlayer.Faction.InternalName); disguiseInfantryBody = infantryBody; } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithDockingOverlay.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithDockingOverlay.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithDockingOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithDockingOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,7 +26,7 @@ [Desc("Position relative to body")] public readonly WVec Offset = WVec.Zero; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithEmbeddedTurretSpriteBody.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithEmbeddedTurretSpriteBody.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithEmbeddedTurretSpriteBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithEmbeddedTurretSpriteBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,6 +23,9 @@ [Desc("This actor has turret art with facings baked into the sprite.")] public class WithEmbeddedTurretSpriteBodyInfo : WithSpriteBodyInfo, Requires, Requires { + [Desc("Number of facings for gameplay calculations. -1 indicates auto-detection from the sequence.")] + public readonly int QuantizedFacings = -1; + public override object Create(ActorInitializer init) { return new WithEmbeddedTurretSpriteBody(init, this); } public override IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) @@ -34,9 +37,7 @@ var wsb = init.Actor.TraitInfos().FirstOrDefault(); // Show the correct turret facing - var facing = init.Contains() ? init.Get().Value(init.World) : t.InitialFacing; - - var anim = new Animation(init.World, image, () => facing); + var anim = new Animation(init.World, image, t.WorldFacingFromInit(init)); anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), wsb.Sequence)); yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale); @@ -45,31 +46,33 @@ public class WithEmbeddedTurretSpriteBody : WithSpriteBody { + readonly WithEmbeddedTurretSpriteBodyInfo info; readonly Turreted turreted; - static Func MakeTurretFacingFunc(Actor self) + static Func MakeTurretFacingFunc(Actor self) { // Turret artwork is baked into the sprite, so only the first turret makes sense. var turreted = self.TraitsImplementing().FirstOrDefault(); - return () => turreted.TurretFacing; + return () => turreted.WorldOrientation.Yaw; } - public WithEmbeddedTurretSpriteBody(ActorInitializer init, WithSpriteBodyInfo info) + public WithEmbeddedTurretSpriteBody(ActorInitializer init, WithEmbeddedTurretSpriteBodyInfo info) : base(init, info, MakeTurretFacingFunc(init.Self)) { + this.info = info; turreted = init.Self.TraitsImplementing().FirstOrDefault(); } protected override void TraitEnabled(Actor self) { base.TraitEnabled(self); - turreted.QuantizedFacings = DefaultAnimation.CurrentSequence.Facings; + turreted.QuantizedFacings = info.QuantizedFacings >= 0 ? info.QuantizedFacings : DefaultAnimation.CurrentSequence.Facings; } protected override void DamageStateChanged(Actor self) { base.DamageStateChanged(self); - turreted.QuantizedFacings = DefaultAnimation.CurrentSequence.Facings; + turreted.QuantizedFacings = info.QuantizedFacings >= 0 ? info.QuantizedFacings : DefaultAnimation.CurrentSequence.Facings; } } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithGunboatBody.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithGunboatBody.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithGunboatBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithGunboatBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -46,11 +46,11 @@ readonly IFacing facing; readonly Turreted turret; - static Func MakeTurretFacingFunc(Actor self) + static Func MakeTurretFacingFunc(Actor self) { // Turret artwork is baked into the sprite, so only the first turret makes sense. var turreted = self.TraitsImplementing().FirstOrDefault(); - return () => turreted.TurretFacing; + return () => turreted.WorldOrientation.Yaw; } public WithGunboatBody(ActorInitializer init, WithGunboatBodyInfo info) @@ -76,7 +76,7 @@ void ITick.Tick(Actor self) { - if (facing.Facing <= 128) + if (facing.Facing.Angle <= 512) { var left = NormalizeSequence(self, info.LeftSequence); if (DefaultAnimation.CurrentSequence.Name != left) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithHarvesterSpriteBody.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithHarvesterSpriteBody.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithHarvesterSpriteBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithHarvesterSpriteBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,10 +9,6 @@ */ #endregion -using System.Collections.Generic; -using OpenRA.Activities; -using OpenRA.Graphics; -using OpenRA.Mods.Common.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits.Render; using OpenRA.Traits; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithLandingCraftAnimation.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithLandingCraftAnimation.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithLandingCraftAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithLandingCraftAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render { - public class WithLandingCraftAnimationInfo : ITraitInfo, Requires, Requires, Requires + public class WithLandingCraftAnimationInfo : TraitInfo, Requires, Requires, Requires { public readonly HashSet OpenTerrainTypes = new HashSet { "Clear" }; @@ -33,7 +33,7 @@ [Desc("Which sprite body to play the animation on.")] public readonly string Body = "body"; - public object Create(ActorInitializer init) { return new WithLandingCraftAnimation(init, this); } + public override object Create(ActorInitializer init) { return new WithLandingCraftAnimation(init, this); } } public class WithLandingCraftAnimation : ITick @@ -56,7 +56,7 @@ public bool ShouldBeOpen() { - if (move.CurrentMovementTypes.HasFlag(MovementType.Horizontal) || self.World.Map.DistanceAboveTerrain(self.CenterPosition).Length > 0) + if (move.CurrentMovementTypes != MovementType.None || self.World.Map.DistanceAboveTerrain(self.CenterPosition).Length > 0) return false; return cargo.CurrentAdjacentCells.Any(c => self.World.Map.Contains(c) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithRoof.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithRoof.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithRoof.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithRoof.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,12 +16,12 @@ namespace OpenRA.Mods.Cnc.Traits.Render { [Desc("Provides an overlay for the Tiberian Dawn hover craft.")] - public class WithRoofInfo : ITraitInfo, Requires + public class WithRoofInfo : TraitInfo, Requires { [SequenceReference] public readonly string Sequence = "roof"; - public object Create(ActorInitializer init) { return new WithRoof(init.Self, this); } + public override object Create(ActorInitializer init) { return new WithRoof(init.Self, this); } } public class WithRoof @@ -29,7 +29,7 @@ public WithRoof(Actor self, WithRoofInfo info) { var rs = self.Trait(); - var roof = new Animation(self.World, rs.GetImage(self), () => self.Trait().Facing); + var roof = new Animation(self.World, rs.GetImage(self), RenderSprites.MakeFacingFunc(self)); roof.Play(info.Sequence); rs.Add(new AnimationWithOffset(roof, null, null, 1024)); } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithTeslaChargeAnimation.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithTeslaChargeAnimation.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithTeslaChargeAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithTeslaChargeAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render { [Desc("This actor displays a charge-up animation before firing.")] - public class WithTeslaChargeAnimationInfo : ITraitInfo, Requires, Requires + public class WithTeslaChargeAnimationInfo : TraitInfo, Requires, Requires { [SequenceReference] [Desc("Sequence to use for charge animation.")] @@ -25,7 +25,7 @@ [Desc("Which sprite body to play the animation on.")] public readonly string Body = "body"; - public object Create(ActorInitializer init) { return new WithTeslaChargeAnimation(init, this); } + public override object Create(ActorInitializer init) { return new WithTeslaChargeAnimation(init, this); } } public class WithTeslaChargeAnimation : INotifyTeslaCharging @@ -39,7 +39,7 @@ wsb = init.Self.TraitsImplementing().Single(w => w.Info.Name == info.Body); } - void INotifyTeslaCharging.Charging(Actor self, Target target) + void INotifyTeslaCharging.Charging(Actor self, in Target target) { wsb.PlayCustomAnimation(self, info.ChargeSequence, () => wsb.CancelCustomAnimation(self)); } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithTeslaChargeOverlay.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithTeslaChargeOverlay.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithTeslaChargeOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithTeslaChargeOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,20 +17,20 @@ namespace OpenRA.Mods.Cnc.Traits.Render { [Desc("Rendered together with AttackCharge.")] - public class WithTeslaChargeOverlayInfo : ITraitInfo, Requires + public class WithTeslaChargeOverlayInfo : TraitInfo, Requires { [SequenceReference] [Desc("Sequence name to use")] public readonly string Sequence = "active"; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; [Desc("Custom palette is a player palette BaseName")] public readonly bool IsPlayerPalette = false; - public object Create(ActorInitializer init) { return new WithTeslaChargeOverlay(init, this); } + public override object Create(ActorInitializer init) { return new WithTeslaChargeOverlay(init, this); } } public class WithTeslaChargeOverlay : INotifyTeslaCharging, INotifyDamageStateChanged, INotifySold @@ -53,7 +53,7 @@ info.Palette, info.IsPlayerPalette); } - void INotifyTeslaCharging.Charging(Actor self, Target target) + void INotifyTeslaCharging.Charging(Actor self, in Target target) { charging = true; overlay.PlayThen(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.Sequence), () => charging = false); diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,7 +21,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render { // TODO: This trait is hacky and should go away as soon as we support granting a condition on docking, in favor of toggling two regular WithVoxelBodies - public class WithVoxelUnloadBodyInfo : ITraitInfo, IRenderActorPreviewVoxelsInfo, Requires + public class WithVoxelUnloadBodyInfo : TraitInfo, IRenderActorPreviewVoxelsInfo, Requires { [Desc("Voxel sequence name to use when docked to a refinery.")] public readonly string UnloadSequence = "unload"; @@ -32,7 +32,7 @@ [Desc("Defines if the Voxel should have a shadow.")] public readonly bool ShowShadow = true; - public object Create(ActorInitializer init) { return new WithVoxelUnloadBody(init.Self, this); } + public override object Create(ActorInitializer init) { return new WithVoxelUnloadBody(init.Self, this); } public IEnumerable RenderPreviewVoxels( ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func orientation, int facings, PaletteReference p) @@ -40,7 +40,7 @@ var body = init.Actor.TraitInfo(); var model = init.World.ModelCache.GetModelSequence(image, IdleSequence); yield return new ModelAnimation(model, () => WVec.Zero, - () => new[] { body.QuantizeOrientation(orientation(), facings) }, + () => body.QuantizeOrientation(orientation(), facings), () => false, () => 0, ShowShadow); } } @@ -59,7 +59,7 @@ var idleModel = self.World.ModelCache.GetModelSequence(rv.Image, info.IdleSequence); modelAnimation = new ModelAnimation(idleModel, () => WVec.Zero, - () => new[] { body.QuantizeOrientation(self, self.Orientation) }, + () => body.QuantizeOrientation(self, self.Orientation), () => Docked, () => 0, info.ShowShadow); @@ -67,7 +67,7 @@ var unloadModel = self.World.ModelCache.GetModelSequence(rv.Image, info.UnloadSequence); rv.Add(new ModelAnimation(unloadModel, () => WVec.Zero, - () => new[] { body.QuantizeOrientation(self, self.Orientation) }, + () => body.QuantizeOrientation(self, self.Orientation), () => !Docked, () => 0, info.ShowShadow)); } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,7 +20,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render { - public class WithVoxelWalkerBodyInfo : ITraitInfo, IRenderActorPreviewVoxelsInfo, Requires, Requires, Requires + public class WithVoxelWalkerBodyInfo : TraitInfo, IRenderActorPreviewVoxelsInfo, Requires, Requires, Requires { public readonly string Sequence = "idle"; @@ -29,17 +29,17 @@ [Desc("Defines if the Voxel should have a shadow.")] public readonly bool ShowShadow = true; - public object Create(ActorInitializer init) { return new WithVoxelWalkerBody(init.Self, this); } + public override object Create(ActorInitializer init) { return new WithVoxelWalkerBody(init.Self, this); } public IEnumerable RenderPreviewVoxels( ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func orientation, int facings, PaletteReference p) { var model = init.World.ModelCache.GetModelSequence(image, Sequence); var body = init.Actor.TraitInfo(); - var frame = init.Contains() ? init.Get() : 0; + var frame = init.GetValue(this, 0); yield return new ModelAnimation(model, () => WVec.Zero, - () => new[] { body.QuantizeOrientation(orientation(), facings) }, + () => body.QuantizeOrientation(orientation(), facings), () => false, () => frame, ShowShadow); } } @@ -64,7 +64,7 @@ var model = self.World.ModelCache.GetModelSequence(rv.Image, info.Sequence); frames = model.Frames; modelAnimation = new ModelAnimation(model, () => WVec.Zero, - () => new[] { body.QuantizeOrientation(self, self.Orientation) }, + () => body.QuantizeOrientation(self, self.Orientation), () => false, () => frame, info.ShowShadow); rv.Add(modelAnimation); @@ -72,8 +72,8 @@ void ITick.Tick(Actor self) { - if (movement.CurrentMovementTypes.HasFlag(MovementType.Horizontal) - || movement.CurrentMovementTypes.HasFlag(MovementType.Turn)) + if (movement.CurrentMovementTypes.HasMovementType(MovementType.Horizontal) + || movement.CurrentMovementTypes.HasMovementType(MovementType.Turn)) tick++; if (tick < info.TickRate) @@ -95,13 +95,9 @@ } } - public class BodyAnimationFrameInit : IActorInit + public class BodyAnimationFrameInit : ValueActorInit { - [FieldFromYamlKey] - readonly uint value = 0; - - public BodyAnimationFrameInit() { } - public BodyAnimationFrameInit(uint init) { value = init; } - public uint Value(World world) { return value; } + public BodyAnimationFrameInit(uint value) + : base(value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/ResourcePurifier.cs openra-20210321/OpenRA.Mods.Cnc/Traits/ResourcePurifier.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/ResourcePurifier.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/ResourcePurifier.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using OpenRA.Mods.Common; using OpenRA.Mods.Common.Effects; using OpenRA.Mods.Common.Traits; using OpenRA.Traits; @@ -52,12 +51,7 @@ protected override void Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query other player traits from self, knowing that - // it refers to the same actor as self.Owner.PlayerActor - var playerActor = self.Info.Name == "player" ? self : self.Owner.PlayerActor; - playerResources = playerActor.Trait(); + playerResources = self.Owner.PlayerActor.Trait(); base.Created(self); } @@ -67,7 +61,7 @@ if (IsTraitDisabled) return; - var cash = Util.ApplyPercentageModifiers(amount, modifier); + var cash = OpenRA.Mods.Common.Util.ApplyPercentageModifiers(amount, modifier); playerResources.GiveCash(cash); if (Info.ShowTicks && self.Info.HasTraitInfo()) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/AttackOrderPower.cs openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/AttackOrderPower.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/AttackOrderPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/AttackOrderPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,6 +22,18 @@ { class AttackOrderPowerInfo : SupportPowerInfo, Requires { + [Desc("Range circle color.")] + public readonly Color CircleColor = Color.Red; + + [Desc("Range circle line width.")] + public readonly float CircleWidth = 1; + + [Desc("Range circle border color.")] + public readonly Color CircleBorderColor = Color.FromArgb(96, Color.Black); + + [Desc("Range circle border width.")] + public readonly float CircleBorderWidth = 3; + public override object Create(ActorInitializer init) { return new AttackOrderPower(init.Self, this); } } @@ -38,7 +50,6 @@ public override void SelectTarget(Actor self, string order, SupportPowerManager manager) { - Game.Sound.PlayToPlayer(SoundType.UI, manager.Self.Owner, Info.SelectTargetSound); self.World.OrderGenerator = new SelectAttackPowerTarget(self, order, manager, info.Cursor, MouseButton.Left, attack); } @@ -57,7 +68,7 @@ base.Created(self); } - void INotifyBurstComplete.FiredBurst(Actor self, Target target, Armament a) + void INotifyBurstComplete.FiredBurst(Actor self, in Target target, Armament a) { self.World.IssueOrder(new Order("Stop", self, false)); } @@ -109,7 +120,7 @@ protected override void Tick(World world) { // Cancel the OG if we can't use the power - if (!manager.Powers.ContainsKey(order)) + if (!manager.Powers.TryGetValue(order, out var p) || !p.Active || !p.Ready) world.CancelInputMode(); } @@ -118,21 +129,26 @@ protected override IEnumerable RenderAnnotations(WorldRenderer wr, World world) { + var info = instance.Info as AttackOrderPowerInfo; foreach (var a in instance.Instances.Where(i => !i.IsTraitPaused)) { yield return new RangeCircleAnnotationRenderable( a.Self.CenterPosition, attack.GetMinimumRange(), 0, - Color.Red, - Color.FromArgb(96, Color.Black)); + info.CircleColor, + info.CircleWidth, + info.CircleBorderColor, + info.CircleBorderWidth); yield return new RangeCircleAnnotationRenderable( a.Self.CenterPosition, attack.GetMaximumRange(), 0, - Color.Red, - Color.FromArgb(96, Color.Black)); + info.CircleColor, + info.CircleWidth, + info.CircleBorderColor, + info.CircleBorderWidth); } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/ChronoshiftPower.cs openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/ChronoshiftPower.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/ChronoshiftPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/ChronoshiftPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; -using OpenRA.Mods.Common.Graphics; using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; @@ -22,8 +21,13 @@ { class ChronoshiftPowerInfo : SupportPowerInfo { - [Desc("Target actor selection radius in cells.")] - public readonly int Range = 1; + [FieldLoader.Require] + [Desc("Size of the footprint of the affected area.")] + public readonly CVec Dimensions = CVec.Zero; + + [FieldLoader.Require] + [Desc("Actual footprint. Cells marked as x will be affected.")] + public readonly string Footprint = string.Empty; [Desc("Ticks until returning after teleportation.")] public readonly int Duration = 750; @@ -33,24 +37,24 @@ public readonly string FootprintImage = "overlay"; - [SequenceReference("FootprintImage", true)] + [SequenceReference(nameof(FootprintImage), prefix: true)] public readonly string ValidFootprintSequence = "target-valid"; - [SequenceReference("FootprintImage")] + [SequenceReference(nameof(FootprintImage))] public readonly string InvalidFootprintSequence = "target-invalid"; - [SequenceReference("FootprintImage")] + [SequenceReference(nameof(FootprintImage))] public readonly string SourceFootprintSequence = "target-select"; public readonly bool KillCargo = true; - [Desc("Cursor sequence to use when selecting targets for the chronoshift.")] + [Desc("Cursor to display when selecting targets for the chronoshift.")] public readonly string SelectionCursor = "chrono-select"; - [Desc("Cursor sequence to use when targeting an area for the chronoshift.")] + [Desc("Cursor to display when targeting an area for the chronoshift.")] public readonly string TargetCursor = "chrono-target"; - [Desc("Cursor sequence to use when the targeted area is blocked.")] + [Desc("Cursor to display when the targeted area is blocked.")] public readonly string TargetBlockedCursor = "move-blocked"; public override object Create(ActorInitializer init) { return new ChronoshiftPower(init.Self, this); } @@ -58,12 +62,18 @@ class ChronoshiftPower : SupportPower { + readonly char[] footprint; + readonly CVec dimensions; + public ChronoshiftPower(Actor self, ChronoshiftPowerInfo info) - : base(self, info) { } + : base(self, info) + { + footprint = info.Footprint.Where(c => !char.IsWhiteSpace(c)).ToArray(); + dimensions = info.Dimensions; + } public override void SelectTarget(Actor self, string order, SupportPowerManager manager) { - Game.Sound.PlayToPlayer(SoundType.UI, manager.Self.Owner, Info.SelectTargetSound); self.World.OrderGenerator = new SelectChronoshiftTarget(Self.World, order, manager, this); } @@ -91,8 +101,7 @@ public IEnumerable UnitsInRange(CPos xy) { - var range = ((ChronoshiftPowerInfo)Info).Range; - var tiles = Self.World.Map.FindTilesInCircle(xy, range); + var tiles = CellsMatching(xy, footprint, dimensions); var units = new HashSet(); foreach (var t in tiles) units.UnionWith(Self.World.ActorMap.GetActorsAt(t)); @@ -105,9 +114,8 @@ if (!Self.Owner.Shroud.IsExplored(xy)) return false; - var range = ((ChronoshiftPowerInfo)Info).Range; - var sourceTiles = Self.World.Map.FindTilesInCircle(xy, range); - var destTiles = Self.World.Map.FindTilesInCircle(sourceLocation, range); + var sourceTiles = CellsMatching(xy, footprint, dimensions); + var destTiles = CellsMatching(sourceLocation, footprint, dimensions); if (!sourceTiles.Any() || !destTiles.Any()) return false; @@ -132,7 +140,8 @@ class SelectChronoshiftTarget : OrderGenerator { readonly ChronoshiftPower power; - readonly int range; + readonly char[] footprint; + readonly CVec dimensions; readonly Sprite tile; readonly SupportPowerManager manager; readonly string order; @@ -148,7 +157,8 @@ this.power = power; var info = (ChronoshiftPowerInfo)power.Info; - range = info.Range; + footprint = info.Footprint.Where(c => !char.IsWhiteSpace(c)).ToArray(); + dimensions = info.Dimensions; tile = world.Map.Rules.Sequences.GetSequence(info.FootprintImage, info.SourceFootprintSequence).GetSprite(0); } @@ -164,7 +174,7 @@ protected override void Tick(World world) { // Cancel the OG if we can't use the power - if (!manager.Powers.ContainsKey(order)) + if (!manager.Powers.TryGetValue(order, out var p) || !p.Active || !p.Ready) world.CancelInputMode(); } @@ -179,8 +189,10 @@ { if (unit.CanBeViewedByPlayer(manager.Self.Owner)) { - var bounds = unit.TraitsImplementing().FirstNonEmptyBounds(unit, wr); - yield return new SelectionBoxAnnotationRenderable(unit, bounds, Color.Red); + var decorations = unit.TraitsImplementing().FirstEnabledTraitOrDefault(); + if (decorations != null) + foreach (var d in decorations.RenderSelectionAnnotations(unit, wr, Color.Red)) + yield return d; } } } @@ -188,10 +200,10 @@ protected override IEnumerable Render(WorldRenderer wr, World world) { var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos); - var tiles = world.Map.FindTilesInCircle(xy, range); + var tiles = power.CellsMatching(xy, footprint, dimensions); var palette = wr.Palette(((ChronoshiftPowerInfo)power.Info).TargetOverlayPalette); foreach (var t in tiles) - yield return new SpriteRenderable(tile, wr.World.Map.CenterOfCell(t), WVec.Zero, -511, palette, 1f, true); + yield return new SpriteRenderable(tile, wr.World.Map.CenterOfCell(t), WVec.Zero, -511, palette, 1f, true, true); } protected override string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi) @@ -204,7 +216,8 @@ { readonly ChronoshiftPower power; readonly CPos sourceLocation; - readonly int range; + readonly char[] footprint; + readonly CVec dimensions; readonly Sprite validTile, invalidTile, sourceTile; readonly SupportPowerManager manager; readonly string order; @@ -217,7 +230,8 @@ this.sourceLocation = sourceLocation; var info = (ChronoshiftPowerInfo)power.Info; - range = info.Range; + footprint = info.Footprint.Where(c => !char.IsWhiteSpace(c)).ToArray(); + dimensions = info.Dimensions; var sequences = world.Map.Rules.Sequences; var tilesetValid = info.ValidFootprintSequence + "-" + world.Map.Tileset.ToLowerInvariant(); @@ -260,7 +274,7 @@ protected override void Tick(World world) { // Cancel the OG if we can't use the power - if (!manager.Powers.ContainsKey(order)) + if (!manager.Powers.TryGetValue(order, out var p) || !p.Active || !p.Ready) world.CancelInputMode(); } @@ -271,10 +285,10 @@ // Destination tiles var delta = xy - sourceLocation; - foreach (var t in world.Map.FindTilesInCircle(sourceLocation, range)) + foreach (var t in power.CellsMatching(sourceLocation, footprint, dimensions)) { var tile = manager.Self.Owner.Shroud.IsExplored(t + delta) ? validTile : invalidTile; - yield return new SpriteRenderable(tile, wr.World.Map.CenterOfCell(t + delta), WVec.Zero, -511, palette, 1f, true); + yield return new SpriteRenderable(tile, wr.World.Map.CenterOfCell(t + delta), WVec.Zero, -511, palette, 1f, true, true); } // Unit previews @@ -286,7 +300,7 @@ var canEnter = manager.Self.Owner.Shroud.IsExplored(targetCell) && unit.Trait().CanChronoshiftTo(unit, targetCell); var tile = canEnter ? validTile : invalidTile; - yield return new SpriteRenderable(tile, wr.World.Map.CenterOfCell(targetCell), WVec.Zero, -511, palette, 1f, true); + yield return new SpriteRenderable(tile, wr.World.Map.CenterOfCell(targetCell), WVec.Zero, -511, palette, 1f, true, true); } var offset = world.Map.CenterOfCell(xy) - world.Map.CenterOfCell(sourceLocation); @@ -302,8 +316,10 @@ { if (unit.CanBeViewedByPlayer(manager.Self.Owner)) { - var bounds = unit.TraitsImplementing().FirstNonEmptyBounds(unit, wr); - yield return new SelectionBoxAnnotationRenderable(unit, bounds, Color.Red); + var decorations = unit.TraitsImplementing().FirstEnabledTraitOrDefault(); + if (decorations != null) + foreach (var d in decorations.RenderSelectionAnnotations(unit, wr, Color.Red)) + yield return d; } } } @@ -313,8 +329,8 @@ var palette = wr.Palette(power.Info.IconPalette); // Source tiles - foreach (var t in world.Map.FindTilesInCircle(sourceLocation, range)) - yield return new SpriteRenderable(sourceTile, wr.World.Map.CenterOfCell(t), WVec.Zero, -511, palette, 1f, true); + foreach (var t in power.CellsMatching(sourceLocation, footprint, dimensions)) + yield return new SpriteRenderable(sourceTile, wr.World.Map.CenterOfCell(t), WVec.Zero, -511, palette, 1f, true, true); } bool IsValidTarget(CPos xy) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/DropPodsPower.cs openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/DropPodsPower.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/DropPodsPower.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/DropPodsPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,158 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.GameRules; +using OpenRA.Mods.Cnc.Effects; +using OpenRA.Mods.Common; +using OpenRA.Mods.Common.Activities; +using OpenRA.Mods.Common.Traits; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Cnc.Traits +{ + public class DropPodsPowerInfo : SupportPowerInfo, IRulesetLoaded + { + [FieldLoader.Require] + [Desc("Drop pod unit")] + [ActorReference(new[] { typeof(AircraftInfo), typeof(FallsToEarthInfo) })] + public readonly string[] UnitTypes = null; + + [Desc("Number of drop pods spawned.")] + public readonly int2 Drops = new int2(5, 8); + + [Desc("Sets the approach direction.")] + public readonly WAngle PodFacing = new WAngle(128); + + [Desc("Maximum offset from targetLocation")] + public readonly int PodScatter = 3; + + [Desc("Effect sequence sprite image")] + public readonly string EntryEffect = "podring"; + + [Desc("Effect sequence to display in the air.")] + [SequenceReference(nameof(EntryEffect))] + public readonly string EntryEffectSequence = "idle"; + + [PaletteReference] + public readonly string EntryEffectPalette = "effect"; + + [ActorReference] + [Desc("Actor to spawn when the attack starts")] + public readonly string CameraActor = null; + + [Desc("Number of ticks to keep the camera alive")] + public readonly int CameraRemoveDelay = 25; + + [Desc("Which weapon to fire")] + [WeaponReference] + public readonly string Weapon = "Vulcan2"; + + public WeaponInfo WeaponInfo { get; private set; } + + [Desc("Apply the weapon impact this many ticks into the effect")] + public readonly int WeaponDelay = 0; + + public override object Create(ActorInitializer init) { return new DropPodsPower(init.Self, this); } + + public override void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + var weaponToLower = (Weapon ?? string.Empty).ToLowerInvariant(); + if (!rules.Weapons.TryGetValue(weaponToLower, out var weapon)) + throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); + + WeaponInfo = weapon; + + base.RulesetLoaded(rules, ai); + } + } + + public class DropPodsPower : SupportPower + { + readonly DropPodsPowerInfo info; + + public DropPodsPower(Actor self, DropPodsPowerInfo info) + : base(self, info) + { + this.info = info; + } + + public override void Activate(Actor self, Order order, SupportPowerManager manager) + { + base.Activate(self, order, manager); + + SendDropPods(self, order, info.PodFacing); + } + + public void SendDropPods(Actor self, Order order, WAngle facing) + { + var actorInfo = self.World.Map.Rules.Actors[info.UnitTypes.First().ToLowerInvariant()]; + var aircraftInfo = actorInfo.TraitInfo(); + var altitude = aircraftInfo.CruiseAltitude.Length; + var approachRotation = WRot.FromYaw(facing); + var fallsToEarthInfo = actorInfo.TraitInfo(); + var delta = new WVec(0, -altitude * aircraftInfo.Speed / fallsToEarthInfo.Velocity.Length, 0).Rotate(approachRotation); + + self.World.AddFrameEndTask(w => + { + var target = order.Target.CenterPosition; + var targetCell = self.World.Map.CellContaining(target); + var podLocations = self.World.Map.FindTilesInCircle(targetCell, info.PodScatter) + .Where(c => aircraftInfo.LandableTerrainTypes.Contains(w.Map.GetTerrainInfo(c).Type) + && !self.World.ActorMap.GetActorsAt(c).Any()); + + if (!podLocations.Any()) + return; + + if (info.CameraActor != null) + { + var camera = w.CreateActor(info.CameraActor, new TypeDictionary + { + new LocationInit(targetCell), + new OwnerInit(self.Owner), + }); + + camera.QueueActivity(new Wait(info.CameraRemoveDelay)); + camera.QueueActivity(new RemoveSelf()); + } + + PlayLaunchSounds(); + + var drops = self.World.SharedRandom.Next(info.Drops.X, info.Drops.Y); + for (var i = 0; i < drops; i++) + { + var unitType = info.UnitTypes.Random(self.World.SharedRandom); + var podLocation = podLocations.Random(self.World.SharedRandom); + var podTarget = Target.FromCell(w, podLocation); + var location = self.World.Map.CenterOfCell(podLocation) - delta + new WVec(0, 0, altitude); + + var pod = w.CreateActor(false, unitType, new TypeDictionary + { + new CenterPositionInit(location), + new OwnerInit(self.Owner), + new FacingInit(facing) + }); + + var aircraft = pod.Trait(); + if (!aircraft.CanLand(podLocation)) + pod.Dispose(); + else + { + w.Add(new DropPodImpact(self.Owner, info.WeaponInfo, w, location, podTarget, info.WeaponDelay, + info.EntryEffect, info.EntryEffectSequence, info.EntryEffectPalette)); + w.Add(pod); + } + } + }); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/GpsPower.cs openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/GpsPower.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/GpsPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/GpsPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,10 +25,10 @@ public readonly string DoorImage = "atek"; - [SequenceReference("DoorImage")] + [SequenceReference(nameof(DoorImage))] public readonly string DoorSequence = "active"; - [PaletteReference("DoorPaletteIsPlayerPalette")] + [PaletteReference(nameof(DoorPaletteIsPlayerPalette))] [Desc("Palette to use for rendering the launch animation")] public readonly string DoorPalette = "player"; @@ -37,10 +37,10 @@ public readonly string SatelliteImage = "sputnik"; - [SequenceReference("SatelliteImage")] + [SequenceReference(nameof(SatelliteImage))] public readonly string SatelliteSequence = "idle"; - [PaletteReference("SatellitePaletteIsPlayerPalette")] + [PaletteReference(nameof(SatellitePaletteIsPlayerPalette))] [Desc("Palette to use for rendering the satellite projectile")] public readonly string SatellitePalette = "player"; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/GrantPrerequisiteChargeDrainPower.cs openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/GrantPrerequisiteChargeDrainPower.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/GrantPrerequisiteChargeDrainPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/GrantPrerequisiteChargeDrainPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -56,13 +56,7 @@ protected override void Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query other player traits from self, knowing that - // it refers to the same actor as self.Owner.PlayerActor - var playerActor = self.Info.Name == "player" ? self : self.Owner.PlayerActor; - - techTree = playerActor.Trait(); + techTree = self.Owner.PlayerActor.Trait(); base.Created(self); } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/IonCannonPower.cs openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/IonCannonPower.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/SupportPowers/IonCannonPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/SupportPowers/IonCannonPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -30,7 +30,7 @@ [Desc("Effect sequence sprite image")] public readonly string Effect = "ionsfx"; - [SequenceReference("Effect")] + [SequenceReference(nameof(Effect))] [Desc("Effect sequence to display")] public readonly string EffectSequence = "idle"; @@ -52,9 +52,8 @@ public override object Create(ActorInitializer init) { return new IonCannonPower(init.Self, this); } public override void RulesetLoaded(Ruleset rules, ActorInfo ai) { - WeaponInfo weapon; var weaponToLower = (Weapon ?? string.Empty).ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(weaponToLower, out weapon)) + if (!rules.Weapons.TryGetValue(weaponToLower, out var weapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); WeaponInfo = weapon; diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/TDGunboat.cs openra-20210321/OpenRA.Mods.Cnc/Traits/TDGunboat.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/TDGunboat.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/TDGunboat.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,21 +19,22 @@ namespace OpenRA.Mods.Cnc.Traits { - public class TDGunboatInfo : ITraitInfo, IPositionableInfo, IFacingInfo, IMoveInfo, IActorPreviewInitInfo + public class TDGunboatInfo : TraitInfo, IPositionableInfo, IFacingInfo, IMoveInfo, IActorPreviewInitInfo { public readonly int Speed = 28; - [Desc("Facing to use when actor spawns. Only 64 and 192 supported.")] - public readonly int InitialFacing = 64; + [Desc("Facing to use when actor spawns. Only 256 and 768 supported.")] + public readonly WAngle InitialFacing = new WAngle(256); - [Desc("Facing to use for actor previews (map editor, color picker, etc). Only 64 and 192 supported.")] - public readonly int PreviewFacing = 64; + [Desc("Facing to use for actor previews (map editor, color picker, etc). Only 256 and 768 supported.")] + public readonly WAngle PreviewFacing = new WAngle(256); - public virtual object Create(ActorInitializer init) { return new TDGunboat(init, this); } + public override object Create(ActorInitializer init) { return new TDGunboat(init, this); } - public int GetInitialFacing() { return InitialFacing; } + public WAngle GetInitialFacing() { return InitialFacing; } + public Color GetTargetLineColor() { return Color.Green; } - IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) + IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) { yield return new FacingInit(PreviewFacing); } @@ -58,12 +59,22 @@ { public readonly TDGunboatInfo Info; readonly Actor self; + static readonly WAngle Left = new WAngle(256); + static readonly WAngle Right = new WAngle(768); IEnumerable speedModifiers; INotifyVisualPositionChanged[] notifyVisualPositionChanged; + WRot orientation; + [Sync] - public int Facing { get; set; } + public WAngle Facing + { + get { return orientation.Yaw; } + set { orientation = orientation.WithYaw(value); } + } + + public WRot Orientation { get { return orientation; } } [Sync] public WPos CenterPosition { get; private set; } @@ -71,7 +82,7 @@ public CPos TopLeft { get { return self.World.Map.CellContaining(CenterPosition); } } // Isn't used anyway - public int TurnSpeed { get { return 255; } } + public WAngle TurnSpeed { get { return WAngle.Zero; } } CPos cachedLocation; @@ -80,17 +91,19 @@ Info = info; self = init.Self; - if (init.Contains()) - SetPosition(self, init.Get()); - - if (init.Contains()) - SetPosition(self, init.Get()); + var locationInit = init.GetOrDefault(); + if (locationInit != null) + SetPosition(self, locationInit.Value); + + var centerPositionInit = init.GetOrDefault(); + if (centerPositionInit != null) + SetPosition(self, centerPositionInit.Value); - Facing = init.Contains() ? init.Get() : Info.GetInitialFacing(); + Facing = init.GetValue(Info.GetInitialFacing()); // Prevent mappers from setting bogus facings - if (Facing != 64 && Facing != 192) - Facing = Facing > 127 ? 192 : 64; + if (Facing != Left && Facing != Right) + Facing = Facing.Angle > 511 ? Right : Left; } void INotifyCreated.Created(Actor self) @@ -126,27 +139,24 @@ void Turn() { - if (Facing == 64) - Facing = 192; - else - Facing = 64; + Facing = Facing == Left ? Right : Left; } int MovementSpeed { - get { return Util.ApplyPercentageModifiers(Info.Speed, speedModifiers); } + get { return OpenRA.Mods.Common.Util.ApplyPercentageModifiers(Info.Speed, speedModifiers); } } - public Pair[] OccupiedCells() { return new[] { Pair.New(TopLeft, SubCell.FullCell) }; } + public (CPos, SubCell)[] OccupiedCells() { return new[] { (TopLeft, SubCell.FullCell) }; } - WVec MoveStep(int facing) + WVec MoveStep(WAngle facing) { return MoveStep(MovementSpeed, facing); } - WVec MoveStep(int speed, int facing) + WVec MoveStep(int speed, WAngle facing) { - var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing)); + var dir = new WVec(0, -1024, 0).Rotate(WRot.FromYaw(facing)); return speed * dir / 1024; } @@ -174,12 +184,16 @@ public void SetPosition(Actor self, WPos pos) { + if (self.IsInWorld) + self.World.ActorMap.RemoveInfluence(self, this); + CenterPosition = pos; if (!self.IsInWorld) return; self.World.UpdateMaps(self, this); + self.World.ActorMap.AddInfluence(self, this); // This can be called from the constructor before notifyVisualPositionChanged is assigned. if (notifyVisualPositionChanged != null) @@ -189,16 +203,16 @@ public Activity MoveTo(CPos cell, int nearEnough = 0, Actor ignoreActor = null, bool evaluateNearestMovableCell = false, Color? targetLineColor = null) { return null; } - public Activity MoveWithinRange(Target target, WDist range, + public Activity MoveWithinRange(in Target target, WDist range, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; } - public Activity MoveWithinRange(Target target, WDist minRange, WDist maxRange, + public Activity MoveWithinRange(in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; } - public Activity MoveFollow(Actor self, Target target, WDist minRange, WDist maxRange, + public Activity MoveFollow(Actor self, in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; } public Activity ReturnToCell(Actor self) { return null; } - public Activity MoveToTarget(Actor self, Target target, + public Activity MoveToTarget(Actor self, in Target target, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; } - public Activity MoveIntoTarget(Actor self, Target target) { return null; } + public Activity MoveIntoTarget(Actor self, in Target target) { return null; } public Activity VisualMove(Actor self, WPos fromPos, WPos toPos) { return null; } public int EstimatedMoveDuration(Actor self, WPos fromPos, WPos toPos) @@ -211,7 +225,7 @@ // Actors with TDGunboat always move public MovementType CurrentMovementTypes { get { return MovementType.Horizontal; } set { } } - public bool CanEnterTargetNow(Actor self, Target target) + public bool CanEnterTargetNow(Actor self, in Target target) { return false; } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/TransferTimedExternalConditionOnTransform.cs openra-20210321/OpenRA.Mods.Cnc/Traits/TransferTimedExternalConditionOnTransform.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/TransferTimedExternalConditionOnTransform.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/TransferTimedExternalConditionOnTransform.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,13 +18,13 @@ [Desc("A special case trait that re-grants a timed external condition when this actor transforms.", "This trait does not work with permanently granted external conditions.", "This trait changes the external condition source, so cannot be used for conditions that may later be revoked")] - public class TransferTimedExternalConditionOnTransformInfo : ITraitInfo, Requires + public class TransferTimedExternalConditionOnTransformInfo : TraitInfo, Requires { [FieldLoader.Require] [Desc("External condition to transfer")] public readonly string Condition = null; - public object Create(ActorInitializer init) { return new TransferTimedExternalConditionOnTransform(this); } + public override object Create(ActorInitializer init) { return new TransferTimedExternalConditionOnTransform(this); } } public class TransferTimedExternalConditionOnTransform : IConditionTimerWatcher, INotifyTransform @@ -49,8 +49,7 @@ var external = toActor.TraitsImplementing() .FirstOrDefault(t => t.Info.Condition == info.Condition && t.CanGrantCondition(toActor, this)); - if (external != null) - external.GrantCondition(toActor, this, duration, remaining); + external?.GrantCondition(toActor, this, duration, remaining); } void IConditionTimerWatcher.Update(int duration, int remaining) diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/TransformsNearResources.cs openra-20210321/OpenRA.Mods.Cnc/Traits/TransformsNearResources.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/TransformsNearResources.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/TransformsNearResources.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,102 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Mods.Common.Activities; +using OpenRA.Mods.Common.Traits; +using OpenRA.Traits; + +namespace OpenRA.Mods.Cnc.Traits +{ + [Desc("Replace with another actor when a resource spawns adjacent.")] + public class TransformsNearResourcesInfo : TraitInfo + { + [FieldLoader.Require] + [ActorReference] + public readonly string IntoActor = null; + + public readonly CVec Offset = CVec.Zero; + + [Desc("Don't render the make animation.")] + public readonly bool SkipMakeAnims = false; + + [FieldLoader.Require] + [Desc("Resource type which triggers the transformation.")] + public readonly string Type = null; + + [Desc("Resource density threshold which is required.")] + public readonly int Density = 1; + + [Desc("This many adjacent resource tiles are required.")] + public readonly int Adjacency = 1; + + [Desc("The range of time (in ticks) until the transformation starts.")] + public readonly int[] Delay = { 1000, 3000 }; + + public override object Create(ActorInitializer init) { return new TransformsNearResources(init.Self, this); } + } + + public class TransformsNearResources : ITick + { + readonly TransformsNearResourcesInfo info; + readonly ResourceLayer resourceLayer; + int delay; + + public TransformsNearResources(Actor self, TransformsNearResourcesInfo info) + { + resourceLayer = self.World.WorldActor.Trait(); + delay = Common.Util.RandomDelay(self.World, info.Delay); + this.info = info; + } + + void ITick.Tick(Actor self) + { + if (delay < 0) + return; + + var adjacent = 0; + foreach (var direction in CVec.Directions) + { + var location = self.Location + direction; + + var resource = resourceLayer.GetResourceType(location); + if (resource == null || resource.Info.Type != info.Type) + continue; + + var density = resourceLayer.GetResourceDensity(location); + if (density < info.Density) + continue; + + if (++adjacent < info.Adjacency) + continue; + + delay--; + break; + } + + if (delay < 0) + Transform(self); + } + + void Transform(Actor self) + { + var transform = new Transform(self, info.IntoActor); + + var facing = self.TraitOrDefault(); + if (facing != null) + transform.Facing = facing.Facing; + + transform.SkipMakeAnims = info.SkipMakeAnims; + transform.Offset = info.Offset; + + self.QueueActivity(false, transform); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/World/ShroudPalette.cs openra-20210321/OpenRA.Mods.Cnc/Traits/World/ShroudPalette.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/World/ShroudPalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/World/ShroudPalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Cnc.Traits { [Desc("Adds the hard-coded shroud palette to the game")] - class ShroudPaletteInfo : ITraitInfo + class ShroudPaletteInfo : TraitInfo { [PaletteDefinition] [FieldLoader.Require] @@ -29,7 +29,7 @@ [Desc("Palette type")] public readonly bool Fog = false; - public object Create(ActorInitializer init) { return new ShroudPalette(this); } + public override object Create(ActorInitializer init) { return new ShroudPalette(this); } } class ShroudPalette : ILoadsPalettes, IProvidesAssetBrowserPalettes diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/World/TSShroudPalette.cs openra-20210321/OpenRA.Mods.Cnc/Traits/World/TSShroudPalette.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/World/TSShroudPalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/World/TSShroudPalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,14 +19,14 @@ namespace OpenRA.Mods.Cnc.Traits { [Desc("Adds the hard-coded shroud palette to the game")] - class TSShroudPaletteInfo : ITraitInfo + class TSShroudPaletteInfo : TraitInfo { [PaletteDefinition] [FieldLoader.Require] [Desc("Internal palette name")] public readonly string Name = "shroud"; - public object Create(ActorInitializer init) { return new TSShroudPalette(this); } + public override object Create(ActorInitializer init) { return new TSShroudPalette(this); } } class TSShroudPalette : ILoadsPalettes, IProvidesAssetBrowserPalettes diff -Nru openra-20200503/OpenRA.Mods.Cnc/Traits/World/VoxelNormalsPalette.cs openra-20210321/OpenRA.Mods.Cnc/Traits/World/VoxelNormalsPalette.cs --- openra-20200503/OpenRA.Mods.Cnc/Traits/World/VoxelNormalsPalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Traits/World/VoxelNormalsPalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Cnc.Traits { - public class VoxelNormalsPaletteInfo : ITraitInfo + public class VoxelNormalsPaletteInfo : TraitInfo { [PaletteDefinition] public readonly string Name = "normals"; @@ -23,7 +23,7 @@ [Desc("Can be TiberianSun or RedAlert2")] public readonly NormalType Type = NormalType.TiberianSun; - public object Create(ActorInitializer init) { return new VoxelNormalsPalette(this); } + public override object Create(ActorInitializer init) { return new VoxelNormalsPalette(this); } } public class VoxelNormalsPalette : ILoadsPalettes diff -Nru openra-20200503/OpenRA.Mods.Cnc/TraitsInterfaces.cs openra-20210321/OpenRA.Mods.Cnc/TraitsInterfaces.cs --- openra-20200503/OpenRA.Mods.Cnc/TraitsInterfaces.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/TraitsInterfaces.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,5 +14,5 @@ namespace OpenRA.Mods.Cnc.Traits { [RequireExplicitImplementation] - public interface INotifyTeslaCharging { void Charging(Actor self, Target target); } + public interface INotifyTeslaCharging { void Charging(Actor self, in Target target); } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/Util.cs openra-20210321/OpenRA.Mods.Cnc/Util.cs --- openra-20200503/OpenRA.Mods.Cnc/Util.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/Util.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,69 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +namespace OpenRA.Mods.Cnc +{ + public static class Util + { + // TD and RA used a nonlinear mapping between artwork frames and unit facings for units with 32 facings. + // This table defines the exclusive maximum facing for the i'th sprite frame. + // i.e. sprite frame 1 is used for facings 20-55, sprite frame 2 for 56-87, and so on. + // Sprite frame 0 is used for facings smaller than 20 or larger than 999. + static readonly int[] SpriteRanges = + { + 20, 56, 88, 132, 156, 184, 212, 240, + 268, 296, 324, 352, 384, 416, 452, 488, + 532, 568, 604, 644, 668, 696, 724, 752, + 780, 808, 836, 864, 896, 928, 964, 1000 + }; + + // The actual facing associated with each sprite frame. + static readonly WAngle[] SpriteFacings = + { + WAngle.Zero, new WAngle(40), new WAngle(74), new WAngle(112), new WAngle(146), new WAngle(172), new WAngle(200), new WAngle(228), + new WAngle(256), new WAngle(284), new WAngle(312), new WAngle(340), new WAngle(370), new WAngle(402), new WAngle(436), new WAngle(472), + new WAngle(512), new WAngle(552), new WAngle(588), new WAngle(626), new WAngle(658), new WAngle(684), new WAngle(712), new WAngle(740), + new WAngle(768), new WAngle(796), new WAngle(824), new WAngle(852), new WAngle(882), new WAngle(914), new WAngle(948), new WAngle(984) + }; + + /// + /// Calculate the frame index (between 0..numFrames) that + /// should be used for the given facing value, accounting + /// for the non-linear facing mapping for sprites with 32 directions. + /// + public static int ClassicIndexFacing(WAngle facing, int numFrames) + { + if (numFrames == 32) + { + var angle = facing.Angle; + for (var i = 0; i < SpriteRanges.Length; i++) + if (angle < SpriteRanges[i]) + return i; + + return 0; + } + + return Common.Util.IndexFacing(facing, numFrames); + } + + /// + /// Rounds the given facing value to the nearest quantized step, + /// accounting for the non-linear facing mapping for sprites with 32 directions. + /// + public static WAngle ClassicQuantizeFacing(WAngle facing, int steps) + { + if (steps == 32) + return SpriteFacings[ClassicIndexFacing(facing, steps)]; + + return Common.Util.QuantizeFacing(facing, steps); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Cnc/UtilityCommands/ImportRedAlertLegacyMapCommand.cs openra-20210321/OpenRA.Mods.Cnc/UtilityCommands/ImportRedAlertLegacyMapCommand.cs --- openra-20200503/OpenRA.Mods.Cnc/UtilityCommands/ImportRedAlertLegacyMapCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/UtilityCommands/ImportRedAlertLegacyMapCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,6 @@ using OpenRA.Mods.Cnc.FileFormats; using OpenRA.Mods.Common.FileFormats; using OpenRA.Mods.Common.UtilityCommands; -using OpenRA.Primitives; namespace OpenRA.Mods.Cnc.UtilityCommands { @@ -52,17 +51,17 @@ "fpls", "wcrate", "scrate", "barb", "sbag", }; - static Dictionary> overlayResourceMapping = new Dictionary>() + static Dictionary overlayResourceMapping = new Dictionary() { // RA ore & crystals - { "gold01", new Pair(1, 0) }, - { "gold02", new Pair(1, 1) }, - { "gold03", new Pair(1, 2) }, - { "gold04", new Pair(1, 3) }, - { "gem01", new Pair(2, 0) }, - { "gem02", new Pair(2, 1) }, - { "gem03", new Pair(2, 2) }, - { "gem04", new Pair(2, 3) }, + { "gold01", (1, 0) }, + { "gold02", (1, 1) }, + { "gold03", (1, 2) }, + { "gold04", (1, 3) }, + { "gem01", (2, 0) }, + { "gem02", (2, 1) }, + { "gem03", (2, 2) }, + { "gem04", (2, 3) }, }; void UnpackTileData(MemoryStream ms) @@ -101,13 +100,13 @@ for (var i = 0; i < MapSize; i++) { var o = ms.ReadUInt8(); - var res = Pair.New((byte)0, (byte)0); + var res = (Type: (byte)0, Index: (byte)0); if (o != 255 && overlayResourceMapping.ContainsKey(redAlertOverlayNames[o])) res = overlayResourceMapping[redAlertOverlayNames[o]]; var cell = new CPos(i, j); - Map.Resources[cell] = new ResourceTile(res.First, res.Second); + Map.Resources[cell] = new ResourceTile(res.Type, res.Index); if (o != 255 && overlayActors.Contains(redAlertOverlayNames[o])) { diff -Nru openra-20200503/OpenRA.Mods.Cnc/UtilityCommands/ImportTiberianDawnLegacyMapCommand.cs openra-20210321/OpenRA.Mods.Cnc/UtilityCommands/ImportTiberianDawnLegacyMapCommand.cs --- openra-20200503/OpenRA.Mods.Cnc/UtilityCommands/ImportTiberianDawnLegacyMapCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/UtilityCommands/ImportTiberianDawnLegacyMapCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,6 @@ using System.Linq; using OpenRA.Mods.Common.FileFormats; using OpenRA.Mods.Common.UtilityCommands; -using OpenRA.Primitives; namespace OpenRA.Mods.Cnc.UtilityCommands { @@ -40,21 +39,21 @@ } } - static Dictionary> overlayResourceMapping = new Dictionary>() + static Dictionary overlayResourceMapping = new Dictionary() { // Tiberium - { "ti1", new Pair(1, 0) }, - { "ti2", new Pair(1, 1) }, - { "ti3", new Pair(1, 2) }, - { "ti4", new Pair(1, 3) }, - { "ti5", new Pair(1, 4) }, - { "ti6", new Pair(1, 5) }, - { "ti7", new Pair(1, 6) }, - { "ti8", new Pair(1, 7) }, - { "ti9", new Pair(1, 8) }, - { "ti10", new Pair(1, 9) }, - { "ti11", new Pair(1, 10) }, - { "ti12", new Pair(1, 11) }, + { "ti1", (1, 0) }, + { "ti2", (1, 1) }, + { "ti3", (1, 2) }, + { "ti4", (1, 3) }, + { "ti5", (1, 4) }, + { "ti6", (1, 5) }, + { "ti7", (1, 6) }, + { "ti8", (1, 7) }, + { "ti9", (1, 8) }, + { "ti10", (1, 9) }, + { "ti11", (1, 10) }, + { "ti12", (1, 11) }, }; void UnpackTileData(Stream ms) @@ -93,12 +92,12 @@ var loc = Exts.ParseIntegerInvariant(kv.Key); var cell = new CPos(loc % MapSize, loc / MapSize); - var res = Pair.New((byte)0, (byte)0); + var res = (Type: (byte)0, Index: (byte)0); var type = kv.Value.ToLowerInvariant(); if (overlayResourceMapping.ContainsKey(type)) res = overlayResourceMapping[type]; - Map.Resources[cell] = new ResourceTile(res.First, res.Second); + Map.Resources[cell] = new ResourceTile(res.Type, res.Index); if (overlayActors.Contains(type)) { var ar = new ActorReference(type) @@ -115,7 +114,17 @@ public override string ParseTreeActor(string input) { - return input.Split(',')[0].ToLowerInvariant(); + var tree = input.Split(',')[0].ToLowerInvariant(); + + switch (tree) + { + case "split2": + return "t03.transformable"; + case "split3": + return "t13.transformable"; + default: + return tree; + } } public override CPos ParseActorLocation(string input, int loc) diff -Nru openra-20200503/OpenRA.Mods.Cnc/UtilityCommands/ImportTSMapCommand.cs openra-20210321/OpenRA.Mods.Cnc/UtilityCommands/ImportTSMapCommand.cs --- openra-20200503/OpenRA.Mods.Cnc/UtilityCommands/ImportTSMapCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/UtilityCommands/ImportTSMapCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -108,6 +108,7 @@ { 0x7D, "lobrdg_r_sw" }, // lobrdg4 // Other + { 0x1B, "bigblue" }, { 0xA7, "veinhole" }, { 0xA8, "srock01" }, { 0xA9, "srock02" }, @@ -241,6 +242,14 @@ { "gatick", "ttnk" } }; + static readonly string[] LampActors = + { + "GALITE", "INGALITE", "NEGLAMP", "REDLAMP", "NEGRED", "GRENLAMP", "BLUELAMP", "YELWLAMP", + "INYELWLAMP", "PURPLAMP", "INPURPLAMP", "INORANLAMP", "INGRNLMP", "INREDLMP", "INBLULMP" + }; + + static readonly string[] CreepActors = { "DOGGIE", "VISC_SML", "VISC_LRG", "JFISH" }; + [Desc("FILENAME", "Convert a Tiberian Sun map to the OpenRA format.")] void IUtilityCommand.Run(Utility utility, string[] args) { @@ -273,6 +282,7 @@ ReadWaypoints(map, file, fullSize); ReadOverlay(map, file, fullSize); ReadLighting(map, file); + ReadLamps(map, file); var spawnCount = map.ActorDefinitions.Count(n => n.Value.Value == "mpspawn"); var mapPlayers = new MapPlayers(map.Rules, spawnCount); @@ -394,8 +404,7 @@ if (overlayType == 0xFF) continue; - string actorType; - if (OverlayToActor.TryGetValue(overlayType, out actorType)) + if (OverlayToActor.TryGetValue(overlayType, out var actorType)) { if (string.IsNullOrEmpty(actorType)) continue; @@ -406,19 +415,13 @@ // Only import the top-left cell of multi-celled overlays var aboveType = overlayPack[overlayIndex[cell - new CVec(1, 0)]]; if (shape.Width > 1 && aboveType != 0xFF) - { - string a; - if (OverlayToActor.TryGetValue(aboveType, out a) && a == actorType) + if (OverlayToActor.TryGetValue(aboveType, out var a) && a == actorType) continue; - } var leftType = overlayPack[overlayIndex[cell - new CVec(0, 1)]]; if (shape.Height > 1 && leftType != 0xFF) - { - string a; - if (OverlayToActor.TryGetValue(leftType, out a) && a == actorType) + if (OverlayToActor.TryGetValue(leftType, out var a) && a == actorType) continue; - } } var ar = new ActorReference(actorType) @@ -427,8 +430,7 @@ new OwnerInit("Neutral") }; - DamageState damageState; - if (OverlayToHealth.TryGetValue(overlayType, out damageState)) + if (OverlayToHealth.TryGetValue(overlayType, out var damageState)) { var health = 100; if (damageState == DamageState.Critical) @@ -474,8 +476,7 @@ var dy = rx + ry - fullSize.X - 1; var cell = new MPos(dx / 2, dy).ToCPos(map); - int wpindex; - var ar = new ActorReference((!int.TryParse(kv.Key, out wpindex) || wpindex > 7) ? "waypoint" : "mpspawn"); + var ar = new ActorReference((!int.TryParse(kv.Key, out var wpindex) || wpindex > 7) ? "waypoint" : "mpspawn"); ar.Add(new LocationInit(cell)); ar.Add(new OwnerInit("Neutral")); @@ -526,7 +527,7 @@ var health = short.Parse(entries[2]); var rx = int.Parse(entries[3]); var ry = int.Parse(entries[4]); - var facing = (byte)(byte.Parse(entries[5]) + 96); + var facing = (byte)(224 - byte.Parse(entries[5])); var dx = rx - ry + fullSize.X - 1; var dy = rx + ry - fullSize.X - 1; @@ -535,14 +536,13 @@ var ar = new ActorReference(name) { new LocationInit(cell), - new OwnerInit("Neutral") + new OwnerInit(CreepActors.Contains(entries[1]) ? "Creeps" : "Neutral") }; if (health != 256) ar.Add(new HealthInit(100 * health / 256)); - if (facing != 96) - ar.Add(new FacingInit(facing)); + ar.Add(new FacingInit(WAngle.FromFacing(facing))); if (isDeployed) ar.Add(new DeployStateInit(DeployState.Deployed)); @@ -556,29 +556,91 @@ static void ReadLighting(Map map, IniFile file) { - var lightingTypes = new[] { "Red", "Green", "Blue", "Ambient" }; + var lightingTypes = new Dictionary() + { + { "Red", "RedTint" }, + { "Green", "GreenTint" }, + { "Blue", "BlueTint" }, + { "Ambient", "Intensity" }, + { "Level", "HeightStep" }, + { "Ground", null } + }; + var lightingSection = file.GetSection("Lighting"); + var parsed = new Dictionary(); var lightingNodes = new List(); foreach (var kv in lightingSection) { - if (lightingTypes.Contains(kv.Key)) - { - var val = FieldLoader.GetValue(kv.Key, kv.Value); - if (val != 1.0f) - lightingNodes.Add(new MiniYamlNode(kv.Key, FieldSaver.FormatValue(val))); - } + if (lightingTypes.ContainsKey(kv.Key)) + parsed[kv.Key] = FieldLoader.GetValue(kv.Key, kv.Value); else Console.WriteLine("Ignoring unknown lighting type: `{0}`".F(kv.Key)); } + // Merge Ground into Ambient + float ground = 0; + if (parsed.TryGetValue("Ground", out ground)) + { + if (!parsed.ContainsKey("Ambient")) + parsed["Ambient"] = 1f; + parsed["Ambient"] -= ground; + } + + foreach (var node in lightingTypes) + { + if (node.Value != null && parsed.TryGetValue(node.Key, out var val) && ((node.Key == "Level" && val != 0) || (node.Key != "Level" && val != 1.0f))) + lightingNodes.Add(new MiniYamlNode(node.Value, FieldSaver.FormatValue(val))); + } + if (lightingNodes.Any()) { - map.RuleDefinitions.Nodes.Add(new MiniYamlNode("World", new MiniYaml("", new List() + map.RuleDefinitions.Nodes.Add(new MiniYamlNode("^BaseWorld", new MiniYaml("", new List() { - new MiniYamlNode("GlobalLightingPaletteEffect", new MiniYaml("", lightingNodes)) + new MiniYamlNode("TerrainLighting", new MiniYaml("", lightingNodes)) }))); } } + + static void ReadLamps(Map map, IniFile file) + { + var lightingTypes = new Dictionary() + { + { "LightIntensity", "Intensity" }, + { "LightRedTint", "RedTint" }, + { "LightGreenTint", "GreenTint" }, + { "LightBlueTint", "BlueTint" }, + }; + + foreach (var lamp in LampActors) + { + var lightingSection = file.GetSection(lamp, true); + var lightingNodes = new List(); + + foreach (var kv in lightingSection) + { + if (kv.Key == "LightVisibility") + { + // Convert leptons to WDist + var visibility = FieldLoader.GetValue(kv.Key, kv.Value); + lightingNodes.Add(new MiniYamlNode("Range", FieldSaver.FormatValue(new WDist(visibility * 4)))); + } + else if (lightingTypes.ContainsKey(kv.Key)) + { + // Some maps use "," instead of "."! + var value = FieldLoader.GetValue(kv.Key, kv.Value.Replace(',', '.')); + lightingNodes.Add(new MiniYamlNode(lightingTypes[kv.Key], FieldSaver.FormatValue(value))); + } + } + + if (lightingNodes.Any()) + { + map.RuleDefinitions.Nodes.Add(new MiniYamlNode(lamp, new MiniYaml("", new List() + { + new MiniYamlNode("TerrainLightSource", new MiniYaml("", lightingNodes)) + }))); + } + } + } } } diff -Nru openra-20200503/OpenRA.Mods.Cnc/UtilityCommands/LegacySequenceImporter.cs openra-20210321/OpenRA.Mods.Cnc/UtilityCommands/LegacySequenceImporter.cs --- openra-20200503/OpenRA.Mods.Cnc/UtilityCommands/LegacySequenceImporter.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/UtilityCommands/LegacySequenceImporter.cs 2021-03-21 11:10:05.000000000 +0000 @@ -265,9 +265,8 @@ else Console.WriteLine("\t\tFacings: 8"); - int length, stride; - int.TryParse(splitting[2], out stride); - int.TryParse(splitting[1], out length); + int.TryParse(splitting[2], out var stride); + int.TryParse(splitting[1], out var length); if (stride != 0 && stride != length) Console.WriteLine("\t\tStride: " + stride); } diff -Nru openra-20200503/OpenRA.Mods.Cnc/UtilityCommands/LegacyTilesetImporter.cs openra-20210321/OpenRA.Mods.Cnc/UtilityCommands/LegacyTilesetImporter.cs --- openra-20200503/OpenRA.Mods.Cnc/UtilityCommands/LegacyTilesetImporter.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Cnc/UtilityCommands/LegacyTilesetImporter.cs 2021-03-21 11:10:05.000000000 +0000 @@ -65,8 +65,7 @@ var name = args.Length > 3 ? args[3] : Path.GetFileNameWithoutExtension(args[2]); metadata.AppendLine("\tName: {0}".F(name)); metadata.AppendLine("\tId: {0}".F(name.ToUpperInvariant())); - metadata.AppendLine("\tPalette: iso{0}.pal".F(extension)); - metadata.AppendLine("\tHeightDebugColors: 00000080, 00004480, 00008880, 0000CC80, 0000FF80, 4400CC80," + + metadata.AppendLine("\tHeightDebugColors: 00000080, 00004480, 00008880, 0000CC80, 0000FF80, 4400CC80," + " 88008880, CC004480, FF110080, FF550080, FF990080, FFDD0080, DDFF0080, 99FF0080, 55FF0080, 11FF0080"); // Loop over template sets @@ -96,7 +95,7 @@ using (var s = modData.DefaultFileSystem.Open(templateFilename)) { data.AppendLine("\tTemplate@{0}:".F(templateIndex)); - data.AppendLine("\t\tCategory: {0}".F(sectionCategory)); + data.AppendLine("\t\tCategories: {0}".F(sectionCategory)); usedCategories.Add(sectionCategory); data.AppendLine("\t\tId: {0}".F(templateIndex)); @@ -144,8 +143,8 @@ if (rampType != 0) data.AppendLine("\t\t\t\tRampType: {0}".F(rampType)); - data.AppendLine("\t\t\t\tLeftColor: {0:X2}{1:X2}{2:X2}".F(s.ReadUInt8(), s.ReadUInt8(), s.ReadUInt8())); - data.AppendLine("\t\t\t\tRightColor: {0:X2}{1:X2}{2:X2}".F(s.ReadUInt8(), s.ReadUInt8(), s.ReadUInt8())); + data.AppendLine("\t\t\t\tMinColor: {0:X2}{1:X2}{2:X2}".F(s.ReadUInt8(), s.ReadUInt8(), s.ReadUInt8())); + data.AppendLine("\t\t\t\tMaxColor: {0:X2}{1:X2}{2:X2}".F(s.ReadUInt8(), s.ReadUInt8(), s.ReadUInt8())); data.AppendLine("\t\t\t\tZOffset: {0}".F(-tileSize.Height / 2.0f)); data.AppendLine("\t\t\t\tZRamp: 0"); } diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/FallToEarth.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/FallToEarth.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/FallToEarth.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/FallToEarth.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System; -using System.Linq; using OpenRA.Activities; using OpenRA.Mods.Common.Traits; using OpenRA.Traits; @@ -30,7 +29,7 @@ this.info = info; IsInterruptible = false; aircraft = self.Trait(); - if (info.MaximumSpinSpeed != 0) + if (!info.MaximumSpinSpeed.HasValue || info.MaximumSpinSpeed.Value != WAngle.Zero) acceleration = self.World.SharedRandom.Next(2) * 2 - 1; } @@ -49,12 +48,13 @@ return true; } - if (info.MaximumSpinSpeed != 0) + if (acceleration != 0) { - if (info.MaximumSpinSpeed < 0 || Math.Abs(spin) < info.MaximumSpinSpeed) - spin += acceleration; // TODO: Possibly unhardcode this + if (!info.MaximumSpinSpeed.HasValue || Math.Abs(spin) < info.MaximumSpinSpeed.Value.Angle) + spin += 4 * acceleration; // TODO: Possibly unhardcode this - aircraft.Facing = (aircraft.Facing + spin) % 256; + // Allow for negative spin values and convert from facing to angle units + aircraft.Facing = new WAngle(aircraft.Facing.Angle + spin); } var move = info.Moves ? aircraft.FlyStep(aircraft.Facing) : WVec.Zero; diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyAttack.cs 2021-03-21 11:10:05.000000000 +0000 @@ -37,7 +37,7 @@ bool hasTicked; bool returnToBase; - public FlyAttack(Actor self, AttackSource source, Target target, bool forceAttack, Color? targetLineColor) + public FlyAttack(Actor self, AttackSource source, in Target target, bool forceAttack, Color? targetLineColor) { this.source = source; this.target = target; @@ -90,8 +90,7 @@ if (attackAircraft.IsTraitPaused) return false; - bool targetIsHiddenActor; - target = target.Recalculate(self.Owner, out targetIsHiddenActor); + target = target.Recalculate(self.Owner, out var targetIsHiddenActor); attackAircraft.SetRequestedTarget(self, target, forceAttack); hasTicked = true; @@ -129,8 +128,8 @@ return true; // AbortOnResupply cancels the current activity (after resupplying) plus any queued activities - if (attackAircraft.Info.AbortOnResupply && NextActivity != null) - NextActivity.Cancel(self); + if (attackAircraft.Info.AbortOnResupply) + NextActivity?.Cancel(self); QueueChild(new ReturnToBase(self)); returnToBase = true; @@ -143,6 +142,13 @@ // We don't know where the target actually is, so move to where we last saw it if (useLastVisibleTarget) { + // HACK: Bot players ignore the standard visibility checks in target.Recalculate, + // which means that targetIsHiddenActor is always false, allowing lastVisibleMaximumRange + // to be assigned zero range by attackAircraft.GetMaximumRangeVersusTarget for e.g. cloaked actors. + // Catch and cancel this edge case to avoid the aircraft stopping mid-air! + if (self.Owner.IsBot && lastVisibleMaximumRange == WDist.Zero) + return true; + // We've reached the assumed position but it is not there - give up if (checkTarget.IsInRange(pos, lastVisibleMaximumRange)) return true; @@ -153,7 +159,7 @@ } var delta = attackAircraft.GetTargetPosition(pos, target) - pos; - var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : aircraft.Facing; + var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw : aircraft.Facing; QueueChild(new TakeOff(self)); @@ -165,7 +171,7 @@ // The aircraft must keep moving forward even if it is already in an ideal position. else if (attackAircraft.Info.AttackType == AirAttackType.Strafe) - QueueChild(new StrafeAttackRun(self, attackAircraft, target, strafeDistance != WDist.Zero ? strafeDistance : lastVisibleMaximumRange)); + QueueChild(new StrafeAttackRun(self, attackAircraft, aircraft, target, strafeDistance != WDist.Zero ? strafeDistance : lastVisibleMaximumRange)); else if (attackAircraft.Info.AttackType == AirAttackType.Default && !aircraft.Info.CanHover) QueueChild(new FlyAttackRun(self, target, lastVisibleMaximumRange)); @@ -208,11 +214,12 @@ class FlyAttackRun : Activity { + readonly WDist exitRange; + Target target; - WDist exitRange; bool targetIsVisibleActor; - public FlyAttackRun(Actor self, Target t, WDist exitRange) + public FlyAttackRun(Actor self, in Target t, WDist exitRange) { ChildHasPriority = false; @@ -226,6 +233,9 @@ if (target.IsValidFor(self)) { QueueChild(new Fly(self, target, target.CenterPosition)); + + // Fly a single tick forward so we have passed the target and start flying out of range facing away from it + QueueChild(new FlyForward(self, 1)); QueueChild(new Fly(self, target, exitRange, WDist.MaxValue, target.CenterPosition)); } else @@ -239,8 +249,7 @@ // Cancel the run if the target become invalid (e.g. killed) while visible var targetWasVisibleActor = targetIsVisibleActor; - bool targetIsHiddenActor; - target = target.Recalculate(self.Owner, out targetIsHiddenActor); + target = target.Recalculate(self.Owner, out var targetIsHiddenActor); targetIsVisibleActor = target.Type == TargetType.Actor && !targetIsHiddenActor; if (targetWasVisibleActor && !target.IsValidFor(self)) @@ -252,16 +261,19 @@ class StrafeAttackRun : Activity { - Target target; - WDist exitRange; readonly AttackAircraft attackAircraft; + readonly Aircraft aircraft; + readonly WDist exitRange; - public StrafeAttackRun(Actor self, AttackAircraft attackAircraft, Target t, WDist exitRange) + Target target; + + public StrafeAttackRun(Actor self, AttackAircraft attackAircraft, Aircraft aircraft, in Target t, WDist exitRange) { ChildHasPriority = false; target = t; this.attackAircraft = attackAircraft; + this.aircraft = aircraft; this.exitRange = exitRange; } @@ -271,7 +283,11 @@ if (target.IsValidFor(self)) { QueueChild(new Fly(self, target, target.CenterPosition)); - QueueChild(new Fly(self, target, exitRange, WDist.MaxValue, target.CenterPosition)); + QueueChild(new FlyForward(self, exitRange)); + + // Exit the range and then fly enough to turn towards the target for another run + var distanceToTurn = new WDist(aircraft.Info.Speed * 256 / aircraft.Info.TurnSpeed.Angle); + QueueChild(new Fly(self, target, exitRange + distanceToTurn, WDist.MaxValue, target.CenterPosition)); } else Cancel(self); @@ -284,8 +300,7 @@ // Strafe attacks target the ground below the original target // Update the position if we seen the target move; keep the previous one if it dies or disappears - bool targetIsHiddenActor; - target = target.Recalculate(self.Owner, out targetIsHiddenActor); + target = target.Recalculate(self.Owner, out var targetIsHiddenActor); if (!targetIsHiddenActor && target.Type == TargetType.Actor) attackAircraft.SetRequestedTarget(self, Target.FromTargetPositions(target), true); diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/Fly.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/Fly.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/Fly.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/Fly.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,13 +31,13 @@ bool useLastVisibleTarget; readonly List positionBuffer = new List(); - public Fly(Actor self, Target t, WDist nearEnough, WPos? initialTargetPosition = null, Color? targetLineColor = null) + public Fly(Actor self, in Target t, WDist nearEnough, WPos? initialTargetPosition = null, Color? targetLineColor = null) : this(self, t, initialTargetPosition, targetLineColor) { this.nearEnough = nearEnough; } - public Fly(Actor self, Target t, WPos? initialTargetPosition = null, Color? targetLineColor = null) + public Fly(Actor self, in Target t, WPos? initialTargetPosition = null, Color? targetLineColor = null) { aircraft = self.Trait(); target = t; @@ -52,7 +52,7 @@ lastVisibleTarget = Target.FromPos(initialTargetPosition.Value); } - public Fly(Actor self, Target t, WDist minRange, WDist maxRange, + public Fly(Actor self, in Target t, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null) : this(self, t, initialTargetPosition, targetLineColor) { @@ -60,16 +60,29 @@ this.minRange = minRange; } - public static void FlyTick(Actor self, Aircraft aircraft, int desiredFacing, WDist desiredAltitude, WVec moveOverride, int turnSpeedOverride = -1) + public static void FlyTick(Actor self, Aircraft aircraft, WAngle desiredFacing, WDist desiredAltitude, WVec moveOverride, bool idleTurn = false) { var dat = self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition); var move = aircraft.Info.CanSlide ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing); if (moveOverride != WVec.Zero) move = moveOverride; - var turnSpeed = turnSpeedOverride > -1 ? turnSpeedOverride : aircraft.TurnSpeed; + var oldFacing = aircraft.Facing; + var turnSpeed = idleTurn ? aircraft.IdleTurnSpeed ?? aircraft.TurnSpeed : aircraft.TurnSpeed; aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, turnSpeed); + var roll = idleTurn ? aircraft.Info.IdleRoll ?? aircraft.Info.Roll : aircraft.Info.Roll; + if (roll != WAngle.Zero) + { + var desiredRoll = aircraft.Facing == desiredFacing ? WAngle.Zero : + new WAngle(roll.Angle * Util.GetTurnDirection(aircraft.Facing, oldFacing)); + + aircraft.Roll = Util.TickFacing(aircraft.Roll, desiredRoll, aircraft.Info.RollSpeed); + } + + if (aircraft.Info.Pitch != WAngle.Zero) + aircraft.Pitch = Util.TickFacing(aircraft.Pitch, aircraft.Info.Pitch, aircraft.Info.PitchSpeed); + // Note: we assume that if move.Z is not zero, it's intentional and we want to move in that vertical direction instead of towards desiredAltitude. // If that is not desired, the place that calls this should make sure moveOverride.Z is zero. if (dat != desiredAltitude || move.Z != 0) @@ -83,18 +96,18 @@ aircraft.SetPosition(self, aircraft.CenterPosition + move); } - public static void FlyTick(Actor self, Aircraft aircraft, int desiredFacing, WDist desiredAltitude, int turnSpeedOverride = -1) + public static void FlyTick(Actor self, Aircraft aircraft, WAngle desiredFacing, WDist desiredAltitude, bool idleTurn = false) { - FlyTick(self, aircraft, desiredFacing, desiredAltitude, WVec.Zero, turnSpeedOverride); + FlyTick(self, aircraft, desiredFacing, desiredAltitude, WVec.Zero, idleTurn); } // Should only be used for vertical-only movement, usually VTOL take-off or land. Terrain-induced altitude changes should always be handled by FlyTick. - public static bool VerticalTakeOffOrLandTick(Actor self, Aircraft aircraft, int desiredFacing, WDist desiredAltitude, int turnSpeedOverride = -1) + public static bool VerticalTakeOffOrLandTick(Actor self, Aircraft aircraft, WAngle desiredFacing, WDist desiredAltitude, bool idleTurn = false) { var dat = self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition); var move = WVec.Zero; - var turnSpeed = turnSpeedOverride > -1 ? turnSpeedOverride : aircraft.TurnSpeed; + var turnSpeed = idleTurn ? aircraft.IdleTurnSpeed ?? aircraft.TurnSpeed : aircraft.TurnSpeed; aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, turnSpeed); if (dat != desiredAltitude) @@ -151,8 +164,7 @@ return false; } - bool targetIsHiddenActor; - target = target.Recalculate(self.Owner, out targetIsHiddenActor); + target = target.Recalculate(self.Owner, out var targetIsHiddenActor); if (!targetIsHiddenActor && target.Type == TargetType.Actor) lastVisibleTarget = Target.FromTargetPositions(target); @@ -173,7 +185,7 @@ return true; var isSlider = aircraft.Info.CanSlide; - var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : aircraft.Facing; + var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw : aircraft.Facing; var move = isSlider ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing); // Inside the minimum range, so reverse if we CanSlide, otherwise face away from the target. @@ -183,8 +195,7 @@ FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, -move); else { - desiredFacing = Util.NormalizeFacing(desiredFacing + 128); - FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, move); + FlyTick(self, aircraft, desiredFacing + new WAngle(512), aircraft.Info.CruiseAltitude, move); } return false; @@ -230,10 +241,9 @@ // The current facing is a tangent of the minimal turn circle. // Make a perpendicular vector, and use it to locate the turn's center. - var turnCenterFacing = aircraft.Facing; - turnCenterFacing += Util.GetNearestFacing(aircraft.Facing, desiredFacing) > 0 ? 64 : -64; + var turnCenterFacing = aircraft.Facing + new WAngle(Util.GetTurnDirection(aircraft.Facing, desiredFacing) * 256); - var turnCenterDir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(turnCenterFacing)); + var turnCenterDir = new WVec(0, -1024, 0).Rotate(WRot.FromYaw(turnCenterFacing)); turnCenterDir *= turnRadius; turnCenterDir /= 1024; @@ -263,12 +273,12 @@ yield return new TargetLineNode(useLastVisibleTarget ? lastVisibleTarget : target, targetLineColor.Value); } - public static int CalculateTurnRadius(int speed, int turnSpeed) + public static int CalculateTurnRadius(int speed, WAngle turnSpeed) { // turnSpeed -> divide into 256 to get the number of ticks per complete rotation // speed -> multiply to get distance travelled per rotation (circumference) - // 45 -> divide by 2*pi to get the turn radius: 45==256/(2*pi), with some extra leeway - return turnSpeed > 0 ? 45 * speed / turnSpeed : 0; + // 180 -> divide by 2*pi to get the turn radius: 180==1024/(2*pi), with some extra leeway + return turnSpeed.Angle > 0 ? 180 * speed / turnSpeed.Angle : 0; } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyFollow.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,7 +28,7 @@ bool useLastVisibleTarget; bool wasMovingWithinRange; - public FlyFollow(Actor self, Target target, WDist minRange, WDist maxRange, + public FlyFollow(Actor self, in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition, Color? targetLineColor = null) { this.target = target; @@ -55,8 +55,7 @@ if (IsCanceling) return true; - bool targetIsHiddenActor; - target = target.Recalculate(self.Owner, out targetIsHiddenActor); + target = target.Recalculate(self.Owner, out var targetIsHiddenActor); if (!targetIsHiddenActor && target.Type == TargetType.Actor) lastVisibleTarget = Target.FromTargetPositions(target); diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyForward.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyForward.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyForward.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyForward.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,64 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Activities; +using OpenRA.Mods.Common.Traits; + +namespace OpenRA.Mods.Common.Activities +{ + public class FlyForward : Activity + { + readonly Aircraft aircraft; + readonly WDist cruiseAltitude; + readonly int flyTicks; + int remainingDistance; + int ticks; + + FlyForward(Actor self) + { + aircraft = self.Trait(); + cruiseAltitude = aircraft.Info.CruiseAltitude; + } + + public FlyForward(Actor self, int ticks = -1) + : this(self) + { + flyTicks = ticks; + } + + public FlyForward(Actor self, WDist distance) + : this(self) + { + remainingDistance = distance.Length; + } + + public override bool Tick(Actor self) + { + // Refuse to take off if it would land immediately again. + if (aircraft.ForceLanding) + { + Cancel(self); + return true; + } + + // Having flyTicks < 0 is valid and means the actor flies until this activity is canceled + if (IsCanceling || (flyTicks > 0 && ticks++ >= flyTicks) || (flyTicks == 0 && remainingDistance <= 0)) + return true; + + // FlyTick moves the aircraft while FlyStep calculates how far we are moving + if (remainingDistance != 0) + remainingDistance -= aircraft.FlyStep(aircraft.Facing).HorizontalLength; + + Fly.FlyTick(self, aircraft, aircraft.Facing, cruiseAltitude); + return false; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyIdle.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyIdle.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyIdle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyIdle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,16 +20,16 @@ { readonly Aircraft aircraft; readonly INotifyIdle[] tickIdles; - readonly int turnSpeed; + readonly bool idleTurn; int remainingTicks; - public FlyIdle(Actor self, int ticks = -1, bool tickIdle = true) + public FlyIdle(Actor self, int ticks = -1, bool idleTurn = true) { aircraft = self.Trait(); - turnSpeed = aircraft.Info.IdleTurnSpeed > -1 ? aircraft.Info.IdleTurnSpeed : aircraft.TurnSpeed; remainingTicks = ticks; + this.idleTurn = idleTurn; - if (tickIdle) + if (idleTurn) tickIdles = self.TraitsImplementing().ToArray(); } @@ -48,15 +48,16 @@ foreach (var tickIdle in tickIdles) tickIdle.TickIdle(self); - if (!aircraft.Info.CanHover) + if (aircraft.Info.IdleSpeed > 0 || (!aircraft.Info.CanHover && aircraft.Info.IdleSpeed < 0)) { - // We can't possibly turn this fast - var desiredFacing = aircraft.Facing + 64; + var speed = aircraft.Info.IdleSpeed < 0 ? aircraft.Info.Speed : aircraft.Info.IdleSpeed; // This override is necessary, otherwise aircraft with CanSlide would circle sideways - var move = aircraft.FlyStep(aircraft.Facing); + var move = aircraft.FlyStep(speed, aircraft.Facing); - Fly.FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, move, turnSpeed); + // We can't possibly turn this fast + var desiredFacing = aircraft.Facing + new WAngle(256); + Fly.FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, move, idleTurn); } return false; diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyOffMap.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyOffMap.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyOffMap.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyOffMap.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,7 +29,7 @@ this.endingDelay = endingDelay; } - public FlyOffMap(Actor self, Target target, int endingDelay = 25) + public FlyOffMap(Actor self, in Target target, int endingDelay = 25) : this(self, endingDelay) { this.target = target; @@ -41,7 +41,7 @@ if (hasTarget) { QueueChild(new Fly(self, target)); - QueueChild(new FlyTimed(-1, self)); + QueueChild(new FlyForward(self)); return; } @@ -49,7 +49,7 @@ if (aircraft.Info.VTOL && self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition) != aircraft.Info.CruiseAltitude) QueueChild(new TakeOff(self)); - QueueChild(new FlyTimed(-1, self)); + QueueChild(new FlyForward(self)); } public override bool Tick(Actor self) diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyTimed.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyTimed.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/FlyTimed.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/FlyTimed.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using OpenRA.Activities; -using OpenRA.Mods.Common.Traits; - -namespace OpenRA.Mods.Common.Activities -{ - public class FlyTimed : Activity - { - readonly Aircraft aircraft; - readonly WDist cruiseAltitude; - int remainingTicks; - - public FlyTimed(int ticks, Actor self) - { - remainingTicks = ticks; - aircraft = self.Trait(); - cruiseAltitude = aircraft.Info.CruiseAltitude; - } - - public override bool Tick(Actor self) - { - // Refuse to take off if it would land immediately again. - if (aircraft.ForceLanding) - { - Cancel(self); - return true; - } - - if (IsCanceling || remainingTicks-- == 0) - return true; - - Fly.FlyTick(self, aircraft, aircraft.Facing, cruiseAltitude); - - return false; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/Land.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/Land.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/Land.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/Land.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,7 +22,7 @@ { readonly Aircraft aircraft; readonly WVec offset; - readonly int desiredFacing; + readonly WAngle? desiredFacing; readonly bool assignTargetOnFirstRun; readonly CPos[] clearCells; readonly WDist landRange; @@ -34,22 +34,22 @@ bool landingInitiated; bool finishedApproach; - public Land(Actor self, int facing = -1, Color? targetLineColor = null) + public Land(Actor self, WAngle? facing = null, Color? targetLineColor = null) : this(self, Target.Invalid, new WDist(-1), WVec.Zero, facing, null) { assignTargetOnFirstRun = true; } - public Land(Actor self, Target target, int facing = -1, Color? targetLineColor = null) + public Land(Actor self, in Target target, WAngle? facing = null, Color? targetLineColor = null) : this(self, target, new WDist(-1), WVec.Zero, facing, targetLineColor: targetLineColor) { } - public Land(Actor self, Target target, WDist landRange, int facing = -1, Color? targetLineColor = null) + public Land(Actor self, in Target target, WDist landRange, WAngle? facing = null, Color? targetLineColor = null) : this(self, target, landRange, WVec.Zero, facing, targetLineColor: targetLineColor) { } - public Land(Actor self, Target target, WVec offset, int facing = -1, Color? targetLineColor = null) + public Land(Actor self, in Target target, WVec offset, WAngle? facing = null, Color? targetLineColor = null) : this(self, target, WDist.Zero, offset, facing, targetLineColor: targetLineColor) { } - public Land(Actor self, Target target, WDist landRange, WVec offset, int facing = -1, CPos[] clearCells = null, Color? targetLineColor = null) + public Land(Actor self, in Target target, WDist landRange, WVec offset, WAngle? facing = null, CPos[] clearCells = null, Color? targetLineColor = null) { aircraft = self.Trait(); this.target = target; @@ -60,7 +60,7 @@ // NOTE: desiredFacing = -1 means we should not prefer any particular facing and instead just // use whatever facing gives us the most direct path to the landing site. - if (facing == -1 && aircraft.Info.TurnToLand) + if (!facing.HasValue && aircraft.Info.TurnToLand) desiredFacing = aircraft.Info.InitialFacing; else desiredFacing = facing; @@ -141,9 +141,10 @@ QueueChild(new Fly(self, Target.FromPos(targetPosition))); return false; } - else if (desiredFacing != -1 && desiredFacing != aircraft.Facing) + + if (desiredFacing.HasValue && desiredFacing.Value != aircraft.Facing) { - QueueChild(new Turn(self, desiredFacing)); + QueueChild(new Turn(self, desiredFacing.Value)); return false; } } @@ -158,18 +159,18 @@ // Approach landing from the opposite direction of the desired facing // TODO: Calculate sensible trajectory without preferred facing. - var rotation = WRot.Zero; - if (desiredFacing != -1) - rotation = WRot.FromFacing(desiredFacing); + var rotation = WRot.None; + if (desiredFacing.HasValue) + rotation = WRot.FromYaw(desiredFacing.Value); var approachStart = targetPosition + new WVec(0, landDistance, altitude).Rotate(rotation); // Add 10% to the turning radius to ensure we have enough room var speed = aircraft.MovementSpeed * 32 / 35; - var turnRadius = Fly.CalculateTurnRadius(speed, aircraft.Info.TurnSpeed); + var turnRadius = Fly.CalculateTurnRadius(speed, aircraft.TurnSpeed); // Find the center of the turning circles for clockwise and counterclockwise turns - var angle = WAngle.FromFacing(aircraft.Facing); + var angle = aircraft.Facing; var fwd = -new WVec(angle.Sin(), angle.Cos(), 0); // Work out whether we should turn clockwise or counter-clockwise for approach @@ -196,7 +197,7 @@ var w2 = approachCenter + tangentOffset; var w3 = approachStart; - turnRadius = Fly.CalculateTurnRadius(aircraft.Info.Speed, aircraft.Info.TurnSpeed); + turnRadius = Fly.CalculateTurnRadius(aircraft.Info.Speed, aircraft.TurnSpeed); // Move along approach trajectory. QueueChild(new Fly(self, Target.FromPos(w1), WDist.Zero, new WDist(turnRadius * 3))); @@ -252,7 +253,7 @@ } var landingAlt = self.World.Map.DistanceAboveTerrain(targetPosition) + aircraft.LandAltitude; - Fly.FlyTick(self, aircraft, d.Yaw.Facing, landingAlt); + Fly.FlyTick(self, aircraft, d.Yaw, landingAlt); return false; } diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; using OpenRA.Activities; @@ -26,7 +25,7 @@ readonly Rearmable rearmable; readonly bool alwaysLand; Actor dest; - int facing = -1; + WAngle? facing; public ReturnToBase(Actor self, Actor dest = null, bool alwaysLand = false) { @@ -111,10 +110,13 @@ if (ShouldLandAtBuilding(self, dest)) { - var exit = dest.FirstExitOrDefault(); - var offset = exit != null ? exit.Info.SpawnOffset : WVec.Zero; - if (aircraft.Info.TurnToDock || !aircraft.Info.VTOL) - facing = aircraft.Info.InitialFacing; + var exit = dest.NearestExitOrDefault(self.CenterPosition); + var offset = WVec.Zero; + if (exit != null) + { + offset = exit.Info.SpawnOffset; + facing = exit.Info.Facing; + } aircraft.MakeReservation(dest); QueueChild(new Land(self, Target.FromActor(dest), offset, facing, Color.Green)); @@ -129,7 +131,7 @@ public override IEnumerable TargetLineNodes(Actor self) { if (ChildActivity == null) - yield return new TargetLineNode(Target.FromActor(dest), Color.Green); + yield return new TargetLineNode(Target.FromActor(dest), aircraft.Info.TargetLineColor); else foreach (var n in ChildActivity.TargetLineNodes(self)) yield return n; diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Air/TakeOff.cs openra-20210321/OpenRA.Mods.Common/Activities/Air/TakeOff.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Air/TakeOff.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Air/TakeOff.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,11 +9,8 @@ */ #endregion -using System.Collections.Generic; using OpenRA.Activities; using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; -using OpenRA.Traits; namespace OpenRA.Mods.Common.Activities { diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Attack.cs openra-20210321/OpenRA.Mods.Common/Activities/Attack.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Attack.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Attack.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,7 @@ [Flags] protected enum AttackStatus { UnableToAttack, NeedsToTurn, NeedsToMove, Attacking } - readonly AttackFrontal[] attackTraits; + readonly IEnumerable attackTraits; readonly RevealsShroud[] revealsShroud; readonly IMove move; readonly IFacing facing; @@ -45,13 +45,13 @@ WDist maxRange; AttackStatus attackStatus = AttackStatus.UnableToAttack; - public Attack(Actor self, Target target, bool allowMovement, bool forceAttack, Color? targetLineColor = null) + public Attack(Actor self, in Target target, bool allowMovement, bool forceAttack, Color? targetLineColor = null) { this.target = target; this.targetLineColor = targetLineColor; this.forceAttack = forceAttack; - attackTraits = self.TraitsImplementing().ToArray(); + attackTraits = self.TraitsImplementing().ToArray().Where(Exts.IsTraitEnabled); revealsShroud = self.TraitsImplementing().ToArray(); facing = self.Trait(); positionable = self.Trait(); @@ -64,8 +64,11 @@ || target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain) { lastVisibleTarget = Target.FromPos(target.CenterPosition); + + // Lambdas can't use 'in' variables, so capture a copy for later + var rangeTarget = target; lastVisibleMaximumRange = attackTraits.Where(x => !x.IsTraitDisabled) - .Min(x => x.GetMaximumRangeVersusTarget(target)); + .Min(x => x.GetMaximumRangeVersusTarget(rangeTarget)); if (target.Type == TargetType.Actor) { @@ -90,13 +93,18 @@ if (IsCanceling) return true; - bool targetIsHiddenActor; - target = RecalculateTarget(self, out targetIsHiddenActor); + if (!attackTraits.Any()) + { + Cancel(self); + return false; + } + + target = RecalculateTarget(self, out var targetIsHiddenActor); + if (!targetIsHiddenActor && target.Type == TargetType.Actor) { lastVisibleTarget = Target.FromTargetPositions(target); - lastVisibleMaximumRange = attackTraits.Where(x => !x.IsTraitDisabled) - .Min(x => x.GetMaximumRangeVersusTarget(target)); + lastVisibleMaximumRange = attackTraits.Min(x => x.GetMaximumRangeVersusTarget(target)); lastVisibleOwner = target.Actor.Owner; lastVisibleTargetTypes = target.Actor.GetEnabledTargetTypes(); @@ -132,7 +140,7 @@ attackStatus = AttackStatus.UnableToAttack; - foreach (var attack in attackTraits.Where(x => !x.IsTraitDisabled)) + foreach (var attack in attackTraits) { var status = TickAttack(self, attack); attack.IsAiming = status == AttackStatus.Attacking || status == AttackStatus.NeedsToTurn; @@ -200,10 +208,17 @@ if (!attack.TargetInFiringArc(self, target, attack.Info.FacingTolerance)) { - var desiredFacing = (attack.GetTargetPosition(pos, target) - pos).Yaw.Facing; - attackStatus |= AttackStatus.NeedsToTurn; - QueueChild(new Turn(self, desiredFacing)); - return AttackStatus.NeedsToTurn; + var desiredFacing = (attack.GetTargetPosition(pos, target) - pos).Yaw; + + // Don't queue a turn activity: Executing a child takes an additional tick during which the target may have moved again + facing.Facing = Util.TickFacing(facing.Facing, desiredFacing, facing.TurnSpeed); + + // Check again if we turned enough and directly continue attacking if we did + if (!attack.TargetInFiringArc(self, target, attack.Info.FacingTolerance)) + { + attackStatus |= AttackStatus.NeedsToTurn; + return AttackStatus.NeedsToTurn; + } } attackStatus |= AttackStatus.Attacking; diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/CaptureActor.cs openra-20210321/OpenRA.Mods.Common/Activities/CaptureActor.cs --- openra-20200503/OpenRA.Mods.Common/Activities/CaptureActor.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/CaptureActor.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,12 +22,25 @@ Actor enterActor; CaptureManager enterCaptureManager; - public CaptureActor(Actor self, Target target) - : base(self, target, Color.Crimson) + public CaptureActor(Actor self, in Target target, Color? targetLineColor) + : base(self, target, targetLineColor) { manager = self.Trait(); } + protected override void TickInner(Actor self, in Target target, bool targetIsDeadOrHiddenActor) + { + if (target.Type == TargetType.Actor && enterActor != target.Actor) + { + enterActor = target.Actor; + enterCaptureManager = target.Actor.TraitOrDefault(); + } + + if (!targetIsDeadOrHiddenActor && target.Type != TargetType.FrozenActor && + (enterCaptureManager == null || !enterCaptureManager.CanBeTargetedBy(enterActor, self, manager))) + Cancel(self, true); + } + protected override bool TryStartEnter(Actor self, Actor targetActor) { if (enterActor != targetActor) @@ -46,8 +59,7 @@ // StartCapture returns false when a capture delay is enabled // We wait until it returns true before allowing entering the target - Captures captures; - if (!manager.StartCapture(self, enterActor, enterCaptureManager, out captures)) + if (!manager.StartCapture(self, enterActor, enterCaptureManager, out var captures)) return false; if (!captures.Info.ConsumedByCapture) @@ -112,12 +124,8 @@ foreach (var t in enterActor.TraitsImplementing()) t.OnCapture(enterActor, self, oldOwner, self.Owner, captures.Info.CaptureTypes); - if (self.Owner.Stances[oldOwner].HasStance(captures.Info.PlayerExperienceStances)) - { - var exp = self.Owner.PlayerActor.TraitOrDefault(); - if (exp != null) - exp.GiveExperience(captures.Info.PlayerExperience); - } + if (self.Owner.RelationshipWith(oldOwner).HasStance(captures.Info.PlayerExperienceRelationships)) + self.Owner.PlayerActor.TraitOrDefault()?.GiveExperience(captures.Info.PlayerExperience); if (captures.Info.ConsumedByCapture) self.Dispose(); diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/DeliverResources.cs openra-20210321/OpenRA.Mods.Common/Activities/DeliverResources.cs --- openra-20200503/OpenRA.Mods.Common/Activities/DeliverResources.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/DeliverResources.cs 2021-03-21 11:10:05.000000000 +0000 @@ -85,9 +85,9 @@ public override IEnumerable TargetLineNodes(Actor self) { if (proc != null) - yield return new TargetLineNode(Target.FromActor(proc), Color.Green); + yield return new TargetLineNode(Target.FromActor(proc), harv.Info.DeliverLineColor); else - yield return new TargetLineNode(Target.FromActor(harv.LinkedProc), Color.Green); + yield return new TargetLineNode(Target.FromActor(harv.LinkedProc), harv.Info.DeliverLineColor); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/DeliverUnit.cs openra-20210321/OpenRA.Mods.Common/Activities/DeliverUnit.cs --- openra-20200503/OpenRA.Mods.Common/Activities/DeliverUnit.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/DeliverUnit.cs 2021-03-21 11:10:05.000000000 +0000 @@ -32,7 +32,7 @@ assignTargetOnFirstRun = true; } - public DeliverUnit(Actor self, Target destination, WDist deliverRange) + public DeliverUnit(Actor self, in Target destination, WDist deliverRange) { this.destination = destination; this.deliverRange = deliverRange; @@ -60,7 +60,7 @@ public override IEnumerable TargetLineNodes(Actor self) { - yield return new TargetLineNode(destination, Color.Yellow); + yield return new TargetLineNode(destination, carryall.Info.TargetLineColor); } class ReleaseUnit : Activity @@ -84,15 +84,7 @@ var targetPosition = self.CenterPosition + body.LocalToWorld(localOffset); var targetLocation = self.World.Map.CellContaining(targetPosition); carryall.Carryable.Trait().SetPosition(carryall.Carryable, targetLocation, SubCell.FullCell); - - // HACK: directly manipulate the turret facings to match the new orientation - // This can eventually go away, when we make turret facings relative to the body - var carryableFacing = carryall.Carryable.Trait(); - var facingDelta = facing.Facing - carryableFacing.Facing; - foreach (var t in carryall.Carryable.TraitsImplementing()) - t.TurretFacing += facingDelta; - - carryableFacing.Facing = facing.Facing; + carryall.Carryable.Trait().Facing = facing.Facing; // Put back into world self.World.AddFrameEndTask(w => diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Demolish.cs openra-20210321/OpenRA.Mods.Common/Activities/Demolish.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Demolish.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Demolish.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,21 +23,23 @@ readonly int flashes; readonly int flashesDelay; readonly int flashInterval; + readonly BitSet damageTypes; readonly INotifyDemolition[] notifiers; readonly EnterBehaviour enterBehaviour; Actor enterActor; IDemolishable[] enterDemolishables; - public Demolish(Actor self, Target target, EnterBehaviour enterBehaviour, int delay, - int flashes, int flashesDelay, int flashInterval) - : base(self, target, Color.Crimson) + public Demolish(Actor self, in Target target, EnterBehaviour enterBehaviour, int delay, int flashes, + int flashesDelay, int flashInterval, BitSet damageTypes, Color? targetLineColor) + : base(self, target, targetLineColor) { notifiers = self.TraitsImplementing().ToArray(); this.delay = delay; this.flashes = flashes; this.flashesDelay = flashesDelay; this.flashInterval = flashInterval; + this.damageTypes = damageTypes; this.enterBehaviour = enterBehaviour; } @@ -75,7 +77,7 @@ ind.Demolishing(self); foreach (var d in enterDemolishables) - d.Demolish(enterActor, self, delay); + d.Demolish(enterActor, self, delay, damageTypes); if (enterBehaviour == EnterBehaviour.Dispose) self.Dispose(); diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/DeployForGrantedCondition.cs openra-20210321/OpenRA.Mods.Common/Activities/DeployForGrantedCondition.cs --- openra-20200503/OpenRA.Mods.Common/Activities/DeployForGrantedCondition.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/DeployForGrantedCondition.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,8 +31,8 @@ protected override void OnFirstRun(Actor self) { // Turn to the required facing. - if (deploy.DeployState == DeployState.Undeployed && deploy.Info.Facing != -1 && canTurn && !moving) - QueueChild(new Turn(self, deploy.Info.Facing)); + if (deploy.DeployState == DeployState.Undeployed && deploy.Info.Facing.HasValue && canTurn && !moving) + QueueChild(new Turn(self, deploy.Info.Facing.Value)); } public override bool Tick(Actor self) diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/DonateCash.cs openra-20210321/OpenRA.Mods.Common/Activities/DonateCash.cs --- openra-20200503/OpenRA.Mods.Common/Activities/DonateCash.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/DonateCash.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,8 +21,8 @@ readonly int payload; readonly int playerExperience; - public DonateCash(Actor self, Target target, int payload, int playerExperience) - : base(self, target, Color.Yellow) + public DonateCash(Actor self, in Target target, int payload, int playerExperience, Color? targetLineColor) + : base(self, target, targetLineColor) { this.payload = payload; this.playerExperience = playerExperience; diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/DonateExperience.cs openra-20210321/OpenRA.Mods.Common/Activities/DonateExperience.cs --- openra-20200503/OpenRA.Mods.Common/Activities/DonateExperience.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/DonateExperience.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,8 +23,8 @@ Actor enterActor; GainsExperience enterGainsExperience; - public DonateExperience(Actor self, Target target, int level, int playerExperience) - : base(self, target, Color.Yellow) + public DonateExperience(Actor self, in Target target, int level, int playerExperience, Color? targetLineColor) + : base(self, target, targetLineColor) { this.level = level; this.playerExperience = playerExperience; diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Enter.cs openra-20210321/OpenRA.Mods.Common/Activities/Enter.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Enter.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Enter.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,7 +31,7 @@ bool useLastVisibleTarget; EnterState lastState = EnterState.Approaching; - protected Enter(Actor self, Target target, Color? targetLineColor = null) + protected Enter(Actor self, in Target target, Color? targetLineColor = null) { move = self.Trait(); this.target = target; @@ -43,7 +43,7 @@ /// Called early in the activity tick to allow subclasses to update state. /// Call Cancel(self, true) if it is no longer valid to enter /// - protected virtual void TickInner(Actor self, Target target, bool targetIsDeadOrHiddenActor) { } + protected virtual void TickInner(Actor self, in Target target, bool targetIsDeadOrHiddenActor) { } /// /// Called when the actor is ready to transition from approaching to entering the target actor. @@ -53,17 +53,16 @@ protected virtual bool TryStartEnter(Actor self, Actor targetActor) { return true; } /// - /// Called when the actor has entered the target actor - /// Return true if the action succeeded and the actor should be Killed/Disposed - /// (assuming the relevant EnterBehaviour), or false if the actor should exit unharmed + /// Called when the actor has entered the target actor. + /// Actor will be be Killed/Disposed or they will enter/exit unharmed. + /// Depends on either the EnterBehaviour of the actor or the requirements of an overriding function. /// protected virtual void OnEnterComplete(Actor self, Actor targetActor) { } public override bool Tick(Actor self) { // Update our view of the target - bool targetIsHiddenActor; - target = target.Recalculate(self.Owner, out targetIsHiddenActor); + target = target.Recalculate(self.Owner, out var targetIsHiddenActor); if (!targetIsHiddenActor && target.Type == TargetType.Actor) lastVisibleTarget = Target.FromTargetPositions(target); diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/FindAndDeliverResources.cs openra-20210321/OpenRA.Mods.Common/Activities/FindAndDeliverResources.cs --- openra-20200503/OpenRA.Mods.Common/Activities/FindAndDeliverResources.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/FindAndDeliverResources.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,7 +24,6 @@ readonly Harvester harv; readonly HarvesterInfo harvInfo; readonly Mobile mobile; - readonly LocomotorInfo locomotorInfo; readonly ResourceClaimLayer claimLayer; readonly IPathFinder pathFinder; readonly DomainIndex domainIndex; @@ -43,7 +42,6 @@ harv = self.Trait(); harvInfo = self.Info.TraitInfo(); mobile = self.Trait(); - locomotorInfo = mobile.Info.LocomotorInfo; claimLayer = self.World.WorldActor.Trait(); pathFinder = self.World.WorldActor.Trait(); domainIndex = self.World.WorldActor.Trait(); @@ -195,7 +193,7 @@ // Find any harvestable resources: List path; using (var search = PathSearch.Search(self.World, mobile.Locomotor, self, BlockedByActor.Stationary, loc => - domainIndex.IsPassable(self.Location, loc, locomotorInfo) && harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc)) + domainIndex.IsPassable(self.Location, loc, mobile.Locomotor) && harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc)) .WithCustomCost(loc => { if ((loc - searchFromLoc.Value).LengthSquared > searchRadiusSquared) @@ -245,9 +243,9 @@ yield return n; if (orderLocation != null) - yield return new TargetLineNode(Target.FromCell(self.World, orderLocation.Value), Color.Crimson); + yield return new TargetLineNode(Target.FromCell(self.World, orderLocation.Value), harvInfo.HarvestLineColor); else if (deliverActor != null) - yield return new TargetLineNode(Target.FromActor(deliverActor), Color.Green); + yield return new TargetLineNode(Target.FromActor(deliverActor), harvInfo.DeliverLineColor); } CPos? GetSearchFromProcLocation(Actor self) diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/HarvesterDockSequence.cs openra-20210321/OpenRA.Mods.Common/Activities/HarvesterDockSequence.cs --- openra-20200503/OpenRA.Mods.Common/Activities/HarvesterDockSequence.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/HarvesterDockSequence.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,11 +20,11 @@ { public abstract class HarvesterDockSequence : Activity { - protected enum DockingState { Wait, Turn, Dock, Loop, Undock, Complete } + protected enum DockingState { Wait, Turn, Drag, Dock, Loop, Undock, Complete } protected readonly Actor Refinery; protected readonly Harvester Harv; - protected readonly int DockAngle; + protected readonly WAngle DockAngle; protected readonly bool IsDragRequired; protected readonly WVec DragOffset; protected readonly int DragLength; @@ -33,7 +33,7 @@ protected DockingState dockingState; - public HarvesterDockSequence(Actor self, Actor refinery, int dockAngle, bool isDragRequired, WVec dragOffset, int dragLength) + public HarvesterDockSequence(Actor self, Actor refinery, WAngle dockAngle, bool isDragRequired, WVec dragOffset, int dragLength) { dockingState = DockingState.Turn; Refinery = refinery; @@ -54,22 +54,30 @@ return false; case DockingState.Turn: - dockingState = DockingState.Dock; + dockingState = DockingState.Drag; QueueChild(new Turn(self, DockAngle)); + return false; + + case DockingState.Drag: + if (IsCanceling || !Refinery.IsInWorld || Refinery.IsDead) + return true; + + dockingState = DockingState.Dock; if (IsDragRequired) QueueChild(new Drag(self, StartDrag, EndDrag, DragLength)); + return false; case DockingState.Dock: - if (Refinery.IsInWorld && !Refinery.IsDead) - foreach (var nd in Refinery.TraitsImplementing()) - nd.Docked(Refinery, self); + if (!IsCanceling && Refinery.IsInWorld && !Refinery.IsDead) + OnStateDock(self); + else + dockingState = DockingState.Undock; - OnStateDock(self); return false; case DockingState.Loop: - if (!Refinery.IsInWorld || Refinery.IsDead || Harv.TickUnload(self, Refinery)) + if (IsCanceling || !Refinery.IsInWorld || Refinery.IsDead || Harv.TickUnload(self, Refinery)) dockingState = DockingState.Undock; return false; @@ -79,10 +87,6 @@ return false; case DockingState.Complete: - if (Refinery.IsInWorld && !Refinery.IsDead) - foreach (var nd in Refinery.TraitsImplementing()) - nd.Undocked(Refinery, self); - Harv.LastLinkedProc = Harv.LinkedProc; Harv.LinkProc(self, null); if (IsDragRequired) @@ -94,12 +98,6 @@ throw new InvalidOperationException("Invalid harvester dock state"); } - public override void Cancel(Actor self, bool keepQueue = false) - { - dockingState = DockingState.Undock; - base.Cancel(self); - } - public override IEnumerable GetTargets(Actor self) { yield return Target.FromActor(Refinery); diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/HarvestResource.cs openra-20210321/OpenRA.Mods.Common/Activities/HarvestResource.cs --- openra-20200503/OpenRA.Mods.Common/Activities/HarvestResource.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/HarvestResource.cs 2021-03-21 11:10:05.000000000 +0000 @@ -109,7 +109,7 @@ public override IEnumerable TargetLineNodes(Actor self) { - yield return new TargetLineNode(Target.FromCell(self.World, targetCell), Color.Crimson); + yield return new TargetLineNode(Target.FromCell(self.World, targetCell), harvInfo.HarvestLineColor); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs openra-20210321/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,18 +19,19 @@ { public class AttackMoveActivity : Activity { - readonly Func getInner; + readonly Func getMove; readonly bool isAssaultMove; - AutoTarget autoTarget; - ConditionManager conditionManager; - AttackMove attackMove; - int token = ConditionManager.InvalidConditionToken; + readonly AutoTarget autoTarget; + readonly AttackMove attackMove; - public AttackMoveActivity(Actor self, Func getInner, bool assaultMoving = false) + bool runningMoveActivity = false; + int token = Actor.InvalidConditionToken; + Target target = Target.Invalid; + + public AttackMoveActivity(Actor self, Func getMove, bool assaultMoving = false) { - this.getInner = getInner; + this.getMove = getMove; autoTarget = self.TraitOrDefault(); - conditionManager = self.TraitOrDefault(); attackMove = self.TraitOrDefault(); isAssaultMove = assaultMoving; ChildHasPriority = false; @@ -38,47 +39,56 @@ protected override void OnFirstRun(Actor self) { - // Start moving. - QueueChild(getInner()); - - if (conditionManager == null || attackMove == null) + if (attackMove == null || autoTarget == null) + { + QueueChild(getMove()); return; + } - if (!isAssaultMove && !string.IsNullOrEmpty(attackMove.Info.AttackMoveCondition)) - token = conditionManager.GrantCondition(self, attackMove.Info.AttackMoveCondition); - else if (isAssaultMove && !string.IsNullOrEmpty(attackMove.Info.AssaultMoveCondition)) - token = conditionManager.GrantCondition(self, attackMove.Info.AssaultMoveCondition); + if (isAssaultMove) + token = self.GrantCondition(attackMove.Info.AssaultMoveCondition); + else + token = self.GrantCondition(attackMove.Info.AttackMoveCondition); } public override bool Tick(Actor self) { - // We are not currently attacking a target, so scan for new targets. - if (!IsCanceling && ChildActivity != null && ChildActivity.NextActivity == null && autoTarget != null) + if (IsCanceling || attackMove == null || autoTarget == null) + return TickChild(self); + + // We are currently not attacking, so scan for new targets. + if (ChildActivity == null || runningMoveActivity) { - // ScanForTarget already limits the scanning rate for performance so we don't need to do that here. - var target = autoTarget.ScanForTarget(self, false, true); + // Use the standard ScanForTarget rate limit while we are running the move activity to save performance. + // Override the rate limit if our attack activity has completed so we can immediately acquire a new target instead of moving. + target = autoTarget.ScanForTarget(self, false, true, !runningMoveActivity); + + // Cancel the current move activity and queue attack activities if we find a new target. if (target.Type != TargetType.Invalid) { - // We have found a target so cancel the current move activity and queue attack activities. - ChildActivity.Cancel(self); - var attackBases = autoTarget.ActiveAttackBases; - foreach (var ab in attackBases) + runningMoveActivity = false; + ChildActivity?.Cancel(self); + + foreach (var ab in autoTarget.ActiveAttackBases) QueueChild(ab.GetAttackActivity(self, AttackSource.AttackMove, target, false, false)); + } - // Make sure to continue moving when the attack activities have finished. - QueueChild(getInner()); + // Continue with the move activity (or queue a new one) when there are no targets. + if (ChildActivity == null) + { + runningMoveActivity = true; + QueueChild(getMove()); } } - // The last queued childactivity is guaranteed to be the inner move, so if the childactivity - // queue is empty it means we have reached our destination and there are no more enemies on our path. - return TickChild(self); + // If the move activity finished, we have reached our destination and there are no more enemies on our path. + return TickChild(self) && runningMoveActivity; } protected override void OnLastRun(Actor self) { - if (conditionManager != null && token != ConditionManager.InvalidConditionToken) - token = conditionManager.RevokeCondition(self, token); + if (token != Actor.InvalidConditionToken) + token = self.RevokeCondition(token); } public override IEnumerable GetTargets(Actor self) @@ -91,7 +101,7 @@ public override IEnumerable TargetLineNodes(Actor self) { - foreach (var n in getInner().TargetLineNodes(self)) + foreach (var n in getMove().TargetLineNodes(self)) yield return n; yield break; diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Move/Drag.cs openra-20210321/OpenRA.Mods.Common/Activities/Move/Drag.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Move/Drag.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Move/Drag.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,9 +24,9 @@ WPos start, end; int length; int ticks = 0; - int desiredFacing; + WAngle? desiredFacing; - public Drag(Actor self, WPos start, WPos end, int length, int facing = -1) + public Drag(Actor self, WPos start, WPos end, int length, WAngle? facing = null) { positionable = self.Trait(); disableable = self.TraitOrDefault() as IDisabledTrait; @@ -39,8 +39,8 @@ protected override void OnFirstRun(Actor self) { - if (desiredFacing != -1) - QueueChild(new Turn(self, desiredFacing)); + if (desiredFacing.HasValue) + QueueChild(new Turn(self, desiredFacing.Value)); } public override bool Tick(Actor self) diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Move/Follow.cs openra-20210321/OpenRA.Mods.Common/Activities/Move/Follow.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Move/Follow.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Move/Follow.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,7 +28,7 @@ bool useLastVisibleTarget; bool wasMovingWithinRange; - public Follow(Actor self, Target target, WDist minRange, WDist maxRange, + public Follow(Actor self, in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition, Color? targetLineColor = null) { this.target = target; @@ -51,8 +51,7 @@ if (IsCanceling) return true; - bool targetIsHiddenActor; - target = target.Recalculate(self.Owner, out targetIsHiddenActor); + target = target.Recalculate(self.Owner, out var targetIsHiddenActor); if (!targetIsHiddenActor && target.Type == TargetType.Actor) lastVisibleTarget = Target.FromTargetPositions(target); diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Move/MoveAdjacentTo.cs openra-20210321/OpenRA.Mods.Common/Activities/Move/MoveAdjacentTo.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Move/MoveAdjacentTo.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Move/MoveAdjacentTo.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; using OpenRA.Activities; @@ -42,7 +41,7 @@ protected CPos lastVisibleTargetLocation; bool useLastVisibleTarget; - public MoveAdjacentTo(Actor self, Target target, WPos? initialTargetPosition = null, Color? targetLineColor = null) + public MoveAdjacentTo(Actor self, in Target target, WPos? initialTargetPosition = null, Color? targetLineColor = null) { this.target = target; this.targetLineColor = targetLineColor; @@ -89,9 +88,8 @@ public override bool Tick(Actor self) { - bool targetIsHiddenActor; var oldTargetLocation = lastVisibleTargetLocation; - target = target.Recalculate(self.Owner, out targetIsHiddenActor); + target = target.Recalculate(self.Owner, out var targetIsHiddenActor); if (!targetIsHiddenActor && target.Type == TargetType.Actor) { lastVisibleTarget = Target.FromTargetPositions(target); @@ -135,7 +133,7 @@ searchCells.Clear(); searchCellsTick = self.World.WorldTick; foreach (var cell in CandidateMovementCells(self)) - if (domainIndex.IsPassable(loc, cell, Mobile.Info.LocomotorInfo) && Mobile.CanEnterCell(cell)) + if (domainIndex.IsPassable(loc, cell, Mobile.Locomotor) && Mobile.CanEnterCell(cell)) searchCells.Add(cell); } diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Move/Move.cs openra-20210321/OpenRA.Mods.Common/Activities/Move/Move.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Move/Move.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Move/Move.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,7 +52,8 @@ // Ignores lane bias and nearby units public Move(Actor self, CPos destination, Color? targetLineColor = null) { - mobile = self.Trait(); + // PERF: Because we can be sure that OccupiesSpace is Mobile here, we can save some performance by avoiding querying for the trait. + mobile = (Mobile)self.OccupiesSpace; getPath = check => { @@ -72,7 +73,8 @@ public Move(Actor self, CPos destination, WDist nearEnough, Actor ignoreActor = null, bool evaluateNearestMovableCell = false, Color? targetLineColor = null) { - mobile = self.Trait(); + // PERF: Because we can be sure that OccupiesSpace is Mobile here, we can save some performance by avoiding querying for the trait. + mobile = (Mobile)self.OccupiesSpace; getPath = check => { @@ -93,7 +95,8 @@ public Move(Actor self, CPos destination, SubCell subCell, WDist nearEnough, Color? targetLineColor = null) { - mobile = self.Trait(); + // PERF: Because we can be sure that OccupiesSpace is Mobile here, we can save some performance by avoiding querying for the trait. + mobile = (Mobile)self.OccupiesSpace; getPath = check => mobile.Pathfinder.FindUnitPathToRange( mobile.FromCell, subCell, self.World.Map.CenterOfSubCell(destination, subCell), nearEnough, self, check); @@ -105,7 +108,8 @@ public Move(Actor self, Target target, WDist range, Color? targetLineColor = null) { - mobile = self.Trait(); + // PERF: Because we can be sure that OccupiesSpace is Mobile here, we can save some performance by avoiding querying for the trait. + mobile = (Mobile)self.OccupiesSpace; getPath = check => { @@ -123,7 +127,8 @@ public Move(Actor self, Func> getPath, Color? targetLineColor = null) { - mobile = self.Trait(); + // PERF: Because we can be sure that OccupiesSpace is Mobile here, we can save some performance by avoiding querying for the trait. + mobile = (Mobile)self.OccupiesSpace; this.getPath = getPath; @@ -172,8 +177,7 @@ if (IsCanceling && mobile.CanStayInCell(mobile.ToCell)) { - if (path != null) - path.Clear(); + path?.Clear(); return true; } @@ -196,16 +200,16 @@ if (nextCell == null) return false; - var firstFacing = self.World.Map.FacingBetween(mobile.FromCell, nextCell.Value.First, mobile.Facing); + var firstFacing = self.World.Map.FacingBetween(mobile.FromCell, nextCell.Value.Cell, mobile.Facing); if (firstFacing != mobile.Facing) { - path.Add(nextCell.Value.First); + path.Add(nextCell.Value.Cell); QueueChild(new Turn(self, firstFacing)); mobile.TurnToMove = true; return false; } - mobile.SetLocation(mobile.FromCell, mobile.FromSubCell, nextCell.Value.First, nextCell.Value.Second); + mobile.SetLocation(mobile.FromCell, mobile.FromSubCell, nextCell.Value.Cell, nextCell.Value.SubCell); var map = self.World.Map; var from = (mobile.FromCell.Layer == 0 ? map.CenterOfCell(mobile.FromCell) : @@ -219,7 +223,7 @@ return false; } - Pair? PopPath(Actor self) + (CPos Cell, SubCell SubCell)? PopPath(Actor self) { if (path.Count == 0) return null; @@ -305,7 +309,7 @@ var newCell = path[path.Count - 1]; path.RemoveAt(path.Count - 1); - return Pair.New(newCell, mobile.GetAvailableSubCell(nextCell, mobile.FromSubCell, ignoreActor)); + return (newCell, mobile.GetAvailableSubCell(nextCell, mobile.FromSubCell, ignoreActor)); } else if (mobile.IsBlocking) { @@ -316,7 +320,7 @@ if ((nextCell - newCell).Value.LengthSquared > 2) path.Add(mobile.ToCell); - return Pair.New(newCell.Value, mobile.GetAvailableSubCell(newCell.Value, mobile.FromSubCell, ignoreActor)); + return (newCell.Value, mobile.GetAvailableSubCell(newCell.Value, mobile.FromSubCell, ignoreActor)); } } @@ -326,7 +330,7 @@ hasWaited = false; path.RemoveAt(path.Count - 1); - return Pair.New(nextCell, mobile.GetAvailableSubCell(nextCell, mobile.FromSubCell, ignoreActor)); + return (nextCell, mobile.GetAvailableSubCell(nextCell, mobile.FromSubCell, ignoreActor)); } protected override void OnLastRun(Actor self) @@ -372,7 +376,8 @@ public override IEnumerable TargetLineNodes(Actor self) { - if (targetLineColor != null) + // destination might be initialized with null, but will be set in a subsequent tick + if (targetLineColor != null && destination != null) yield return new TargetLineNode(Target.FromCell(self.World, destination.Value), targetLineColor.Value); } @@ -380,7 +385,7 @@ { protected readonly Move Move; protected readonly WPos From, To; - protected readonly int FromFacing, ToFacing; + protected readonly WAngle FromFacing, ToFacing; protected readonly bool EnableArc; protected readonly WPos ArcCenter; protected readonly int ArcFromLength; @@ -391,7 +396,7 @@ protected readonly int MoveFractionTotal; protected int moveFraction; - public MovePart(Move move, WPos from, WPos to, int fromFacing, int toFacing, int startingFraction) + public MovePart(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing, int startingFraction) { Move = move; From = from; @@ -403,23 +408,29 @@ IsInterruptible = false; // See comments in Move.Cancel() // Calculate an elliptical arc that joins from and to - var delta = Util.NormalizeFacing(fromFacing - toFacing); - if (delta != 0 && delta != 128) + var delta = (fromFacing - toFacing).Angle; + if (delta != 0 && delta != 512) { // The center of rotation is where the normal vectors cross - var u = new WVec(1024, 0, 0).Rotate(WRot.FromFacing(fromFacing)); - var v = new WVec(1024, 0, 0).Rotate(WRot.FromFacing(toFacing)); - var w = from - to; - var s = (v.Y * w.X - v.X * w.Y) * 1024 / (v.X * u.Y - v.Y * u.X); - var x = from.X + s * u.X / 1024; - var y = from.Y + s * u.Y / 1024; - - ArcCenter = new WPos(x, y, 0); - ArcFromLength = (ArcCenter - from).HorizontalLength; - ArcFromAngle = (ArcCenter - from).Yaw; - ArcToLength = (ArcCenter - to).HorizontalLength; - ArcToAngle = (ArcCenter - to).Yaw; - EnableArc = true; + var u = new WVec(1024, 0, 0).Rotate(WRot.FromYaw(fromFacing)); + var v = new WVec(1024, 0, 0).Rotate(WRot.FromYaw(toFacing)); + + // Make sure that u and v aren't parallel, which may happen due to rounding + // in WVec.Rotate if delta is close but not necessarily equal to 0 or 512 + if (v.X * u.Y != v.Y * u.X) + { + var w = from - to; + var s = (v.Y * w.X - v.X * w.Y) * 1024 / (v.X * u.Y - v.Y * u.X); + var x = from.X + s * u.X / 1024; + var y = from.Y + s * u.Y / 1024; + + ArcCenter = new WPos(x, y, 0); + ArcFromLength = (ArcCenter - from).HorizontalLength; + ArcFromAngle = (ArcCenter - from).Yaw; + ArcToLength = (ArcCenter - to).HorizontalLength; + ArcToAngle = (ArcCenter - to).Yaw; + EnableArc = true; + } } } @@ -464,15 +475,18 @@ else pos = WPos.Lerp(From, To, moveFraction, MoveFractionTotal); + if (self.Location.Layer == 0) + pos -= new WVec(WDist.Zero, WDist.Zero, self.World.Map.DistanceAboveTerrain(pos)); + mobile.SetVisualPosition(self, pos); } else mobile.SetVisualPosition(self, To); if (moveFraction >= MoveFractionTotal) - mobile.Facing = ToFacing & 0xFF; + mobile.Facing = ToFacing; else - mobile.Facing = int2.Lerp(FromFacing, ToFacing, moveFraction, MoveFractionTotal) & 0xFF; + mobile.Facing = WAngle.Lerp(FromFacing, ToFacing, moveFraction, MoveFractionTotal); } protected abstract MovePart OnComplete(Actor self, Mobile mobile, Move parent); @@ -485,16 +499,20 @@ class MoveFirstHalf : MovePart { - public MoveFirstHalf(Move move, WPos from, WPos to, int fromFacing, int toFacing, int startingFraction) + public MoveFirstHalf(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing, int startingFraction) : base(move, from, to, fromFacing, toFacing, startingFraction) { } static bool IsTurn(Mobile mobile, CPos nextCell, Map map) { + // Some actors with a limited number of sprite facings should never move along curved trajectories. + if (mobile.Info.AlwaysTurnInPlace) + return false; + // Tight U-turns should be done in place instead of making silly looking loops. var nextFacing = map.FacingBetween(nextCell, mobile.ToCell, mobile.Facing); var currentFacing = map.FacingBetween(mobile.ToCell, mobile.FromCell, mobile.Facing); - var delta = Util.NormalizeFacing(nextFacing - currentFacing); - return delta != 0 && (delta < 96 || delta > 160); + var delta = (nextFacing - currentFacing).Angle; + return delta != 0 && (delta < 384 || delta > 640); } protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent) @@ -506,23 +524,23 @@ var nextCell = parent.PopPath(self); if (nextCell != null) { - if (!mobile.IsTraitPaused && !mobile.IsTraitDisabled && IsTurn(mobile, nextCell.Value.First, map)) + if (!mobile.IsTraitPaused && !mobile.IsTraitDisabled && IsTurn(mobile, nextCell.Value.Cell, map)) { - var nextSubcellOffset = map.Grid.OffsetOfSubCell(nextCell.Value.Second); + var nextSubcellOffset = map.Grid.OffsetOfSubCell(nextCell.Value.SubCell); var ret = new MoveFirstHalf( Move, Util.BetweenCells(self.World, mobile.FromCell, mobile.ToCell) + (fromSubcellOffset + toSubcellOffset) / 2, - Util.BetweenCells(self.World, mobile.ToCell, nextCell.Value.First) + (toSubcellOffset + nextSubcellOffset) / 2, + Util.BetweenCells(self.World, mobile.ToCell, nextCell.Value.Cell) + (toSubcellOffset + nextSubcellOffset) / 2, mobile.Facing, - Util.GetNearestFacing(mobile.Facing, map.FacingBetween(mobile.ToCell, nextCell.Value.First, mobile.Facing)), + map.FacingBetween(mobile.ToCell, nextCell.Value.Cell, mobile.Facing), moveFraction - MoveFractionTotal); mobile.FinishedMoving(self); - mobile.SetLocation(mobile.ToCell, mobile.ToSubCell, nextCell.Value.First, nextCell.Value.Second); + mobile.SetLocation(mobile.ToCell, mobile.ToSubCell, nextCell.Value.Cell, nextCell.Value.SubCell); return ret; } - parent.path.Add(nextCell.Value.First); + parent.path.Add(nextCell.Value.Cell); } var toPos = mobile.ToCell.Layer == 0 ? map.CenterOfCell(mobile.ToCell) : @@ -544,7 +562,7 @@ class MoveSecondHalf : MovePart { - public MoveSecondHalf(Move move, WPos from, WPos to, int fromFacing, int toFacing, int startingFraction) + public MoveSecondHalf(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing, int startingFraction) : base(move, from, to, fromFacing, toFacing, startingFraction) { } protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent) diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Move/MoveWithinRange.cs openra-20210321/OpenRA.Mods.Common/Activities/Move/MoveWithinRange.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Move/MoveWithinRange.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Move/MoveWithinRange.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,7 +21,7 @@ readonly WDist maxRange; readonly WDist minRange; - public MoveWithinRange(Actor self, Target target, WDist minRange, WDist maxRange, + public MoveWithinRange(Actor self, in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null) : base(self, target, initialTargetPosition, targetLineColor) { diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Move/VisualMoveIntoTarget.cs openra-20210321/OpenRA.Mods.Common/Activities/Move/VisualMoveIntoTarget.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Move/VisualMoveIntoTarget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Move/VisualMoveIntoTarget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,7 @@ readonly WDist targetMovementThreshold; WPos targetStartPos; - public VisualMoveIntoTarget(Actor self, Target target, WDist targetMovementThreshold, Color? targetLineColor = null) + public VisualMoveIntoTarget(Actor self, in Target target, WDist targetMovementThreshold, Color? targetLineColor = null) { mobile = self.Trait(); this.target = target; @@ -55,7 +55,7 @@ // Turn if required var delta = targetPos - currentPos; - var facing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : mobile.Facing; + var facing = delta.HorizontalLengthSquared != 0 ? delta.Yaw : mobile.Facing; if (facing != mobile.Facing) { mobile.Facing = Util.TickFacing(mobile.Facing, facing, mobile.TurnSpeed); diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/PickupUnit.cs openra-20210321/OpenRA.Mods.Common/Activities/PickupUnit.cs --- openra-20200503/OpenRA.Mods.Common/Activities/PickupUnit.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/PickupUnit.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Collections.Generic; using OpenRA.Activities; using OpenRA.Mods.Common.Traits; @@ -49,12 +48,16 @@ protected override void OnFirstRun(Actor self) { + // The cargo might have become invalid while we were moving towards it. + if (cargo.IsDead || carryable.IsTraitDisabled || !cargo.AppearsFriendlyTo(self)) + return; + if (carryall.ReserveCarryable(self, cargo)) { // Fly to the target and wait for it to be locked for pickup // These activities will be cancelled and replaced by Land once the target has been locked QueueChild(new Fly(self, Target.FromActor(cargo))); - QueueChild(new FlyIdle(self, tickIdle: false)); + QueueChild(new FlyIdle(self, idleTurn: false)); } } @@ -113,7 +116,7 @@ public override IEnumerable TargetLineNodes(Actor self) { - yield return new TargetLineNode(Target.FromActor(cargo), Color.Yellow); + yield return new TargetLineNode(Target.FromActor(cargo), carryall.Info.TargetLineColor); } class AttachUnit : Activity diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/RepairBridge.cs openra-20210321/OpenRA.Mods.Common/Activities/RepairBridge.cs --- openra-20200503/OpenRA.Mods.Common/Activities/RepairBridge.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/RepairBridge.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,8 +24,8 @@ BridgeHut enterHut; LegacyBridgeHut enterLegacyHut; - public RepairBridge(Actor self, Target target, EnterBehaviour enterBehaviour, string notification) - : base(self, target, Color.Yellow) + public RepairBridge(Actor self, in Target target, EnterBehaviour enterBehaviour, string notification, Color targetLineColor) + : base(self, target, targetLineColor) { this.enterBehaviour = enterBehaviour; this.notification = notification; diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/RepairBuilding.cs openra-20210321/OpenRA.Mods.Common/Activities/RepairBuilding.cs --- openra-20200503/OpenRA.Mods.Common/Activities/RepairBuilding.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/RepairBuilding.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,9 +21,10 @@ Actor enterActor; IHealth enterHealth; + EngineerRepairable enterEngineerRepariable; - public RepairBuilding(Actor self, Target target, EngineerRepairInfo info) - : base(self, target, Color.Yellow) + public RepairBuilding(Actor self, in Target target, EngineerRepairInfo info) + : base(self, target, info.TargetLineColor) { this.info = info; } @@ -32,11 +33,12 @@ { enterActor = targetActor; enterHealth = targetActor.TraitOrDefault(); + enterEngineerRepariable = targetActor.TraitOrDefault(); // Make sure we can still repair the target before entering // (but not before, because this may stop the actor in the middle of nowhere) - var stance = self.Owner.Stances[enterActor.Owner]; - if (enterHealth == null || enterHealth.DamageState == DamageState.Undamaged || !info.ValidStances.HasStance(stance)) + var stance = self.Owner.RelationshipWith(enterActor.Owner); + if (enterHealth == null || enterHealth.DamageState == DamageState.Undamaged || enterEngineerRepariable == null || enterEngineerRepariable.IsTraitDisabled || !info.ValidRelationships.HasStance(stance)) { Cancel(self, true); return false; @@ -52,11 +54,14 @@ if (targetActor != enterActor) return; + if (enterEngineerRepariable.IsTraitDisabled) + return; + if (enterHealth.DamageState == DamageState.Undamaged) return; - var stance = self.Owner.Stances[enterActor.Owner]; - if (!info.ValidStances.HasStance(stance)) + var stance = self.Owner.RelationshipWith(enterActor.Owner); + if (!info.ValidRelationships.HasStance(stance)) return; if (enterHealth.DamageState == DamageState.Undamaged) diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Resupply.cs openra-20210321/OpenRA.Mods.Common/Activities/Resupply.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Resupply.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Resupply.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,11 +29,15 @@ readonly RepairableNear repairableNear; readonly Rearmable rearmable; readonly INotifyResupply[] notifyResupplies; + readonly INotifyBeingResupplied[] notifyBeingResupplied; readonly ICallForTransport[] transportCallers; readonly IMove move; readonly Aircraft aircraft; + readonly IMoveInfo moveInfo; readonly bool stayOnResupplier; readonly bool wasRepaired; + readonly PlayerResources playerResources; + readonly int unitCost; int remainingTicks; bool played; @@ -51,9 +55,15 @@ repairableNear = self.TraitOrDefault(); rearmable = self.TraitOrDefault(); notifyResupplies = host.TraitsImplementing().ToArray(); + notifyBeingResupplied = self.TraitsImplementing().ToArray(); transportCallers = self.TraitsImplementing().ToArray(); move = self.Trait(); aircraft = move as Aircraft; + moveInfo = self.Info.TraitInfo(); + playerResources = self.Owner.PlayerActor.Trait(); + + var valued = self.Info.TraitInfoOrDefault(); + unitCost = valued != null ? valued.Cost : 0; var cannotRepairAtHost = health == null || health.DamageState == DamageState.Undamaged || !allRepairsUnits.Any() @@ -121,18 +131,15 @@ else if (activeResupplyTypes != 0 && aircraft == null && !isCloseEnough) { var targetCell = self.World.Map.CellContaining(host.Actor.CenterPosition); - - QueueChild(move.MoveWithinRange(host, closeEnough, targetLineColor: Color.Green)); + QueueChild(move.MoveWithinRange(host, closeEnough, targetLineColor: moveInfo.GetTargetLineColor())); // HACK: Repairable needs the actor to move to host center. // TODO: Get rid of this or at least replace it with something less hacky. if (repairableNear == null) - QueueChild(move.MoveTo(targetCell)); + QueueChild(move.MoveTo(targetCell, targetLineColor: moveInfo.GetTargetLineColor())); var delta = (self.CenterPosition - host.CenterPosition).LengthSquared; - var transport = transportCallers.FirstOrDefault(t => t.MinimumDistance.LengthSquared < delta); - if (transport != null) - transport.RequestTransport(self, targetCell); + transportCallers.FirstOrDefault(t => t.MinimumDistance.LengthSquared < delta)?.RequestTransport(self, targetCell); return false; } @@ -143,6 +150,9 @@ actualResupplyStarted = true; foreach (var notifyResupply in notifyResupplies) notifyResupply.BeforeResupply(host.Actor, self, activeResupplyTypes); + + foreach (var br in notifyBeingResupplied) + br.StartingResupply(self, host.Actor); } if (activeResupplyTypes.HasFlag(ResupplyType.Repair)) @@ -180,10 +190,18 @@ public override IEnumerable TargetLineNodes(Actor self) { if (ChildActivity == null) - yield return new TargetLineNode(host, Color.Green); + yield return new TargetLineNode(host, moveInfo.GetTargetLineColor()); else - foreach (var n in ChildActivity.TargetLineNodes(self)) - yield return n; + { + var current = ChildActivity; + while (current != null) + { + foreach (var n in current.TargetLineNodes(self)) + yield return n; + + current = current.NextActivity; + } + } } void OnResupplyEnding(Actor self, bool isHostInvalid = false) @@ -195,7 +213,7 @@ { if (self.CurrentActivity.NextActivity == null && rp != null && rp.Path.Count > 0) foreach (var cell in rp.Path) - QueueChild(move.MoveTo(cell, 1, ignoreActor: repairableNear != null ? null : host.Actor, targetLineColor: Color.Green)); + QueueChild(new AttackMoveActivity(self, () => move.MoveTo(cell, 1, ignoreActor: repairableNear != null ? null : host.Actor, targetLineColor: aircraft.Info.TargetLineColor))); else QueueChild(new TakeOff(self)); @@ -216,18 +234,20 @@ { if (rp != null && rp.Path.Count > 0) foreach (var cell in rp.Path) - QueueChild(move.MoveTo(cell, 1, repairableNear != null ? null : host.Actor, true)); + QueueChild(new AttackMoveActivity(self, () => move.MoveTo(cell, 1, repairableNear != null ? null : host.Actor, true, moveInfo.GetTargetLineColor()))); else if (repairableNear == null) QueueChild(move.MoveToTarget(self, host)); } else if (repairableNear == null && !(self.CurrentActivity.NextActivity is Move)) QueueChild(move.MoveToTarget(self, host)); } + + foreach (var br in notifyBeingResupplied) + br.StoppingResupply(self, isHostInvalid ? null : host.Actor); } void RepairTick(Actor self) { - // First active. var repairsUnits = allRepairsUnits.FirstOrDefault(r => !r.IsTraitDisabled && !r.IsTraitPaused); if (repairsUnits == null) { @@ -240,11 +260,7 @@ if (health.DamageState == DamageState.Undamaged) { if (host.Actor.Owner != self.Owner) - { - var exp = host.Actor.Owner.PlayerActor.TraitOrDefault(); - if (exp != null) - exp.GiveExperience(repairsUnits.Info.PlayerExperience); - } + host.Actor.Owner.PlayerActor.TraitOrDefault()?.GiveExperience(repairsUnits.Info.PlayerExperience); Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", repairsUnits.Info.FinishRepairingNotification, self.Owner.Faction.InternalName); @@ -254,12 +270,11 @@ if (remainingTicks == 0) { - var valued = self.Info.TraitInfoOrDefault(); - var unitCost = valued != null ? valued.Cost : 0; var hpToRepair = repairable != null && repairable.Info.HpPerStep > 0 ? repairable.Info.HpPerStep : repairsUnits.Info.HpPerStep; // Cast to long to avoid overflow when multiplying by the health - var cost = Math.Max(1, (int)(((long)hpToRepair * unitCost * repairsUnits.Info.ValuePercentage) / (health.MaxHP * 100L))); + var value = (long)unitCost * repairsUnits.Info.ValuePercentage; + var cost = value == 0 ? 0 : Math.Max(1, (int)(hpToRepair * value / (health.MaxHP * 100L))); if (!played) { @@ -267,13 +282,13 @@ Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", repairsUnits.Info.StartRepairingNotification, self.Owner.Faction.InternalName); } - if (!self.Owner.PlayerActor.Trait().TakeCash(cost, true)) + if (!playerResources.TakeCash(cost, true)) { remainingTicks = 1; return; } - self.InflictDamage(host.Actor, new Damage(-hpToRepair)); + self.InflictDamage(host.Actor, new Damage(-hpToRepair, repairsUnits.Info.RepairDamageTypes)); remainingTicks = repairsUnits.Info.Interval; } else diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/RideTransport.cs openra-20210321/OpenRA.Mods.Common/Activities/RideTransport.cs --- openra-20200503/OpenRA.Mods.Common/Activities/RideTransport.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/RideTransport.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,8 +23,8 @@ Cargo enterCargo; Aircraft enterAircraft; - public RideTransport(Actor self, Target target) - : base(self, target, Color.Green) + public RideTransport(Actor self, in Target target, Color? targetLineColor) + : base(self, target, targetLineColor) { passenger = self.Trait(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/SpriteHarvesterDockSequence.cs openra-20210321/OpenRA.Mods.Common/Activities/SpriteHarvesterDockSequence.cs --- openra-20200503/OpenRA.Mods.Common/Activities/SpriteHarvesterDockSequence.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/SpriteHarvesterDockSequence.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using OpenRA.Activities; using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits.Render; @@ -19,8 +18,9 @@ { readonly WithSpriteBody wsb; readonly WithDockingAnimationInfo wda; + protected bool dockAnimPlayed; - public SpriteHarvesterDockSequence(Actor self, Actor refinery, int dockAngle, bool isDragRequired, WVec dragOffset, int dragLength) + public SpriteHarvesterDockSequence(Actor self, Actor refinery, WAngle dockAngle, bool isDragRequired, WVec dragOffset, int dragLength) : base(self, refinery, dockAngle, isDragRequired, dragOffset, dragLength) { wsb = self.Trait(); @@ -31,21 +31,35 @@ { foreach (var trait in self.TraitsImplementing()) trait.Docked(); + foreach (var nd in Refinery.TraitsImplementing()) + nd.Docked(Refinery, self); wsb.PlayCustomAnimation(self, wda.DockSequence, () => wsb.PlayCustomAnimationRepeating(self, wda.DockLoopSequence)); + dockAnimPlayed = true; dockingState = DockingState.Loop; } public override void OnStateUndock(Actor self) { + // If dock animation hasn't played, we didn't actually dock and have to skip the undock anim and notification + if (!dockAnimPlayed) + { + dockingState = DockingState.Complete; + return; + } + + dockingState = DockingState.Wait; wsb.PlayCustomAnimationBackwards(self, wda.DockSequence, () => { dockingState = DockingState.Complete; foreach (var trait in self.TraitsImplementing()) trait.Undocked(); + + if (Refinery.IsInWorld && !Refinery.IsDead) + foreach (var nd in Refinery.TraitsImplementing()) + nd.Undocked(Refinery, self); }); - dockingState = DockingState.Wait; } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Transform.cs openra-20210321/OpenRA.Mods.Common/Activities/Transform.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Transform.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Transform.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,7 +22,7 @@ { public readonly string ToActor; public CVec Offset = CVec.Zero; - public int Facing = 96; + public WAngle Facing = new WAngle(384); public string[] Sounds = { }; public string Notification = null; public int ForceHealthPercentage = 0; @@ -151,7 +151,7 @@ readonly Target target; readonly Color? targetLineColor; - public IssueOrderAfterTransform(string orderString, Target target, Color? targetLineColor = null) + public IssueOrderAfterTransform(string orderString, in Target target, Color? targetLineColor = null) { this.orderString = orderString; this.target = target; diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/Turn.cs openra-20210321/OpenRA.Mods.Common/Activities/Turn.cs --- openra-20200503/OpenRA.Mods.Common/Activities/Turn.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/Turn.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,9 +19,9 @@ { readonly Mobile mobile; readonly IFacing facing; - readonly int desiredFacing; + readonly WAngle desiredFacing; - public Turn(Actor self, int desiredFacing) + public Turn(Actor self, WAngle desiredFacing) { mobile = self.TraitOrDefault(); facing = self.Trait(); diff -Nru openra-20200503/OpenRA.Mods.Common/Activities/UnloadCargo.cs openra-20210321/OpenRA.Mods.Common/Activities/UnloadCargo.cs --- openra-20200503/OpenRA.Mods.Common/Activities/UnloadCargo.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Activities/UnloadCargo.cs 2021-03-21 11:10:05.000000000 +0000 @@ -38,7 +38,7 @@ assignTargetOnFirstRun = true; } - public UnloadCargo(Actor self, Target destination, WDist unloadRange, bool unloadAll = true) + public UnloadCargo(Actor self, in Target destination, WDist unloadRange, bool unloadAll = true) { this.self = self; cargo = self.Trait(); @@ -50,15 +50,15 @@ this.unloadRange = unloadRange; } - public Pair? ChooseExitSubCell(Actor passenger) + public (CPos Cell, SubCell SubCell)? ChooseExitSubCell(Actor passenger) { var pos = passenger.Trait(); return cargo.CurrentAdjacentCells .Shuffle(self.World.SharedRandom) - .Select(c => Pair.New(c, pos.GetAvailableSubCell(c))) - .Cast?>() - .FirstOrDefault(s => s.Value.Second != SubCell.Invalid); + .Select(c => (c, pos.GetAvailableSubCell(c))) + .Cast<(CPos, SubCell SubCell)?>() + .FirstOrDefault(s => s.Value.SubCell != SubCell.Invalid); } IEnumerable BlockedExitCells(Actor passenger) @@ -121,7 +121,7 @@ var move = actor.Trait(); var pos = actor.Trait(); - pos.SetPosition(actor, exitSubCell.Value.First, exitSubCell.Value.Second); + pos.SetPosition(actor, exitSubCell.Value.Cell, exitSubCell.Value.SubCell); pos.SetVisualPosition(actor, spawn); actor.CancelActivity(); diff -Nru openra-20200503/OpenRA.Mods.Common/ActorExts.cs openra-20210321/OpenRA.Mods.Common/ActorExts.cs --- openra-20200503/OpenRA.Mods.Common/ActorExts.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/ActorExts.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common @@ -37,35 +36,33 @@ public static bool AppearsFriendlyTo(this Actor self, Actor toActor) { - var stance = toActor.Owner.Stances[self.Owner]; - if (stance == Stance.Ally) + var stance = toActor.Owner.RelationshipWith(self.Owner); + if (stance == PlayerRelationship.Ally) return true; if (self.EffectiveOwner != null && self.EffectiveOwner.Disguised && !toActor.Info.HasTraitInfo()) - return toActor.Owner.Stances[self.EffectiveOwner.Owner] == Stance.Ally; + return toActor.Owner.RelationshipWith(self.EffectiveOwner.Owner) == PlayerRelationship.Ally; return false; } public static bool AppearsHostileTo(this Actor self, Actor toActor) { - var stance = toActor.Owner.Stances[self.Owner]; - if (stance == Stance.Ally) - return false; /* otherwise, we'll hate friendly disguised spies */ + var stance = toActor.Owner.RelationshipWith(self.Owner); + if (stance == PlayerRelationship.Ally) + return false; if (self.EffectiveOwner != null && self.EffectiveOwner.Disguised && !toActor.Info.HasTraitInfo()) - return toActor.Owner.Stances[self.EffectiveOwner.Owner] == Stance.Enemy; + return toActor.Owner.RelationshipWith(self.EffectiveOwner.Owner) == PlayerRelationship.Enemy; - return stance == Stance.Enemy; + return stance == PlayerRelationship.Enemy; } public static void NotifyBlocker(this Actor self, IEnumerable blockers) { foreach (var blocker in blockers) - { foreach (var moveBlocked in blocker.TraitsImplementing()) moveBlocked.OnNotifyBlockingMove(blocker, self); - } } public static void NotifyBlocker(this Actor self, CPos position) diff -Nru openra-20200503/OpenRA.Mods.Common/ActorInitializer.cs openra-20210321/OpenRA.Mods.Common/ActorInitializer.cs --- openra-20200503/OpenRA.Mods.Common/ActorInitializer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/ActorInitializer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,77 +10,152 @@ #endregion using System; +using System.ComponentModel; +using System.Reflection; +using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.Common { - public class FacingInit : IActorInit + public class FacingInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - readonly int value = 128; - - public FacingInit() { } - public FacingInit(int init) { value = init; } - public int Value(World world) { return value; } + public FacingInit(WAngle value) + : base(value) { } } - public class CreationActivityDelayInit : IActorInit + public class CreationActivityDelayInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - readonly int value = 0; - - public CreationActivityDelayInit() { } - public CreationActivityDelayInit(int init) { value = init; } - public int Value(World world) { return value; } + public CreationActivityDelayInit(int value) + : base(value) { } } - public class DynamicFacingInit : IActorInit> + public class DynamicFacingInit : ValueActorInit>, ISingleInstanceInit { - readonly Func func; - - public DynamicFacingInit(Func func) { this.func = func; } - public Func Value(World world) { return func; } + public DynamicFacingInit(Func value) + : base(value) { } } - public class SubCellInit : IActorInit + // Cannot use ValueInit because map.yaml is expected to use the numeric value instead of enum name + public class SubCellInit : ActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - readonly byte value = (byte)SubCell.FullCell; + readonly int value; + public SubCellInit(SubCell value) + { + this.value = (int)value; + } + + public virtual SubCell Value { get { return (SubCell)value; } } + + public void Initialize(MiniYaml yaml) + { + Initialize((int)FieldLoader.GetValue("value", typeof(int), yaml.Value)); + } - public SubCellInit() { } - public SubCellInit(byte init) { value = init; } - public SubCellInit(SubCell init) { value = (byte)init; } - public SubCell Value(World world) { return (SubCell)value; } + public void Initialize(int value) + { + var field = GetType().GetField("value", BindingFlags.NonPublic | BindingFlags.Instance); + if (field != null) + field.SetValue(this, value); + } + + public override MiniYaml Save() + { + return new MiniYaml(FieldSaver.FormatValue(value)); + } } - public class CenterPositionInit : IActorInit + public class CenterPositionInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - readonly WPos value = WPos.Zero; - - public CenterPositionInit() { } - public CenterPositionInit(WPos init) { value = init; } - public WPos Value(World world) { return value; } + public CenterPositionInit(WPos value) + : base(value) { } } // Allows maps / transformations to specify the faction variant of an actor. - public class FactionInit : IActorInit + public class FactionInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - public readonly string Faction; - - public FactionInit() { } - public FactionInit(string faction) { Faction = faction; } - public string Value(World world) { return Faction; } + public FactionInit(string value) + : base(value) { } } - public class EffectiveOwnerInit : IActorInit + public class EffectiveOwnerInit : ValueActorInit { - [FieldFromYamlKey] - readonly Player value = null; - - public EffectiveOwnerInit() { } - public EffectiveOwnerInit(Player owner) { value = owner; } - Player IActorInit.Value(World world) { return value; } + public EffectiveOwnerInit(Player value) + : base(value) { } + } + + internal class ActorInitLoader : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + return new ActorInitActorReference(value as string); + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string)) + { + var reference = value as ActorInitActorReference; + if (reference != null) + return reference.InternalName; + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + [TypeConverter(typeof(ActorInitLoader))] + public class ActorInitActorReference + { + public readonly string InternalName; + readonly Actor actor; + + public ActorInitActorReference(Actor actor) + { + this.actor = actor; + } + + public ActorInitActorReference(string internalName) + { + InternalName = internalName; + } + + Actor InnerValue(World world) + { + if (actor != null) + return actor; + + var sma = world.WorldActor.Trait(); + return sma.Actors[InternalName]; + } + + /// + /// The lazy value may reference other actors that have not been created + /// yet, so must not be resolved from the actor constructor or Created method. + /// Use a FrameEndTask or wait until it is actually needed. + /// + public Lazy Actor(World world) + { + return new Lazy(() => InnerValue(world)); + } + + public static implicit operator ActorInitActorReference(Actor a) + { + return new ActorInitActorReference(a); + } + + public static implicit operator ActorInitActorReference(string mapName) + { + return new ActorInitActorReference(mapName); + } } } diff -Nru openra-20200503/OpenRA.Mods.Common/AIUtils.cs openra-20210321/OpenRA.Mods.Common/AIUtils.cs --- openra-20200503/OpenRA.Mods.Common/AIUtils.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/AIUtils.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ { public enum BuildingType { Building, Defense, Refinery } - public enum WaterCheck { NotChecked, EnoughWater, NotEnoughWater } + public enum WaterCheck { NotChecked, EnoughWater, NotEnoughWater, DontCheck } public static class AIUtils { @@ -30,7 +30,7 @@ return cells.Select(a => map.FindTilesInCircle(a.Location, radius) .Count(c => map.Contains(c) && terrainTypes.Contains(map.GetTerrainInfo(c).Type) && Util.AdjacentCells(world, Target.FromCell(world, c)) - .All(ac => terrainTypes.Contains(map.GetTerrainInfo(ac).Type)))) + .All(ac => map.Contains(ac) && terrainTypes.Contains(map.GetTerrainInfo(ac).Type)))) .Any(availableCells => availableCells > 0); } @@ -65,7 +65,7 @@ public static List FindEnemiesByCommonName(HashSet commonNames, Player player) { - return player.World.Actors.Where(a => !a.IsDead && player.Stances[a.Owner] == Stance.Enemy && + return player.World.Actors.Where(a => !a.IsDead && player.RelationshipWith(a.Owner) == PlayerRelationship.Enemy && commonNames.Contains(a.Info.Name)).ToList(); } diff -Nru openra-20200503/OpenRA.Mods.Common/ColorValidator.cs openra-20210321/OpenRA.Mods.Common/ColorValidator.cs --- openra-20200503/OpenRA.Mods.Common/ColorValidator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/ColorValidator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Graphics; using OpenRA.Primitives; using OpenRA.Support; @@ -58,14 +57,10 @@ public bool IsValid(Color askedColor, out Color forbiddenColor, IEnumerable terrainColors, IEnumerable playerColors, HashSet errorMessages = null) { // Validate color against HSV - float h, s, v; - int a; - - askedColor.ToAhsv(out a, out h, out s, out v); + askedColor.ToAhsv(out _, out _, out var s, out var v); if (s < HsvSaturationRange[0] || s > HsvSaturationRange[1] || v < HsvValueRange[0] || v > HsvValueRange[1]) { - if (errorMessages != null) - errorMessages.Add("Color was adjusted to be inside the allowed range."); + errorMessages?.Add("Color was adjusted to be inside the allowed range."); forbiddenColor = askedColor; return false; } @@ -73,16 +68,14 @@ // Validate color against the current map tileset if (!IsValid(askedColor, terrainColors, out forbiddenColor)) { - if (errorMessages != null) - errorMessages.Add("Color was adjusted to be less similar to the terrain."); + errorMessages?.Add("Color was adjusted to be less similar to the terrain."); return false; } // Validate color against other clients if (!IsValid(askedColor, playerColors, out forbiddenColor)) { - if (errorMessages != null) - errorMessages.Add("Color was adjusted to be less similar to another player."); + errorMessages?.Add("Color was adjusted to be less similar to another player."); return false; } @@ -96,9 +89,8 @@ { if (TeamColorPresets.Any()) { - Color forbidden; foreach (var c in TeamColorPresets.Shuffle(random)) - if (IsValid(c, out forbidden, terrainColors, playerColors)) + if (IsValid(c, out _, terrainColors, playerColors)) return c; } @@ -108,7 +100,6 @@ public Color RandomValidColor(MersenneTwister random, IEnumerable terrainColors, IEnumerable playerColors) { Color color; - Color forbidden; do { var h = random.Next(255) / 255f; @@ -116,7 +107,7 @@ var v = float2.Lerp(HsvValueRange[0], HsvValueRange[1], random.NextFloat()); color = Color.FromAhsv(h, s, v); } - while (!IsValid(color, out forbidden, terrainColors, playerColors)); + while (!IsValid(color, out _, terrainColors, playerColors)); return color; } @@ -125,8 +116,7 @@ { var errorMessages = new HashSet(); - Color forbiddenColor; - if (IsValid(askedColor, out forbiddenColor, terrainColors, playerColors, errorMessages)) + if (IsValid(askedColor, out var forbiddenColor, terrainColors, playerColors, errorMessages)) return askedColor; // Vector between the 2 colors diff -Nru openra-20200503/OpenRA.Mods.Common/Commands/DevCommands.cs openra-20210321/OpenRA.Mods.Common/Commands/DevCommands.cs --- openra-20200503/OpenRA.Mods.Common/Commands/DevCommands.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Commands/DevCommands.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System; -using System.Globalization; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; @@ -148,8 +147,7 @@ var orderString = toAll ? "DevGiveCashAll" : "DevGiveCash"; var giveCashOrder = new Order(orderString, world.LocalPlayer.PlayerActor, false); - int cash; - int.TryParse(arg, out cash); + int.TryParse(arg, out var cash); giveCashOrder.ExtraData = (uint)cash; world.IssueOrder(giveCashOrder); diff -Nru openra-20200503/OpenRA.Mods.Common/Commands/HelpCommand.cs openra-20210321/OpenRA.Mods.Common/Commands/HelpCommand.cs --- openra-20200503/OpenRA.Mods.Common/Commands/HelpCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Commands/HelpCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -45,8 +45,7 @@ foreach (var key in console.Commands.Keys) { - string description; - if (!helpDescriptions.TryGetValue(key, out description)) + if (!helpDescriptions.TryGetValue(key, out var description)) description = "no description available."; Game.Debug("{0}: {1}", key, description); diff -Nru openra-20200503/OpenRA.Mods.Common/DiscordService.cs openra-20210321/OpenRA.Mods.Common/DiscordService.cs --- openra-20200503/OpenRA.Mods.Common/DiscordService.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/DiscordService.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,213 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using DiscordRPC; +using DiscordRPC.Message; +using OpenRA.Network; + +namespace OpenRA.Mods.Common +{ + public enum DiscordState + { + Unknown, + InMenu, + InMapEditor, + InSkirmishLobby, + InMultiplayerLobby, + PlayingMultiplayer, + WatchingReplay, + PlayingCampaign, + PlayingSkirmish + } + + public sealed class DiscordService : IGlobalModData, IDisposable + { + public readonly string ApplicationId = null; + DiscordRpcClient client; + DiscordState currentState; + + static DiscordService instance; + static DiscordService Service + { + get + { + if (instance != null) + return instance; + + if (!Game.ModData.Manifest.Contains()) + return null; + + instance = Game.ModData.Manifest.Get(); + return instance; + } + } + + public DiscordService(MiniYaml yaml) + { + FieldLoader.Load(this, yaml); + + // HACK: Prevent service from starting when launching the utility or server. + if (Game.Renderer == null) + return; + + client = new DiscordRpcClient(ApplicationId, autoEvents: true) + { + SkipIdenticalPresence = false + }; + + client.OnJoin += OnJoin; + client.OnJoinRequested += OnJoinRequested; + + // HACK: We need to set HasRegisteredUriScheme to bypass the check that is done when calling SetPresence with a joinSecret. + // DiscordRpc lib expect us to register uri handlers with RegisterUriScheme(), we are doing it ourselves in our installers/launchers. + client.GetType().GetProperty("HasRegisteredUriScheme").SetValue(client, true); + + client.SetSubscription(EventType.Join | EventType.JoinRequest); + client.Initialize(); + } + + void OnJoinRequested(object sender, JoinRequestMessage args) + { + var client = (DiscordRpcClient)sender; + client.Respond(args, true); + } + + void OnJoin(object sender, JoinMessage args) + { + if (currentState != DiscordState.InMenu) + return; + + var server = args.Secret.Split('|'); + Game.RunAfterTick(() => + { + Game.RemoteDirectConnect(new ConnectionTarget(server[0], int.Parse(server[1]))); + }); + } + + void SetStatus(DiscordState state, string details = null, string secret = null, int? players = null, int? slots = null) + { + if (currentState == state) + return; + + if (instance == null) + return; + + string stateText; + DateTime? timestamp = null; + Party party = null; + Secrets secrets = null; + + switch (state) + { + case DiscordState.InMenu: + stateText = "In menu"; + break; + case DiscordState.InMapEditor: + stateText = "In Map Editor"; + break; + case DiscordState.InSkirmishLobby: + stateText = "In Skirmish Lobby"; + break; + case DiscordState.InMultiplayerLobby: + stateText = "In Multiplayer Lobby"; + timestamp = DateTime.UtcNow; + party = new Party + { + ID = Secrets.CreateFriendlySecret(new Random()), + Size = players.Value, + Max = slots.Value + }; + secrets = new Secrets + { + JoinSecret = secret + }; + break; + case DiscordState.PlayingMultiplayer: + stateText = "Playing Multiplayer"; + timestamp = DateTime.UtcNow; + break; + case DiscordState.PlayingCampaign: + stateText = "Playing Campaign"; + timestamp = DateTime.UtcNow; + break; + case DiscordState.WatchingReplay: + stateText = "Watching Replay"; + timestamp = DateTime.UtcNow; + break; + case DiscordState.PlayingSkirmish: + stateText = "Playing Skirmish"; + timestamp = DateTime.UtcNow; + break; + default: + throw new ArgumentOutOfRangeException("state", state, null); + } + + var richPresence = new RichPresence + { + Details = details, + State = stateText, + Assets = new Assets + { + LargeImageKey = "large", + LargeImageText = Game.ModData.Manifest.Metadata.Title, + }, + Timestamps = timestamp.HasValue ? new Timestamps(timestamp.Value) : null, + Party = party, + Secrets = secrets + }; + + client.SetPresence(richPresence); + currentState = state; + } + + void UpdateParty(int players, int slots) + { + if (client.CurrentPresence.Party != null) + { + client.UpdatePartySize(players, slots); + return; + } + + client.UpdateParty(new Party + { + ID = Secrets.CreateFriendlySecret(new Random()), + Size = players, + Max = slots + }); + } + + public void Dispose() + { + if (client != null) + { + client.Dispose(); + client = null; + instance = null; + } + } + + public static void UpdateStatus(DiscordState state, string details = null, string secret = null, int? players = null, int? slots = null) + { + Service?.SetStatus(state, details, secret, players, slots); + } + + public static void UpdatePlayers(int players, int slots) + { + Service?.UpdateParty(players, slots); + } + + public static void UpdateDetails(string details) + { + Service?.client.UpdateDetails(details); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/EditorBrushes/EditorActorBrush.cs openra-20210321/OpenRA.Mods.Common/EditorBrushes/EditorActorBrush.cs --- openra-20200503/OpenRA.Mods.Common/EditorBrushes/EditorActorBrush.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/EditorBrushes/EditorActorBrush.cs 2021-03-21 11:10:05.000000000 +0000 @@ -62,7 +62,7 @@ if (!actor.Footprint.All(c => world.Map.Tiles.Contains(c.Key))) return true; - var action = new AddActorAction(editorLayer, actor.Actor); + var action = new AddActorAction(editorLayer, actor.Export()); editorActionManager.Add(action); } diff -Nru openra-20200503/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs openra-20210321/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs --- openra-20200503/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs 2021-03-21 11:10:05.000000000 +0000 @@ -116,7 +116,7 @@ var dest = new CellRegion(gridType, source.TopLeft + offset, source.BottomRight + offset); var previews = new Dictionary(); - var tiles = new Dictionary>(); + var tiles = new Dictionary(); var copyFilters = getCopyFilters(); foreach (var cell in source) @@ -124,7 +124,7 @@ if (!mapTiles.Contains(cell) || !mapTiles.Contains(cell + offset)) continue; - tiles.Add(cell + offset, Tuple.Create(mapTiles[cell], mapResources[cell], mapHeight[cell])); + tiles.Add(cell + offset, (mapTiles[cell], mapResources[cell], mapHeight[cell])); if (copyFilters.HasFlag(MapCopyFilters.Actors)) { @@ -134,11 +134,11 @@ continue; var copy = preview.Export(); - if (copy.InitDict.Contains()) + var locationInit = copy.GetOrDefault(); + if (locationInit != null) { - var location = copy.InitDict.Get(); - copy.InitDict.Remove(location); - copy.InitDict.Add(new LocationInit(location.Value(worldRenderer.World) + offset)); + copy.RemoveAll(); + copy.Add(new LocationInit(locationInit.Value + offset)); } previews.Add(preview.ID, copy); @@ -178,7 +178,7 @@ public string Text { get; private set; } readonly MapCopyFilters copyFilters; - readonly Dictionary> tiles; + readonly Dictionary tiles; readonly Dictionary previews; readonly EditorActorLayer editorLayer; readonly CellRegion dest; @@ -191,7 +191,7 @@ readonly Queue addedActorPreviews = new Queue(); public CopyPasteEditorAction(MapCopyFilters copyFilters, Map map, - Dictionary> tiles, Dictionary previews, + Dictionary tiles, Dictionary previews, EditorActorLayer editorLayer, CellRegion dest) { this.copyFilters = copyFilters; @@ -219,12 +219,12 @@ undoCopyPastes.Enqueue(new UndoCopyPaste(kv.Key, mapTiles[kv.Key], mapResources[kv.Key], mapHeight[kv.Key])); if (copyFilters.HasFlag(MapCopyFilters.Terrain)) - mapTiles[kv.Key] = kv.Value.Item1; + mapTiles[kv.Key] = kv.Value.Tile; if (copyFilters.HasFlag(MapCopyFilters.Resources)) - mapResources[kv.Key] = kv.Value.Item2; + mapResources[kv.Key] = kv.Value.Resource; - mapHeight[kv.Key] = kv.Value.Item3; + mapHeight[kv.Key] = kv.Value.Height; } if (copyFilters.HasFlag(MapCopyFilters.Actors)) diff -Nru openra-20200503/OpenRA.Mods.Common/EditorBrushes/EditorDefaultBrush.cs openra-20210321/OpenRA.Mods.Common/EditorBrushes/EditorDefaultBrush.cs --- openra-20200503/OpenRA.Mods.Common/EditorBrushes/EditorDefaultBrush.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/EditorBrushes/EditorDefaultBrush.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,6 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; -using OpenRA.Traits; namespace OpenRA.Mods.Common.Widgets { diff -Nru openra-20200503/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs openra-20210321/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs --- openra-20200503/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs 2021-03-21 11:10:05.000000000 +0000 @@ -115,69 +115,7 @@ if (replace.Type == Template) return; - var queue = new Queue(); - var touched = new CellLayer(map); - - var tileset = map.Rules.TileSet; - var template = tileset.Templates[Template]; - - Action maybeEnqueue = newCell => - { - if (map.Contains(cell) && !touched[newCell]) - { - queue.Enqueue(newCell); - touched[newCell] = true; - } - }; - - Func shouldPaint = cellToCheck => - { - for (var y = 0; y < template.Size.Y; y++) - { - for (var x = 0; x < template.Size.X; x++) - { - var c = cellToCheck + new CVec(x, y); - if (!map.Contains(c) || mapTiles[c].Type != replace.Type) - return false; - } - } - - return true; - }; - - Func findEdge = (refCell, direction) => - { - while (true) - { - var newCell = refCell + direction; - if (!shouldPaint(newCell)) - return refCell; - refCell = newCell; - } - }; - - queue.Enqueue(cell); - while (queue.Count > 0) - { - var queuedCell = queue.Dequeue(); - if (!shouldPaint(queuedCell)) - continue; - - var previousCell = findEdge(queuedCell, new CVec(-1 * template.Size.X, 0)); - var nextCell = findEdge(queuedCell, new CVec(1 * template.Size.X, 0)); - - for (var x = previousCell.X; x <= nextCell.X; x += template.Size.X) - { - PaintCell(new CPos(x, queuedCell.Y), isMoving); - var upperCell = new CPos(x, queuedCell.Y - (1 * template.Size.Y)); - var lowerCell = new CPos(x, queuedCell.Y + (1 * template.Size.Y)); - - if (shouldPaint(upperCell)) - maybeEnqueue(upperCell); - if (shouldPaint(lowerCell)) - maybeEnqueue(lowerCell); - } - } + editorActionManager.Add(new FloodFillEditorAction(Template, map, cell)); } bool PlacementOverlapsSameTemplate(TerrainTemplateInfo template, CPos cell) @@ -277,6 +215,141 @@ } } } + + class FloodFillEditorAction : IEditorAction + { + public string Text { get; private set; } + + readonly ushort template; + readonly Map map; + readonly CPos cell; + + readonly Queue undoTiles = new Queue(); + readonly TerrainTemplateInfo terrainTemplate; + + public FloodFillEditorAction(ushort template, Map map, CPos cell) + { + this.template = template; + this.map = map; + this.cell = cell; + + var tileset = map.Rules.TileSet; + terrainTemplate = tileset.Templates[template]; + Text = "Filled with tile {0}".F(terrainTemplate.Id); + } + + public void Execute() + { + Do(); + } + + public void Do() + { + var queue = new Queue(); + var touched = new CellLayer(map); + var mapTiles = map.Tiles; + var replace = mapTiles[cell]; + + Action maybeEnqueue = newCell => + { + if (map.Contains(cell) && !touched[newCell]) + { + queue.Enqueue(newCell); + touched[newCell] = true; + } + }; + + Func shouldPaint = cellToCheck => + { + for (var y = 0; y < terrainTemplate.Size.Y; y++) + { + for (var x = 0; x < terrainTemplate.Size.X; x++) + { + var c = cellToCheck + new CVec(x, y); + if (!map.Contains(c) || mapTiles[c].Type != replace.Type) + return false; + } + } + + return true; + }; + + Func findEdge = (refCell, direction) => + { + while (true) + { + var newCell = refCell + direction; + if (!shouldPaint(newCell)) + return refCell; + refCell = newCell; + } + }; + + queue.Enqueue(cell); + while (queue.Count > 0) + { + var queuedCell = queue.Dequeue(); + if (!shouldPaint(queuedCell)) + continue; + + var previousCell = findEdge(queuedCell, new CVec(-1 * terrainTemplate.Size.X, 0)); + var nextCell = findEdge(queuedCell, new CVec(1 * terrainTemplate.Size.X, 0)); + + for (var x = previousCell.X; x <= nextCell.X; x += terrainTemplate.Size.X) + { + PaintSingleCell(new CPos(x, queuedCell.Y)); + var upperCell = new CPos(x, queuedCell.Y - (1 * terrainTemplate.Size.Y)); + var lowerCell = new CPos(x, queuedCell.Y + (1 * terrainTemplate.Size.Y)); + + if (shouldPaint(upperCell)) + maybeEnqueue(upperCell); + if (shouldPaint(lowerCell)) + maybeEnqueue(lowerCell); + } + } + } + + public void Undo() + { + var mapTiles = map.Tiles; + var mapHeight = map.Height; + + while (undoTiles.Count > 0) + { + var undoTile = undoTiles.Dequeue(); + + mapTiles[undoTile.Cell] = undoTile.MapTile; + mapHeight[undoTile.Cell] = undoTile.Height; + } + } + + void PaintSingleCell(CPos cellToPaint) + { + var mapTiles = map.Tiles; + var mapHeight = map.Height; + var baseHeight = mapHeight.Contains(cellToPaint) ? mapHeight[cellToPaint] : (byte)0; + + var i = 0; + for (var y = 0; y < terrainTemplate.Size.Y; y++) + { + for (var x = 0; x < terrainTemplate.Size.X; x++, i++) + { + if (terrainTemplate.Contains(i) && terrainTemplate[i] != null) + { + var index = terrainTemplate.PickAny ? (byte)Game.CosmeticRandom.Next(0, terrainTemplate.TilesCount) : (byte)i; + var c = cellToPaint + new CVec(x, y); + if (!mapTiles.Contains(c)) + continue; + + undoTiles.Enqueue(new UndoTile(c, mapTiles[c], mapHeight[c])); + + mapTiles[c] = new TerrainTile(template, index); + mapHeight[c] = (byte)(baseHeight + terrainTemplate[index].Height).Clamp(0, map.Grid.MaximumTerrainHeight); + } + } + } + } + } class UndoTile { diff -Nru openra-20200503/OpenRA.Mods.Common/Effects/Beacon.cs openra-20210321/OpenRA.Mods.Common/Effects/Beacon.cs --- openra-20200503/OpenRA.Mods.Common/Effects/Beacon.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Effects/Beacon.cs 2021-03-21 11:10:05.000000000 +0000 @@ -96,17 +96,10 @@ arrowSpeed *= -1; } - if (arrow != null) - arrow.Tick(); - - if (beacon != null) - beacon.Tick(); - - if (circles != null) - circles.Tick(); - - if (clock != null) - clock.Tick(); + arrow?.Tick(); + beacon?.Tick(); + circles?.Tick(); + clock?.Tick(); if (duration > 0 && duration <= tick++) owner.World.AddFrameEndTask(w => w.Remove(this)); diff -Nru openra-20200503/OpenRA.Mods.Common/Effects/RallyPointIndicator.cs openra-20210321/OpenRA.Mods.Common/Effects/RallyPointIndicator.cs --- openra-20200503/OpenRA.Mods.Common/Effects/RallyPointIndicator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Effects/RallyPointIndicator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,22 +17,20 @@ namespace OpenRA.Mods.Common.Effects { - class RallyPointIndicator : IEffect, IEffectAboveShroud, IEffectAnnotation + public class RallyPointIndicator : IEffect, IEffectAboveShroud, IEffectAnnotation { readonly Actor building; readonly RallyPoint rp; readonly Animation flag; readonly Animation circles; - readonly ExitInfo[] exits; List targetLineNodes = new List { }; List cachedLocations; - public RallyPointIndicator(Actor building, RallyPoint rp, ExitInfo[] exits) + public RallyPointIndicator(Actor building, RallyPoint rp) { this.building = building; this.rp = rp; - this.exits = exits; if (rp.Info.Image != null) { @@ -48,18 +46,15 @@ void IEffect.Tick(World world) { - if (flag != null) - flag.Tick(); + flag?.Tick(); - if (circles != null) - circles.Tick(); + circles?.Tick(); if (cachedLocations == null || !cachedLocations.SequenceEqual(rp.Path)) { UpdateTargetLineNodes(world); - if (circles != null) - circles.Play(rp.Info.CirclesSequence); + circles?.Play(rp.Info.CirclesSequence); } if (!building.IsInWorld || building.IsDead) @@ -76,22 +71,8 @@ if (targetLineNodes.Count == 0) return; - var exitPos = building.CenterPosition; - - // Find closest exit - var dist = int.MaxValue; - foreach (var exit in exits) - { - var ep = building.CenterPosition + exit.SpawnOffset; - var len = (targetLineNodes[0] - ep).Length; - if (len < dist) - { - dist = len; - exitPos = ep; - } - } - - targetLineNodes.Insert(0, exitPos); + var exit = building.NearestExitOrDefault(targetLineNodes[0]); + targetLineNodes.Insert(0, building.CenterPosition + (exit?.Info.SpawnOffset ?? WVec.Zero)); } IEnumerable IEffect.Render(WorldRenderer wr) { return SpriteRenderable.None; } diff -Nru openra-20200503/OpenRA.Mods.Common/Effects/RevealShroudEffect.cs openra-20210321/OpenRA.Mods.Common/Effects/RevealShroudEffect.cs --- openra-20200503/OpenRA.Mods.Common/Effects/RevealShroudEffect.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Effects/RevealShroudEffect.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,12 +25,12 @@ readonly Player player; readonly Shroud.SourceType sourceType; readonly WDist revealRadius; - readonly Stance validStances; + readonly PlayerRelationship validStances; readonly int duration; int ticks; - public RevealShroudEffect(WPos pos, WDist radius, Shroud.SourceType type, Player forPlayer, Stance stances, int delay = 0, int duration = 50) + public RevealShroudEffect(WPos pos, WDist radius, Shroud.SourceType type, Player forPlayer, PlayerRelationship stances, int delay = 0, int duration = 50) { this.pos = pos; player = forPlayer; @@ -41,7 +41,11 @@ ticks = -delay; } - void AddCellsToPlayerShroud(Player p, PPos[] uv) { if (!validStances.HasStance(p.Stances[player])) return; p.Shroud.AddSource(this, sourceType, uv); } + void AddCellsToPlayerShroud(Player p, PPos[] uv) + { + if (validStances.HasStance(player.RelationshipWith(p))) + p.Shroud.AddSource(this, sourceType, uv); + } void RemoveCellsFromPlayerShroud(Player p) { p.Shroud.RemoveSource(this); } @@ -52,8 +56,7 @@ if (range == WDist.Zero) return NoCells; - return Shroud.ProjectedCellsInRange(map, pos, WDist.Zero, range) - .ToArray(); + return Shroud.ProjectedCellsInRange(map, pos, WDist.Zero, range).ToArray(); } public void Tick(World world) diff -Nru openra-20200503/OpenRA.Mods.Common/Effects/SpawnActorEffect.cs openra-20210321/OpenRA.Mods.Common/Effects/SpawnActorEffect.cs --- openra-20200503/OpenRA.Mods.Common/Effects/SpawnActorEffect.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Effects/SpawnActorEffect.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,14 +9,11 @@ */ #endregion -using System; using System.Collections.Generic; -using System.Linq; using OpenRA.Activities; using OpenRA.Effects; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; -using OpenRA.Traits; namespace OpenRA.Mods.Common.Effects { diff -Nru openra-20200503/OpenRA.Mods.Common/Effects/SpriteAnnotation.cs openra-20210321/OpenRA.Mods.Common/Effects/SpriteAnnotation.cs --- openra-20200503/OpenRA.Mods.Common/Effects/SpriteAnnotation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Effects/SpriteAnnotation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Collections.Generic; using OpenRA.Effects; using OpenRA.Graphics; diff -Nru openra-20200503/OpenRA.Mods.Common/Effects/SpriteEffect.cs openra-20210321/OpenRA.Mods.Common/Effects/SpriteEffect.cs --- openra-20200503/OpenRA.Mods.Common/Effects/SpriteEffect.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Effects/SpriteEffect.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,14 +31,18 @@ // Facing is last on these overloads partially for backwards compatibility with previous main ctor revision // and partially because most effects don't need it. The latter is also the reason for placement of 'delay'. public SpriteEffect(WPos pos, World world, string image, string sequence, string palette, - bool visibleThroughFog = false, int facing = 0, int delay = 0) - : this(() => pos, () => facing, world, image, sequence, palette, visibleThroughFog, delay) { } + bool visibleThroughFog = false, int delay = 0) + : this(() => pos, () => WAngle.Zero, world, image, sequence, palette, visibleThroughFog, delay) { } public SpriteEffect(Actor actor, World world, string image, string sequence, string palette, - bool visibleThroughFog = false, int facing = 0, int delay = 0) - : this(() => actor.CenterPosition, () => facing, world, image, sequence, palette, visibleThroughFog, delay) { } + bool visibleThroughFog = false, int delay = 0) + : this(() => actor.CenterPosition, () => WAngle.Zero, world, image, sequence, palette, visibleThroughFog, delay) { } + + public SpriteEffect(WPos pos, WAngle facing, World world, string image, string sequence, string palette, + bool visibleThroughFog = false, int delay = 0) + : this(() => pos, () => facing, world, image, sequence, palette, visibleThroughFog, delay) { } - public SpriteEffect(Func posFunc, Func facingFunc, World world, string image, string sequence, string palette, + public SpriteEffect(Func posFunc, Func facingFunc, World world, string image, string sequence, string palette, bool visibleThroughFog = false, int delay = 0) { this.world = world; diff -Nru openra-20200503/OpenRA.Mods.Common/FileFormats/Blast.cs openra-20210321/OpenRA.Mods.Common/FileFormats/Blast.cs --- openra-20200503/OpenRA.Mods.Common/FileFormats/Blast.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/FileFormats/Blast.cs 2021-03-21 11:10:05.000000000 +0000 @@ -107,8 +107,7 @@ for (var i = 0; i < next; i++) output.WriteByte(outBuffer[i]); - if (onProgress != null) - onProgress(input.Position - inputStart, output.Position - outputStart); + onProgress?.Invoke(input.Position - inputStart, output.Position - outputStart); break; } @@ -155,8 +154,7 @@ next = 0; first = false; - if (onProgress != null) - onProgress(input.Position - inputStart, output.Position - outputStart); + onProgress?.Invoke(input.Position - inputStart, output.Position - outputStart); } } while (len != 0); @@ -173,8 +171,7 @@ next = 0; first = false; - if (onProgress != null) - onProgress(input.Position - inputStart, output.Position - outputStart); + onProgress?.Invoke(input.Position - inputStart, output.Position - outputStart); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/FileFormats/IniFile.cs openra-20210321/OpenRA.Mods.Common/FileFormats/IniFile.cs --- openra-20200503/OpenRA.Mods.Common/FileFormats/IniFile.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/FileFormats/IniFile.cs 2021-03-21 11:10:05.000000000 +0000 @@ -62,8 +62,7 @@ return null; var sectionName = m.Groups[1].Value.ToLowerInvariant(); - IniSection ret; - if (!sections.TryGetValue(sectionName, out ret)) + if (!sections.TryGetValue(sectionName, out var ret)) sections.Add(sectionName, ret = new IniSection(sectionName)); return ret; } @@ -102,8 +101,7 @@ public IniSection GetSection(string s, bool allowFail) { - IniSection section; - if (sections.TryGetValue(s.ToLowerInvariant(), out section)) + if (sections.TryGetValue(s.ToLowerInvariant(), out var section)) return section; if (allowFail) @@ -136,8 +134,7 @@ public string GetValue(string key, string defaultValue) { - string s; - return values.TryGetValue(key, out s) ? s : defaultValue; + return values.TryGetValue(key, out var s) ? s : defaultValue; } public IEnumerator> GetEnumerator() diff -Nru openra-20200503/OpenRA.Mods.Common/FileFormats/InstallShieldCABCompression.cs openra-20210321/OpenRA.Mods.Common/FileFormats/InstallShieldCABCompression.cs --- openra-20200503/OpenRA.Mods.Common/FileFormats/InstallShieldCABCompression.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/FileFormats/InstallShieldCABCompression.cs 2021-03-21 11:10:05.000000000 +0000 @@ -243,8 +243,7 @@ toExtract -= bytesToExtract; while (!inf.IsNeedingInput) { - if (onProgress != null) - onProgress((int)(100 * output.Position / file.ExpandedSize)); + onProgress?.Invoke((int)(100 * output.Position / file.ExpandedSize)); var inflated = inf.Inflate(buffer); output.Write(buffer, 0, inflated); @@ -258,8 +257,7 @@ { do { - if (onProgress != null) - onProgress((int)(100 * output.Position / file.ExpandedSize)); + onProgress?.Invoke((int)(100 * output.Position / file.ExpandedSize)); toExtract -= remainingInArchive; output.Write(GetBytes(remainingInArchive), 0, (int)remainingInArchive); @@ -394,8 +392,7 @@ public void ExtractFile(string filename, Stream output, Action onProgress = null) { - FileDescriptor file; - if (!index.TryGetValue(filename, out file)) + if (!index.TryGetValue(filename, out var file)) throw new FileNotFoundException(filename); ExtractFile(file, output, onProgress); diff -Nru openra-20200503/OpenRA.Mods.Common/FileFormats/MSCabCompression.cs openra-20210321/OpenRA.Mods.Common/FileFormats/MSCabCompression.cs --- openra-20200503/OpenRA.Mods.Common/FileFormats/MSCabCompression.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/FileFormats/MSCabCompression.cs 2021-03-21 11:10:05.000000000 +0000 @@ -101,8 +101,7 @@ var decompressedBytes = 0; for (var i = 0; i < folder.BlockCount; i++) { - if (onProgress != null) - onProgress((int)(100 * output.Position / file.DecompressedLength)); + onProgress?.Invoke((int)(100 * output.Position / file.DecompressedLength)); // Ignore checksums stream.Position += 4; diff -Nru openra-20200503/OpenRA.Mods.Common/FileFormats/VqaReader.cs openra-20210321/OpenRA.Mods.Common/FileFormats/VqaReader.cs --- openra-20200503/OpenRA.Mods.Common/FileFormats/VqaReader.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/FileFormats/VqaReader.cs 2021-03-21 11:10:05.000000000 +0000 @@ -39,6 +39,7 @@ byte[] cbf; byte[] cbp; byte[] cbfBuffer; + bool cbpIsCompressed; // Buffer for loading file subchunks, the maximum chunk size of a file is not defined // and the header definition for the size of the biggest chunks (color data) isn't accurate. @@ -314,6 +315,20 @@ // VQA Frame public void DecodeVQFR(Stream s, string parentType = "VQFR") { + // The CBP chunks each contain 1/8th of the full lookup table + // Annoyingly, the complete table is not applied until the frame + // *after* the one that contains the 8th chunk. + // Do we have a set of partial lookup tables ready to apply? + if (currentChunkBuffer == chunkBufferParts && chunkBufferParts != 0) + { + if (!cbpIsCompressed) + cbf = (byte[])cbp.Clone(); + else + LCWDecodeInto(cbp, cbf); + + chunkBufferOffset = currentChunkBuffer = 0; + } + while (true) { // Chunks are aligned on even bytes; may be padded with a single null @@ -360,21 +375,11 @@ // frame-modifier chunk case "CBP0": case "CBPZ": - // Partial buffer is full; dump and recreate - if (currentChunkBuffer == chunkBufferParts) - { - if (type == "CBP0") - cbf = (byte[])cbp.Clone(); - else - LCWDecodeInto(cbp, cbf); - - chunkBufferOffset = currentChunkBuffer = 0; - } - var bytes = s.ReadBytes(subchunkLength); bytes.CopyTo(cbp, chunkBufferOffset); chunkBufferOffset += subchunkLength; currentChunkBuffer++; + cbpIsCompressed = type == "CBPZ"; break; // Palette diff -Nru openra-20200503/OpenRA.Mods.Common/FileSystem/InstallShieldPackage.cs openra-20210321/OpenRA.Mods.Common/FileSystem/InstallShieldPackage.cs --- openra-20200503/OpenRA.Mods.Common/FileSystem/InstallShieldPackage.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/FileSystem/InstallShieldPackage.cs 2021-03-21 11:10:05.000000000 +0000 @@ -109,8 +109,7 @@ public Stream GetStream(string filename) { - Entry e; - if (!index.TryGetValue(filename, out e)) + if (!index.TryGetValue(filename, out var e)) return null; s.Seek(dataStart + e.Offset, SeekOrigin.Begin); diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/ActorPreview.cs openra-20210321/OpenRA.Mods.Common/Graphics/ActorPreview.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/ActorPreview.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/ActorPreview.cs 2021-03-21 11:10:05.000000000 +0000 @@ -32,66 +32,82 @@ public readonly WorldRenderer WorldRenderer; public World World { get { return WorldRenderer.World; } } - readonly TypeDictionary dict; + readonly ActorReference reference; public ActorPreviewInitializer(ActorInfo actor, WorldRenderer worldRenderer, TypeDictionary dict) { Actor = actor; WorldRenderer = worldRenderer; - this.dict = dict; + reference = new ActorReference(actor.Name.ToLowerInvariant(), dict); } - public T Get() where T : IActorInit { return dict.Get(); } - public U Get() where T : IActorInit { return dict.Get().Value(World); } - public bool Contains() where T : IActorInit { return dict.Contains(); } + public ActorPreviewInitializer(ActorReference actor, WorldRenderer worldRenderer) + { + Actor = worldRenderer.World.Map.Rules.Actors[actor.Type.ToLowerInvariant()]; + reference = actor; + WorldRenderer = worldRenderer; + } + + // Forward IActorInitializer queries to the actor reference + // ActorReference can't reference a World instance, which prevents it from implementing this directly. + public T GetOrDefault(TraitInfo info) where T : ActorInit { return reference.GetOrDefault(info); } + public T Get(TraitInfo info) where T : ActorInit { return reference.Get(info); } + public U GetValue(TraitInfo info) where T : ValueActorInit { return reference.GetValue(info); } + public U GetValue(TraitInfo info, U fallback) where T : ValueActorInit { return reference.GetValue(info, fallback); } + public bool Contains(TraitInfo info) where T : ActorInit { return reference.Contains(info); } + public T GetOrDefault() where T : ActorInit, ISingleInstanceInit { return reference.GetOrDefault(); } + public T Get() where T : ActorInit, ISingleInstanceInit { return reference.Get(); } + public U GetValue() where T : ValueActorInit, ISingleInstanceInit { return reference.GetValue(); } + public U GetValue(U fallback) where T : ValueActorInit, ISingleInstanceInit { return reference.GetValue(fallback); } + public bool Contains() where T : ActorInit, ISingleInstanceInit { return reference.Contains(); } public Func GetOrientation() { var facingInfo = Actor.TraitInfoOrDefault(); if (facingInfo == null) - return () => WRot.Zero; + return () => WRot.None; // Dynamic facing takes priority - var dynamicInit = dict.GetOrDefault(); + var dynamicInit = reference.GetOrDefault(); if (dynamicInit != null) { // TODO: Account for terrain slope - var getFacing = dynamicInit.Value(null); - return () => WRot.FromFacing(getFacing()); + var getFacing = dynamicInit.Value; + return () => WRot.FromYaw(getFacing()); } // Fall back to initial actor facing if an Init isn't available - var facingInit = dict.GetOrDefault(); - var facing = facingInit != null ? facingInit.Value(null) : facingInfo.GetInitialFacing(); - var orientation = WRot.FromFacing(facing); + var facingInit = reference.GetOrDefault(); + var facing = facingInit != null ? facingInit.Value : facingInfo.GetInitialFacing(); + var orientation = WRot.FromYaw(facing); return () => orientation; } - public Func GetFacing() + public Func GetFacing() { var facingInfo = Actor.TraitInfoOrDefault(); if (facingInfo == null) - return () => 0; + return () => WAngle.Zero; // Dynamic facing takes priority - var dynamicInit = dict.GetOrDefault(); + var dynamicInit = reference.GetOrDefault(); if (dynamicInit != null) - return dynamicInit.Value(null); + return dynamicInit.Value; // Fall back to initial actor facing if an Init isn't available - var facingInit = dict.GetOrDefault(); - var facing = facingInit != null ? facingInit.Value(null) : facingInfo.GetInitialFacing(); + var facingInit = reference.GetOrDefault(); + var facing = facingInit != null ? facingInit.Value : facingInfo.GetInitialFacing(); return () => facing; } public DamageState GetDamageState() { - var health = dict.GetOrDefault(); + var health = reference.GetOrDefault(); if (health == null) return DamageState.Undamaged; - var hf = health.Value(null); + var hf = health.Value; if (hf <= 0) return DamageState.Dead; diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs openra-20210321/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs 2021-03-21 11:10:05.000000000 +0000 @@ -40,23 +40,21 @@ public class DefaultSpriteSequenceLoader : ISpriteSequenceLoader { - public Action OnMissingSpriteError { get; set; } public DefaultSpriteSequenceLoader(ModData modData) { } - public virtual ISpriteSequence CreateSequence(ModData modData, TileSet tileSet, SpriteCache cache, string sequence, string animation, MiniYaml info) + public virtual ISpriteSequence CreateSequence(ModData modData, string tileSet, SpriteCache cache, string sequence, string animation, MiniYaml info) { return new DefaultSpriteSequence(modData, tileSet, cache, this, sequence, animation, info); } - public IReadOnlyDictionary ParseSequences(ModData modData, TileSet tileSet, SpriteCache cache, MiniYamlNode node) + public IReadOnlyDictionary ParseSequences(ModData modData, string tileSet, SpriteCache cache, MiniYamlNode node) { var sequences = new Dictionary(); var nodes = node.Value.ToDictionary(); - MiniYaml defaults; try { - if (nodes.TryGetValue("Defaults", out defaults)) + if (nodes.TryGetValue("Defaults", out var defaults)) { nodes.Remove("Defaults"); foreach (var n in nodes) @@ -81,8 +79,9 @@ } catch (FileNotFoundException ex) { - // Eat the FileNotFound exceptions from missing sprites - OnMissingSpriteError(ex.Message); + // Defer exception until something tries to access the sequence + // This allows the asset installer and OpenRA.Utility to load the game without having the actor assets + sequences.Add(kvp.Key, new FileNotFoundSequence(ex)); } } } @@ -91,15 +90,43 @@ } } + public class FileNotFoundSequence : ISpriteSequence + { + readonly FileNotFoundException exception; + + public FileNotFoundSequence(FileNotFoundException exception) + { + this.exception = exception; + } + + public string Filename { get { return exception.FileName; } } + + string ISpriteSequence.Name { get { throw exception; } } + int ISpriteSequence.Start { get { throw exception; } } + int ISpriteSequence.Length { get { throw exception; } } + int ISpriteSequence.Stride { get { throw exception; } } + int ISpriteSequence.Facings { get { throw exception; } } + int ISpriteSequence.Tick { get { throw exception; } } + int ISpriteSequence.ZOffset { get { throw exception; } } + int ISpriteSequence.ShadowStart { get { throw exception; } } + int ISpriteSequence.ShadowZOffset { get { throw exception; } } + int[] ISpriteSequence.Frames { get { throw exception; } } + Rectangle ISpriteSequence.Bounds { get { throw exception; } } + bool ISpriteSequence.IgnoreWorldTint { get { throw exception; } } + Sprite ISpriteSequence.GetSprite(int frame) { throw exception; } + Sprite ISpriteSequence.GetSprite(int frame, WAngle facing) { throw exception; } + Sprite ISpriteSequence.GetShadow(int frame, WAngle facing) { throw exception; } + } + public class DefaultSpriteSequence : ISpriteSequence { static readonly WDist DefaultShadowSpriteZOffset = new WDist(-5); protected Sprite[] sprites; - readonly bool reverseFacings, transpose, useClassicFacingFudge; + readonly bool reverseFacings, transpose; + readonly string sequence; protected readonly ISpriteSequenceLoader Loader; - readonly string sequence; public string Name { get; private set; } public int Start { get; private set; } public int Length { get; private set; } @@ -112,18 +139,18 @@ public int ShadowZOffset { get; private set; } public int[] Frames { get; private set; } public Rectangle Bounds { get; private set; } + public bool IgnoreWorldTint { get; private set; } public readonly uint[] EmbeddedPalette; - protected virtual string GetSpriteSrc(ModData modData, TileSet tileSet, string sequence, string animation, string sprite, Dictionary d) + protected virtual string GetSpriteSrc(ModData modData, string tileSet, string sequence, string animation, string sprite, Dictionary d) { return sprite ?? sequence; } protected static T LoadField(Dictionary d, string key, T fallback) { - MiniYaml value; - if (d.TryGetValue(key, out value)) + if (d.TryGetValue(key, out var value)) return FieldLoader.GetValue(key, value.Value); return fallback; @@ -139,7 +166,7 @@ return Rectangle.FromLTRB(left, top, right, bottom); } - public DefaultSpriteSequence(ModData modData, TileSet tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info) + public DefaultSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info) { this.sequence = sequence; Name = animation; @@ -156,7 +183,7 @@ Tick = LoadField(d, "Tick", 40); transpose = LoadField(d, "Transpose", false); Frames = LoadField(d, "Frames", null); - useClassicFacingFudge = LoadField(d, "UseClassicFacingFudge", false); + IgnoreWorldTint = LoadField(d, "IgnoreWorldTint", false); var flipX = LoadField(d, "FlipX", false); var flipY = LoadField(d, "FlipY", false); @@ -168,18 +195,12 @@ Facings = -Facings; } - if (useClassicFacingFudge && Facings != 32) - throw new InvalidOperationException( - "{0}: Sequence {1}.{2}: UseClassicFacingFudge is only valid for 32 facings" - .F(info.Nodes[0].Location, sequence, animation)); - var offset = LoadField(d, "Offset", float3.Zero); var blendMode = LoadField(d, "BlendMode", BlendMode.Alpha); Func> getUsedFrames = frameCount => { - MiniYaml length; - if (d.TryGetValue("Length", out length) && length.Value == "*") + if (d.TryGetValue("Length", out var length) && length.Value == "*") Length = Frames != null ? Frames.Length : frameCount - Start; else Length = LoadField(d, "Length", 1); @@ -196,39 +217,32 @@ Stride = LoadField(d, "Stride", Length); if (Length > Stride) - throw new InvalidOperationException( - "{0}: Sequence {1}.{2}: Length must be <= stride" - .F(info.Nodes[0].Location, sequence, animation)); + throw new YamlException("Sequence {0}.{1}: Length must be <= stride" + .F(sequence, animation)); if (Frames != null && Length > Frames.Length) - throw new InvalidOperationException( - "{0}: Sequence {1}.{2}: Length must be <= Frames.Length" - .F(info.Nodes[0].Location, sequence, animation)); + throw new YamlException("Sequence {0}.{1}: Length must be <= Frames.Length" + .F(sequence, animation)); var end = Start + (Facings - 1) * Stride + Length - 1; if (Frames != null) { foreach (var f in Frames) if (f < 0 || f >= frameCount) - throw new InvalidOperationException( - "{5}: Sequence {0}.{1} defines a Frames override that references frame {4}, but only [{2}..{3}] actually exist" - .F(sequence, animation, Start, end, f, info.Nodes[0].Location)); + throw new YamlException("Sequence {0}.{1} defines a Frames override that references frame {2}, but only [{3}..{4}] actually exist" + .F(sequence, animation, f, Start, end)); if (Start < 0 || end >= Frames.Length) - throw new InvalidOperationException( - "{5}: Sequence {0}.{1} uses indices [{2}..{3}] of the Frames list, but only {4} frames are defined" - .F(sequence, animation, Start, end, Frames.Length, info.Nodes[0].Location)); + throw new YamlException("Sequence {0}.{1} uses indices [{2}..{3}] of the Frames list, but only {4} frames are defined" + .F(sequence, animation, Start, end, Frames.Length)); } else if (Start < 0 || end >= frameCount) - throw new InvalidOperationException( - "{5}: Sequence {0}.{1} uses frames [{2}..{3}], but only 0..{4} actually exist" - .F(sequence, animation, Start, end, frameCount - 1, info.Nodes[0].Location)); + throw new YamlException("Sequence {0}.{1} uses frames [{2}..{3}], but only [0..{4}] actually exist" + .F(sequence, animation, Start, end, frameCount - 1)); if (ShadowStart >= 0 && ShadowStart + (Facings - 1) * Stride + Length > frameCount) - throw new InvalidOperationException( - "{5}: Sequence {0}.{1}'s shadow frames use frames [{2}..{3}], but only [0..{4}] actually exist" - .F(sequence, animation, ShadowStart, ShadowStart + (Facings - 1) * Stride + Length - 1, frameCount - 1, - info.Nodes[0].Location)); + throw new YamlException("Sequence {0}.{1}'s shadow frames use frames [{2}..{3}], but only [0..{4}] actually exist" + .F(sequence, animation, ShadowStart, ShadowStart + (Facings - 1) * Stride + Length - 1, frameCount - 1)); var usedFrames = new List(); for (var facing = 0; facing < Facings; facing++) @@ -248,8 +262,7 @@ return usedFrames; }; - MiniYaml combine; - if (d.TryGetValue("Combine", out combine)) + if (d.TryGetValue("Combine", out var combine)) { var combined = Enumerable.Empty(); foreach (var sub in combine.Nodes) @@ -266,8 +279,7 @@ Func> subGetUsedFrames = subFrameCount => { - MiniYaml subLengthYaml; - if (sd.TryGetValue("Length", out subLengthYaml) && subLengthYaml.Value == "*") + if (sd.TryGetValue("Length", out var subLengthYaml) && subLengthYaml.Value == "*") subLength = subFrames != null ? subFrames.Length : subFrameCount - subStart; else subLength = LoadField(sd, "Length", 1); @@ -369,22 +381,22 @@ public Sprite GetSprite(int frame) { - return GetSprite(Start, frame, 0); + return GetSprite(Start, frame, WAngle.Zero); } - public Sprite GetSprite(int frame, int facing) + public Sprite GetSprite(int frame, WAngle facing) { return GetSprite(Start, frame, facing); } - public Sprite GetShadow(int frame, int facing) + public Sprite GetShadow(int frame, WAngle facing) { return ShadowStart >= 0 ? GetSprite(ShadowStart, frame, facing) : null; } - protected virtual Sprite GetSprite(int start, int frame, int facing) + protected virtual Sprite GetSprite(int start, int frame, WAngle facing) { - var f = Util.QuantizeFacing(facing, Facings, useClassicFacingFudge); + var f = GetFacingFrameOffset(facing); if (reverseFacings) f = (Facings - f) % Facings; @@ -398,5 +410,10 @@ return sprites[j]; } + + protected virtual int GetFacingFrameOffset(WAngle facing) + { + return Util.IndexFacing(facing, Facings); + } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/DetectionCircleAnnotationRenderable.cs openra-20210321/OpenRA.Mods.Common/Graphics/DetectionCircleAnnotationRenderable.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/DetectionCircleAnnotationRenderable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/DetectionCircleAnnotationRenderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,10 +23,12 @@ readonly WAngle trailSeparation; readonly WAngle trailAngle; readonly Color color; - readonly Color contrastColor; + readonly float width; + readonly Color borderColor; + readonly float borderWidth; public DetectionCircleAnnotationRenderable(WPos centerPosition, WDist radius, int zOffset, - int lineTrails, WAngle trailSeparation, WAngle trailAngle, Color color, Color contrastColor) + int lineTrails, WAngle trailSeparation, WAngle trailAngle, Color color, float width, Color borderColor, float borderWidth) { this.centerPosition = centerPosition; this.radius = radius; @@ -35,7 +37,9 @@ this.trailSeparation = trailSeparation; this.trailAngle = trailAngle; this.color = color; - this.contrastColor = contrastColor; + this.width = width; + this.borderColor = borderColor; + this.borderWidth = borderWidth; } public WPos Pos { get { return centerPosition; } } @@ -46,19 +50,19 @@ public IRenderable WithPalette(PaletteReference newPalette) { return new DetectionCircleAnnotationRenderable(centerPosition, radius, zOffset, - trailCount, trailSeparation, trailAngle, color, contrastColor); + trailCount, trailSeparation, trailAngle, color, width, borderColor, borderWidth); } public IRenderable WithZOffset(int newOffset) { return new DetectionCircleAnnotationRenderable(centerPosition, radius, newOffset, - trailCount, trailSeparation, trailAngle, color, contrastColor); + trailCount, trailSeparation, trailAngle, color, width, borderColor, borderWidth); } public IRenderable OffsetBy(WVec vec) { return new DetectionCircleAnnotationRenderable(centerPosition + vec, radius, zOffset, - trailCount, trailSeparation, trailAngle, color, contrastColor); + trailCount, trailSeparation, trailAngle, color, width, borderColor, borderWidth); } public IRenderable AsDecoration() { return this; } @@ -75,11 +79,11 @@ var length = radius.Length * new WVec(angle.Cos(), angle.Sin(), 0) / 1024; var end = wr.Viewport.WorldToViewPx(wr.Screen3DPosition(centerPosition + length)); var alpha = color.A - i * color.A / trailCount; - cr.DrawLine(center, end, 3, Color.FromArgb(alpha, contrastColor)); - cr.DrawLine(center, end, 1, Color.FromArgb(alpha, color)); + cr.DrawLine(center, end, borderWidth, Color.FromArgb(alpha, borderColor)); + cr.DrawLine(center, end, width, Color.FromArgb(alpha, color)); } - RangeCircleAnnotationRenderable.DrawRangeCircle(wr, centerPosition, radius, 1, color, 3, contrastColor); + RangeCircleAnnotationRenderable.DrawRangeCircle(wr, centerPosition, radius, width, color, borderWidth, borderColor); } public void RenderDebugGeometry(WorldRenderer wr) { } diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/IsometricSelectionBarsAnnotationRenderable.cs openra-20210321/OpenRA.Mods.Common/Graphics/IsometricSelectionBarsAnnotationRenderable.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/IsometricSelectionBarsAnnotationRenderable.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/IsometricSelectionBarsAnnotationRenderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,167 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Graphics +{ + public struct IsometricSelectionBarsAnnotationRenderable : IRenderable, IFinalizedRenderable + { + const int BarWidth = 3; + const int BarHeight = 4; + const int BarStride = 5; + + static readonly Color EmptyColor = Color.FromArgb(160, 30, 30, 30); + static readonly Color DarkEmptyColor = Color.FromArgb(160, 15, 15, 15); + static readonly Color DarkenColor = Color.FromArgb(24, 0, 0, 0); + static readonly Color LightenColor = Color.FromArgb(24, 255, 255, 255); + + readonly WPos pos; + readonly Actor actor; + readonly bool displayHealth; + readonly bool displayExtra; + readonly Polygon bounds; + + public IsometricSelectionBarsAnnotationRenderable(Actor actor, Polygon bounds, bool displayHealth, bool displayExtra) + : this(actor.CenterPosition, actor, bounds) + { + this.displayHealth = displayHealth; + this.displayExtra = displayExtra; + } + + public IsometricSelectionBarsAnnotationRenderable(WPos pos, Actor actor, Polygon bounds) + : this() + { + this.pos = pos; + this.actor = actor; + this.bounds = bounds; + } + + public WPos Pos { get { return pos; } } + public bool DisplayHealth { get { return displayHealth; } } + public bool DisplayExtra { get { return displayExtra; } } + + public PaletteReference Palette { get { return null; } } + public int ZOffset { get { return 0; } } + public bool IsDecoration { get { return true; } } + + public IRenderable WithPalette(PaletteReference newPalette) { return this; } + public IRenderable WithZOffset(int newOffset) { return this; } + public IRenderable OffsetBy(WVec vec) { return new IsometricSelectionBarsAnnotationRenderable(pos + vec, actor, bounds); } + public IRenderable AsDecoration() { return this; } + + void DrawExtraBars(WorldRenderer wr) + { + var i = 1; + foreach (var extraBar in actor.TraitsImplementing()) + { + var value = extraBar.GetValue(); + if (value != 0 || extraBar.DisplayWhenEmpty) + DrawBar(wr, extraBar.GetValue(), extraBar.GetColor(), i++); + } + } + + void DrawBar(WorldRenderer wr, float value, Color barColor, int barNum, float? secondValue = null, Color? secondColor = null) + { + var darkColor = Color.FromArgb(barColor.A, barColor.R / 2, barColor.G / 2, barColor.B / 2); + var barAspect = new float2(1f, 0.5f); + var stepAspect = new float2(1f, -0.5f); + + var offset = barNum * BarStride * barAspect - new float2(0, BarHeight + 1); + var start = wr.Viewport.WorldToViewPx(bounds.Vertices[1]).ToFloat2() + offset; + var end = wr.Viewport.WorldToViewPx(bounds.Vertices[0]).ToFloat2() + offset; + + // HACK: Work around rounding errors that may cause a few-px offset in the end relative to the start + // Force the bar to take a 45 degree angle + end = new float2(end.X, start.Y - (end.X - start.X) / 2); + + // Round the cut point to the nearest pixel to avoid potential off-by-one pixel offsets distorting the bar + var cutX = (int)(float2.Lerp(start.X, end.X, value) + 0.5f); + var cut = new float2(cutX, start.Y - (cutX - start.X) / 2); + + var cr = Game.Renderer.RgbaColorRenderer; + var da = BarWidth * barAspect; + var db = new int2(0, BarHeight); + var dc = da + db; + + // Filled bar + cr.FillRect(start + da, start + dc, cut + dc, cut + da, darkColor); + cr.FillRect(start, start + da, start + dc, start + db, darkColor); + cr.FillRect(start, start + da, cut + da, cut, barColor); + + // Faint marks to break the monotony of the solid bar + var dx = BarWidth; + while (dx < cut.X - start.X) + { + var step = start + dx * stepAspect; + cr.DrawLine(step, step + da, 1, DarkenColor); + cr.DrawLine(step + da, step + dc, 1, LightenColor); + dx += BarWidth; + } + + // Second bar (e.g. applied damage) + if (secondValue.HasValue && secondColor.HasValue) + { + var secondCutX = (int)(float2.Lerp(start.X, end.X, secondValue.Value) + 0.5f); + var secondCut = new float2(secondCutX, start.Y - (secondCutX - start.X) / 2); + var darkSecond = Color.FromArgb(secondColor.Value.A, secondColor.Value.R / 2, secondColor.Value.G / 2, secondColor.Value.B / 2); + + cr.FillRect(cut + da, cut + dc, secondCut + dc, secondCut + da, darkSecond); + cr.FillRect(cut, cut + da, secondCut + da, secondCut, secondColor.Value); + + value = secondValue.Value; + cut = secondCut; + } + + // Empty bar + if (value < 1) + { + cr.FillRect(cut + da, cut + dc, end + dc, end + da, DarkEmptyColor); + cr.FillRect(cut, cut + da, end + da, end, EmptyColor); + } + } + + Color GetHealthColor(IHealth health) + { + if (Game.Settings.Game.UsePlayerStanceColors) + return actor.Owner.PlayerStanceColor(actor); + + return health.DamageState == DamageState.Critical ? Color.Red : + health.DamageState == DamageState.Heavy ? Color.Yellow : Color.LimeGreen; + } + + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } + public void Render(WorldRenderer wr) + { + if (!actor.IsInWorld || actor.IsDead) + return; + + var health = actor.TraitOrDefault(); + + if (DisplayHealth) + { + if (health == null || health.IsDead) + return; + + var displayValue = health.DisplayHP != health.HP ? (float?)health.DisplayHP / health.MaxHP : null; + DrawBar(wr, (float)health.HP / health.MaxHP, GetHealthColor(health), 0, displayValue, Color.OrangeRed); + } + + if (DisplayExtra) + DrawExtraBars(wr); + } + + public void RenderDebugGeometry(WorldRenderer wr) { } + public Rectangle ScreenBounds(WorldRenderer wr) { return Rectangle.Empty; } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/IsometricSelectionBoxAnnotationRenderable.cs openra-20210321/OpenRA.Mods.Common/Graphics/IsometricSelectionBoxAnnotationRenderable.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/IsometricSelectionBoxAnnotationRenderable.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/IsometricSelectionBoxAnnotationRenderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,83 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Primitives; + +namespace OpenRA.Mods.Common.Graphics +{ + public struct IsometricSelectionBoxAnnotationRenderable : IRenderable, IFinalizedRenderable + { + static readonly float2 TLOffset = new float2(-12, -6); + static readonly float2 TROffset = new float2(12, -6); + static readonly float2 TOffset = new float2(0, -13); + static readonly float2[] Offsets = + { + -TROffset, -TLOffset, -TOffset, + TROffset, -TOffset, -TLOffset, + -TLOffset, TOffset, TROffset, + TLOffset, TROffset, TOffset, + -TROffset, TOffset, TLOffset, + TLOffset, -TOffset, -TROffset + }; + + readonly WPos pos; + readonly Polygon bounds; + readonly Color color; + + public IsometricSelectionBoxAnnotationRenderable(Actor actor, Polygon bounds, Color color) + { + pos = actor.CenterPosition; + this.bounds = bounds; + this.color = color; + } + + public IsometricSelectionBoxAnnotationRenderable(WPos pos, Polygon bounds, Color color) + { + this.pos = pos; + this.bounds = bounds; + this.color = color; + } + + public WPos Pos { get { return pos; } } + + public PaletteReference Palette { get { return null; } } + public int ZOffset { get { return 0; } } + public bool IsDecoration { get { return true; } } + + public IRenderable WithPalette(PaletteReference newPalette) { return this; } + public IRenderable WithZOffset(int newOffset) { return this; } + public IRenderable OffsetBy(WVec vec) { return new IsometricSelectionBoxAnnotationRenderable(pos + vec, bounds, color); } + public IRenderable AsDecoration() { return this; } + + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } + + public void Render(WorldRenderer wr) + { + var screen = bounds.Vertices.Select(v => wr.Viewport.WorldToViewPx(v).ToFloat2()).ToArray(); + + var tl = new float2(-12, -6); + var tr = new float2(12, -6); + var t = new float2(0, -13); + + var cr = Game.Renderer.RgbaColorRenderer; + for (var i = 0; i < 6; i++) + { + cr.DrawLine(new float3[] { screen[i] + Offsets[3 * i], screen[i], screen[i] + Offsets[3 * i + 1] }, 1, color, true); + cr.DrawLine(new float3[] { screen[i], screen[i] + Offsets[3 * i + 2] }, 1, color, true); + } + } + + public void RenderDebugGeometry(WorldRenderer wr) { } + public Rectangle ScreenBounds(WorldRenderer wr) { return Rectangle.Empty; } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/ModelRenderable.cs openra-20210321/OpenRA.Mods.Common/Graphics/ModelRenderable.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/ModelRenderable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/ModelRenderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Graphics { - public struct ModelRenderable : IRenderable + public struct ModelRenderable : IRenderable, ITintableRenderable { readonly IEnumerable models; readonly WPos pos; @@ -30,11 +30,22 @@ readonly PaletteReference normalsPalette; readonly PaletteReference shadowPalette; readonly float scale; + readonly float3 tint; public ModelRenderable( - IEnumerable models, WPos pos, int zOffset, WRot camera, float scale, - WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, + IEnumerable models, WPos pos, int zOffset, in WRot camera, float scale, + in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, PaletteReference color, PaletteReference normals, PaletteReference shadow) + : this(models, pos, zOffset, camera, scale, + lightSource, lightAmbientColor, lightDiffuseColor, + color, normals, shadow, + float3.Ones) { } + + public ModelRenderable( + IEnumerable models, WPos pos, int zOffset, in WRot camera, float scale, + in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, + PaletteReference color, PaletteReference normals, PaletteReference shadow, + in float3 tint) { this.models = models; this.pos = pos; @@ -47,6 +58,7 @@ palette = color; normalsPalette = normals; shadowPalette = shadow; + this.tint = tint; } public WPos Pos { get { return pos; } } @@ -59,7 +71,7 @@ return new ModelRenderable( models, pos, zOffset, camera, scale, lightSource, lightAmbientColor, lightDiffuseColor, - newPalette, normalsPalette, shadowPalette); + newPalette, normalsPalette, shadowPalette, tint); } public IRenderable WithZOffset(int newOffset) @@ -67,7 +79,7 @@ return new ModelRenderable( models, pos, newOffset, camera, scale, lightSource, lightAmbientColor, lightDiffuseColor, - palette, normalsPalette, shadowPalette); + palette, normalsPalette, shadowPalette, tint); } public IRenderable OffsetBy(WVec vec) @@ -75,11 +87,19 @@ return new ModelRenderable( models, pos + vec, zOffset, camera, scale, lightSource, lightAmbientColor, lightDiffuseColor, - palette, normalsPalette, shadowPalette); + palette, normalsPalette, shadowPalette, tint); } public IRenderable AsDecoration() { return this; } + public IRenderable WithTint(in float3 newTint) + { + return new ModelRenderable( + models, pos, zOffset, camera, scale, + lightSource, lightAmbientColor, lightDiffuseColor, + palette, normalsPalette, shadowPalette, newTint); + } + // This will need generalizing once we support TS/RA2 terrain static readonly float[] GroundNormal = new float[] { 0, 0, 1, 1 }; public IFinalizedRenderable PrepareRender(WorldRenderer wr) @@ -113,7 +133,7 @@ // HACK: We don't have enough texture channels to pass the depth data to the shader // so for now just offset everything forward so that the back corner is rendered at pos. - pxOrigin -= new float3(0, 0, Screen3DBounds(wr).Second.X); + pxOrigin -= new float3(0, 0, Screen3DBounds(wr).Z.X); var shadowOrigin = pxOrigin - groundZ * (new float2(renderProxy.ShadowDirection, 1)); @@ -122,8 +142,14 @@ var sb = shadowOrigin + psb[2]; var sc = shadowOrigin + psb[1]; var sd = shadowOrigin + psb[3]; - Game.Renderer.WorldRgbaSpriteRenderer.DrawSprite(renderProxy.ShadowSprite, sa, sb, sc, sd); - Game.Renderer.WorldRgbaSpriteRenderer.DrawSprite(renderProxy.Sprite, pxOrigin - 0.5f * renderProxy.Sprite.Size); + + var wrsr = Game.Renderer.WorldRgbaSpriteRenderer; + var t = model.tint; + if (wr.TerrainLighting != null) + t *= wr.TerrainLighting.TintAt(model.pos); + + wrsr.DrawSpriteWithTint(renderProxy.ShadowSprite, sa, sb, sc, sd, t); + wrsr.DrawSpriteWithTint(renderProxy.Sprite, pxOrigin - 0.5f * renderProxy.Sprite.Size, renderProxy.Sprite.Size, t); } public void RenderDebugGeometry(WorldRenderer wr) @@ -157,8 +183,8 @@ foreach (var v in draw) { var bounds = v.Model.Bounds(v.FrameFunc()); - var worldTransform = v.RotationFunc().Reverse().Aggregate(scaleTransform, - (x, y) => OpenRA.Graphics.Util.MatrixMultiply(x, OpenRA.Graphics.Util.MakeFloatMatrix(y.AsMatrix()))); + var rotation = OpenRA.Graphics.Util.MakeFloatMatrix(v.RotationFunc().AsMatrix()); + var worldTransform = OpenRA.Graphics.Util.MatrixMultiply(scaleTransform, rotation); var pxPos = pxOrigin + wr.ScreenVectorComponents(v.OffsetFunc()); var screenTransform = OpenRA.Graphics.Util.MatrixMultiply(cameraTransform, worldTransform); @@ -169,7 +195,7 @@ static readonly uint[] CornerXIndex = new uint[] { 0, 0, 0, 0, 3, 3, 3, 3 }; static readonly uint[] CornerYIndex = new uint[] { 1, 1, 4, 4, 1, 1, 4, 4 }; static readonly uint[] CornerZIndex = new uint[] { 2, 5, 2, 5, 2, 5, 2, 5 }; - static void DrawBoundsBox(WorldRenderer wr, float3 pxPos, float[] transform, float[] bounds, float width, Color c) + static void DrawBoundsBox(WorldRenderer wr, in float3 pxPos, float[] transform, float[] bounds, float width, Color c) { var cr = Game.Renderer.RgbaColorRenderer; var corners = new float2[8]; @@ -195,10 +221,10 @@ public Rectangle ScreenBounds(WorldRenderer wr) { - return Screen3DBounds(wr).First; + return Screen3DBounds(wr).Bounds; } - Pair Screen3DBounds(WorldRenderer wr) + (Rectangle Bounds, float2 Z) Screen3DBounds(WorldRenderer wr) { var pxOrigin = wr.ScreenPosition(model.pos); var draw = model.models.Where(v => v.IsVisible); @@ -215,8 +241,8 @@ foreach (var v in draw) { var bounds = v.Model.Bounds(v.FrameFunc()); - var worldTransform = v.RotationFunc().Reverse().Aggregate(scaleTransform, - (x, y) => OpenRA.Graphics.Util.MatrixMultiply(x, OpenRA.Graphics.Util.MakeFloatMatrix(y.AsMatrix()))); + var rotation = OpenRA.Graphics.Util.MakeFloatMatrix(v.RotationFunc().AsMatrix()); + var worldTransform = OpenRA.Graphics.Util.MatrixMultiply(scaleTransform, rotation); var pxPos = pxOrigin + wr.ScreenVectorComponents(v.OffsetFunc()); var screenTransform = OpenRA.Graphics.Util.MatrixMultiply(cameraTransform, worldTransform); @@ -234,7 +260,7 @@ } } - return Pair.New(Rectangle.FromLTRB((int)minX, (int)minY, (int)maxX, (int)maxY), new float2(minZ, maxZ)); + return (Rectangle.FromLTRB((int)minX, (int)minY, (int)maxX, (int)maxY), new float2(minZ, maxZ)); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/RangeCircleAnnotationRenderable.cs openra-20210321/OpenRA.Mods.Common/Graphics/RangeCircleAnnotationRenderable.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/RangeCircleAnnotationRenderable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/RangeCircleAnnotationRenderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,15 +24,19 @@ readonly WDist radius; readonly int zOffset; readonly Color color; - readonly Color contrastColor; + readonly float width; + readonly Color borderColor; + readonly float borderWidth; - public RangeCircleAnnotationRenderable(WPos centerPosition, WDist radius, int zOffset, Color color, Color contrastColor) + public RangeCircleAnnotationRenderable(WPos centerPosition, WDist radius, int zOffset, Color color, float width, Color borderColor, float borderWidth) { this.centerPosition = centerPosition; this.radius = radius; this.zOffset = zOffset; this.color = color; - this.contrastColor = contrastColor; + this.width = width; + this.borderColor = borderColor; + this.borderWidth = borderWidth; } public WPos Pos { get { return centerPosition; } } @@ -40,19 +44,19 @@ public int ZOffset { get { return zOffset; } } public bool IsDecoration { get { return true; } } - public IRenderable WithPalette(PaletteReference newPalette) { return new RangeCircleAnnotationRenderable(centerPosition, radius, zOffset, color, contrastColor); } - public IRenderable WithZOffset(int newOffset) { return new RangeCircleAnnotationRenderable(centerPosition, radius, newOffset, color, contrastColor); } - public IRenderable OffsetBy(WVec vec) { return new RangeCircleAnnotationRenderable(centerPosition + vec, radius, zOffset, color, contrastColor); } + public IRenderable WithPalette(PaletteReference newPalette) { return new RangeCircleAnnotationRenderable(centerPosition, radius, zOffset, color, width, borderColor, borderWidth); } + public IRenderable WithZOffset(int newOffset) { return new RangeCircleAnnotationRenderable(centerPosition, radius, newOffset, color, width, borderColor, borderWidth); } + public IRenderable OffsetBy(WVec vec) { return new RangeCircleAnnotationRenderable(centerPosition + vec, radius, zOffset, color, width, borderColor, borderWidth); } public IRenderable AsDecoration() { return this; } public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { - DrawRangeCircle(wr, centerPosition, radius, 1, color, 3, contrastColor); + DrawRangeCircle(wr, centerPosition, radius, width, color, borderWidth, borderColor); } public static void DrawRangeCircle(WorldRenderer wr, WPos centerPosition, WDist radius, - float width, Color color, float contrastWidth, Color contrastColor) + float width, Color color, float borderWidth, Color borderColor) { var cr = Game.Renderer.RgbaColorRenderer; var offset = new WVec(radius.Length, 0, 0); @@ -61,8 +65,8 @@ var a = wr.Viewport.WorldToViewPx(wr.ScreenPosition(centerPosition + offset.Rotate(ref RangeCircleStartRotations[i]))); var b = wr.Viewport.WorldToViewPx(wr.ScreenPosition(centerPosition + offset.Rotate(ref RangeCircleEndRotations[i]))); - if (contrastWidth > 0) - cr.DrawLine(a, b, contrastWidth, contrastColor); + if (borderWidth > 0) + cr.DrawLine(a, b, borderWidth, borderColor); if (width > 0) cr.DrawLine(a, b, width, color); diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/TextAnnotationRenderable.cs openra-20210321/OpenRA.Mods.Common/Graphics/TextAnnotationRenderable.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/TextAnnotationRenderable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/TextAnnotationRenderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using OpenRA.Graphics; using OpenRA.Primitives; using OpenRA.Widgets; diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/TilesetSpecificSpriteSequence.cs openra-20210321/OpenRA.Mods.Common/Graphics/TilesetSpecificSpriteSequence.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/TilesetSpecificSpriteSequence.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/TilesetSpecificSpriteSequence.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,8 +25,7 @@ : base(modData) { var metadata = modData.Manifest.Get().Metadata; - MiniYaml yaml; - if (metadata.TryGetValue("DefaultSpriteExtension", out yaml)) + if (metadata.TryGetValue("DefaultSpriteExtension", out var yaml)) DefaultSpriteExtension = yaml.Value; if (metadata.TryGetValue("TilesetExtensions", out yaml)) @@ -36,7 +35,7 @@ TilesetCodes = yaml.ToDictionary(kv => kv.Value); } - public override ISpriteSequence CreateSequence(ModData modData, TileSet tileSet, SpriteCache cache, string sequence, string animation, MiniYaml info) + public override ISpriteSequence CreateSequence(ModData modData, string tileSet, SpriteCache cache, string sequence, string animation, MiniYaml info) { return new TilesetSpecificSpriteSequence(modData, tileSet, cache, this, sequence, animation, info); } @@ -44,25 +43,22 @@ public class TilesetSpecificSpriteSequence : DefaultSpriteSequence { - public TilesetSpecificSpriteSequence(ModData modData, TileSet tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info) + public TilesetSpecificSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info) : base(modData, tileSet, cache, loader, sequence, animation, info) { } - string ResolveTilesetId(TileSet tileSet, Dictionary d) + string ResolveTilesetId(string tileSet, Dictionary d) { - var tsId = tileSet.Id; - - MiniYaml yaml; - if (d.TryGetValue("TilesetOverrides", out yaml)) + if (d.TryGetValue("TilesetOverrides", out var yaml)) { - var tsNode = yaml.Nodes.FirstOrDefault(n => n.Key == tsId); + var tsNode = yaml.Nodes.FirstOrDefault(n => n.Key == tileSet); if (tsNode != null) - tsId = tsNode.Value.Value; + tileSet = tsNode.Value.Value; } - return tsId; + return tileSet; } - protected override string GetSpriteSrc(ModData modData, TileSet tileSet, string sequence, string animation, string sprite, Dictionary d) + protected override string GetSpriteSrc(ModData modData, string tileSet, string sequence, string animation, string sprite, Dictionary d) { var loader = (TilesetSpecificSpriteSequenceLoader)Loader; @@ -70,8 +66,7 @@ if (LoadField(d, "UseTilesetCode", false)) { - string code; - if (loader.TilesetCodes.TryGetValue(ResolveTilesetId(tileSet, d), out code)) + if (loader.TilesetCodes.TryGetValue(ResolveTilesetId(tileSet, d), out var code)) spriteName = spriteName.Substring(0, 1) + code + spriteName.Substring(2, spriteName.Length - 2); } @@ -79,8 +74,7 @@ { var useTilesetExtension = LoadField(d, "UseTilesetExtension", false); - string tilesetExtension; - if (useTilesetExtension && loader.TilesetExtensions.TryGetValue(ResolveTilesetId(tileSet, d), out tilesetExtension)) + if (useTilesetExtension && loader.TilesetExtensions.TryGetValue(ResolveTilesetId(tileSet, d), out var tilesetExtension)) return spriteName + tilesetExtension; return spriteName + loader.DefaultSpriteExtension; diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/UIModelRenderable.cs openra-20210321/OpenRA.Mods.Common/Graphics/UIModelRenderable.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/UIModelRenderable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/UIModelRenderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -34,7 +34,7 @@ public UIModelRenderable( IEnumerable models, WPos effectiveWorldPos, int2 screenPos, int zOffset, - WRot camera, float scale, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, + in WRot camera, float scale, in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, PaletteReference color, PaletteReference normals, PaletteReference shadow) { this.models = models; @@ -106,13 +106,13 @@ public Rectangle ScreenBounds(WorldRenderer wr) { - return Screen3DBounds(wr).First; + return Screen3DBounds(wr).Bounds; } static readonly uint[] CornerXIndex = { 0, 0, 0, 0, 3, 3, 3, 3 }; static readonly uint[] CornerYIndex = { 1, 1, 4, 4, 1, 1, 4, 4 }; static readonly uint[] CornerZIndex = { 2, 5, 2, 5, 2, 5, 2, 5 }; - Pair Screen3DBounds(WorldRenderer wr) + (Rectangle Bounds, float2 Z) Screen3DBounds(WorldRenderer wr) { var pxOrigin = model.screenPos; var draw = model.models.Where(v => v.IsVisible); @@ -129,8 +129,8 @@ foreach (var v in draw) { var bounds = v.Model.Bounds(v.FrameFunc()); - var worldTransform = v.RotationFunc().Reverse().Aggregate(scaleTransform, - (x, y) => OpenRA.Graphics.Util.MatrixMultiply(x, OpenRA.Graphics.Util.MakeFloatMatrix(y.AsMatrix()))); + var rotation = OpenRA.Graphics.Util.MakeFloatMatrix(v.RotationFunc().AsMatrix()); + var worldTransform = OpenRA.Graphics.Util.MatrixMultiply(scaleTransform, rotation); var pxPos = pxOrigin + wr.ScreenVectorComponents(v.OffsetFunc()); var screenTransform = OpenRA.Graphics.Util.MatrixMultiply(cameraTransform, worldTransform); @@ -148,7 +148,7 @@ } } - return Pair.New(Rectangle.FromLTRB((int)minX, (int)minY, (int)maxX, (int)maxY), new float2(minZ, maxZ)); + return (Rectangle.FromLTRB((int)minX, (int)minY, (int)maxX, (int)maxY), new float2(minZ, maxZ)); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Graphics/UITextRenderable.cs openra-20210321/OpenRA.Mods.Common/Graphics/UITextRenderable.cs --- openra-20200503/OpenRA.Mods.Common/Graphics/UITextRenderable.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Graphics/UITextRenderable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,71 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Graphics; +using OpenRA.Primitives; +using OpenRA.Widgets; + +namespace OpenRA.Mods.Common.Graphics +{ + public struct UITextRenderable : IRenderable, IFinalizedRenderable + { + readonly SpriteFont font; + readonly WPos effectiveWorldPos; + readonly int2 screenPos; + readonly int zOffset; + readonly Color color; + readonly Color bgDark; + readonly Color bgLight; + readonly string text; + + public UITextRenderable(SpriteFont font, WPos effectiveWorldPos, int2 screenPos, int zOffset, Color color, Color bgDark, Color bgLight, string text) + { + this.font = font; + this.effectiveWorldPos = effectiveWorldPos; + this.screenPos = screenPos; + this.zOffset = zOffset; + this.color = color; + this.bgDark = bgDark; + this.bgLight = bgLight; + this.text = text; + } + + public UITextRenderable(SpriteFont font, WPos effectiveWorldPos, int2 screenPos, int zOffset, Color color, string text) + : this(font, effectiveWorldPos, screenPos, zOffset, color, + ChromeMetrics.Get("TextContrastColorDark"), + ChromeMetrics.Get("TextContrastColorLight"), + text) { } + + public WPos Pos { get { return effectiveWorldPos; } } + public PaletteReference Palette { get { return null; } } + public int ZOffset { get { return zOffset; } } + public bool IsDecoration { get { return true; } } + + public IRenderable WithPalette(PaletteReference newPalette) { return new UITextRenderable(font, effectiveWorldPos, screenPos, zOffset, color, text); } + public IRenderable WithZOffset(int newOffset) { return new UITextRenderable(font, effectiveWorldPos, screenPos, zOffset, color, text); } + public IRenderable OffsetBy(WVec vec) { return new UITextRenderable(font, effectiveWorldPos + vec, screenPos, zOffset, color, text); } + public IRenderable AsDecoration() { return this; } + + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } + public void Render(WorldRenderer wr) + { + font.DrawTextWithContrast(text, screenPos, color, bgDark, bgLight, 1); + } + + public void RenderDebugGeometry(WorldRenderer wr) + { + var size = font.Measure(text).ToFloat2(); + Game.Renderer.RgbaColorRenderer.DrawRect(screenPos - 0.5f * size, screenPos + 0.5f * size, 1, Color.Red); + } + + public Rectangle ScreenBounds(WorldRenderer wr) { return Rectangle.Empty; } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckActorReferences.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckActorReferences.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckActorReferences.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckActorReferences.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,6 +13,7 @@ using System.Linq; using System.Reflection; using OpenRA.GameRules; +using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.Common.Lint @@ -21,16 +22,16 @@ { Action emitError; - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { this.emitError = emitError; foreach (var actorInfo in rules.Actors) - foreach (var traitInfo in actorInfo.Value.TraitInfos()) + foreach (var traitInfo in actorInfo.Value.TraitInfos()) CheckTrait(actorInfo.Value, traitInfo, rules); } - void CheckTrait(ActorInfo actorInfo, ITraitInfo traitInfo, Ruleset rules) + void CheckTrait(ActorInfo actorInfo, TraitInfo traitInfo, Ruleset rules) { var actualType = traitInfo.GetType(); foreach (var field in actualType.GetFields()) @@ -50,12 +51,12 @@ } void CheckActorReference(ActorInfo actorInfo, - ITraitInfo traitInfo, + TraitInfo traitInfo, FieldInfo fieldInfo, IReadOnlyDictionary dict, ActorReferenceAttribute attribute) { - var values = LintExts.GetFieldValues(traitInfo, fieldInfo, emitError); + var values = LintExts.GetFieldValues(traitInfo, fieldInfo, emitError, attribute.DictionaryReference); foreach (var value in values) { if (value == null) @@ -81,7 +82,7 @@ } void CheckWeaponReference(ActorInfo actorInfo, - ITraitInfo traitInfo, + TraitInfo traitInfo, FieldInfo fieldInfo, IReadOnlyDictionary dict, WeaponReferenceAttribute attribute) @@ -92,14 +93,14 @@ if (value == null) continue; - if (!dict.ContainsKey(value.ToLower())) + if (!dict.ContainsKey(value.ToLowerInvariant())) emitError("{0}.{1}.{2}: Missing weapon `{3}`." .F(actorInfo.Name, traitInfo.GetType().Name, fieldInfo.Name, value)); } } void CheckVoiceReference(ActorInfo actorInfo, - ITraitInfo traitInfo, + TraitInfo traitInfo, FieldInfo fieldInfo, IReadOnlyDictionary dict, VoiceSetReferenceAttribute attribute) @@ -110,7 +111,7 @@ if (value == null) continue; - if (!dict.ContainsKey(value.ToLower())) + if (!dict.ContainsKey(value.ToLowerInvariant())) emitError("{0}.{1}.{2}: Missing voice `{3}`." .F(actorInfo.Name, traitInfo.GetType().Name, fieldInfo.Name, value)); } diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckAngle.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckAngle.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckAngle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckAngle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ { class CheckAngle : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var weaponInfo in rules.Weapons) { diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckChromeHotkeys.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckChromeHotkeys.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckChromeHotkeys.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckChromeHotkeys.cs 2021-03-21 11:10:05.000000000 +0000 @@ -41,7 +41,7 @@ var checkWidgetFields = modData.ObjectCreator.GetTypesImplementing() .SelectMany(w => w.GetFields() .Where(f => f.FieldType == typeof(HotkeyReference)) - .Select(f => Pair.New(w.Name.Substring(0, w.Name.Length - 6), f.Name))) + .Select(f => (w.Name.Substring(0, w.Name.Length - 6), f.Name))) .ToArray(); var customLintMethods = new Dictionary>(); @@ -64,7 +64,7 @@ } } - void CheckInner(ModData modData, string[] namedKeys, Pair[] checkWidgetFields, Dictionary> customLintMethods, + void CheckInner(ModData modData, string[] namedKeys, (string Widget, string Field)[] checkWidgetFields, Dictionary> customLintMethods, List nodes, string filename, MiniYamlNode parent, Action emitError, Action emitWarning) { foreach (var node in nodes) @@ -74,26 +74,23 @@ foreach (var x in checkWidgetFields) { - if (node.Key == x.Second && parent != null && parent.Key.StartsWith(x.First, StringComparison.Ordinal)) + if (node.Key == x.Field && parent != null && parent.Key.StartsWith(x.Widget, StringComparison.Ordinal)) { // Keys are valid if they refer to a named key or can be parsed as a regular Hotkey. - Hotkey unused; - if (!namedKeys.Contains(node.Value.Value) && !Hotkey.TryParse(node.Value.Value, out unused)) + if (!namedKeys.Contains(node.Value.Value) && !Hotkey.TryParse(node.Value.Value, out var unused)) emitError("{0} refers to a Key named `{1}` that does not exist".F(node.Location, node.Value.Value)); } } // Check runtime-defined hotkey names - List checkMethods; var widgetType = node.Key.Split('@')[0]; - if (customLintMethods.TryGetValue(widgetType, out checkMethods)) + if (customLintMethods.TryGetValue(widgetType, out var checkMethods)) { var type = modData.ObjectCreator.FindType(widgetType + "Widget"); var keyNames = checkMethods.SelectMany(m => (IEnumerable)type.GetMethod(m).Invoke(null, new object[] { node, emitError, emitWarning })); - Hotkey unused; foreach (var name in keyNames) - if (!namedKeys.Contains(name) && !Hotkey.TryParse(name, out unused)) + if (!namedKeys.Contains(name) && !Hotkey.TryParse(name, out var unused)) emitError("{0} refers to a Key named `{1}` that does not exist".F(node.Location, name)); } @@ -111,10 +108,9 @@ checkArgKeys.AddRange(type.GetCustomAttributes(true).SelectMany(x => x.LogicArgKeys)); } - Hotkey unused; foreach (var n in node.Value.Nodes) if (checkArgKeys.Contains(n.Key)) - if (!namedKeys.Contains(n.Value.Value) && !Hotkey.TryParse(n.Value.Value, out unused)) + if (!namedKeys.Contains(n.Value.Value) && !Hotkey.TryParse(n.Value.Value, out var unused)) emitError("{0} {1}:{2} refers to a Key named `{3}` that does not exist".F(filename, node.Value.Value, n.Key, n.Value.Value)); } diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckConditions.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckConditions.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckConditions.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckConditions.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,21 +12,20 @@ using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.Common.Lint { public class CheckConditions : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorInfo in rules.Actors) { var granted = new HashSet(); var consumed = new HashSet(); - foreach (var trait in actorInfo.Value.TraitInfos()) + foreach (var trait in actorInfo.Value.TraitInfos()) { var fieldConsumed = trait.GetType().GetFields() .Where(x => x.HasAttribute()) @@ -60,9 +59,6 @@ var ungranted = consumed.Except(granted); if (ungranted.Any()) emitError("Actor type `{0}` consumes conditions that are not granted: {1}".F(actorInfo.Key, ungranted.JoinWith(", "))); - - if ((consumed.Any() || granted.Any()) && actorInfo.Value.TraitInfoOrDefault() == null) - emitError("Actor type `{0}` defines conditions but does not include a ConditionManager".F(actorInfo.Key)); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,13 +11,13 @@ using System; using System.Linq; -using OpenRA.Traits; +using OpenRA.Mods.Common.Traits; namespace OpenRA.Mods.Common.Lint { public class CheckConflictingMouseBounds : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorInfo in rules.Actors) { diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckDefaultVisibility.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckDefaultVisibility.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckDefaultVisibility.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckDefaultVisibility.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ { class CheckDefaultVisibility : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorInfo in rules.Actors) { diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckHitShapes.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckHitShapes.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckHitShapes.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckHitShapes.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ { class CheckHitShapes : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorInfo in rules.Actors) { diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckLocomotorReferences.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckLocomotorReferences.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckLocomotorReferences.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckLocomotorReferences.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ { public class CheckLocomotorReferences : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { var worldActor = rules.Actors["world"]; var locomotorInfos = worldActor.TraitInfos().ToArray(); @@ -29,7 +29,7 @@ foreach (var actorInfo in rules.Actors) { - foreach (var traitInfo in actorInfo.Value.TraitInfos()) + foreach (var traitInfo in actorInfo.Value.TraitInfos()) { var fields = traitInfo.GetType().GetFields().Where(f => f.HasAttribute()); foreach (var field in fields) diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckNotifications.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckNotifications.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckNotifications.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckNotifications.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,17 +12,18 @@ using System; using System.Linq; using OpenRA.GameRules; +using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.Common.Lint { class CheckNotifications : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorInfo in rules.Actors) { - foreach (var traitInfo in actorInfo.Value.TraitInfos()) + foreach (var traitInfo in actorInfo.Value.TraitInfos()) { var fields = traitInfo.GetType().GetFields(); foreach (var field in fields.Where(x => x.HasAttribute())) @@ -43,9 +44,8 @@ if (string.IsNullOrEmpty(notification)) continue; - SoundInfo soundInfo; - if (string.IsNullOrEmpty(type) || !rules.Notifications.TryGetValue(type.ToLowerInvariant(), out soundInfo) || - !soundInfo.Notifications.ContainsKey(notification)) + if (string.IsNullOrEmpty(type) || !rules.Notifications.TryGetValue(type.ToLowerInvariant(), out var soundInfo) || + !soundInfo.Notifications.ContainsKey(notification)) emitError("Undefined notification reference {0}.{1} detected at {2} for {3}".F( type ?? "(null)", notification, traitInfo.GetType().Name, actorInfo.Key)); } diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckPalettes.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckPalettes.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckPalettes.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckPalettes.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,13 +21,13 @@ List palettes = new List(); List playerPalettes = new List(); - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { GetPalettes(emitError, rules); foreach (var actorInfo in rules.Actors) { - foreach (var traitInfo in actorInfo.Value.TraitInfos()) + foreach (var traitInfo in actorInfo.Value.TraitInfos()) { var fields = traitInfo.GetType().GetFields(); foreach (var field in fields.Where(x => x.HasAttribute())) @@ -115,7 +115,7 @@ { foreach (var actorInfo in rules.Actors) { - foreach (var traitInfo in actorInfo.Value.TraitInfos()) + foreach (var traitInfo in actorInfo.Value.TraitInfos()) { var fields = traitInfo.GetType().GetFields(); foreach (var field in fields.Where(x => x.HasAttribute())) diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckPlayers.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckPlayers.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckPlayers.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckPlayers.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,8 +13,6 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; -using OpenRA.Scripting; using OpenRA.Traits; namespace OpenRA.Mods.Common.Lint @@ -24,8 +22,10 @@ public void Run(Action emitError, Action emitWarning, ModData modData, Map map) { var players = new MapPlayers(map.PlayerDefinitions).Players; - var worldOwnerFound = false; + if (players.Count > 64) + emitError("Defining more than 64 players is not allowed."); + var worldOwnerFound = false; var playerNames = players.Values.Select(p => p.Name).ToHashSet(); foreach (var player in players.Values) { @@ -57,7 +57,6 @@ emitError("Found no player owning the world."); var worldActor = map.Rules.Actors["world"]; - var factions = worldActor.TraitInfos().Select(f => f.InternalName).ToHashSet(); foreach (var player in players.Values) if (!string.IsNullOrWhiteSpace(player.Faction) && !factions.Contains(player.Faction)) @@ -70,7 +69,7 @@ foreach (var kv in map.ActorDefinitions.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); - spawns.Add(s.InitDict.Get().Value(null)); + spawns.Add(s.Get().Value); } if (playerCount > spawns.Count) @@ -88,17 +87,16 @@ foreach (var kv in map.ActorDefinitions) { var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); - var ownerInit = actorReference.InitDict.GetOrDefault(); + var ownerInit = actorReference.GetOrDefault(); if (ownerInit == null) emitError("Actor {0} is not owned by any player.".F(kv.Key)); else { - var ownerName = ownerInit.PlayerName; + var ownerName = ownerInit.InternalName; if (!playerNames.Contains(ownerName)) emitError("Actor {0} is owned by unknown player {1}.".F(kv.Key, ownerName)); - RequiresSpecificOwnersInfo info; - if (actorsWithRequiredOwner.TryGetValue(kv.Value.Value, out info)) + if (actorsWithRequiredOwner.TryGetValue(kv.Value.Value, out var info)) if (!info.ValidOwnerNames.Contains(ownerName)) emitError("Actor {0} owner {1} is not one of ValidOwnerNames: {2}".F(kv.Key, ownerName, info.ValidOwnerNames.JoinWith(", "))); } diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckRangeLimit.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckRangeLimit.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckRangeLimit.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckRangeLimit.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ { class CheckRangeLimit : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var weaponInfo in rules.Weapons) { diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckRevealFootprint.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckRevealFootprint.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckRevealFootprint.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckRevealFootprint.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ { class CheckRevealFootprint : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorInfo in rules.Actors) { diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckSequences.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckSequences.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckSequences.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckSequences.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,160 +13,136 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using OpenRA.Graphics; using OpenRA.Mods.Common.Traits.Render; using OpenRA.Traits; namespace OpenRA.Mods.Common.Lint { - class CheckSequences : ILintMapPass + class CheckSequences : ILintRulesPass { - Action emitError; - - List sequenceDefinitions; - - public void Run(Action emitError, Action emitWarning, ModData modData, Map map) + void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { - if (map.SequenceDefinitions == null) - return; - - this.emitError = emitError; - - sequenceDefinitions = MiniYaml.Load(map, modData.Manifest.Sequences, map.SequenceDefinitions); + // Custom maps define rules.Sequences, default mod rules leave it null. + if (rules.Sequences == null) + { + foreach (var kv in modData.DefaultSequences) + { + Console.WriteLine("Testing default sequences for {0}", kv.Key); + Run(emitError, emitWarning, rules, kv.Value); + } + } + else if (!modData.DefaultSequences.Values.Contains(rules.Sequences)) + Run(emitError, emitWarning, rules, rules.Sequences); + } - var rules = map.Rules; + void Run(Action emitError, Action emitWarning, Ruleset rules, SequenceProvider sequences) + { var factions = rules.Actors["world"].TraitInfos().Select(f => f.InternalName).ToArray(); - var sequenceProviders = new[] { rules.Sequences }; - foreach (var actorInfo in rules.Actors) { - foreach (var renderInfo in actorInfo.Value.TraitInfos()) + // Actors may have 0 or 1 RenderSprites traits + var renderInfo = actorInfo.Value.TraitInfoOrDefault(); + if (renderInfo == null) + continue; + + var images = new HashSet() { - foreach (var faction in factions) - { - foreach (var sequenceProvider in sequenceProviders) - { - var image = renderInfo.GetImage(actorInfo.Value, sequenceProvider, faction); - if (sequenceDefinitions.All(s => s.Key != image.ToLowerInvariant())) - emitError("Sprite image {0} from actor {1} using faction {2} has no sequence definition." - .F(image, actorInfo.Value.Name, faction)); - } - } - } + renderInfo.GetImage(actorInfo.Value, sequences, null).ToLowerInvariant() + }; + + // Some actors define faction-specific artwork + foreach (var faction in factions) + images.Add(renderInfo.GetImage(actorInfo.Value, sequences, faction).ToLowerInvariant()); - foreach (var traitInfo in actorInfo.Value.TraitInfos()) + foreach (var traitInfo in actorInfo.Value.TraitInfos()) { + // Remove the "Info" suffix + var traitName = traitInfo.GetType().Name; + traitName = traitName.Remove(traitName.Length - 4); + var fields = traitInfo.GetType().GetFields(); foreach (var field in fields) { - if (field.HasAttribute()) + var sequenceReference = field.GetCustomAttributes(true).FirstOrDefault(); + if (sequenceReference == null) + continue; + + // Some sequences may specify their own Image override + IEnumerable sequenceImages = images; + if (!string.IsNullOrEmpty(sequenceReference.ImageReference)) { - var sequences = LintExts.GetFieldValues(traitInfo, field, emitError); - foreach (var sequence in sequences) + var imageField = fields.First(f => f.Name == sequenceReference.ImageReference); + var imageOverride = (string)imageField.GetValue(traitInfo); + if (string.IsNullOrEmpty(imageOverride)) { - if (string.IsNullOrEmpty(sequence)) - continue; + if (!sequenceReference.AllowNullImage) + emitError("Actor type `{0}` trait `{1}` must define a value for `{2}`".F(actorInfo.Value.Name, traitName, sequenceReference.ImageReference)); + continue; + } + + sequenceImages = new[] { imageOverride.ToLowerInvariant() }; + } - var renderInfo = actorInfo.Value.TraitInfos().FirstOrDefault(); - if (renderInfo == null) - continue; + foreach (var sequence in LintExts.GetFieldValues(traitInfo, field, emitError, sequenceReference.DictionaryReference)) + { + if (string.IsNullOrEmpty(sequence)) + continue; - foreach (var faction in factions) + foreach (var i in sequenceImages) + { + if (sequenceReference.Prefix) { - var sequenceReference = field.GetCustomAttributes(true).FirstOrDefault(); - if (sequenceReference != null && !string.IsNullOrEmpty(sequenceReference.ImageReference)) - { - var imageField = fields.FirstOrDefault(f => f.Name == sequenceReference.ImageReference); - if (imageField != null) - { - foreach (var imageOverride in LintExts.GetFieldValues(traitInfo, imageField, emitError)) - { - if (string.IsNullOrEmpty(imageOverride)) - { - emitWarning("Custom sprite image of actor {0} is null.".F(actorInfo.Value.Name)); - continue; - } - - if (sequenceDefinitions.All(s => s.Key != imageOverride.ToLowerInvariant())) - emitError("Custom sprite image {0} from actor {1} has no sequence definition.".F(imageOverride, actorInfo.Value.Name)); - else - CheckDefinitions(imageOverride, sequenceReference, actorInfo, sequence, faction, field, traitInfo); - } - } - } - else - { - foreach (var sequenceProvider in sequenceProviders) - { - var image = renderInfo.GetImage(actorInfo.Value, sequenceProvider, faction); - CheckDefinitions(image, sequenceReference, actorInfo, sequence, faction, field, traitInfo); - } - } + // TODO: Remove prefixed sequence references and instead use explicit lists of lintable references + if (!sequences.Sequences(i).Any(s => s.StartsWith(sequence))) + emitWarning("Actor type `{0}` trait `{1}` field `{2}` defines a prefix `{3}` that does not match any sequences on image `{4}`.".F(actorInfo.Value.Name, traitName, field.Name, sequence, i)); } + else if (!sequences.HasSequence(i, sequence)) + emitError("Actor type `{0}` trait `{1}` field `{2}` references an undefined sequence `{3}` on image `{4}`.".F(actorInfo.Value.Name, traitName, field.Name, sequence, i)); } } } } + } + + foreach (var weaponInfo in rules.Weapons) + { + var projectileInfo = weaponInfo.Value.Projectile; + if (projectileInfo == null) + continue; - foreach (var weaponInfo in rules.Weapons) + var fields = projectileInfo.GetType().GetFields(); + foreach (var field in fields) { - var projectileInfo = weaponInfo.Value.Projectile; - if (projectileInfo == null) + var sequenceReference = field.GetCustomAttributes(true).FirstOrDefault(); + if (sequenceReference == null) continue; - var fields = projectileInfo.GetType().GetFields(); - foreach (var field in fields) + // All weapon sequences must specify their corresponding image + var image = ((string)fields.First(f => f.Name == sequenceReference.ImageReference).GetValue(projectileInfo)); + if (string.IsNullOrEmpty(image)) { - if (field.HasAttribute()) - { - var sequences = LintExts.GetFieldValues(projectileInfo, field, emitError); - foreach (var sequence in sequences) - { - if (string.IsNullOrEmpty(sequence)) - continue; + if (!sequenceReference.AllowNullImage) + emitError("Weapon type `{0}` projectile field `{1}` must define a value".F(weaponInfo.Key, sequenceReference.ImageReference)); - var sequenceReference = field.GetCustomAttributes(true).FirstOrDefault(); - if (sequenceReference != null && !string.IsNullOrEmpty(sequenceReference.ImageReference)) - { - var imageField = fields.FirstOrDefault(f => f.Name == sequenceReference.ImageReference); - if (imageField != null) - { - foreach (var imageOverride in LintExts.GetFieldValues(projectileInfo, imageField, emitError)) - { - if (!string.IsNullOrEmpty(imageOverride)) - { - var definitions = sequenceDefinitions.FirstOrDefault(n => n.Key == imageOverride.ToLowerInvariant()); - if (definitions == null) - emitError("Can't find sequence definition for projectile image {0} at weapon {1}.".F(imageOverride, weaponInfo.Key)); - else if (!definitions.Value.Nodes.Any(n => n.Key == sequence)) - emitError("Projectile sprite image {0} from weapon {1} does not define sequence {2} from field {3} of {4}" - .F(imageOverride, weaponInfo.Key, sequence, field.Name, projectileInfo)); - } - } - } - } - } - } + continue; } - } - } - } - void CheckDefinitions(string image, SequenceReferenceAttribute sequenceReference, - KeyValuePair actorInfo, string sequence, string faction, FieldInfo field, ITraitInfo traitInfo) - { - var definitions = sequenceDefinitions.FirstOrDefault(n => n.Key == image.ToLowerInvariant()); - if (definitions != null) - { - if (sequenceReference != null && sequenceReference.Prefix) - { - if (!definitions.Value.Nodes.Any(n => n.Key.StartsWith(sequence))) - emitError("Sprite image {0} from actor {1} of faction {2} does not define sequence prefix {3} from field {4} of {5}" - .F(image, actorInfo.Value.Name, faction, sequence, field.Name, traitInfo)); - } - else if (definitions.Value.Nodes.All(n => n.Key != sequence)) - { - emitError("Sprite image {0} from actor {1} of faction {2} does not define sequence {3} from field {4} of {5}" - .F(image, actorInfo.Value.Name, faction, sequence, field.Name, traitInfo)); + image = image.ToLowerInvariant(); + foreach (var sequence in LintExts.GetFieldValues(projectileInfo, field, emitError, sequenceReference.DictionaryReference)) + { + if (string.IsNullOrEmpty(sequence)) + continue; + + if (sequenceReference.Prefix) + { + // TODO: Remove prefixed sequence references and instead use explicit lists of lintable references + if (!sequences.Sequences(image).Any(s => s.StartsWith(sequence))) + emitWarning("Weapon type `{0}` projectile field `{1}` defines a prefix `{2}` that does not match any sequences on image `{3}`.".F(weaponInfo.Key, field.Name, sequence, image)); + } + else if (!sequences.HasSequence(image, sequence)) + emitError("Weapon type `{0}` projectile field `{1}` references an undefined sequence `{2}` on image `{3}`.".F(weaponInfo.Key, field.Name, sequence, image)); + } } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckSpriteBodies.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckSpriteBodies.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckSpriteBodies.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckSpriteBodies.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ { class CheckSpriteBodies : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorInfo in rules.Actors) { diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckTooltips.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckTooltips.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckTooltips.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckTooltips.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ { class CheckTooltips : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorInfo in rules.Actors) { diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckTraitPrerequisites.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckTraitPrerequisites.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckTraitPrerequisites.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckTraitPrerequisites.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ { public class CheckTraitPrerequisites : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorInfo in rules.Actors) { diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/CheckVoiceReferences.cs openra-20210321/OpenRA.Mods.Common/Lint/CheckVoiceReferences.cs --- openra-20200503/OpenRA.Mods.Common/Lint/CheckVoiceReferences.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/CheckVoiceReferences.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,17 +11,18 @@ using System; using System.Linq; +using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.Common.Lint { public class CheckVoiceReferences : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorInfo in rules.Actors) { - foreach (var traitInfo in actorInfo.Value.TraitInfos()) + foreach (var traitInfo in actorInfo.Value.TraitInfos()) { var fields = traitInfo.GetType().GetFields().Where(f => f.HasAttribute()); foreach (var field in fields) @@ -43,7 +44,7 @@ { var soundInfo = rules.Voices[voiceSet.ToLowerInvariant()]; - foreach (var traitInfo in actorInfo.TraitInfos()) + foreach (var traitInfo in actorInfo.TraitInfos()) { var fields = traitInfo.GetType().GetFields().Where(f => f.HasAttribute()); foreach (var field in fields) diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/LintBuildablePrerequisites.cs openra-20210321/OpenRA.Mods.Common/Lint/LintBuildablePrerequisites.cs --- openra-20200503/OpenRA.Mods.Common/Lint/LintBuildablePrerequisites.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/LintBuildablePrerequisites.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ { class LintBuildablePrerequisites : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { var providedPrereqs = rules.Actors.SelectMany(a => a.Value.TraitInfos().SelectMany(p => p.Prerequisites(a.Value))); diff -Nru openra-20200503/OpenRA.Mods.Common/Lint/LintExts.cs openra-20210321/OpenRA.Mods.Common/Lint/LintExts.cs --- openra-20200503/OpenRA.Mods.Common/Lint/LintExts.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Lint/LintExts.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,12 +15,14 @@ using System.Linq; using System.Reflection; using OpenRA.Support; +using OpenRA.Traits; namespace OpenRA.Mods.Common.Lint { public class LintExts { - public static IEnumerable GetFieldValues(object ruleInfo, FieldInfo fieldInfo, Action emitError) + public static IEnumerable GetFieldValues(object ruleInfo, FieldInfo fieldInfo, Action emitError, + LintDictionaryReference dictionaryReference = LintDictionaryReference.None) { var type = fieldInfo.FieldType; if (type == typeof(string)) @@ -35,11 +37,38 @@ return expr != null ? expr.Variables : Enumerable.Empty(); } - throw new InvalidOperationException("Bad type for reference on {0}.{1}. Supported types: string, IEnumerable, BooleanExpression, IntegerExpression" - .F(ruleInfo.GetType().Name, fieldInfo.Name)); + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // Use an intermediate list to cover the unlikely case where both keys and values are lintable + var dictionaryValues = new List(); + if (dictionaryReference.HasFlag(LintDictionaryReference.Keys) && type.GenericTypeArguments[0] == typeof(string)) + dictionaryValues.AddRange((IEnumerable)((IDictionary)fieldInfo.GetValue(ruleInfo)).Keys); + + if (dictionaryReference.HasFlag(LintDictionaryReference.Values) && type.GenericTypeArguments[1] == typeof(string)) + dictionaryValues.AddRange((IEnumerable)((IDictionary)fieldInfo.GetValue(ruleInfo)).Values); + + if (dictionaryReference.HasFlag(LintDictionaryReference.Values) && type.GenericTypeArguments[1] == typeof(IEnumerable)) + foreach (var row in (IEnumerable>)((IDictionary)fieldInfo.GetValue(ruleInfo)).Values) + dictionaryValues.AddRange(row); + + return dictionaryValues; + } + + var supportedTypes = new[] + { + "string", "IEnumerable", + "Dictionary (LintDictionaryReference.Keys)", + "Dictionary (LintDictionaryReference.Values)", + "Dictionary> (LintDictionaryReference.Values)", + "BooleanExpression", "IntegerExpression" + }; + + throw new InvalidOperationException("Bad type for reference on {0}.{1}. Supported types: {2}" + .F(ruleInfo.GetType().Name, fieldInfo.Name, supportedTypes.JoinWith(", "))); } - public static IEnumerable GetPropertyValues(object ruleInfo, PropertyInfo propertyInfo, Action emitError) + public static IEnumerable GetPropertyValues(object ruleInfo, PropertyInfo propertyInfo, Action emitError, + LintDictionaryReference dictionaryReference = LintDictionaryReference.None) { var type = propertyInfo.PropertyType; if (type == typeof(string)) @@ -54,8 +83,34 @@ return expr != null ? expr.Variables : Enumerable.Empty(); } - throw new InvalidOperationException("Bad type for reference on {0}.{1}. Supported types: string, IEnumerable, BooleanExpression, IntegerExpression" - .F(ruleInfo.GetType().Name, propertyInfo.Name)); + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // Use an intermediate list to cover the unlikely case where both keys and values are lintable + var dictionaryValues = new List(); + if (dictionaryReference.HasFlag(LintDictionaryReference.Keys) && type.GenericTypeArguments[0] == typeof(string)) + dictionaryValues.AddRange((IEnumerable)((IDictionary)propertyInfo.GetValue(ruleInfo)).Keys); + + if (dictionaryReference.HasFlag(LintDictionaryReference.Values) && type.GenericTypeArguments[1] == typeof(string)) + dictionaryValues.AddRange((IEnumerable)((IDictionary)propertyInfo.GetValue(ruleInfo)).Values); + + if (dictionaryReference.HasFlag(LintDictionaryReference.Values) && type.GenericTypeArguments[1] == typeof(IEnumerable)) + foreach (var row in (IEnumerable>)((IDictionary)propertyInfo.GetValue(ruleInfo)).Values) + dictionaryValues.AddRange(row); + + return dictionaryValues; + } + + var supportedTypes = new[] + { + "string", "IEnumerable", + "Dictionary (LintDictionaryReference.Keys)", + "Dictionary (LintDictionaryReference.Values)", + "Dictionary> (LintDictionaryReference.Values)", + "BooleanExpression", "IntegerExpression" + }; + + throw new InvalidOperationException("Bad type for reference on {0}.{1}. Supported types: {2}" + .F(ruleInfo.GetType().Name, propertyInfo.Name, supportedTypes.JoinWith(", "))); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs openra-20210321/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs --- openra-20200503/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs 2021-03-21 11:10:05.000000000 +0000 @@ -53,19 +53,12 @@ } // Join a server directly - var connect = Launch.GetConnectAddress(); - if (!string.IsNullOrEmpty(connect)) + var connect = Launch.GetConnectEndPoint(); + if (connect != null) { - var parts = connect.Split(':'); - - if (parts.Length == 2) - { - var host = parts[0]; - var port = Exts.ParseIntegerInvariant(parts[1]); - Game.LoadShellMap(); - Game.RemoteDirectConnect(host, port); - return; - } + Game.LoadShellMap(); + Game.RemoteDirectConnect(connect); + return; } // Start a map directly @@ -112,18 +105,21 @@ public virtual bool BeforeLoad() { + var graphicSettings = Game.Settings.Graphics; + // Reset the UI scaling if the user has configured a UI scale that pushes us below the minimum allowed effective resolution var minResolution = ModData.Manifest.Get().MinEffectiveResolution; var resolution = Game.Renderer.Resolution; if ((resolution.Width < minResolution.Width || resolution.Height < minResolution.Height) && Game.Settings.Graphics.UIScale > 1.0f) { - Game.Settings.Graphics.UIScale = 1.0f; + graphicSettings.UIScale = 1.0f; Game.Renderer.SetUIScale(1.0f); } // Saved settings may have been invalidated by a hardware change - Game.Settings.Graphics.GLProfile = Game.Renderer.GLProfile; - Game.Settings.Graphics.VideoDisplay = Game.Renderer.CurrentDisplay; + graphicSettings.VideoDisplay = Game.Renderer.CurrentDisplay; + if (graphicSettings.GLProfile != GLProfile.Automatic && graphicSettings.GLProfile != Game.Renderer.GLProfile) + graphicSettings.GLProfile = GLProfile.Automatic; // If a ModContent section is defined then we need to make sure that the // required content is installed or switch to the defined content installer. diff -Nru openra-20200503/OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs openra-20210321/OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs --- openra-20200503/OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Collections.Generic; using OpenRA.Graphics; using OpenRA.Mods.Common.Widgets; diff -Nru openra-20200503/OpenRA.Mods.Common/LoadScreens/ModContentLoadScreen.cs openra-20210321/OpenRA.Mods.Common/LoadScreens/ModContentLoadScreen.cs --- openra-20200503/OpenRA.Mods.Common/LoadScreens/ModContentLoadScreen.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/LoadScreens/ModContentLoadScreen.cs 2021-03-21 11:10:05.000000000 +0000 @@ -49,8 +49,7 @@ public override void StartGame(Arguments args) { var modId = args.GetValue("Content.Mod", null); - Manifest selectedMod; - if (modId == null || !Game.Mods.TryGetValue(modId, out selectedMod)) + if (modId == null || !Game.Mods.TryGetValue(modId, out var selectedMod)) throw new InvalidOperationException("Invalid or missing Content.Mod argument."); var content = selectedMod.Get(Game.ModData.ObjectCreator); diff -Nru openra-20200503/OpenRA.Mods.Common/LoadScreens/SheetLoadScreen.cs openra-20210321/OpenRA.Mods.Common/LoadScreens/SheetLoadScreen.cs --- openra-20200503/OpenRA.Mods.Common/LoadScreens/SheetLoadScreen.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/LoadScreens/SheetLoadScreen.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,8 +52,7 @@ dpiScale = scale; // Force images to be reloaded on the next display - if (sheet != null) - sheet.Dispose(); + sheet?.Dispose(); sheet = null; } @@ -73,7 +72,7 @@ density = 2; } - using (var stream = ModData.DefaultFileSystem.Open(Info[key])) + using (var stream = ModData.DefaultFileSystem.Open(Platform.ResolvePath(Info[key]))) { sheet = new Sheet(SheetType.BGRA, stream); sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear; @@ -94,8 +93,8 @@ protected override void Dispose(bool disposing) { - if (disposing && sheet != null) - sheet.Dispose(); + if (disposing) + sheet?.Dispose(); base.Dispose(disposing); } diff -Nru openra-20200503/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj openra-20210321/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj --- openra-20200503/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj 2021-03-21 11:10:05.000000000 +0000 @@ -1,12 +1,12 @@  - net461 + net472 true true - 5 + 7.3 true true - ../mods/common + ../bin false AnyCPU false @@ -21,28 +21,14 @@ false - - ..\thirdparty\download\FuzzyLogicLibrary.dll - False - - - ..\thirdparty\download\rix0rrr.BeaconLib.dll - False - - - ..\thirdparty\download\Eluant.dll - False - - - ..\thirdparty\download\ICSharpCode.SharpZipLib.dll - False - - - False + + + + diff -Nru openra-20200503/OpenRA.Mods.Common/Orders/BeaconOrderGenerator.cs openra-20210321/OpenRA.Mods.Common/Orders/BeaconOrderGenerator.cs --- openra-20200503/OpenRA.Mods.Common/Orders/BeaconOrderGenerator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Orders/BeaconOrderGenerator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,6 @@ yield return new Order("PlaceBeacon", world.LocalPlayer.PlayerActor, Target.FromCell(world, cell), false) { SuppressVisualFeedback = true }; } - protected override void Tick(World world) { } protected override IEnumerable Render(WorldRenderer wr, World world) { yield break; } protected override IEnumerable RenderAboveShroud(WorldRenderer wr, World world) { yield break; } protected override IEnumerable RenderAnnotations(WorldRenderer wr, World world) { yield break; } diff -Nru openra-20200503/OpenRA.Mods.Common/Orders/DeployOrderTargeter.cs openra-20210321/OpenRA.Mods.Common/Orders/DeployOrderTargeter.cs --- openra-20200503/OpenRA.Mods.Common/Orders/DeployOrderTargeter.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Orders/DeployOrderTargeter.cs 2021-03-21 11:10:05.000000000 +0000 @@ -33,9 +33,9 @@ public string OrderID { get; private set; } public int OrderPriority { get; private set; } - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (target.Type != TargetType.Actor) return false; diff -Nru openra-20200503/OpenRA.Mods.Common/Orders/EnterAlliedActorTargeter.cs openra-20210321/OpenRA.Mods.Common/Orders/EnterAlliedActorTargeter.cs --- openra-20200503/OpenRA.Mods.Common/Orders/EnterAlliedActorTargeter.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Orders/EnterAlliedActorTargeter.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,15 +14,19 @@ namespace OpenRA.Mods.Common.Orders { - public class EnterAlliedActorTargeter : UnitOrderTargeter where T : ITraitInfo + public class EnterAlliedActorTargeter : UnitOrderTargeter where T : ITraitInfoInterface { + readonly string enterCursor; + readonly string enterBlockedCursor; readonly Func canTarget; readonly Func useEnterCursor; - public EnterAlliedActorTargeter(string order, int priority, + public EnterAlliedActorTargeter(string order, int priority, string enterCursor, string enterBlockedCursor, Func canTarget, Func useEnterCursor) - : base(order, priority, "enter", false, true) + : base(order, priority, enterCursor, false, true) { + this.enterCursor = enterCursor; + this.enterBlockedCursor = enterBlockedCursor; this.canTarget = canTarget; this.useEnterCursor = useEnterCursor; } @@ -32,7 +36,7 @@ if (!self.Owner.IsAlliedWith(target.Owner) || !target.Info.HasTraitInfo() || !canTarget(target, modifiers)) return false; - cursor = useEnterCursor(target) ? "enter" : "enter-blocked"; + cursor = useEnterCursor(target) ? enterCursor : enterBlockedCursor; return true; } diff -Nru openra-20200503/OpenRA.Mods.Common/Orders/GuardOrderGenerator.cs openra-20210321/OpenRA.Mods.Common/Orders/GuardOrderGenerator.cs --- openra-20200503/OpenRA.Mods.Common/Orders/GuardOrderGenerator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Orders/GuardOrderGenerator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,31 +28,31 @@ yield break; var target = FriendlyGuardableUnits(world, mi).FirstOrDefault(); - if (target == null || Subjects.All(s => s.IsDead)) + if (target == null) yield break; world.CancelInputMode(); var queued = mi.Modifiers.HasModifier(Modifiers.Shift); - foreach (var subject in Subjects) - if (subject != target) - yield return new Order(OrderName, subject, Target.FromActor(target), queued); + yield return new Order(OrderName, null, Target.FromActor(target), queued, null, subjects.Where(s => s != target).ToArray()); } - public override void Tick(World world) + public override void SelectionChanged(World world, IEnumerable selected) { - if (Subjects.All(s => s.IsDead || !s.Info.HasTraitInfo())) + // Guarding doesn't work without AutoTarget, so require at least one unit in the selection to have it + subjects = selected.Where(s => !s.IsDead && s.Info.HasTraitInfo()); + if (!subjects.Any(s => s.Info.HasTraitInfo())) world.CancelInputMode(); } public override string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi) { - if (!Subjects.Any()) + if (!subjects.Any()) return null; - var multiple = Subjects.Count() > 1; + var multiple = subjects.Count() > 1; var canGuard = FriendlyGuardableUnits(world, mi) - .Any(a => multiple || a != Subjects.First()); + .Any(a => multiple || a != subjects.First()); return canGuard ? Cursor : "move-blocked"; } diff -Nru openra-20200503/OpenRA.Mods.Common/Orders/OrderGenerator.cs openra-20210321/OpenRA.Mods.Common/Orders/OrderGenerator.cs --- openra-20200503/OpenRA.Mods.Common/Orders/OrderGenerator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Orders/OrderGenerator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ { public abstract class OrderGenerator : IOrderGenerator { - public IEnumerable Order(World world, CPos cell, int2 worldPixel, MouseInput mi) + public virtual IEnumerable Order(World world, CPos cell, int2 worldPixel, MouseInput mi) { if ((mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down) || (mi.Button == MouseButton.Right && mi.Event == MouseInputEvent.Up)) return OrderInner(world, cell, worldPixel, mi); @@ -32,12 +32,14 @@ string IOrderGenerator.GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi) { return GetCursor(world, cell, worldPixel, mi); } void IOrderGenerator.Deactivate() { } bool IOrderGenerator.HandleKeyPress(KeyInput e) { return false; } + void IOrderGenerator.SelectionChanged(World world, IEnumerable selected) { SelectionChanged(world, selected); } - protected abstract void Tick(World world); + protected virtual void Tick(World world) { } protected abstract IEnumerable Render(WorldRenderer wr, World world); protected abstract IEnumerable RenderAboveShroud(WorldRenderer wr, World world); protected abstract IEnumerable RenderAnnotations(WorldRenderer wr, World world); protected abstract string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi); protected abstract IEnumerable OrderInner(World world, CPos cell, int2 worldPixel, MouseInput mi); + protected virtual void SelectionChanged(World world, IEnumerable selected) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs openra-20210321/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs --- openra-20200503/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,7 +13,6 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; -using OpenRA.Mods.Common.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; using OpenRA.Traits; @@ -82,9 +81,9 @@ } } + readonly World world; readonly ProductionQueue queue; readonly PlaceBuildingInfo placeBuildingInfo; - readonly BuildingInfluence buildingInfluence; readonly ResourceLayer resourceLayer; readonly Viewport viewport; readonly VariantWrapper[] variants; @@ -92,10 +91,9 @@ public PlaceBuildingOrderGenerator(ProductionQueue queue, string name, WorldRenderer worldRenderer) { - var world = queue.Actor.World; this.queue = queue; + world = queue.Actor.World; placeBuildingInfo = queue.Actor.Owner.PlayerActor.Info.TraitInfo(); - buildingInfluence = world.WorldActor.Trait(); resourceLayer = world.WorldActor.TraitOrDefault(); viewport = worldRenderer.Viewport; @@ -219,18 +217,19 @@ world.CancelInputMode(); foreach (var v in variants) - if (v.Preview != null) - v.Preview.Tick(); + v.Preview?.Tick(); } + void IOrderGenerator.SelectionChanged(World world, IEnumerable selected) { } + bool AcceptsPlug(CPos cell, PlugInfo plug) { - var host = buildingInfluence.GetBuildingAt(cell); - if (host == null) - return false; + foreach (var a in world.ActorMap.GetActorsAt(cell)) + foreach (var p in a.TraitsImplementing()) + if (p.AcceptsPlug(a, plug.Type)) + return true; - var location = host.Location; - return host.TraitsImplementing().Any(p => p.AcceptsPlug(host, plug.Type)); + return false; } IEnumerable IOrderGenerator.Render(WorldRenderer wr, World world) { yield break; } @@ -263,9 +262,9 @@ { foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, actorInfo, buildingInfo, owner)) { - var lineBuildable = world.IsCellBuildable(t.First, actorInfo, buildingInfo); - var lineCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, t.First); - footprint.Add(t.First, MakeCellType(lineBuildable && lineCloseEnough, true)); + var lineBuildable = world.IsCellBuildable(t.Cell, actorInfo, buildingInfo); + var lineCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, t.Cell); + footprint.Add(t.Cell, MakeCellType(lineBuildable && lineCloseEnough, true)); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Orders/RepairOrderGenerator.cs openra-20210321/OpenRA.Mods.Common/Orders/RepairOrderGenerator.cs --- openra-20200503/OpenRA.Mods.Common/Orders/RepairOrderGenerator.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Orders/RepairOrderGenerator.cs 2021-03-21 11:10:05.000000000 +0000 @@ -70,10 +70,7 @@ if (repairBuilding == null) yield break; - yield return new Order(orderId, underCursor, Target.FromActor(repairBuilding), mi.Modifiers.HasModifier(Modifiers.Shift)) - { - VisualFeedbackTarget = Target.FromActor(underCursor) - }; + yield return new Order(orderId, underCursor, Target.FromActor(repairBuilding), Target.FromActor(underCursor), mi.Modifiers.HasModifier(Modifiers.Shift)); } protected override void Tick(World world) diff -Nru openra-20200503/OpenRA.Mods.Common/Orders/UnitOrderTargeter.cs openra-20210321/OpenRA.Mods.Common/Orders/UnitOrderTargeter.cs --- openra-20200503/OpenRA.Mods.Common/Orders/UnitOrderTargeter.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Orders/UnitOrderTargeter.cs 2021-03-21 11:10:05.000000000 +0000 @@ -32,12 +32,12 @@ public string OrderID { get; private set; } public int OrderPriority { get; private set; } public bool? ForceAttack = null; - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } public abstract bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor); public abstract bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor); - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { var type = target.Type; if (type != TargetType.Actor && type != TargetType.FrozenActor) @@ -50,12 +50,11 @@ return false; var owner = type == TargetType.FrozenActor ? target.FrozenActor.Owner : target.Actor.Owner; - var playerRelationship = self.Owner.Stances[owner]; - - if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && playerRelationship == Stance.Ally && !targetAllyUnits) + var playerRelationship = self.Owner.RelationshipWith(owner); + if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && playerRelationship == PlayerRelationship.Ally && !targetAllyUnits) return false; - if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && playerRelationship == Stance.Enemy && !targetEnemyUnits) + if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && playerRelationship == PlayerRelationship.Enemy && !targetEnemyUnits) return false; return type == TargetType.FrozenActor ? diff -Nru openra-20200503/OpenRA.Mods.Common/Pathfinder/BasePathSearch.cs openra-20210321/OpenRA.Mods.Common/Pathfinder/BasePathSearch.cs --- openra-20200503/OpenRA.Mods.Common/Pathfinder/BasePathSearch.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Pathfinder/BasePathSearch.cs 2021-03-21 11:10:05.000000000 +0000 @@ -27,7 +27,7 @@ /// /// Stores the analyzed nodes by the expand function /// - IEnumerable> Considered { get; } + IEnumerable<(CPos Cell, int Cost)> Considered { get; } Player Owner { get; } @@ -68,7 +68,7 @@ protected IPriorityQueue OpenQueue { get; private set; } - public abstract IEnumerable> Considered { get; } + public abstract IEnumerable<(CPos Cell, int Cost)> Considered { get; } public Player Owner { get { return Graph.Actor.Owner; } } public int MaxCost { get; protected set; } @@ -96,7 +96,7 @@ // Determine the minimum possible cost for moving horizontally between cells based on terrain speeds. // The minimum possible cost diagonally is then Sqrt(2) times more costly. - cellCost = graph.Actor.Trait().Locomotor.Info.TerrainSpeeds.Values.Min(ti => ti.Cost); + cellCost = ((Mobile)graph.Actor.OccupiesSpace).Info.LocomotorInfo.TerrainSpeeds.Values.Min(ti => ti.Cost); diagonalCellCost = cellCost * 141421 / 100000; } diff -Nru openra-20200503/OpenRA.Mods.Common/Pathfinder/PathCacheStorage.cs openra-20210321/OpenRA.Mods.Common/Pathfinder/PathCacheStorage.cs --- openra-20200503/OpenRA.Mods.Common/Pathfinder/PathCacheStorage.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Pathfinder/PathCacheStorage.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,8 +52,7 @@ public List Retrieve(string key) { - CachedPath cached; - if (cachedPaths.TryGetValue(key, out cached)) + if (cachedPaths.TryGetValue(key, out var cached)) { if (IsExpired(cached)) { diff -Nru openra-20200503/OpenRA.Mods.Common/Pathfinder/PathGraph.cs openra-20210321/OpenRA.Mods.Common/Pathfinder/PathGraph.cs --- openra-20200503/OpenRA.Mods.Common/Pathfinder/PathGraph.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Pathfinder/PathGraph.cs 2021-03-21 11:10:05.000000000 +0000 @@ -87,13 +87,12 @@ readonly BlockedByActor checkConditions; readonly Locomotor locomotor; - readonly LocomotorInfo.WorldMovementInfo worldMovementInfo; readonly CellInfoLayerPool.PooledCellInfoLayer pooledLayer; readonly bool checkTerrainHeight; CellLayer groundInfo; - readonly Dictionary>> customLayerInfo = - new Dictionary>>(); + readonly Dictionary Info)> customLayerInfo = + new Dictionary)>(); public PathGraph(CellInfoLayerPool layerPool, Locomotor locomotor, Actor actor, World world, BlockedByActor check) { @@ -105,10 +104,9 @@ .Where(cml => cml.EnabledForActor(actor.Info, locomotorInfo)); foreach (var cml in layers) - customLayerInfo[cml.Index] = Pair.New(cml, pooledLayer.GetLayer()); + customLayerInfo[cml.Index] = (cml, pooledLayer.GetLayer()); World = world; - worldMovementInfo = locomotorInfo.GetWorldMovementInfo(world); Actor = actor; LaneBias = 1; checkConditions = check; @@ -135,7 +133,7 @@ public List GetConnections(CPos position) { - var info = position.Layer == 0 ? groundInfo : customLayerInfo[position.Layer].Second; + var info = position.Layer == 0 ? groundInfo : customLayerInfo[position.Layer].Info; var previousPos = info[position].PreviousPos; var dx = position.X - previousPos.X; @@ -156,8 +154,8 @@ { foreach (var cli in customLayerInfo.Values) { - var layerPosition = new CPos(position.X, position.Y, cli.First.Index); - var entryCost = cli.First.EntryMovementCost(Actor.Info, locomotor.Info, layerPosition); + var layerPosition = new CPos(position.X, position.Y, cli.Layer.Index); + var entryCost = cli.Layer.EntryMovementCost(Actor.Info, locomotor.Info, layerPosition); if (entryCost != CostForInvalidCell) validNeighbors.Add(new GraphConnection(layerPosition, entryCost)); } @@ -165,7 +163,7 @@ else { var layerPosition = new CPos(position.X, position.Y, 0); - var exitCost = customLayerInfo[position.Layer].First.ExitMovementCost(Actor.Info, locomotor.Info, layerPosition); + var exitCost = customLayerInfo[position.Layer].Layer.ExitMovementCost(Actor.Info, locomotor.Info, layerPosition); if (exitCost != CostForInvalidCell) validNeighbors.Add(new GraphConnection(layerPosition, exitCost)); } @@ -224,8 +222,8 @@ public CellInfo this[CPos pos] { - get { return (pos.Layer == 0 ? groundInfo : customLayerInfo[pos.Layer].Second)[pos]; } - set { (pos.Layer == 0 ? groundInfo : customLayerInfo[pos.Layer].Second)[pos] = value; } + get { return (pos.Layer == 0 ? groundInfo : customLayerInfo[pos.Layer].Info)[pos]; } + set { (pos.Layer == 0 ? groundInfo : customLayerInfo[pos.Layer].Info)[pos] = value; } } public void Dispose() diff -Nru openra-20200503/OpenRA.Mods.Common/Pathfinder/PathSearch.cs openra-20210321/OpenRA.Mods.Common/Pathfinder/PathSearch.cs --- openra-20200503/OpenRA.Mods.Common/Pathfinder/PathSearch.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Pathfinder/PathSearch.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; @@ -31,19 +30,19 @@ return LayerPoolTable.GetValue(world, CreateLayerPool); } - public override IEnumerable> Considered + public override IEnumerable<(CPos, int)> Considered { get { return considered; } } - LinkedList> considered; + LinkedList<(CPos, int)> considered; #region Constructors private PathSearch(IGraph graph) : base(graph) { - considered = new LinkedList>(); + considered = new LinkedList<(CPos, int)>(); } public static IPathSearch Search(World world, Locomotor locomotor, Actor self, BlockedByActor check, Func goalCondition) @@ -95,7 +94,7 @@ var connection = new GraphConnection(location, cost); OpenQueue.Add(connection); StartPoints.Add(connection); - considered.AddLast(new Pair(location, 0)); + considered.AddLast((location, 0)); } #endregion @@ -147,7 +146,7 @@ if (gCost > MaxCost) MaxCost = gCost; - considered.AddLast(new Pair(neighborCPos, gCost)); + considered.AddLast((neighborCPos, gCost)); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Projectiles/AreaBeam.cs openra-20210321/OpenRA.Mods.Common/Projectiles/AreaBeam.cs --- openra-20200503/OpenRA.Mods.Common/Projectiles/AreaBeam.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Projectiles/AreaBeam.cs 2021-03-21 11:10:05.000000000 +0000 @@ -47,9 +47,12 @@ [Desc("Ranges at which each Falloff step is defined.")] public readonly WDist[] Range = { WDist.Zero, new WDist(int.MaxValue) }; - [Desc("Maximum offset at the maximum range.")] + [Desc("The maximum/constant/incremental inaccuracy used in conjunction with the InaccuracyType property.")] public readonly WDist Inaccuracy = WDist.Zero; + [Desc("Controls the way inaccuracy is calculated. Possible values are 'Maximum' - scale from 0 to max with range, 'PerCellIncrement' - scale from 0 with range and 'Absolute' - use set value regardless of range.")] + public readonly InaccuracyType InaccuracyType = InaccuracyType.Maximum; + [Desc("Can this projectile be blocked when hitting actors with an IBlocksProjectiles trait.")] public readonly bool Blockable = false; @@ -93,7 +96,7 @@ WPos target; int length; - int towardsTargetFacing; + WAngle towardsTargetFacing; int headTicks; int tailTicks; bool isHeadTravelling = true; @@ -128,16 +131,15 @@ target = args.PassiveTarget; if (info.Inaccuracy.Length > 0) { - var inaccuracy = Util.ApplyPercentageModifiers(info.Inaccuracy.Length, args.InaccuracyModifiers); - var maxOffset = inaccuracy * (target - headPos).Length / args.Weapon.Range.Length; - target += WVec.FromPDF(world.SharedRandom, 2) * maxOffset / 1024; + var maxInaccuracyOffset = Util.GetProjectileInaccuracy(info.Inaccuracy.Length, info.InaccuracyType, args); + target += WVec.FromPDF(world.SharedRandom, 2) * maxInaccuracyOffset / 1024; } - towardsTargetFacing = (target - headPos).Yaw.Facing; + towardsTargetFacing = (target - headPos).Yaw; // Update the target position with the range we shoot beyond the target by // I.e. we can deliberately overshoot, so aim for that position - var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(towardsTargetFacing)); + var dir = new WVec(0, -1024, 0).Rotate(WRot.FromYaw(towardsTargetFacing)); target += dir * info.BeyondTargetRange.Length / 1024; length = Math.Max((target - headPos).Length / speed.Length, 1); @@ -160,11 +162,11 @@ else { target = guidedTargetPos; - towardsTargetFacing = (target - args.Source).Yaw.Facing; + towardsTargetFacing = (target - args.Source).Yaw; // Update the target position with the range we shoot beyond the target by // I.e. we can deliberately overshoot, so aim for that position - var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(towardsTargetFacing)); + var dir = new WVec(0, -1024, 0).Rotate(WRot.FromYaw(towardsTargetFacing)); target += dir * info.BeyondTargetRange.Length / 1024; } } @@ -216,9 +218,7 @@ } // Check for blocking actors - WPos blockedPos; - if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, tailPos, headPos, - info.Width, out blockedPos)) + if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, tailPos, headPos, info.Width, out var blockedPos)) { headPos = blockedPos; target = headPos; @@ -235,6 +235,12 @@ var warheadArgs = new WarheadArgs(args) { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(args.Source, target), args.CurrentMuzzleFacing()), + + // Calculating an impact position is bogus for line damage. + // FindActorsOnLine guarantees that the beam touches the target's HitShape, + // so we just assume a center hit to avoid bogus warhead recalculations. + ImpactPosition = a.CenterPosition, DamageModifiers = adjustedModifiers.ToArray(), }; diff -Nru openra-20200503/OpenRA.Mods.Common/Projectiles/Bullet.cs openra-20210321/OpenRA.Mods.Common/Projectiles/Bullet.cs --- openra-20200503/OpenRA.Mods.Common/Projectiles/Bullet.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Projectiles/Bullet.cs 2021-03-21 11:10:05.000000000 +0000 @@ -27,17 +27,20 @@ [Desc("Projectile speed in WDist / tick, two values indicate variable velocity.")] public readonly WDist[] Speed = { new WDist(17) }; - [Desc("Maximum offset at the maximum range.")] + [Desc("The maximum/constant/incremental inaccuracy used in conjunction with the InaccuracyType property.")] public readonly WDist Inaccuracy = WDist.Zero; + [Desc("Controls the way inaccuracy is calculated. Possible values are 'Maximum' - scale from 0 to max with range, 'PerCellIncrement' - scale from 0 with range and 'Absolute' - use set value regardless of range.")] + public readonly InaccuracyType InaccuracyType = InaccuracyType.Maximum; + [Desc("Image to display.")] public readonly string Image = null; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Loop a randomly chosen sequence of Image from this list while this projectile is moving.")] public readonly string[] Sequences = { "idle" }; - [PaletteReference] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("The palette used to draw this projectile.")] public readonly string Palette = "effect"; @@ -54,7 +57,7 @@ [Desc("Trail animation.")] public readonly string TrailImage = null; - [SequenceReference("TrailImage")] + [SequenceReference(nameof(TrailImage), allowNullImage: true)] [Desc("Loop a randomly chosen sequence of TrailImage from this list while this projectile is moving.")] public readonly string[] TrailSequences = { "idle" }; @@ -64,7 +67,7 @@ [Desc("Delay in ticks until trail animation is spawned.")] public readonly int TrailDelay = 1; - [PaletteReference("TrailUsePlayerPalette")] + [PaletteReference(nameof(TrailUsePlayerPalette))] [Desc("Palette used to render the trail sequence.")] public readonly string TrailPalette = "effect"; @@ -87,8 +90,14 @@ [Desc("Modify distance of each bounce by this percentage of previous distance.")] public readonly int BounceRangeModifier = 60; - [Desc("If projectile touches an actor with one of these stances during or after the first bounce, trigger explosion.")] - public readonly Stance ValidBounceBlockerStances = Stance.Enemy | Stance.Neutral; + [Desc("Sound to play when the projectile hits the ground, but not the target.")] + public readonly string BounceSound = null; + + [Desc("Terrain where the projectile explodes instead of bouncing.")] + public readonly HashSet InvalidBounceTerrain = new HashSet(); + + [Desc("Trigger the explosion if the projectile touches an actor thats owner has these player relationships.")] + public readonly PlayerRelationship ValidBounceBlockerRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral; [Desc("Altitude above terrain below which to explode. Zero effectively deactivates airburst.")] public readonly WDist AirburstAltitude = WDist.Zero; @@ -108,7 +117,7 @@ readonly BulletInfo info; readonly ProjectileArgs args; readonly Animation anim; - readonly int facing; + readonly WAngle facing; readonly WAngle angle; readonly WDist speed; readonly string trailPalette; @@ -116,7 +125,7 @@ ContrailRenderable contrail; [Sync] - WPos pos, target, source; + WPos pos, lastPos, target, source; int length; int ticks, smokeTicks; @@ -144,21 +153,19 @@ target = args.PassiveTarget; if (info.Inaccuracy.Length > 0) { - var inaccuracy = Util.ApplyPercentageModifiers(info.Inaccuracy.Length, args.InaccuracyModifiers); - var range = Util.ApplyPercentageModifiers(args.Weapon.Range.Length, args.RangeModifiers); - var maxOffset = inaccuracy * (target - pos).Length / range; - target += WVec.FromPDF(world.SharedRandom, 2) * maxOffset / 1024; + var maxInaccuracyOffset = Util.GetProjectileInaccuracy(info.Inaccuracy.Length, info.InaccuracyType, args); + target += WVec.FromPDF(world.SharedRandom, 2) * maxInaccuracyOffset / 1024; } if (info.AirburstAltitude > WDist.Zero) target += new WVec(WDist.Zero, WDist.Zero, info.AirburstAltitude); - facing = (target - pos).Yaw.Facing; + facing = (target - pos).Yaw; length = Math.Max((target - pos).Length / speed.Length, 1); if (!string.IsNullOrEmpty(info.Image)) { - anim = new Animation(world, info.Image, new Func(GetEffectiveFacing)); + anim = new Animation(world, info.Image, new Func(GetEffectiveFacing)); anim.PlayRepeating(info.Sequences.Random(world.SharedRandom)); } @@ -176,42 +183,46 @@ remainingBounces = info.BounceCount; } - int GetEffectiveFacing() + WAngle GetEffectiveFacing() { var at = (float)ticks / (length - 1); var attitude = angle.Tan() * (1 - 2 * at) / (4 * 1024); - var u = (facing % 128) / 128f; - var scale = 512 * u * (1 - u); + var u = (facing.Angle % 512) / 512f; + var scale = 2048 * u * (1 - u); - return (int)(facing < 128 - ? facing - scale * attitude - : facing + scale * attitude); + var effective = (int)(facing.Angle < 512 + ? facing.Angle - scale * attitude + : facing.Angle + scale * attitude); + + return new WAngle(effective); } public void Tick(World world) { - if (anim != null) - anim.Tick(); + anim?.Tick(); - var lastPos = pos; + lastPos = pos; pos = WPos.LerpQuadratic(source, target, angle, ticks, length); + if (ShouldExplode(world)) + Explode(world); + } + + bool ShouldExplode(World world) + { // Check for walls or other blocking obstacles - var shouldExplode = false; - WPos blockedPos; - if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, lastPos, pos, info.Width, - out blockedPos)) + if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, lastPos, pos, info.Width, out var blockedPos)) { pos = blockedPos; - shouldExplode = true; + return true; } if (!string.IsNullOrEmpty(info.TrailImage) && --smokeTicks < 0) { var delayedPos = WPos.LerpQuadratic(source, target, angle, ticks - info.TrailDelay, length); - world.AddFrameEndTask(w => w.Add(new SpriteEffect(delayedPos, w, info.TrailImage, info.TrailSequences.Random(world.SharedRandom), - trailPalette, facing: GetEffectiveFacing()))); + world.AddFrameEndTask(w => w.Add(new SpriteEffect(delayedPos, GetEffectiveFacing(), w, + info.TrailImage, info.TrailSequences.Random(world.SharedRandom), trailPalette))); smokeTicks = info.TrailInterval; } @@ -224,28 +235,40 @@ if (flightLengthReached && shouldBounce) { - shouldExplode |= AnyValidTargetsInRadius(world, pos, info.Width, args.SourceActor, true); + var cell = world.Map.CellContaining(pos); + if (!world.Map.Contains(cell)) + return true; + + if (info.InvalidBounceTerrain.Contains(world.Map.GetTerrainInfo(cell).Type)) + return true; + + if (AnyValidTargetsInRadius(world, pos, info.Width, args.SourceActor, true)) + return true; + target += (pos - source) * info.BounceRangeModifier / 100; var dat = world.Map.DistanceAboveTerrain(target); target += new WVec(0, 0, -dat.Length); length = Math.Max((target - pos).Length / speed.Length, 1); + ticks = 0; source = pos; + Game.Sound.Play(SoundType.World, info.BounceSound, source); remainingBounces--; } // Flight length reached / exceeded - shouldExplode |= flightLengthReached && !shouldBounce; + if (flightLengthReached && !shouldBounce) + return true; // Driving into cell with higher height level - shouldExplode |= world.Map.DistanceAboveTerrain(pos).Length < 0; + if (world.Map.DistanceAboveTerrain(pos).Length < 0) + return true; // After first bounce, check for targets each tick - if (remainingBounces < info.BounceCount) - shouldExplode |= AnyValidTargetsInRadius(world, pos, info.Width, args.SourceActor, true); + if (remainingBounces < info.BounceCount && AnyValidTargetsInRadius(world, pos, info.Width, args.SourceActor, true)) + return true; - if (shouldExplode) - Explode(world); + return false; } public IEnumerable Render(WorldRenderer wr) @@ -280,7 +303,13 @@ world.AddFrameEndTask(w => w.Remove(this)); - args.Weapon.Impact(Target.FromPos(pos), new WarheadArgs(args)); + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(lastPos, pos), args.Facing), + ImpactPosition = pos, + }; + + args.Weapon.Impact(Target.FromPos(pos), warheadArgs); } bool AnyValidTargetsInRadius(World world, WPos pos, WDist radius, Actor firedBy, bool checkTargetType) @@ -290,7 +319,7 @@ if (checkTargetType && !Target.FromActor(victim).IsValidFor(firedBy)) continue; - if (!info.ValidBounceBlockerStances.HasStance(victim.Owner.Stances[firedBy.Owner])) + if (!info.ValidBounceBlockerRelationships.HasStance(firedBy.Owner.RelationshipWith(victim.Owner))) continue; // If the impact position is within any actor's HitShape, we have a direct hit diff -Nru openra-20200503/OpenRA.Mods.Common/Projectiles/GravityBomb.cs openra-20210321/OpenRA.Mods.Common/Projectiles/GravityBomb.cs --- openra-20200503/OpenRA.Mods.Common/Projectiles/GravityBomb.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Projectiles/GravityBomb.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,11 +20,11 @@ { public readonly string Image = null; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Loop a randomly chosen sequence of Image from this list while falling.")] public readonly string[] Sequences = { "idle" }; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Sequence to play when launched. Skipped if null or empty.")] public readonly string OpenSequence = null; @@ -58,7 +58,7 @@ WVec velocity; [Sync] - WPos pos; + WPos pos, lastPos; public GravityBomb(GravityBombInfo info, ProjectileArgs args) { @@ -66,7 +66,7 @@ this.args = args; pos = args.Source; var convertedVelocity = new WVec(info.Velocity.Y, -info.Velocity.X, info.Velocity.Z); - velocity = convertedVelocity.Rotate(WRot.FromFacing(args.Facing)); + velocity = convertedVelocity.Rotate(WRot.FromYaw(args.Facing)); acceleration = new WVec(info.Acceleration.Y, -info.Acceleration.X, info.Acceleration.Z); if (!string.IsNullOrEmpty(info.Image)) @@ -82,6 +82,7 @@ public void Tick(World world) { + lastPos = pos; pos += velocity; velocity += acceleration; @@ -90,11 +91,16 @@ pos += new WVec(0, 0, args.PassiveTarget.Z - pos.Z); world.AddFrameEndTask(w => w.Remove(this)); - args.Weapon.Impact(Target.FromPos(pos), new WarheadArgs(args)); + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(lastPos, pos), args.Facing), + ImpactPosition = pos, + }; + + args.Weapon.Impact(Target.FromPos(pos), warheadArgs); } - if (anim != null) - anim.Tick(); + anim?.Tick(); } public IEnumerable Render(WorldRenderer wr) diff -Nru openra-20200503/OpenRA.Mods.Common/Projectiles/InstantHit.cs openra-20210321/OpenRA.Mods.Common/Projectiles/InstantHit.cs --- openra-20200503/OpenRA.Mods.Common/Projectiles/InstantHit.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Projectiles/InstantHit.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,9 +21,12 @@ [Desc("Simple, invisible, usually direct-on-target projectile.")] public class InstantHitInfo : IProjectileInfo { - [Desc("Maximum offset at the maximum range.")] + [Desc("The maximum/constant/incremental inaccuracy used in conjunction with the InaccuracyType property.")] public readonly WDist Inaccuracy = WDist.Zero; + [Desc("Controls the way inaccuracy is calculated. Possible values are 'Maximum' - scale from 0 to max with range, 'PerCellIncrement' - scale from 0 with range and 'Absolute' - use set value regardless of range.")] + public readonly InaccuracyType InaccuracyType = InaccuracyType.Maximum; + [Desc("Projectile can be blocked.")] public readonly bool Blockable = false; @@ -53,9 +56,9 @@ target = args.GuidedTarget; else if (info.Inaccuracy.Length > 0) { - var inaccuracy = Util.ApplyPercentageModifiers(info.Inaccuracy.Length, args.InaccuracyModifiers); - var maxOffset = inaccuracy * (args.PassiveTarget - args.Source).Length / args.Weapon.Range.Length; - target = Target.FromPos(args.PassiveTarget + WVec.FromPDF(args.SourceActor.World.SharedRandom, 2) * maxOffset / 1024); + var maxInaccuracyOffset = Util.GetProjectileInaccuracy(info.Inaccuracy.Length, info.InaccuracyType, args); + var inaccuracyOffset = WVec.FromPDF(args.SourceActor.World.SharedRandom, 2) * maxInaccuracyOffset / 1024; + target = Target.FromPos(args.PassiveTarget + inaccuracyOffset); } else target = Target.FromPos(args.PassiveTarget); @@ -63,22 +66,22 @@ public void Tick(World world) { + // If GuidedTarget has become invalid due to getting killed the same tick, + // we need to set target to args.PassiveTarget to prevent target.CenterPosition below from crashing. + if (target.Type == TargetType.Invalid) + target = Target.FromPos(args.PassiveTarget); + // Check for blocking actors - WPos blockedPos; - if (info.Blockable) + if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, args.Source, target.CenterPosition, info.Width, out var blockedPos)) + target = Target.FromPos(blockedPos); + + var warheadArgs = new WarheadArgs(args) { - // If GuidedTarget has become invalid due to getting killed the same tick, - // we need to set target to args.PassiveTarget to prevent target.CenterPosition below from crashing. - // The warheads have target validity checks themselves so they don't need this, but AnyBlockingActorsBetween does. - if (target.Type == TargetType.Invalid) - target = Target.FromPos(args.PassiveTarget); - - if (BlocksProjectiles.AnyBlockingActorsBetween(world, args.Source, target.CenterPosition, - info.Width, out blockedPos)) - target = Target.FromPos(blockedPos); - } + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(args.Source, target.CenterPosition), args.Facing), + ImpactPosition = target.CenterPosition, + }; - args.Weapon.Impact(target, new WarheadArgs(args)); + args.Weapon.Impact(target, warheadArgs); world.AddFrameEndTask(w => w.Remove(this)); } diff -Nru openra-20200503/OpenRA.Mods.Common/Projectiles/LaserZap.cs openra-20210321/OpenRA.Mods.Common/Projectiles/LaserZap.cs --- openra-20200503/OpenRA.Mods.Common/Projectiles/LaserZap.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Projectiles/LaserZap.cs 2021-03-21 11:10:05.000000000 +0000 @@ -49,9 +49,12 @@ [Desc("Beam follows the target.")] public readonly bool TrackTarget = true; - [Desc("Maximum offset at the maximum range.")] + [Desc("The maximum/constant/incremental inaccuracy used in conjunction with the InaccuracyType property.")] public readonly WDist Inaccuracy = WDist.Zero; + [Desc("Controls the way inaccuracy is calculated. Possible values are 'Maximum' - scale from 0 to max with range, 'PerCellIncrement' - scale from 0 with range and 'Absolute' - use set value regardless of range.")] + public readonly InaccuracyType InaccuracyType = InaccuracyType.Maximum; + [Desc("Beam can be blocked.")] public readonly bool Blockable = false; @@ -75,7 +78,7 @@ [Desc("Impact animation.")] public readonly string HitAnim = null; - [SequenceReference("HitAnim")] + [SequenceReference(nameof(HitAnim), allowNullImage: true)] [Desc("Sequence of impact animation to use.")] public readonly string HitAnimSequence = "idle"; @@ -85,7 +88,7 @@ [Desc("Image containing launch effect sequence.")] public readonly string LaunchEffectImage = null; - [SequenceReference("LaunchEffectImage")] + [SequenceReference(nameof(LaunchEffectImage), allowNullImage: true)] [Desc("Launch effect sequence to play.")] public readonly string LaunchEffectSequence = null; @@ -129,9 +132,8 @@ if (info.Inaccuracy.Length > 0) { - var inaccuracy = OpenRA.Mods.Common.Util.ApplyPercentageModifiers(info.Inaccuracy.Length, args.InaccuracyModifiers); - var maxOffset = inaccuracy * (target - source).Length / args.Weapon.Range.Length; - target += WVec.FromPDF(args.SourceActor.World.SharedRandom, 2) * maxOffset / 1024; + var maxInaccuracyOffset = Util.GetProjectileInaccuracy(info.Inaccuracy.Length, info.InaccuracyType, args); + target += WVec.FromPDF(args.SourceActor.World.SharedRandom, 2) * maxInaccuracyOffset / 1024; } if (!string.IsNullOrEmpty(info.HitAnim)) @@ -156,16 +158,20 @@ target = args.Weapon.TargetActorCenter ? args.GuidedTarget.CenterPosition : args.GuidedTarget.Positions.PositionClosestTo(source); // Check for blocking actors - WPos blockedPos; - if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, source, target, - info.Width, out blockedPos)) + if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, source, target, info.Width, out var blockedPos)) { target = blockedPos; } if (ticks < info.DamageDuration && --interval <= 0) { - args.Weapon.Impact(Target.FromPos(target), new WarheadArgs(args)); + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(source, target), args.CurrentMuzzleFacing()), + ImpactPosition = target, + }; + + args.Weapon.Impact(Target.FromPos(target), warheadArgs); interval = info.DamageInterval; } diff -Nru openra-20200503/OpenRA.Mods.Common/Projectiles/Missile.cs openra-20210321/OpenRA.Mods.Common/Projectiles/Missile.cs --- openra-20200503/OpenRA.Mods.Common/Projectiles/Missile.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Projectiles/Missile.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,11 +26,11 @@ [Desc("Name of the image containing the projectile sequence.")] public readonly string Image = null; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Loop a randomly chosen sequence of Image from this list while this projectile is moving.")] public readonly string[] Sequences = { "idle" }; - [PaletteReference] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Palette used to render the projectile sequence.")] public readonly string Palette = "effect"; @@ -70,9 +70,12 @@ [Desc("Width of projectile (used for finding blocking actors).")] public readonly WDist Width = new WDist(1); - [Desc("Maximum inaccuracy offset at the maximum range")] + [Desc("The maximum/constant/incremental inaccuracy used in conjunction with the InaccuracyType property.")] public readonly WDist Inaccuracy = WDist.Zero; + [Desc("Controls the way inaccuracy is calculated. Possible values are 'Maximum' - scale from 0 to max with range, 'PerCellIncrement' - scale from 0 with range and 'Absolute' - use set value regardless of range.")] + public readonly InaccuracyType InaccuracyType = InaccuracyType.Absolute; + [Desc("Inaccuracy override when sucessfully locked onto target. Defaults to Inaccuracy if negative.")] public readonly WDist LockOnInaccuracy = new WDist(-1); @@ -80,10 +83,10 @@ public readonly int LockOnProbability = 100; [Desc("Horizontal rate of turn.")] - public readonly int HorizontalRateOfTurn = 5; + public readonly WAngle HorizontalRateOfTurn = new WAngle(20); [Desc("Vertical rate of turn.")] - public readonly int VerticalRateOfTurn = 6; + public readonly WAngle VerticalRateOfTurn = new WAngle(24); [Desc("Gravity applied while in free fall.")] public readonly int Gravity = 10; @@ -106,11 +109,11 @@ [Desc("Image that contains the trail animation.")] public readonly string TrailImage = null; - [SequenceReference("TrailImage")] + [SequenceReference(nameof(TrailImage), allowNullImage: true)] [Desc("Loop a randomly chosen sequence of TrailImage from this list while this projectile is moving.")] public readonly string[] TrailSequences = { "idle" }; - [PaletteReference("TrailUsePlayerPalette")] + [PaletteReference(nameof(TrailUsePlayerPalette))] [Desc("Palette used to render the trail sequence.")] public readonly string TrailPalette = "effect"; @@ -203,7 +206,7 @@ WDist distanceCovered; WDist rangeLimit; - int renderFacing; + WAngle renderFacing; [Sync] int hFacing; @@ -217,10 +220,11 @@ this.args = args; pos = args.Source; - hFacing = args.Facing; + hFacing = args.Facing.Facing; gravity = new WVec(0, 0, -info.Gravity); targetPosition = args.PassiveTarget; - rangeLimit = info.RangeLimit != WDist.Zero ? info.RangeLimit : args.Weapon.Range; + var limit = info.RangeLimit != WDist.Zero ? info.RangeLimit : args.Weapon.Range; + rangeLimit = new WDist(Util.ApplyPercentageModifiers(limit.Length, args.RangeModifiers)); minLaunchSpeed = info.MinimumLaunchSpeed.Length > -1 ? info.MinimumLaunchSpeed.Length : info.Speed.Length; maxLaunchSpeed = info.MaximumLaunchSpeed.Length > -1 ? info.MaximumLaunchSpeed.Length : info.Speed.Length; maxSpeed = info.Speed.Length; @@ -235,8 +239,8 @@ var inaccuracy = lockOn && info.LockOnInaccuracy.Length > -1 ? info.LockOnInaccuracy.Length : info.Inaccuracy.Length; if (inaccuracy > 0) { - inaccuracy = Util.ApplyPercentageModifiers(inaccuracy, args.InaccuracyModifiers); - offset = WVec.FromPDF(world.SharedRandom, 2) * inaccuracy / 1024; + var maxInaccuracyOffset = Util.GetProjectileInaccuracy(info.Inaccuracy.Length, info.InaccuracyType, args); + offset = WVec.FromPDF(world.SharedRandom, 2) * maxInaccuracyOffset / 1024; } DetermineLaunchSpeedAndAngle(world, out speed, out vFacing); @@ -284,7 +288,7 @@ // to hit the target without passing it by (and thus having to do horizontal loops) var minSpeed = ((System.Math.Min(predClfDist * 1024 / (1024 - WAngle.FromFacing(vFacing).Sin()), (relTarHorDist + predClfDist) * 1024 / (2 * (2048 - WAngle.FromFacing(vFacing).Sin()))) - * info.VerticalRateOfTurn * 157) / 6400).Clamp(minLaunchSpeed, maxLaunchSpeed); + * info.VerticalRateOfTurn.Facing * 157) / 6400).Clamp(minLaunchSpeed, maxLaunchSpeed); if ((sbyte)vFacing < 0) speed = minSpeed; @@ -296,7 +300,7 @@ var vFac = vFacing; speed = BisectionSearch(minSpeed, maxLaunchSpeed, spd => { - var lpRds = LoopRadius(spd, info.VerticalRateOfTurn); + var lpRds = LoopRadius(spd, info.VerticalRateOfTurn.Facing); return WillClimbWithinDistance(vFac, lpRds, predClfDist, diffClfMslHgt) || WillClimbAroundInclineTop(vFac, lpRds, predClfDist, diffClfMslHgt, spd); }); @@ -316,7 +320,7 @@ void DetermineLaunchSpeedAndAngle(World world, out int speed, out int vFacing) { speed = maxLaunchSpeed; - loopRadius = LoopRadius(speed, info.VerticalRateOfTurn); + loopRadius = LoopRadius(speed, info.VerticalRateOfTurn.Facing); // Compute current distance from target position var tarDistVec = targetPosition + offset - pos; @@ -425,10 +429,10 @@ if ((tp.Actor.CenterPosition - pos).HorizontalLengthSquared > tp.Trait.Range.LengthSquared) return false; - if (!tp.Trait.DeflectionStances.HasStance(tp.Actor.Owner.Stances[args.SourceActor.Owner])) + if (!tp.Trait.DeflectionStances.HasStance(tp.Actor.Owner.RelationshipWith(args.SourceActor.Owner))) return false; - return tp.Actor.World.SharedRandom.Next(100 / tp.Trait.Chance) == 0; + return tp.Actor.World.SharedRandom.Next(100) < tp.Trait.Chance; } void ChangeSpeed(int sign = 1) @@ -436,7 +440,7 @@ speed = (speed + sign * info.Acceleration.Length).Clamp(0, maxSpeed); // Compute the vertical loop radius - loopRadius = LoopRadius(speed, info.VerticalRateOfTurn); + loopRadius = LoopRadius(speed, info.VerticalRateOfTurn.Facing); } WVec FreefallTick() @@ -505,7 +509,7 @@ // If missile is below incline top height and facing downwards, bring back // its vertical facing above zero as soon as possible if ((sbyte)vFacing < 0) - desiredVFacing = info.VerticalRateOfTurn; + desiredVFacing = info.VerticalRateOfTurn.Facing; // Missile will climb around incline top if bringing vertical facing // down to zero on an arc of radius loopRadius @@ -521,7 +525,7 @@ // for which the missile will be able to climb terrAltDiff w-units // within hHeightChange w-units all the while ending the ascent // with vertical facing 0 - for (var vFac = System.Math.Min(vFacing + info.VerticalRateOfTurn - 1, 63); vFac >= vFacing; vFac--) + for (var vFac = System.Math.Min(vFacing + info.VerticalRateOfTurn.Facing - 1, 63); vFac >= vFacing; vFac--) if (!WillClimbWithinDistance(vFac, loopRadius, predClfDist, diffClfMslHgt) && !(predClfDist <= loopRadius * (1024 - WAngle.FromFacing(vFac).Sin()) / 1024 && WillClimbAroundInclineTop(vFac, loopRadius, predClfDist, diffClfMslHgt, speed))) @@ -596,7 +600,7 @@ // and thus needs smaller vertical facings so as not // to hit the ground prematurely if (targetPassedBy) - desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn, info.VerticalRateOfTurn); + desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn.Facing, info.VerticalRateOfTurn.Facing); else if (lastHt == 0) { // Before the target is passed by, missile speed should be changed // Target's height above loop's center @@ -658,7 +662,7 @@ if (info.TerrainHeightAware && edgeVector.Length > loopRadius && lastHt > targetPosition.Z) { int vFac; - for (vFac = vFacing + 1; vFac <= vFacing + info.VerticalRateOfTurn - 1; vFac++) + for (vFac = vFacing + 1; vFac <= vFacing + info.VerticalRateOfTurn.Facing - 1; vFac++) { // Vector from missile's current position pointing to the loop's center radius = new WVec(loopRadius, 0, 0) @@ -677,7 +681,7 @@ // Aim for the target var vDist = new WVec(-relTarHgt, -relTarHorDist, 0); desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing; - if (desiredVFacing < 0 && info.VerticalRateOfTurn < (sbyte)vFacing) + if (desiredVFacing < 0 && info.VerticalRateOfTurn.Facing < (sbyte)vFacing) desiredVFacing = 0; } } @@ -687,7 +691,7 @@ // Aim for the target var vDist = new WVec(-relTarHgt, relTarHorDist, 0); desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing; - if (desiredVFacing < 0 && info.VerticalRateOfTurn < (sbyte)vFacing) + if (desiredVFacing < 0 && info.VerticalRateOfTurn.Facing < (sbyte)vFacing) desiredVFacing = 0; } } @@ -702,7 +706,7 @@ if (-diffClfMslHgt > info.CruiseAltitude.Length) desiredVFacing = -desiredVFacing; - desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn, info.VerticalRateOfTurn); + desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn.Facing, info.VerticalRateOfTurn.Facing); ChangeSpeed(); } @@ -718,7 +722,7 @@ if (-diffClfMslHgt > info.CruiseAltitude.Length) desiredVFacing = -desiredVFacing; - desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn, info.VerticalRateOfTurn); + desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn.Facing, info.VerticalRateOfTurn.Facing); ChangeSpeed(); } @@ -776,8 +780,8 @@ desiredHFacing = hFacing; // Compute new direction the projectile will be facing - hFacing = Util.TickFacing(hFacing, desiredHFacing, info.HorizontalRateOfTurn); - vFacing = Util.TickFacing(vFacing, desiredVFacing, info.VerticalRateOfTurn); + hFacing = Util.TickFacing(hFacing, desiredHFacing, info.HorizontalRateOfTurn.Facing); + vFacing = Util.TickFacing(vFacing, desiredVFacing, info.VerticalRateOfTurn.Facing); // Compute the projectile's guided displacement return new WVec(0, -1024 * speed, 0) @@ -789,8 +793,7 @@ public void Tick(World world) { ticks++; - if (anim != null) - anim.Tick(); + anim?.Tick(); // Switch from freefall mode to homing mode if (ticks == info.HomingActivationDelay + 1) @@ -799,7 +802,7 @@ speed = velocity.Length; // Compute the vertical loop radius - loopRadius = LoopRadius(speed, info.VerticalRateOfTurn); + loopRadius = LoopRadius(speed, info.VerticalRateOfTurn.Facing); } // Switch from homing mode to freefall mode @@ -835,7 +838,7 @@ else move = HomingTick(world, tarDistVec, relTarHorDist); - renderFacing = new WVec(move.X, move.Y - move.Z, 0).Yaw.Facing; + renderFacing = new WVec(move.X, move.Y - move.Z, 0).Yaw; // Move the missile var lastPos = pos; @@ -846,9 +849,7 @@ // Check for walls or other blocking obstacles var shouldExplode = false; - WPos blockedPos; - if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, lastPos, pos, info.Width, - out blockedPos)) + if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, lastPos, pos, info.Width, out var blockedPos)) { pos = blockedPos; shouldExplode = true; @@ -857,8 +858,8 @@ // Create the sprite trail effect if (!string.IsNullOrEmpty(info.TrailImage) && --ticksToNextSmoke < 0 && (state != States.Freefall || info.TrailWhenDeactivated)) { - world.AddFrameEndTask(w => w.Add(new SpriteEffect(pos - 3 * move / 2, w, info.TrailImage, info.TrailSequences.Random(world.SharedRandom), - trailPalette, facing: renderFacing))); + world.AddFrameEndTask(w => w.Add(new SpriteEffect(pos - 3 * move / 2, renderFacing, w, + info.TrailImage, info.TrailSequences.Random(world.SharedRandom), trailPalette))); ticksToNextSmoke = info.TrailInterval; } @@ -891,7 +892,13 @@ if (ticks <= info.Arm) return; - args.Weapon.Impact(Target.FromPos(pos), new WarheadArgs(args)); + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, WAngle.FromFacing(vFacing), WAngle.FromFacing(hFacing)), + ImpactPosition = pos, + }; + + args.Weapon.Impact(Target.FromPos(pos), warheadArgs); } public IEnumerable Render(WorldRenderer wr) diff -Nru openra-20200503/OpenRA.Mods.Common/Projectiles/NukeLaunch.cs openra-20210321/OpenRA.Mods.Common/Projectiles/NukeLaunch.cs --- openra-20200503/OpenRA.Mods.Common/Projectiles/NukeLaunch.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Projectiles/NukeLaunch.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,6 @@ using OpenRA.Effects; using OpenRA.GameRules; using OpenRA.Graphics; -using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.Common.Effects @@ -27,7 +26,6 @@ readonly string weaponPalette; readonly string upSequence; readonly string downSequence; - readonly string flashType; readonly WPos ascendSource; readonly WPos ascendTarget; @@ -51,7 +49,7 @@ public NukeLaunch(Player firedBy, string name, WeaponInfo weapon, string weaponPalette, string upSequence, string downSequence, WPos launchPos, WPos targetPos, WDist detonationAltitude, bool removeOnDetonation, WDist velocity, int launchDelay, int impactDelay, - bool skipAscent, string flashType, + bool skipAscent, string trailImage, string[] trailSequences, string trailPalette, bool trailUsePlayerPalette, int trailDelay, int trailInterval) { this.firedBy = firedBy; @@ -62,12 +60,11 @@ this.launchDelay = launchDelay; this.impactDelay = impactDelay; turn = skipAscent ? 0 : impactDelay / 2; - this.flashType = flashType; this.trailImage = trailImage; this.trailSequences = trailSequences; this.trailPalette = trailPalette; if (trailUsePlayerPalette) - trailPalette += firedBy.InternalName; + this.trailPalette += firedBy.InternalName; this.trailInterval = trailInterval; this.trailDelay = trailDelay; @@ -151,10 +148,6 @@ weapon.Impact(target, warheadArgs); - foreach (var flash in world.WorldActor.TraitsImplementing()) - if (flash.Info.Type == flashType) - flash.Enable(-1); - detonated = true; } diff -Nru openra-20200503/OpenRA.Mods.Common/Projectiles/Railgun.cs openra-20210321/OpenRA.Mods.Common/Projectiles/Railgun.cs --- openra-20200503/OpenRA.Mods.Common/Projectiles/Railgun.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Projectiles/Railgun.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,9 +25,12 @@ [Desc("Damage all units hit by the beam instead of just the target?")] public readonly bool DamageActorsInLine = false; - [Desc("Maximum offset at the maximum range.")] + [Desc("The maximum/constant/incremental inaccuracy used in conjunction with the InaccuracyType property.")] public readonly WDist Inaccuracy = WDist.Zero; + [Desc("Controls the way inaccuracy is calculated. Possible values are 'Maximum' - scale from 0 to max with range, 'PerCellIncrement' - scale from 0 with range and 'Absolute' - use set value regardless of range.")] + public readonly InaccuracyType InaccuracyType = InaccuracyType.Maximum; + [Desc("Can this projectile be blocked when hitting actors with an IBlocksProjectiles trait.")] public readonly bool Blockable = false; @@ -84,7 +87,7 @@ public readonly string HitAnim = null; [Desc("Sequence of impact animation to use.")] - [SequenceReference("HitAnim")] + [SequenceReference(nameof(HitAnim), allowNullImage: true)] public readonly string HitAnimSequence = "idle"; [PaletteReference] @@ -98,7 +101,7 @@ } } - public class Railgun : IProjectile + public class Railgun : IProjectile, ISync { readonly ProjectileArgs args; readonly RailgunInfo info; @@ -108,6 +111,8 @@ int ticks; bool animationComplete; + + [Sync] WPos target; // Computing these in Railgun instead of RailgunRenderable saves Info.Duration ticks of computation. @@ -128,6 +133,12 @@ BeamColor = beamColor; HelixColor = helixColor; + if (info.Inaccuracy.Length > 0) + { + var maxInaccuracyOffset = Util.GetProjectileInaccuracy(info.Inaccuracy.Length, info.InaccuracyType, args); + target += WVec.FromPDF(args.SourceActor.World.SharedRandom, 2) * maxInaccuracyOffset / 1024; + } + if (!string.IsNullOrEmpty(info.HitAnim)) hitanim = new Animation(args.SourceActor.World, info.HitAnim); @@ -137,9 +148,8 @@ void CalculateVectors() { // Check for blocking actors - WPos blockedPos; if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(args.SourceActor.World, target, args.Source, - info.BeamWidth, out blockedPos)) + info.BeamWidth, out var blockedPos)) target = blockedPos; // Note: WAngle.Sin(x) = 1024 * Math.Sin(2pi/1024 * x) @@ -188,17 +198,36 @@ animationComplete = true; if (!info.DamageActorsInLine) - args.Weapon.Impact(Target.FromPos(target), new WarheadArgs(args)); + { + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(args.Source, target), args.Facing), + ImpactPosition = target, + }; + + args.Weapon.Impact(Target.FromPos(target), warheadArgs); + } else { var actors = world.FindActorsOnLine(args.Source, target, info.BeamWidth); foreach (var a in actors) - args.Weapon.Impact(Target.FromActor(a), new WarheadArgs(args)); + { + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(args.Source, target), args.Facing), + + // Calculating an impact position is bogus for line damage. + // FindActorsOnLine guarantees that the beam touches the target's HitShape, + // so we just assume a center hit to avoid bogus warhead recalculations. + ImpactPosition = a.CenterPosition, + }; + + args.Weapon.Impact(Target.FromActor(a), warheadArgs); + } } } - if (hitanim != null) - hitanim.Tick(); + hitanim?.Tick(); if (ticks++ > info.Duration && animationComplete) world.AddFrameEndTask(w => w.Remove(this)); diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/CallLuaFunc.cs openra-20210321/OpenRA.Mods.Common/Scripting/CallLuaFunc.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/CallLuaFunc.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/CallLuaFunc.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,8 +31,7 @@ { try { - if (function != null) - function.Call().Dispose(); + function?.Call().Dispose(); } catch (Exception ex) { diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/ActorGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/ActorGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/ActorGlobal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/ActorGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,10 @@ #endregion using System; +using System.Collections.Generic; using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; using Eluant; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; @@ -24,6 +27,85 @@ public ActorGlobal(ScriptContext context) : base(context) { } + ActorInit CreateInit(string initName, LuaValue value) + { + // Find the requested type + var initInstance = initName.Split(ActorInfo.TraitInstanceSeparator); + var initType = Game.ModData.ObjectCreator.FindType(initInstance[0] + "Init"); + if (initType == null) + throw new LuaException("Unknown initializer type '{0}'".F(initInstance[0])); + + // Construct the ActorInit. + var init = (ActorInit)FormatterServices.GetUninitializedObject(initType); + if (initInstance.Length > 1) + initType.GetField("InstanceName").SetValue(init, initInstance[1]); + + var compositeInit = init as CompositeActorInit; + var tableValue = value as LuaTable; + if (tableValue != null && compositeInit != null) + { + var args = compositeInit.InitializeArgs(); + var initValues = new Dictionary(); + foreach (var kv in tableValue) + { + using (kv.Key) + using (kv.Value) + { + var key = kv.Key.ToString(); + if (!args.TryGetValue(key, out var type)) + throw new LuaException("Unknown initializer type '{0}.{1}'".F(initInstance[0], key)); + + var isActorReference = type == typeof(ActorInitActorReference); + if (isActorReference) + type = kv.Value is LuaString ? typeof(string) : typeof(Actor); + + if (!kv.Value.TryGetClrValue(type, out var clrValue)) + throw new LuaException("Invalid data type for '{0}.{1}' (expected {2}, got {3})".F(initInstance[0], key, type.Name, kv.Value.WrappedClrType())); + + if (isActorReference) + clrValue = type == typeof(string) ? new ActorInitActorReference((string)clrValue) : new ActorInitActorReference((Actor)clrValue); + + initValues[key] = clrValue; + } + } + + compositeInit.Initialize(initValues); + return init; + } + + // HACK: Backward compatibility for legacy int facings + var facingInit = init as FacingInit; + if (facingInit != null) + { + if (value.TryGetClrValue(out int facing)) + { + facingInit.Initialize(WAngle.FromFacing(facing)); + Game.Debug("Initializing Facing with integers is deprecated. Use Angle instead."); + return facingInit; + } + } + + var initializers = initType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .Where(m => m.Name == "Initialize" && m.GetParameters().Length == 1); + + foreach (var initializer in initializers) + { + var parameterType = initializer.GetParameters().First().ParameterType; + var valueType = parameterType.IsEnum ? Enum.GetUnderlyingType(parameterType) : parameterType; + + // Try and coerce the table value to the required type + if (!value.TryGetClrValue(valueType, out var clrValue)) + continue; + + initializer.Invoke(init, new[] { clrValue }); + + return init; + } + + var types = initializers.Select(y => y.GetParameters()[0].ParameterType.Name).JoinWith(", "); + throw new LuaException("Invalid data type for '{0}' (expected one of {1})".F(initInstance[0], types)); + } + [Desc("Create a new actor. initTable specifies a list of key-value pairs that defines the initial parameters for the actor's traits.")] public Actor Create(string type, bool addToWorld, LuaTable initTable) { @@ -34,28 +116,7 @@ { using (kv.Key) using (kv.Value) - { - // Find the requested type - var typeName = kv.Key.ToString(); - var initType = Game.ModData.ObjectCreator.FindType(typeName + "Init"); - if (initType == null) - throw new LuaException("Unknown initializer type '{0}'".F(typeName)); - - // Cast it up to an IActorInit - var genericType = initType.GetInterfaces() - .First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IActorInit<>)); - var innerType = genericType.GetGenericArguments().First(); - var valueType = innerType.IsEnum ? Enum.GetUnderlyingType(innerType) : innerType; - - // Try and coerce the table value to the required type - object value; - if (!kv.Value.TryGetClrValue(valueType, out value)) - throw new LuaException("Invalid data type for '{0}' (expected '{1}')".F(typeName, valueType.Name)); - - // Construct the ActorInit. Phew! - var test = initType.GetConstructor(new[] { innerType }).Invoke(new[] { value }); - initDict.Add(test); - } + initDict.Add(CreateInit(kv.Key.ToString(), kv.Value)); } var owner = initDict.GetOrDefault(); @@ -74,8 +135,7 @@ "An optional second value can be used to exactly specify the producing queue type.")] public int BuildTime(string type, string queue = null) { - ActorInfo ai; - if (!Context.World.Map.Rules.Actors.TryGetValue(type, out ai)) + if (!Context.World.Map.Rules.Actors.TryGetValue(type, out var ai)) throw new LuaException("Unknown actor type '{0}'".F(type)); var bi = ai.TraitInfoOrDefault(); @@ -122,8 +182,7 @@ [Desc("Returns the cruise altitude of the requested unit type (zero if it is ground-based).")] public int CruiseAltitude(string type) { - ActorInfo ai; - if (!Context.World.Map.Rules.Actors.TryGetValue(type, out ai)) + if (!Context.World.Map.Rules.Actors.TryGetValue(type, out var ai)) throw new LuaException("Unknown actor type '{0}'".F(type)); var pi = ai.TraitInfoOrDefault(); @@ -132,8 +191,7 @@ public int Cost(string type) { - ActorInfo ai; - if (!Context.World.Map.Rules.Actors.TryGetValue(type, out ai)) + if (!Context.World.Map.Rules.Actors.TryGetValue(type, out var ai)) throw new LuaException("Unknown actor type '{0}'".F(type)); var vi = ai.TraitInfoOrDefault(); diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/AngleGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/AngleGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/AngleGlobal.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/AngleGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,34 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Scripting; + +namespace OpenRA.Mods.Common.Scripting.Global +{ + [ScriptGlobal("Angle")] + public class AngleGlobal : ScriptGlobal + { + public AngleGlobal(ScriptContext context) + : base(context) { } + + public WAngle North { get { return WAngle.Zero; } } + public WAngle NorthWest { get { return new WAngle(128); } } + public WAngle West { get { return new WAngle(256); } } + public WAngle SouthWest { get { return new WAngle(384); } } + public WAngle South { get { return new WAngle(512); } } + public WAngle SouthEast { get { return new WAngle(640); } } + public WAngle East { get { return new WAngle(768); } } + public WAngle NorthEast { get { return new WAngle(896); } } + + [Desc("Create an arbitrary angle.")] + public WAngle New(int a) { return new WAngle(a); } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/ColorGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/ColorGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/ColorGlobal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/ColorGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using Eluant; -using OpenRA.Graphics; using OpenRA.Primitives; using OpenRA.Scripting; @@ -46,8 +45,7 @@ [Desc("Create a new color with the specified red/green/blue/[alpha] hex string (rrggbb[aa]).")] public Color FromHex(string value) { - Color color; - if (Color.TryParse(value, out color)) + if (Color.TryParse(value, out var color)) return color; throw new LuaException("Invalid rrggbb[aa] hex string."); diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/FacingGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/FacingGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/FacingGlobal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/FacingGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,13 +19,18 @@ public FacingGlobal(ScriptContext context) : base(context) { } - public int North { get { return 0; } } - public int NorthWest { get { return 32; } } - public int West { get { return 64; } } - public int SouthWest { get { return 96; } } - public int South { get { return 128; } } - public int SouthEast { get { return 160; } } - public int East { get { return 192; } } - public int NorthEast { get { return 224; } } + void Deprecated() + { + Game.Debug("The Facing table is deprecated. Use Angle instead."); + } + + public int North { get { Deprecated(); return 0; } } + public int NorthWest { get { Deprecated(); return 32; } } + public int West { get { Deprecated(); return 64; } } + public int SouthWest { get { Deprecated(); return 96; } } + public int South { get { Deprecated(); return 128; } } + public int SouthEast { get { Deprecated(); return 160; } } + public int East { get { Deprecated(); return 192; } } + public int NorthEast { get { Deprecated(); return 224; } } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/MapGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/MapGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/MapGlobal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/MapGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,12 +21,14 @@ { readonly SpawnMapActors sma; readonly World world; + readonly GameSettings gameSettings; public MapGlobal(ScriptContext context) : base(context) { sma = context.World.WorldActor.Trait(); world = context.World; + gameSettings = Game.Settings.Game; // Register map actors as globals (yuck!) foreach (var kv in sma.Actors) @@ -109,6 +111,9 @@ [Desc("Returns true if there is only one human player.")] public bool IsSinglePlayer { get { return Context.World.LobbyInfo.NonBotPlayers.Count() == 1; } } + [Desc("Returns true if this is a shellmap and the player has paused animations.")] + public bool IsPausedShellmap { get { return Context.World.Type == WorldType.Shellmap && gameSettings.PauseShellmap; } } + [Desc("Returns the value of a `ScriptLobbyDropdown` selected in the game lobby.")] public LuaValue LobbyOption(string id) { @@ -128,9 +133,7 @@ "the map file (or nil, if the actor is dead or not found).")] public Actor NamedActor(string actorName) { - Actor ret; - - if (!sma.Actors.TryGetValue(actorName, out ret)) + if (!sma.Actors.TryGetValue(actorName, out var ret)) return null; if (ret.Disposed) diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/MediaGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/MediaGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/MediaGlobal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/MediaGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,6 @@ using Eluant; using OpenRA.Effects; using OpenRA.GameRules; -using OpenRA.Graphics; using OpenRA.Mods.Common.Effects; using OpenRA.Mods.Common.FileFormats; using OpenRA.Mods.Common.Traits; @@ -206,8 +205,8 @@ if (string.IsNullOrEmpty(prefix)) Game.AddSystemLine(text); - - Game.AddSystemLine(prefix, text); + else + Game.AddSystemLine(prefix, text); } [Desc("Displays a debug message to the player, if \"Show Map Debug Messages\" is checked in the settings.")] diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/RadarGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/RadarGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/RadarGlobal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/RadarGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,14 +29,7 @@ [Desc("Creates a new radar ping that stays for the specified time at the specified WPos.")] public void Ping(Player player, WPos position, Color color, int duration = 30 * 25) { - if (radarPings != null) - { - radarPings.Add( - () => player.World.RenderPlayer == player, - position, - color, - duration); - } + radarPings?.Add(() => player.World.RenderPlayer == player, position, color, duration); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/ReinforcementsGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,12 +9,10 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; using Eluant; using OpenRA.Activities; -using OpenRA.Effects; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Effects; using OpenRA.Mods.Common.Traits; @@ -37,8 +35,7 @@ Actor CreateActor(Player owner, string actorType, bool addToWorld, CPos? entryLocation = null, CPos? nextLocation = null) { - ActorInfo ai; - if (!Context.World.Map.Rules.Actors.TryGetValue(actorType, out ai)) + if (!Context.World.Map.Rules.Actors.TryGetValue(actorType, out var ai)) throw new LuaException("Unknown actor type '{0}'".F(actorType)); var initDict = new TypeDictionary(); @@ -55,11 +52,12 @@ } if (entryLocation.HasValue && nextLocation.HasValue) - initDict.Add(new FacingInit(Context.World.Map.FacingBetween(CPos.Zero, CPos.Zero + (nextLocation.Value - entryLocation.Value), 0))); - - var actor = Context.World.CreateActor(addToWorld, actorType, initDict); + { + var facing = Context.World.Map.FacingBetween(CPos.Zero, CPos.Zero + (nextLocation.Value - entryLocation.Value), WAngle.Zero); + initDict.Add(new FacingInit(facing)); + } - return actor; + return Context.World.CreateActor(addToWorld, actorType, initDict); } void Move(Actor actor, CPos dest) diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/TriggerGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/TriggerGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/TriggerGlobal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/TriggerGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -74,7 +74,7 @@ } [Desc("Call a function when the actor is damaged. The callback " + - "function will be called as func(Actor self, Actor attacker).")] + "function will be called as func(Actor self, Actor attacker, int damage).")] public void OnDamaged(Actor a, LuaFunction func) { GetScriptTriggers(a).RegisterCallback(Trigger.OnDamaged, func, Context); diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/UserInterfaceGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/UserInterfaceGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/UserInterfaceGlobal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/UserInterfaceGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using OpenRA.Graphics; using OpenRA.Mods.Common.Widgets; using OpenRA.Primitives; using OpenRA.Scripting; diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Global/UtilsGlobal.cs openra-20210321/OpenRA.Mods.Common/Scripting/Global/UtilsGlobal.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Global/UtilsGlobal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Global/UtilsGlobal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,7 +13,6 @@ using Eluant; using OpenRA.Mods.Common.Widgets; using OpenRA.Scripting; -using OpenRA.Widgets; namespace OpenRA.Mods.Common.Scripting { diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/LuaScript.cs openra-20210321/OpenRA.Mods.Common/Scripting/LuaScript.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/LuaScript.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/LuaScript.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,11 +19,11 @@ namespace OpenRA.Mods.Common.Scripting { [Desc("Part of the new Lua API.")] - public class LuaScriptInfo : ITraitInfo, Requires + public class LuaScriptInfo : TraitInfo, Requires { public readonly HashSet Scripts = new HashSet(); - public object Create(ActorInitializer init) { return new LuaScript(this); } + public override object Create(ActorInitializer init) { return new LuaScript(this); } } public class LuaScript : ITick, IWorldLoaded, INotifyActorDisposing @@ -54,8 +54,7 @@ if (disposed) return; - if (context != null) - context.Dispose(); + context?.Dispose(); disposed = true; } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/AirstrikeProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/AirstrikeProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/AirstrikeProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/AirstrikeProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -27,19 +27,27 @@ ap = self.TraitsImplementing().First(); } - [Desc("Activate the actor's Airstrike Power.")] + [Desc("Activate the actor's Airstrike Power. Returns the aircraft that will attack.")] + public Actor[] TargetAirstrike(WPos target, WAngle? facing = null) + { + return ap.SendAirstrike(Self, target, facing); + } + + [Desc("Activate the actor's Airstrike Power. DEPRECATED! Will be removed.")] public void SendAirstrike(WPos target, bool randomize = true, int facing = 0) { - ap.SendAirstrike(Self, target, randomize, facing); + Game.Debug("SendAirstrike is deprecated. Use TargetAirstrike instead."); + ap.SendAirstrike(Self, target, randomize ? (WAngle?)null : WAngle.FromFacing(facing)); } - [Desc("Activate the actor's Airstrike Power.")] + [Desc("Activate the actor's Airstrike Power. DEPRECATED! Will be removed.")] public void SendAirstrikeFrom(CPos from, CPos to) { + Game.Debug("SendAirstrikeFrom is deprecated. Use TargetAirstrike instead."); var i = Self.World.Map.CenterOfCell(from); var j = Self.World.Map.CenterOfCell(to); - ap.SendAirstrike(Self, j, false, (i - j).Yaw.Facing); + ap.SendAirstrike(Self, j, (i - j).Yaw); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/CaptureProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/CaptureProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/CaptureProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/CaptureProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -35,7 +35,8 @@ if (targetManager == null || !targetManager.CanBeTargetedBy(target, Self, captureManager)) throw new LuaException("Actor '{0}' cannot capture actor '{1}'!".F(Self, target)); - Self.QueueActivity(new CaptureActor(Self, Target.FromActor(target))); + // NB: Scripted actions get no visible targetlines. + Self.QueueActivity(new CaptureActor(Self, Target.FromActor(target), null)); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/CloakProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/CloakProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/CloakProperties.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/CloakProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,39 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.Common.Traits; +using OpenRA.Scripting; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Scripting +{ + [ScriptPropertyGroup("Cloak")] + public class CloakProperties : ScriptActorProperties, Requires + { + readonly Cloak[] cloaks; + + public CloakProperties(ScriptContext context, Actor self) + : base(context, self) + { + cloaks = self.TraitsImplementing().ToArray(); + } + + [Desc("Returns true if the actor is cloaked.")] + public bool IsCloaked + { + get + { + return cloaks.Any(c => c.Cloaked); + } + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/CombatProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/CombatProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/CombatProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/CombatProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Linq; using Eluant; using OpenRA.Activities; diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/ConditionProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/ConditionProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/ConditionProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/ConditionProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,9 +9,8 @@ */ #endregion -using System.Collections.Generic; -using System.IO; using System.Linq; +using Eluant; using OpenRA.Mods.Common.Traits; using OpenRA.Scripting; using OpenRA.Traits; @@ -31,14 +30,14 @@ [Desc("Grant an external condition on this actor and return the revocation token.", "Conditions must be defined on an ExternalConditions trait on the actor.", - "If duration > 0 the condition will be automatically revoked after the defined number of ticks")] + "If duration > 0 the condition will be automatically revoked after the defined number of ticks.")] public int GrantCondition(string condition, int duration = 0) { var external = externalConditions .FirstOrDefault(t => t.Info.Condition == condition && t.CanGrantCondition(Self, this)); if (external == null) - throw new InvalidDataException("Condition `{0}` has not been listed on an enabled ExternalCondition trait".F(condition)); + throw new LuaException("Condition `{0}` has not been listed on an enabled ExternalCondition trait".F(condition)); return external.GrantCondition(Self, this, duration); } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/DeliveryProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/DeliveryProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/DeliveryProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/DeliveryProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using Eluant; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; using OpenRA.Scripting; using OpenRA.Traits; @@ -34,7 +33,9 @@ public void DeliverCash(Actor target) { var t = Target.FromActor(target); - Self.QueueActivity(new DonateCash(Self, t, info.Payload, info.PlayerExperience)); + + // NB: Scripted actions get no visible targetlines. + Self.QueueActivity(new DonateCash(Self, t, info.Payload, info.PlayerExperience, null)); } } @@ -63,9 +64,10 @@ return; var level = gainsExperience.Level; - var t = Target.FromActor(target); - Self.QueueActivity(new DonateExperience(Self, t, level, deliversExperience.PlayerExperience)); + + // NB: Scripted actions get no visible targetlines. + Self.QueueActivity(new DonateExperience(Self, t, level, deliversExperience.PlayerExperience, null)); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,8 +31,9 @@ [Desc("Demolish the target actor.")] public void Demolish(Actor target) { + // NB: Scripted actions get no visible targetlines. Self.QueueActivity(new Demolish(Self, Target.FromActor(target), info.EnterBehaviour, info.DetonationDelay, - info.Flashes, info.FlashesDelay, info.FlashInterval)); + info.Flashes, info.FlashesDelay, info.FlashInterval, info.DamageTypes, null)); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/GainsExperienceProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/GainsExperienceProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/GainsExperienceProperties.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/GainsExperienceProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,53 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Mods.Common.Traits; +using OpenRA.Scripting; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Scripting +{ + [ScriptPropertyGroup("Experience")] + public class GainsExperienceProperties : ScriptActorProperties, Requires + { + readonly GainsExperience exp; + + public GainsExperienceProperties(ScriptContext context, Actor self) + : base(context, self) + { + exp = self.Trait(); + } + + [Desc("The actor's amount of experience.")] + public int Experience { get { return exp.Experience; } } + + [Desc("The actor's level.")] + public int Level { get { return exp.Level; } } + + [Desc("The actor's maximum possible level.")] + public int MaxLevel { get { return exp.MaxLevel; } } + + [Desc("Returns true if the actor can gain a level.")] + public bool CanGainLevel { get { return exp.CanGainLevel; } } + + [Desc("Gives the actor experience. If 'silent' is true, no animation or sound will be played if the actor levels up.")] + public void GiveExperience(int amount, bool silent = false) + { + exp.GiveExperience(amount, silent); + } + + [Desc("Gives the actor level(s). If 'silent' is true, no animation or sound will be played.")] + public void GiveLevels(int numLevels, bool silent = false) + { + exp.GiveLevels(numLevels, silent); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/GeneralProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/GeneralProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/GeneralProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/GeneralProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -122,7 +122,7 @@ public WPos CenterPosition { get { return Self.CenterPosition; } } [Desc("The direction that the actor is facing.")] - public int Facing + public WAngle Facing { get { @@ -172,10 +172,7 @@ { get { - if (autotarget == null) - return null; - - return autotarget.Stance.ToString(); + return autotarget?.Stance.ToString(); } set @@ -183,8 +180,7 @@ if (autotarget == null) return; - UnitStance stance; - if (!Enum.TryParse(value, true, out stance)) + if (!Enum.TryParse(value, true, out var stance)) throw new LuaException("Unknown stance type '{0}'".F(value)); autotarget.PredictedStance = stance; @@ -198,10 +194,8 @@ get { var tooltip = tooltips.FirstEnabledTraitOrDefault(); - if (tooltip == null) - return null; - return tooltip.Info.Name; + return tooltip?.Info.Name; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/HealthProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/HealthProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/HealthProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/HealthProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,6 +9,8 @@ */ #endregion +using Eluant; +using OpenRA.Primitives; using OpenRA.Scripting; using OpenRA.Traits; @@ -34,10 +36,18 @@ [Desc("Maximum health of the actor.")] public int MaxHealth { get { return health.MaxHP; } } - [Desc("Kill the actor.")] - public void Kill() + [Desc("Kill the actor. damageTypes may be omitted, specified as a string, or as table of strings.")] + public void Kill(object damageTypes = null) { - health.InflictDamage(Self, Self, new Damage(health.MaxHP), true); + Damage damage; + if (damageTypes is string d) + damage = new Damage(health.MaxHP, new BitSet(new[] { d })); + else if (damageTypes is LuaTable t && t.TryGetClrValue(out string[] ds)) + damage = new Damage(health.MaxHP, new BitSet(ds)); + else + damage = new Damage(health.MaxHP); + + health.InflictDamage(Self, Self, damage, true); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/MobileProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/MobileProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/MobileProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/MobileProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -63,7 +63,7 @@ [Desc("Move to and enter the transport.")] public void EnterTransport(Actor transport) { - Self.QueueActivity(new RideTransport(Self, Target.FromActor(transport))); + Self.QueueActivity(new RideTransport(Self, Target.FromActor(transport), null)); } [Desc("Whether the actor can move (false if immobilized).")] diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/ParatroopersProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/ParatroopersProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/ParatroopersProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/ParatroopersProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,29 +28,18 @@ } [Desc("Activate the actor's Paratroopers Power. Returns the aircraft that will drop the reinforcements.")] - public Actor[] ActivateParatroopers(WPos target, int facing = -1) + public Actor[] TargetParatroopers(WPos target, WAngle? facing = null) { var actors = pp.SendParatroopers(Self, target, facing); - return actors.First; - } - - [Desc("Activate the actor's Paratroopers Power. Returns the dropped units. DEPRECATED! Will be removed.")] - public Actor[] SendParatroopers(WPos target, bool randomize = true, int facing = 0) - { - Game.Debug("SendParatroopers is deprecated. Use ActivateParatroopers instead."); - var actors = pp.SendParatroopers(Self, target, randomize ? -1 : facing); - return actors.Second; + return actors.Aircraft; } - [Desc("Activate the actor's Paratroopers Power. Returns the dropped units. DEPRECATED! Will be removed.")] - public Actor[] SendParatroopersFrom(CPos from, CPos to) + [Desc("Activate the actor's Paratroopers Power. Returns the aircraft that will drop the reinforcements. DEPRECATED! Will be removed.")] + public Actor[] ActivateParatroopers(WPos target, int facing = -1) { - Game.Debug("SendParatroopersFrom is deprecated. Use ActivateParatroopers instead."); - var i = Self.World.Map.CenterOfCell(from); - var j = Self.World.Map.CenterOfCell(to); - - var actors = pp.SendParatroopers(Self, j, (i - j).Yaw.Facing); - return actors.Second; + Game.Debug("SendParatroopersFrom is deprecated. Use TargetParatroopers instead."); + var actors = pp.SendParatroopers(Self, target, facing == -1 ? (WAngle?)null : WAngle.FromFacing(facing)); + return actors.Aircraft; } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/PlayerConditionProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/PlayerConditionProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/PlayerConditionProperties.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/PlayerConditionProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,59 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using Eluant; +using OpenRA.Mods.Common.Traits; +using OpenRA.Scripting; + +namespace OpenRA.Mods.Common.Scripting +{ + [ScriptPropertyGroup("Player")] + public class PlayerConditionProperties : ScriptPlayerProperties + { + readonly ExternalCondition[] externalConditions; + + public PlayerConditionProperties(ScriptContext context, Player player) + : base(context, player) + { + externalConditions = player.PlayerActor.TraitsImplementing().ToArray(); + } + + [Desc("Grant an external condition on the player actor and return the revocation token.", + "Conditions must be defined on an ExternalConditions trait on the player actor.", + "If duration > 0 the condition will be automatically revoked after the defined number of ticks.")] + public int GrantCondition(string condition, int duration = 0) + { + var external = externalConditions + .FirstOrDefault(t => t.Info.Condition == condition && t.CanGrantCondition(Player.PlayerActor, this)); + + if (external == null) + throw new LuaException("Condition `{0}` has not been listed on an enabled ExternalCondition trait".F(condition)); + + return external.GrantCondition(Player.PlayerActor, this, duration); + } + + [Desc("Revoke a condition using the token returned by GrantCondition.")] + public void RevokeCondition(int token) + { + foreach (var external in externalConditions) + if (external.TryRevokeCondition(Player.PlayerActor, this, token)) + break; + } + + [Desc("Check whether this player actor accepts a specific external condition.")] + public bool AcceptsCondition(string condition) + { + return externalConditions + .Any(t => t.Info.Condition == condition && t.CanGrantCondition(Player.PlayerActor, this)); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/PlayerProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/PlayerProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/PlayerProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/PlayerProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -39,13 +39,26 @@ [Desc("The player's spawnpoint ID.")] public int Spawn { get { return Player.SpawnPoint; } } + [Desc("The player's home/starting location.")] + public CPos HomeLocation { get { return Player.HomeLocation; } } + [Desc("The player's team ID.")] public int Team { get { var c = Player.World.LobbyInfo.Clients.FirstOrDefault(i => i.Index == Player.ClientIndex); - return c != null ? c.Team : 0; + return c?.Team ?? 0; + } + } + + [Desc("The player's handicap level.")] + public int Handicap + { + get + { + var c = Player.World.LobbyInfo.Clients.FirstOrDefault(i => i.Index == Player.ClientIndex); + return c?.Handicap ?? 0; } } @@ -77,8 +90,7 @@ { var result = new List(); - ActorInfo ai; - if (!Context.World.Map.Rules.Actors.TryGetValue(type, out ai)) + if (!Context.World.Map.Rules.Actors.TryGetValue(type, out var ai)) throw new LuaException("Unknown actor type '{0}'".F(type)); result.AddRange(Player.World.Actors diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/ProductionProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/ProductionProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/ProductionProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/ProductionProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -38,8 +38,7 @@ "If 'Buildable.BuildAtProductionType' is not set either, a random exit will be selected.")] public void Produce(string actorType, string factionVariant = null, string productionType = null) { - ActorInfo actorInfo; - if (!Self.World.Map.Rules.Actors.TryGetValue(actorType, out actorInfo)) + if (!Self.World.Map.Rules.Actors.TryGetValue(actorType, out var actorInfo)) throw new LuaException("Unknown actor type '{0}'".F(actorType)); var bi = actorInfo.TraitInfo(); @@ -58,7 +57,7 @@ new FactionInit(factionVariant ?? BuildableInfo.GetInitialFaction(actorInfo, p.Faction)) }; - if (p.Produce(Self, actorInfo, type, inits)) + if (p.Produce(Self, actorInfo, type, inits, 0)) return true; } @@ -87,7 +86,7 @@ if (rp.Path.Count > 0) return rp.Path.Last(); - var exit = Self.FirstExitOrDefault(); + var exit = Self.NearestExitOrDefault(Self.CenterPosition); if (exit != null) return Self.Location + exit.Info.ExitCell; diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/ScaredCatProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/ScaredCatProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/ScaredCatProperties.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/ScaredCatProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,36 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Mods.Common.Traits; +using OpenRA.Scripting; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Scripting +{ + [ScriptPropertyGroup("Movement")] + public class ScaredCatProperties : ScriptActorProperties, Requires + { + readonly ScaredyCat scaredyCat; + + public ScaredCatProperties(ScriptContext context, Actor self) + : base(context, self) + { + scaredyCat = self.Trait(); + } + + [ScriptActorPropertyActivity] + [Desc("Makes the unit automatically run around and become faster.")] + public void Panic() + { + scaredyCat.Panic(); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/Properties/TransportProperties.cs openra-20210321/OpenRA.Mods.Common/Scripting/Properties/TransportProperties.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/Properties/TransportProperties.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/Properties/TransportProperties.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,6 +29,9 @@ cargo = self.Trait(); } + [Desc("Returns references to passengers inside the transport.")] + public Actor[] Passengers { get { return cargo.Passengers.ToArray(); } } + [Desc("Specifies whether transport has any passengers.")] public bool HasPassengers { get { return cargo.Passengers.Any(); } } @@ -44,8 +47,8 @@ cargo.Load(Self, a); } - [Desc("Remove the first actor from the transport. This actor is not added to the world.")] - public Actor UnloadPassenger() { return cargo.Unload(Self); } + [Desc("Remove an existing actor (or first actor if none specified) from the transport. This actor is not added to the world.")] + public Actor UnloadPassenger(Actor a = null) { return cargo.Unload(Self, a); } [ScriptActorPropertyActivity] [Desc("Command transport to unload passengers.")] diff -Nru openra-20200503/OpenRA.Mods.Common/Scripting/ScriptTriggers.cs openra-20210321/OpenRA.Mods.Common/Scripting/ScriptTriggers.cs --- openra-20200503/OpenRA.Mods.Common/Scripting/ScriptTriggers.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Scripting/ScriptTriggers.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,9 +28,9 @@ } [Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")] - public class ScriptTriggersInfo : ITraitInfo + public class ScriptTriggersInfo : TraitInfo { - public object Create(ActorInitializer init) { return new ScriptTriggers(init.World, init.Self); } + public override object Create(ActorInitializer init) { return new ScriptTriggers(init.World, init.Self); } } public sealed class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, INotifyOtherProduction, @@ -118,7 +118,8 @@ try { using (var b = e.Attacker.ToLuaValue(f.Context)) - f.Function.Call(f.Self, b).Dispose(); + using (var c = e.Damage.Value.ToLuaValue(f.Context)) + f.Function.Call(f.Self, b, c).Dispose(); } catch (Exception ex) { diff -Nru openra-20200503/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs openra-20210321/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs --- openra-20200503/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,8 +12,8 @@ using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; +using OpenRA.Mods.Common.Widgets.Logic; using OpenRA.Network; using OpenRA.Primitives; using OpenRA.Server; @@ -43,46 +43,54 @@ { "name", Name }, { "faction", Faction }, { "team", Team }, + { "handicap", Handicap }, { "spawn", Spawn }, + { "clear_spawn", ClearPlayerSpawn }, { "color", PlayerColor }, { "sync_lobby", SyncLobby } }; static bool ValidateSlotCommand(S server, Connection conn, Session.Client client, string arg, bool requiresHost) { - if (!server.LobbyInfo.Slots.ContainsKey(arg)) + lock (server.LobbyInfo) { - Log.Write("server", "Invalid slot: {0}", arg); - return false; - } + if (!server.LobbyInfo.Slots.ContainsKey(arg)) + { + Log.Write("server", "Invalid slot: {0}", arg); + return false; + } - if (requiresHost && !client.IsAdmin) - { - server.SendOrderTo(conn, "Message", "Only the host can do that."); - return false; - } + if (requiresHost && !client.IsAdmin) + { + server.SendOrderTo(conn, "Message", "Only the host can do that."); + return false; + } - return true; + return true; + } } public static bool ValidateCommand(S server, Connection conn, Session.Client client, string cmd) { - // Kick command is always valid for the host - if (cmd.StartsWith("kick ")) - return true; - - if (server.State == ServerState.GameStarted) - { - server.SendOrderTo(conn, "Message", "Cannot change state when game started. ({0})".F(cmd)); - return false; - } - else if (client.State == Session.ClientState.Ready && !(cmd.StartsWith("state") || cmd == "startgame")) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Cannot change state when marked as ready."); - return false; - } + // Kick command is always valid for the host + if (cmd.StartsWith("kick ")) + return true; - return true; + if (server.State == ServerState.GameStarted) + { + server.SendOrderTo(conn, "Message", "Cannot change state when game started. ({0})".F(cmd)); + return false; + } + else if (client.State == Session.ClientState.Ready && !(cmd.StartsWith("state") || cmd == "startgame")) + { + server.SendOrderTo(conn, "Message", "Cannot change state when marked as ready."); + return false; + } + + return true; + } } public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd) @@ -93,8 +101,7 @@ var cmdName = cmd.Split(' ').First(); var cmdValue = cmd.Split(' ').Skip(1).JoinWith(" "); - Func a; - if (!commandHandlers.TryGetValue(cmdName, out a)) + if (!commandHandlers.TryGetValue(cmdName, out var a)) return false; return a(server, conn, client, cmdValue); @@ -102,777 +109,932 @@ static void CheckAutoStart(S server) { - var nonBotPlayers = server.LobbyInfo.NonBotPlayers; + lock (server.LobbyInfo) + { + var nonBotPlayers = server.LobbyInfo.NonBotPlayers; + + // Are all players and admin (could be spectating) ready? + if (nonBotPlayers.Any(c => c.State != Session.ClientState.Ready) || + server.LobbyInfo.Clients.First(c => c.IsAdmin).State != Session.ClientState.Ready) + return; + + // Does server have at least 2 human players? + if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer && nonBotPlayers.Count() < 2) + return; + + // Are the map conditions satisfied? + if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required && server.LobbyInfo.ClientInSlot(sl.Key) == null)) + return; - // Are all players and admin (could be spectating) ready? - if (nonBotPlayers.Any(c => c.State != Session.ClientState.Ready) || - server.LobbyInfo.Clients.First(c => c.IsAdmin).State != Session.ClientState.Ready) - return; - - // Does server have at least 2 human players? - if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer && nonBotPlayers.Count() < 2) - return; - - // Are the map conditions satisfied? - if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required && server.LobbyInfo.ClientInSlot(sl.Key) == null)) - return; + if (LobbyUtils.InsufficientEnabledSpawnPoints(server.Map, server.LobbyInfo)) + return; - server.StartGame(); + server.StartGame(); + } } static bool State(S server, Connection conn, Session.Client client, string s) { - var state = Session.ClientState.Invalid; - if (!Enum.TryParse(s, false, out state)) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Malformed state command"); - return true; - } - - client.State = state; - - Log.Write("server", "Player @{0} is {1}", - conn.Socket.RemoteEndPoint, client.State); + if (!Enum.TryParse(s, false, out var state)) + { + server.SendOrderTo(conn, "Message", "Malformed state command"); + return true; + } - server.SyncLobbyClients(); + client.State = state; + Log.Write("server", "Player @{0} is {1}", conn.Socket.RemoteEndPoint, client.State); - CheckAutoStart(server); + server.SyncLobbyClients(); + CheckAutoStart(server); - return true; + return true; + } } static bool StartGame(S server, Connection conn, Session.Client client, string s) { - if (!client.IsAdmin) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Only the host can start the game."); - return true; - } + if (!client.IsAdmin) + { + server.SendOrderTo(conn, "Message", "Only the host can start the game."); + return true; + } - if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required && - server.LobbyInfo.ClientInSlot(sl.Key) == null)) - { - server.SendOrderTo(conn, "Message", "Unable to start the game until required slots are full."); - return true; - } + if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required && + server.LobbyInfo.ClientInSlot(sl.Key) == null)) + { + server.SendOrderTo(conn, "Message", "Unable to start the game until required slots are full."); + return true; + } + + if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer && server.LobbyInfo.NonBotPlayers.Count() < 2) + { + server.SendOrderTo(conn, "Message", server.TwoHumansRequiredText); + return true; + } + + if (LobbyUtils.InsufficientEnabledSpawnPoints(server.Map, server.LobbyInfo)) + { + server.SendOrderTo(conn, "Message", "Unable to start the game until more spawn points are enabled."); + return true; + } + + server.StartGame(); - if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer && server.LobbyInfo.NonBotPlayers.Count() < 2) - { - server.SendOrderTo(conn, "Message", server.TwoHumansRequiredText); return true; } - - server.StartGame(); - return true; } static bool Slot(S server, Connection conn, Session.Client client, string s) { - if (!server.LobbyInfo.Slots.ContainsKey(s)) + lock (server.LobbyInfo) { - Log.Write("server", "Invalid slot: {0}", s); - return false; - } + if (!server.LobbyInfo.Slots.ContainsKey(s)) + { + Log.Write("server", "Invalid slot: {0}", s); + return false; + } - var slot = server.LobbyInfo.Slots[s]; + var slot = server.LobbyInfo.Slots[s]; - if (slot.Closed || server.LobbyInfo.ClientInSlot(s) != null) - return false; + if (slot.Closed || server.LobbyInfo.ClientInSlot(s) != null) + return false; - // If the previous slot had a locked spawn then we must not carry that to the new slot - var oldSlot = client.Slot != null ? server.LobbyInfo.Slots[client.Slot] : null; - if (oldSlot != null && oldSlot.LockSpawn) - client.SpawnPoint = 0; + // If the previous slot had a locked spawn then we must not carry that to the new slot + var oldSlot = client.Slot != null ? server.LobbyInfo.Slots[client.Slot] : null; + if (oldSlot != null && oldSlot.LockSpawn) + client.SpawnPoint = 0; - client.Slot = s; - S.SyncClientToPlayerReference(client, server.Map.Players.Players[s]); + client.Slot = s; + S.SyncClientToPlayerReference(client, server.Map.Players.Players[s]); - if (!slot.LockColor) - client.PreferredColor = client.Color = SanitizePlayerColor(server, client.Color, client.Index, conn); + if (!slot.LockColor) + client.PreferredColor = client.Color = SanitizePlayerColor(server, client.Color, client.Index, conn); - server.SyncLobbyClients(); - CheckAutoStart(server); + server.SyncLobbyClients(); + CheckAutoStart(server); - return true; + return true; + } } static bool AllowSpectators(S server, Connection conn, Session.Client client, string s) { - if (bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowSpectators)) - { - server.SyncLobbyGlobalSettings(); - return true; - } - else + lock (server.LobbyInfo) { + if (bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowSpectators)) + { + server.SyncLobbyGlobalSettings(); + return true; + } + server.SendOrderTo(conn, "Message", "Malformed allow_spectate command"); + return true; } } static bool Specate(S server, Connection conn, Session.Client client, string s) { - if (server.LobbyInfo.GlobalSettings.AllowSpectators || client.IsAdmin) + lock (server.LobbyInfo) { - client.Slot = null; - client.SpawnPoint = 0; - client.Team = 0; - client.Color = Color.White; - server.SyncLobbyClients(); - CheckAutoStart(server); - return true; - } - else + if (server.LobbyInfo.GlobalSettings.AllowSpectators || client.IsAdmin) + { + client.Slot = null; + client.SpawnPoint = 0; + client.Team = 0; + client.Handicap = 0; + client.Color = Color.White; + server.SyncLobbyClients(); + CheckAutoStart(server); + return true; + } + return false; + } } static bool SlotClose(S server, Connection conn, Session.Client client, string s) { - if (!ValidateSlotCommand(server, conn, client, s, true)) - return false; - - // kick any player that's in the slot - var occupant = server.LobbyInfo.ClientInSlot(s); - if (occupant != null) + lock (server.LobbyInfo) { - if (occupant.Bot != null) + if (!ValidateSlotCommand(server, conn, client, s, true)) + return false; + + // kick any player that's in the slot + var occupant = server.LobbyInfo.ClientInSlot(s); + if (occupant != null) { - server.LobbyInfo.Clients.Remove(occupant); - server.SyncLobbyClients(); - var ping = server.LobbyInfo.PingFromClient(occupant); - if (ping != null) + if (occupant.Bot != null) { - server.LobbyInfo.ClientPings.Remove(ping); - server.SyncClientPing(); + server.LobbyInfo.Clients.Remove(occupant); + server.SyncLobbyClients(); + var ping = server.LobbyInfo.PingFromClient(occupant); + if (ping != null) + { + server.LobbyInfo.ClientPings.Remove(ping); + server.SyncClientPing(); + } } - } - else - { - var occupantConn = server.Conns.FirstOrDefault(c => c.PlayerIndex == occupant.Index); - if (occupantConn != null) + else { - server.SendOrderTo(occupantConn, "ServerError", "Your slot was closed by the host."); - server.DropClient(occupantConn); + var occupantConn = server.Conns.FirstOrDefault(c => c.PlayerIndex == occupant.Index); + if (occupantConn != null) + { + server.SendOrderTo(occupantConn, "ServerError", "Your slot was closed by the host."); + server.DropClient(occupantConn); + } } } - } - server.LobbyInfo.Slots[s].Closed = true; - server.SyncLobbySlots(); + server.LobbyInfo.Slots[s].Closed = true; + server.SyncLobbySlots(); - return true; + return true; + } } static bool SlotOpen(S server, Connection conn, Session.Client client, string s) { - if (!ValidateSlotCommand(server, conn, client, s, true)) - return false; - - var slot = server.LobbyInfo.Slots[s]; - slot.Closed = false; - server.SyncLobbySlots(); - - // Slot may have a bot in it - var occupant = server.LobbyInfo.ClientInSlot(s); - if (occupant != null && occupant.Bot != null) + lock (server.LobbyInfo) { - server.LobbyInfo.Clients.Remove(occupant); - var ping = server.LobbyInfo.PingFromClient(occupant); - if (ping != null) + if (!ValidateSlotCommand(server, conn, client, s, true)) + return false; + + var slot = server.LobbyInfo.Slots[s]; + slot.Closed = false; + server.SyncLobbySlots(); + + // Slot may have a bot in it + var occupant = server.LobbyInfo.ClientInSlot(s); + if (occupant != null && occupant.Bot != null) { - server.LobbyInfo.ClientPings.Remove(ping); - server.SyncClientPing(); + server.LobbyInfo.Clients.Remove(occupant); + var ping = server.LobbyInfo.PingFromClient(occupant); + if (ping != null) + { + server.LobbyInfo.ClientPings.Remove(ping); + server.SyncClientPing(); + } } - } - server.SyncLobbyClients(); + server.SyncLobbyClients(); - return true; + return true; + } } static bool SlotBot(S server, Connection conn, Session.Client client, string s) { - var parts = s.Split(' '); - - if (parts.Length < 3) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Malformed slot_bot command"); - return true; - } - - if (!ValidateSlotCommand(server, conn, client, parts[0], true)) - return false; + var parts = s.Split(' '); + if (parts.Length < 3) + { + server.SendOrderTo(conn, "Message", "Malformed slot_bot command"); + return true; + } - var slot = server.LobbyInfo.Slots[parts[0]]; - var bot = server.LobbyInfo.ClientInSlot(parts[0]); - int controllerClientIndex; - if (!Exts.TryParseIntegerInvariant(parts[1], out controllerClientIndex)) - { - Log.Write("server", "Invalid bot controller client index: {0}", parts[1]); - return false; - } + if (!ValidateSlotCommand(server, conn, client, parts[0], true)) + return false; - // Invalid slot - if (bot != null && bot.Bot == null) - { - server.SendOrderTo(conn, "Message", "Can't add bots to a slot with another client."); - return true; - } + var slot = server.LobbyInfo.Slots[parts[0]]; + var bot = server.LobbyInfo.ClientInSlot(parts[0]); + if (!Exts.TryParseIntegerInvariant(parts[1], out var controllerClientIndex)) + { + Log.Write("server", "Invalid bot controller client index: {0}", parts[1]); + return false; + } - var botType = parts[2]; - var botInfo = server.Map.Rules.Actors["player"].TraitInfos() - .FirstOrDefault(b => b.Type == botType); + // Invalid slot + if (bot != null && bot.Bot == null) + { + server.SendOrderTo(conn, "Message", "Can't add bots to a slot with another client."); + return true; + } - if (botInfo == null) - { - server.SendOrderTo(conn, "Message", "Invalid bot type."); - return true; - } + var botType = parts[2]; + var botInfo = server.Map.Rules.Actors["player"].TraitInfos() + .FirstOrDefault(b => b.Type == botType); - slot.Closed = false; - if (bot == null) - { - // Create a new bot - bot = new Session.Client() + if (botInfo == null) { - Index = server.ChooseFreePlayerIndex(), - Name = botInfo.Name, - Bot = botType, - Slot = parts[0], - Faction = "Random", - SpawnPoint = 0, - Team = 0, - State = Session.ClientState.NotReady, - BotControllerClientIndex = controllerClientIndex - }; + server.SendOrderTo(conn, "Message", "Invalid bot type."); + return true; + } - // Pick a random color for the bot - var validator = server.ModData.Manifest.Get(); - var tileset = server.Map.Rules.TileSet; - var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color); - var playerColors = server.LobbyInfo.Clients.Select(c => c.Color) - .Concat(server.Map.Players.Players.Values.Select(p => p.Color)); - bot.Color = bot.PreferredColor = validator.RandomPresetColor(server.Random, terrainColors, playerColors); + slot.Closed = false; + if (bot == null) + { + // Create a new bot + bot = new Session.Client() + { + Index = server.ChooseFreePlayerIndex(), + Name = botInfo.Name, + Bot = botType, + Slot = parts[0], + Faction = "Random", + SpawnPoint = 0, + Team = 0, + Handicap = 0, + State = Session.ClientState.NotReady, + BotControllerClientIndex = controllerClientIndex + }; + + // Pick a random color for the bot + var validator = server.ModData.Manifest.Get(); + var tileset = server.Map.Rules.TileSet; + var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color); + var playerColors = server.LobbyInfo.Clients.Select(c => c.Color) + .Concat(server.Map.Players.Players.Values.Select(p => p.Color)); + bot.Color = bot.PreferredColor = validator.RandomPresetColor(server.Random, terrainColors, playerColors); - server.LobbyInfo.Clients.Add(bot); - } - else - { - // Change the type of the existing bot - bot.Name = botInfo.Name; - bot.Bot = botType; - } + server.LobbyInfo.Clients.Add(bot); + } + else + { + // Change the type of the existing bot + bot.Name = botInfo.Name; + bot.Bot = botType; + } - S.SyncClientToPlayerReference(bot, server.Map.Players.Players[parts[0]]); - server.SyncLobbyClients(); - server.SyncLobbySlots(); + S.SyncClientToPlayerReference(bot, server.Map.Players.Players[parts[0]]); + server.SyncLobbyClients(); + server.SyncLobbySlots(); - return true; + return true; + } } static bool Map(S server, Connection conn, Session.Client client, string s) { - if (!client.IsAdmin) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Only the host can change the map."); - return true; - } - - var lastMap = server.LobbyInfo.GlobalSettings.Map; - Action selectMap = map => - { - // Make sure the map hasn't changed in the meantime - if (server.LobbyInfo.GlobalSettings.Map != lastMap) - return; - - server.LobbyInfo.GlobalSettings.Map = map.Uid; - - var oldSlots = server.LobbyInfo.Slots.Keys.ToArray(); - server.Map = server.ModData.MapCache[server.LobbyInfo.GlobalSettings.Map]; - - server.LobbyInfo.Slots = server.Map.Players.Players - .Select(p => MakeSlotFromPlayerReference(p.Value)) - .Where(ss => ss != null) - .ToDictionary(ss => ss.PlayerReference, ss => ss); - - LoadMapSettings(server, server.LobbyInfo.GlobalSettings, server.Map.Rules); - - // Reset client states - var selectableFactions = server.Map.Rules.Actors["world"].TraitInfos() - .Where(f => f.Selectable) - .Select(f => f.InternalName) - .ToList(); + if (!client.IsAdmin) + { + server.SendOrderTo(conn, "Message", "Only the host can change the map."); + return true; + } - foreach (var c in server.LobbyInfo.Clients) + var lastMap = server.LobbyInfo.GlobalSettings.Map; + Action selectMap = map => { - c.State = Session.ClientState.Invalid; - if (!selectableFactions.Contains(c.Faction)) - c.Faction = "Random"; - } - - // Reassign players into new slots based on their old slots: - // - Observers remain as observers - // - Players who now lack a slot are made observers - // - Bots who now lack a slot are dropped - // - Bots who are not defined in the map rules are dropped - var botTypes = server.Map.Rules.Actors["player"].TraitInfos().Select(t => t.Type); - var slots = server.LobbyInfo.Slots.Keys.ToArray(); - var i = 0; - foreach (var os in oldSlots) - { - var c = server.LobbyInfo.ClientInSlot(os); - if (c == null) - continue; - - c.SpawnPoint = 0; - c.Slot = i < slots.Length ? slots[i++] : null; - if (c.Slot != null) + lock (server.LobbyInfo) { - // Remove Bot from slot if slot forbids bots - if (c.Bot != null && (!server.Map.Players.Players[c.Slot].AllowBots || !botTypes.Contains(c.Bot))) - server.LobbyInfo.Clients.Remove(c); - S.SyncClientToPlayerReference(c, server.Map.Players.Players[c.Slot]); + // Make sure the map hasn't changed in the meantime + if (server.LobbyInfo.GlobalSettings.Map != lastMap) + return; + + server.LobbyInfo.GlobalSettings.Map = map.Uid; + + var oldSlots = server.LobbyInfo.Slots.Keys.ToArray(); + server.Map = server.ModData.MapCache[server.LobbyInfo.GlobalSettings.Map]; + + server.LobbyInfo.Slots = server.Map.Players.Players + .Select(p => MakeSlotFromPlayerReference(p.Value)) + .Where(ss => ss != null) + .ToDictionary(ss => ss.PlayerReference, ss => ss); + + LoadMapSettings(server, server.LobbyInfo.GlobalSettings, server.Map.Rules); + + // Reset client states + var selectableFactions = server.Map.Rules.Actors["world"].TraitInfos() + .Where(f => f.Selectable) + .Select(f => f.InternalName) + .ToList(); + + foreach (var c in server.LobbyInfo.Clients) + { + c.State = Session.ClientState.Invalid; + if (!selectableFactions.Contains(c.Faction)) + c.Faction = "Random"; + } + + // Reassign players into new slots based on their old slots: + // - Observers remain as observers + // - Players who now lack a slot are made observers + // - Bots who now lack a slot are dropped + // - Bots who are not defined in the map rules are dropped + var botTypes = server.Map.Rules.Actors["player"].TraitInfos().Select(t => t.Type); + var slots = server.LobbyInfo.Slots.Keys.ToArray(); + var i = 0; + foreach (var os in oldSlots) + { + var c = server.LobbyInfo.ClientInSlot(os); + if (c == null) + continue; + + c.SpawnPoint = 0; + c.Slot = i < slots.Length ? slots[i++] : null; + if (c.Slot != null) + { + // Remove Bot from slot if slot forbids bots + if (c.Bot != null && (!server.Map.Players.Players[c.Slot].AllowBots || !botTypes.Contains(c.Bot))) + server.LobbyInfo.Clients.Remove(c); + S.SyncClientToPlayerReference(c, server.Map.Players.Players[c.Slot]); + } + else if (c.Bot != null) + server.LobbyInfo.Clients.Remove(c); + else + c.Color = Color.White; + } + + // Validate if color is allowed and get an alternative if it isn't + foreach (var c in server.LobbyInfo.Clients) + if (c.Slot != null && !server.LobbyInfo.Slots[c.Slot].LockColor) + c.Color = c.PreferredColor = SanitizePlayerColor(server, c.Color, c.Index, conn); + + server.LobbyInfo.DisabledSpawnPoints.Clear(); + + server.SyncLobbyInfo(); + + server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title)); + + if (server.Map.DefinesUnsafeCustomRules) + server.SendMessage("This map contains custom rules. Game experience may change."); + + if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer) + server.SendMessage(server.TwoHumansRequiredText); + else if (server.Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots)) + server.SendMessage("Bots have been disabled on this map."); + + var briefing = MissionBriefingOrDefault(server); + if (briefing != null) + server.SendMessage(briefing); } - else if (c.Bot != null) - server.LobbyInfo.Clients.Remove(c); - else - c.Color = Color.White; - } - - // Validate if color is allowed and get an alternative if it isn't - foreach (var c in server.LobbyInfo.Clients) - if (c.Slot != null && !server.LobbyInfo.Slots[c.Slot].LockColor) - c.Color = c.PreferredColor = SanitizePlayerColor(server, c.Color, c.Index, conn); - - server.SyncLobbyInfo(); - - server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title)); - - if (server.Map.DefinesUnsafeCustomRules) - server.SendMessage("This map contains custom rules. Game experience may change."); - - if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer) - server.SendMessage(server.TwoHumansRequiredText); - else if (server.Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots)) - server.SendMessage("Bots have been disabled on this map."); + }; - var briefing = MissionBriefingOrDefault(server); - if (briefing != null) - server.SendMessage(briefing); - }; + Action queryFailed = () => server.SendOrderTo(conn, "Message", "Map was not found on server."); - Action queryFailed = () => - server.SendOrderTo(conn, "Message", "Map was not found on server."); + var m = server.ModData.MapCache[s]; + if (m.Status == MapStatus.Available || m.Status == MapStatus.DownloadAvailable) + selectMap(m); + else if (server.Settings.QueryMapRepository) + { + server.SendOrderTo(conn, "Message", "Searching for map on the Resource Center..."); + var mapRepository = server.ModData.Manifest.Get().MapRepository; + server.ModData.MapCache.QueryRemoteMapDetails(mapRepository, new[] { s }, selectMap, queryFailed); + } + else + queryFailed(); - var m = server.ModData.MapCache[s]; - if (m.Status == MapStatus.Available || m.Status == MapStatus.DownloadAvailable) - selectMap(m); - else if (server.Settings.QueryMapRepository) - { - server.SendOrderTo(conn, "Message", "Searching for map on the Resource Center..."); - var mapRepository = server.ModData.Manifest.Get().MapRepository; - server.ModData.MapCache.QueryRemoteMapDetails(mapRepository, new[] { s }, selectMap, queryFailed); + return true; } - else - queryFailed(); - - return true; } static bool Option(S server, Connection conn, Session.Client client, string s) { - if (!client.IsAdmin) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Only the host can change the configuration."); - return true; - } + if (!client.IsAdmin) + { + server.SendOrderTo(conn, "Message", "Only the host can change the configuration."); + return true; + } - var allOptions = server.Map.Rules.Actors["player"].TraitInfos() - .Concat(server.Map.Rules.Actors["world"].TraitInfos()) - .SelectMany(t => t.LobbyOptions(server.Map.Rules)); + var allOptions = server.Map.Rules.Actors["player"].TraitInfos() + .Concat(server.Map.Rules.Actors["world"].TraitInfos()) + .SelectMany(t => t.LobbyOptions(server.Map.Rules)); + + // Overwrite keys with duplicate ids + var options = new Dictionary(); + foreach (var o in allOptions) + options[o.Id] = o; + + var split = s.Split(' '); + if (split.Length < 2 || !options.TryGetValue(split[0], out var option) || + !option.Values.ContainsKey(split[1])) + { + server.SendOrderTo(conn, "Message", "Invalid configuration command."); + return true; + } - // Overwrite keys with duplicate ids - var options = new Dictionary(); - foreach (var o in allOptions) - options[o.Id] = o; + if (option.IsLocked) + { + server.SendOrderTo(conn, "Message", "{0} cannot be changed.".F(option.Name)); + return true; + } - var split = s.Split(' '); - LobbyOption option; - if (split.Length < 2 || !options.TryGetValue(split[0], out option) || - !option.Values.ContainsKey(split[1])) - { - server.SendOrderTo(conn, "Message", "Invalid configuration command."); - return true; - } + var oo = server.LobbyInfo.GlobalSettings.LobbyOptions[option.Id]; + if (oo.Value == split[1]) + return true; - if (option.IsLocked) - { - server.SendOrderTo(conn, "Message", "{0} cannot be changed.".F(option.Name)); - return true; - } + oo.Value = oo.PreferredValue = split[1]; - var oo = server.LobbyInfo.GlobalSettings.LobbyOptions[option.Id]; - if (oo.Value == split[1]) - return true; + if (option.Id == "gamespeed") + { + var speed = server.ModData.Manifest.Get().Speeds[oo.Value]; + server.LobbyInfo.GlobalSettings.Timestep = speed.Timestep; + server.LobbyInfo.GlobalSettings.OrderLatency = speed.OrderLatency; + } - oo.Value = oo.PreferredValue = split[1]; + server.SyncLobbyGlobalSettings(); + server.SendMessage(option.ValueChangedMessage(client.Name, split[1])); - if (option.Id == "gamespeed") - { - var speed = server.ModData.Manifest.Get().Speeds[oo.Value]; - server.LobbyInfo.GlobalSettings.Timestep = speed.Timestep; - server.LobbyInfo.GlobalSettings.OrderLatency = speed.OrderLatency; - } + foreach (var c in server.LobbyInfo.Clients) + c.State = Session.ClientState.NotReady; - server.SyncLobbyGlobalSettings(); - server.SendMessage(option.ValueChangedMessage(client.Name, split[1])); + server.SyncLobbyClients(); - return true; + return true; + } } static bool AssignTeams(S server, Connection conn, Session.Client client, string s) { - if (!client.IsAdmin) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Only the host can set that option."); - return true; - } + if (!client.IsAdmin) + { + server.SendOrderTo(conn, "Message", "Only the host can set that option."); + return true; + } - int teamCount; - if (!Exts.TryParseIntegerInvariant(s, out teamCount)) - { - server.SendOrderTo(conn, "Message", "Number of teams could not be parsed: {0}".F(s)); - return true; - } + if (!Exts.TryParseIntegerInvariant(s, out var teamCount)) + { + server.SendOrderTo(conn, "Message", "Number of teams could not be parsed: {0}".F(s)); + return true; + } - var maxTeams = (server.LobbyInfo.Clients.Count(c => c.Slot != null) + 1) / 2; - teamCount = teamCount.Clamp(0, maxTeams); - var clients = server.LobbyInfo.Slots - .Select(slot => server.LobbyInfo.ClientInSlot(slot.Key)) - .Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam); + var maxTeams = (server.LobbyInfo.Clients.Count(c => c.Slot != null) + 1) / 2; + teamCount = teamCount.Clamp(0, maxTeams); + var clients = server.LobbyInfo.Slots + .Select(slot => server.LobbyInfo.ClientInSlot(slot.Key)) + .Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam); + + var assigned = 0; + var clientCount = clients.Count(); + foreach (var player in clients) + { + // Free for all + if (teamCount == 0) + player.Team = 0; + + // Humans vs Bots + else if (teamCount == 1) + player.Team = player.Bot == null ? 1 : 2; + else + player.Team = assigned++ * teamCount / clientCount + 1; + } - var assigned = 0; - var clientCount = clients.Count(); - foreach (var player in clients) - { - // Free for all - if (teamCount == 0) - player.Team = 0; + server.SyncLobbyClients(); - // Humans vs Bots - else if (teamCount == 1) - player.Team = player.Bot == null ? 1 : 2; - else - player.Team = assigned++ * teamCount / clientCount + 1; + return true; } - - server.SyncLobbyClients(); - - return true; } static bool Kick(S server, Connection conn, Session.Client client, string s) { - if (!client.IsAdmin) - { - server.SendOrderTo(conn, "Message", "Only the host can kick players."); - return true; - } - - var split = s.Split(' '); - if (split.Length < 2) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Malformed kick command"); - return true; - } + if (!client.IsAdmin) + { + server.SendOrderTo(conn, "Message", "Only the host can kick players."); + return true; + } - int kickClientID; - Exts.TryParseIntegerInvariant(split[0], out kickClientID); + var split = s.Split(' '); + if (split.Length < 2) + { + server.SendOrderTo(conn, "Message", "Malformed kick command"); + return true; + } - var kickConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == kickClientID); - if (kickConn == null) - { - server.SendOrderTo(conn, "Message", "No-one in that slot."); - return true; - } + Exts.TryParseIntegerInvariant(split[0], out var kickClientID); - var kickClient = server.GetClient(kickConn); - if (server.State == ServerState.GameStarted && !kickClient.IsObserver) - { - server.SendOrderTo(conn, "Message", "Only spectators can be kicked after the game has started."); - return true; - } + var kickConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == kickClientID); + if (kickConn == null) + { + server.SendOrderTo(conn, "Message", "No-one in that slot."); + return true; + } - Log.Write("server", "Kicking client {0}.", kickClientID); - server.SendMessage("{0} kicked {1} from the server.".F(client.Name, kickClient.Name)); - server.SendOrderTo(kickConn, "ServerError", "You have been kicked from the server."); - server.DropClient(kickConn); + var kickClient = server.GetClient(kickConn); + if (server.State == ServerState.GameStarted && !kickClient.IsObserver) + { + server.SendOrderTo(conn, "Message", "Only spectators can be kicked after the game has started."); + return true; + } - bool tempBan; - bool.TryParse(split[1], out tempBan); + Log.Write("server", "Kicking client {0}.", kickClientID); + server.SendMessage("{0} kicked {1} from the server.".F(client.Name, kickClient.Name)); + server.SendOrderTo(kickConn, "ServerError", "You have been kicked from the server."); + server.DropClient(kickConn); - if (tempBan) - { - Log.Write("server", "Temporarily banning client {0} ({1}).", kickClientID, kickClient.IPAddress); - server.SendMessage("{0} temporarily banned {1} from the server.".F(client.Name, kickClient.Name)); - server.TempBans.Add(kickClient.IPAddress); - } + bool.TryParse(split[1], out var tempBan); + if (tempBan) + { + Log.Write("server", "Temporarily banning client {0} ({1}).", kickClientID, kickClient.IPAddress); + server.SendMessage("{0} temporarily banned {1} from the server.".F(client.Name, kickClient.Name)); + server.TempBans.Add(kickClient.IPAddress); + } - server.SyncLobbyClients(); - server.SyncLobbySlots(); + server.SyncLobbyClients(); + server.SyncLobbySlots(); - return true; + return true; + } } static bool MakeAdmin(S server, Connection conn, Session.Client client, string s) { - if (!client.IsAdmin) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Only admins can transfer admin to another player."); - return true; - } + if (!client.IsAdmin) + { + server.SendOrderTo(conn, "Message", "Only admins can transfer admin to another player."); + return true; + } - int newAdminId; - Exts.TryParseIntegerInvariant(s, out newAdminId); - var newAdminConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == newAdminId); + Exts.TryParseIntegerInvariant(s, out var newAdminId); + var newAdminConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == newAdminId); - if (newAdminConn == null) - { - server.SendOrderTo(conn, "Message", "No-one in that slot."); - return true; - } + if (newAdminConn == null) + { + server.SendOrderTo(conn, "Message", "No-one in that slot."); + return true; + } - var newAdminClient = server.GetClient(newAdminConn); - client.IsAdmin = false; - newAdminClient.IsAdmin = true; - server.SendMessage("{0} is now the admin.".F(newAdminClient.Name)); - Log.Write("server", "{0} is now the admin.".F(newAdminClient.Name)); - server.SyncLobbyClients(); + var newAdminClient = server.GetClient(newAdminConn); + client.IsAdmin = false; + newAdminClient.IsAdmin = true; + + var bots = server.LobbyInfo.Slots + .Select(slot => server.LobbyInfo.ClientInSlot(slot.Key)) + .Where(c => c != null && c.Bot != null); + foreach (var b in bots) + b.BotControllerClientIndex = newAdminId; - return true; + server.SendMessage("{0} is now the admin.".F(newAdminClient.Name)); + Log.Write("server", "{0} is now the admin.".F(newAdminClient.Name)); + server.SyncLobbyClients(); + + return true; + } } static bool MakeSpectator(S server, Connection conn, Session.Client client, string s) { - if (!client.IsAdmin) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Only the host can move players to spectators."); - return true; - } + if (!client.IsAdmin) + { + server.SendOrderTo(conn, "Message", "Only the host can move players to spectators."); + return true; + } - int targetId; - Exts.TryParseIntegerInvariant(s, out targetId); - var targetConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == targetId); + Exts.TryParseIntegerInvariant(s, out var targetId); + var targetConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == targetId); - if (targetConn == null) - { - server.SendOrderTo(conn, "Message", "No-one in that slot."); - return true; - } + if (targetConn == null) + { + server.SendOrderTo(conn, "Message", "No-one in that slot."); + return true; + } - var targetClient = server.GetClient(targetConn); - targetClient.Slot = null; - targetClient.SpawnPoint = 0; - targetClient.Team = 0; - targetClient.Color = Color.White; - targetClient.State = Session.ClientState.NotReady; - server.SendMessage("{0} moved {1} to spectators.".F(client.Name, targetClient.Name)); - Log.Write("server", "{0} moved {1} to spectators.".F(client.Name, targetClient.Name)); - server.SyncLobbyClients(); - CheckAutoStart(server); + var targetClient = server.GetClient(targetConn); + targetClient.Slot = null; + targetClient.SpawnPoint = 0; + targetClient.Team = 0; + targetClient.Handicap = 0; + targetClient.Color = Color.White; + targetClient.State = Session.ClientState.NotReady; + server.SendMessage("{0} moved {1} to spectators.".F(client.Name, targetClient.Name)); + Log.Write("server", "{0} moved {1} to spectators.".F(client.Name, targetClient.Name)); + server.SyncLobbyClients(); + CheckAutoStart(server); - return true; + return true; + } } static bool Name(S server, Connection conn, Session.Client client, string s) { - var sanitizedName = Settings.SanitizedPlayerName(s); - if (sanitizedName == client.Name) - return true; + lock (server.LobbyInfo) + { + var sanitizedName = Settings.SanitizedPlayerName(s); + if (sanitizedName == client.Name) + return true; - Log.Write("server", "Player@{0} is now known as {1}.", conn.Socket.RemoteEndPoint, sanitizedName); - server.SendMessage("{0} is now known as {1}.".F(client.Name, sanitizedName)); - client.Name = sanitizedName; - server.SyncLobbyClients(); + Log.Write("server", "Player@{0} is now known as {1}.", conn.Socket.RemoteEndPoint, sanitizedName); + server.SendMessage("{0} is now known as {1}.".F(client.Name, sanitizedName)); + client.Name = sanitizedName; + server.SyncLobbyClients(); - return true; + return true; + } } static bool Faction(S server, Connection conn, Session.Client client, string s) { - var parts = s.Split(' '); - var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); + lock (server.LobbyInfo) + { + var parts = s.Split(' '); + var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); - // Only the host can change other client's info - if (targetClient.Index != client.Index && !client.IsAdmin) - return true; + // Only the host can change other client's info + if (targetClient.Index != client.Index && !client.IsAdmin) + return true; - // Map has disabled faction changes - if (server.LobbyInfo.Slots[targetClient.Slot].LockFaction) - return true; + // Map has disabled faction changes + if (server.LobbyInfo.Slots[targetClient.Slot].LockFaction) + return true; - var factions = server.Map.Rules.Actors["world"].TraitInfos() - .Where(f => f.Selectable).Select(f => f.InternalName); + var factions = server.Map.Rules.Actors["world"].TraitInfos() + .Where(f => f.Selectable).Select(f => f.InternalName); - if (!factions.Contains(parts[1])) - { - server.SendOrderTo(conn, "Message", "Invalid faction selected: {0}".F(parts[1])); - server.SendOrderTo(conn, "Message", "Supported values: {0}".F(factions.JoinWith(", "))); - return true; - } + if (!factions.Contains(parts[1])) + { + server.SendOrderTo(conn, "Message", "Invalid faction selected: {0}".F(parts[1])); + server.SendOrderTo(conn, "Message", "Supported values: {0}".F(factions.JoinWith(", "))); + return true; + } - targetClient.Faction = parts[1]; - server.SyncLobbyClients(); + targetClient.Faction = parts[1]; + server.SyncLobbyClients(); - return true; + return true; + } } static bool Team(S server, Connection conn, Session.Client client, string s) { - var parts = s.Split(' '); - var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); + lock (server.LobbyInfo) + { + var parts = s.Split(' '); + var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); - // Only the host can change other client's info - if (targetClient.Index != client.Index && !client.IsAdmin) - return true; + // Only the host can change other client's info + if (targetClient.Index != client.Index && !client.IsAdmin) + return true; - // Map has disabled team changes - if (server.LobbyInfo.Slots[targetClient.Slot].LockTeam) - return true; + // Map has disabled team changes + if (server.LobbyInfo.Slots[targetClient.Slot].LockTeam) + return true; - int team; - if (!Exts.TryParseIntegerInvariant(parts[1], out team)) - { - Log.Write("server", "Invalid team: {0}", s); - return false; - } + if (!Exts.TryParseIntegerInvariant(parts[1], out var team)) + { + Log.Write("server", "Invalid team: {0}", s); + return false; + } - targetClient.Team = team; - server.SyncLobbyClients(); + targetClient.Team = team; + server.SyncLobbyClients(); - return true; + return true; + } } - static bool Spawn(S server, Connection conn, Session.Client client, string s) + static bool Handicap(S server, Connection conn, Session.Client client, string s) { - var parts = s.Split(' '); - var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); + lock (server.LobbyInfo) + { + var parts = s.Split(' '); + var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); - // Only the host can change other client's info - if (targetClient.Index != client.Index && !client.IsAdmin) - return true; + // Only the host can change other client's info + if (targetClient.Index != client.Index && !client.IsAdmin) + return true; + + // Map has disabled handicap changes + if (server.LobbyInfo.Slots[targetClient.Slot].LockHandicap) + return true; + + if (!Exts.TryParseIntegerInvariant(parts[1], out var handicap)) + { + Log.Write("server", "Invalid handicap: {0}", s); + return false; + } + + // Handicaps may be set between 0 - 95% in steps of 5% + var options = Enumerable.Range(0, 20).Select(i => 5 * i); + if (!options.Contains(handicap)) + { + Log.Write("server", "Invalid handicap: {0}", s); + return false; + } + + targetClient.Handicap = handicap; + server.SyncLobbyClients(); - // Spectators don't need a spawnpoint - if (targetClient.Slot == null) return true; + } + } - // Map has disabled spawn changes - if (server.LobbyInfo.Slots[targetClient.Slot].LockSpawn) + static bool ClearPlayerSpawn(S server, Connection conn, Session.Client client, string s) + { + var spawnPoint = Exts.ParseIntegerInvariant(s); + if (spawnPoint == 0) return true; - int spawnPoint; - if (!Exts.TryParseIntegerInvariant(parts[1], out spawnPoint) - || spawnPoint < 0 || spawnPoint > server.Map.SpawnPoints.Length) + var existingClient = server.LobbyInfo.Clients.FirstOrDefault(cc => cc.SpawnPoint == spawnPoint); + if (client != existingClient && !client.IsAdmin) { - Log.Write("server", "Invalid spawn point: {0}", parts[1]); + server.SendOrderTo(conn, "Message", "Only admins can clear spawn points."); return true; } - if (server.LobbyInfo.Clients.Where(cc => cc != client).Any(cc => (cc.SpawnPoint == spawnPoint) && (cc.SpawnPoint != 0))) + // Clearing a selected spawn point removes the player + if (existingClient != null) { - server.SendOrderTo(conn, "Message", "You cannot occupy the same spawn point as another player."); + // Prevent a map-defined lock spawn from being affected + if (existingClient.Slot != null && server.LobbyInfo.Slots[existingClient.Slot].LockSpawn) + return true; + + existingClient.SpawnPoint = 0; + if (existingClient.State == Session.ClientState.Ready) + existingClient.State = Session.ClientState.NotReady; + + server.SyncLobbyClients(); return true; } - // Check if any other slot has locked the requested spawn - if (spawnPoint > 0) + // Clearing an empty spawn point prevents it from being selected + // Clearing a disabled spawn restores it for use + if (!server.LobbyInfo.DisabledSpawnPoints.Contains(spawnPoint)) + server.LobbyInfo.DisabledSpawnPoints.Add(spawnPoint); + else + server.LobbyInfo.DisabledSpawnPoints.Remove(spawnPoint); + + server.SyncLobbyInfo(); + return true; + } + + static bool Spawn(S server, Connection conn, Session.Client client, string s) + { + lock (server.LobbyInfo) { - var spawnLockedByAnotherSlot = server.LobbyInfo.Slots.Where(ss => ss.Value.LockSpawn).Any(ss => + var parts = s.Split(' '); + var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); + + // Only the host can change other client's info + if (targetClient.Index != client.Index && !client.IsAdmin) + return true; + + // Spectators don't need a spawnpoint + if (targetClient.Slot == null) + return true; + + // Map has disabled spawn changes + if (server.LobbyInfo.Slots[targetClient.Slot].LockSpawn) + return true; + + if (!Exts.TryParseIntegerInvariant(parts[1], out var spawnPoint) + || spawnPoint < 0 || spawnPoint > server.Map.SpawnPoints.Length) { - var pr = PlayerReferenceForSlot(server, ss.Value); - return pr != null && pr.Spawn == spawnPoint; - }); + Log.Write("server", "Invalid spawn point: {0}", parts[1]); + return true; + } - if (spawnLockedByAnotherSlot) + if (server.LobbyInfo.Clients.Where(cc => cc != client).Any(cc => (cc.SpawnPoint == spawnPoint) && (cc.SpawnPoint != 0))) { - server.SendOrderTo(conn, "Message", "The spawn point is locked to another player slot."); + server.SendOrderTo(conn, "Message", "You cannot occupy the same spawn point as another player."); return true; } - } - targetClient.SpawnPoint = spawnPoint; - server.SyncLobbyClients(); + // Check if any other slot has locked the requested spawn + if (spawnPoint > 0) + { + var spawnLockedByAnotherSlot = server.LobbyInfo.Slots.Where(ss => ss.Value.LockSpawn).Any(ss => + { + var pr = PlayerReferenceForSlot(server, ss.Value); + return pr != null && pr.Spawn == spawnPoint; + }); - return true; + if (spawnLockedByAnotherSlot) + { + server.SendOrderTo(conn, "Message", "The spawn point is locked to another player slot."); + return true; + } + } + + targetClient.SpawnPoint = spawnPoint; + server.SyncLobbyClients(); + + return true; + } } static bool PlayerColor(S server, Connection conn, Session.Client client, string s) { - var parts = s.Split(' '); - var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); - - // Only the host can change other client's info - if (targetClient.Index != client.Index && !client.IsAdmin) - return true; + lock (server.LobbyInfo) + { + var parts = s.Split(' '); + var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); - // Spectator or map has disabled color changes - if (targetClient.Slot == null || server.LobbyInfo.Slots[targetClient.Slot].LockColor) - return true; + // Only the host can change other client's info + if (targetClient.Index != client.Index && !client.IsAdmin) + return true; - // Validate if color is allowed and get an alternative it isn't - var newColor = FieldLoader.GetValue("(value)", parts[1]); - targetClient.Color = SanitizePlayerColor(server, newColor, targetClient.Index, conn); + // Spectator or map has disabled color changes + if (targetClient.Slot == null || server.LobbyInfo.Slots[targetClient.Slot].LockColor) + return true; - // Only update player's preferred color if new color is valid - if (newColor == targetClient.Color) - targetClient.PreferredColor = targetClient.Color; + // Validate if color is allowed and get an alternative it isn't + var newColor = FieldLoader.GetValue("(value)", parts[1]); + targetClient.Color = SanitizePlayerColor(server, newColor, targetClient.Index, conn); + + // Only update player's preferred color if new color is valid + if (newColor == targetClient.Color) + targetClient.PreferredColor = targetClient.Color; - server.SyncLobbyClients(); + server.SyncLobbyClients(); - return true; + return true; + } } static bool SyncLobby(S server, Connection conn, Session.Client client, string s) { - if (!client.IsAdmin) + lock (server.LobbyInfo) { - server.SendOrderTo(conn, "Message", "Only the host can set lobby info"); - return true; - } + if (!client.IsAdmin) + { + server.SendOrderTo(conn, "Message", "Only the host can set lobby info"); + return true; + } + + try + { + server.LobbyInfo = Session.Deserialize(s); + server.SyncLobbyInfo(); + } + catch (Exception) + { + server.SendOrderTo(conn, "Message", "Invalid Lobby Info Sent"); + } - var lobbyInfo = Session.Deserialize(s); - if (lobbyInfo == null) - { - server.SendOrderTo(conn, "Message", "Invalid Lobby Info Sent"); return true; } - - server.LobbyInfo = lobbyInfo; - - server.SyncLobbyInfo(); - - return true; } public void ServerStarted(S server) { - // Remote maps are not supported for the initial map - var uid = server.LobbyInfo.GlobalSettings.Map; - server.Map = server.ModData.MapCache[uid]; - if (server.Map.Status != MapStatus.Available) - throw new InvalidOperationException("Map {0} not found".F(uid)); - - server.LobbyInfo.Slots = server.Map.Players.Players - .Select(p => MakeSlotFromPlayerReference(p.Value)) - .Where(s => s != null) - .ToDictionary(s => s.PlayerReference, s => s); + lock (server.LobbyInfo) + { + // Remote maps are not supported for the initial map + var uid = server.LobbyInfo.GlobalSettings.Map; + server.Map = server.ModData.MapCache[uid]; + if (server.Map.Status != MapStatus.Available) + throw new InvalidOperationException("Map {0} not found".F(uid)); - LoadMapSettings(server, server.LobbyInfo.GlobalSettings, server.Map.Rules); + server.LobbyInfo.Slots = server.Map.Players.Players + .Select(p => MakeSlotFromPlayerReference(p.Value)) + .Where(s => s != null) + .ToDictionary(s => s.PlayerReference, s => s); + + LoadMapSettings(server, server.LobbyInfo.GlobalSettings, server.Map.Rules); + } } static Session.Slot MakeSlotFromPlayerReference(PlayerReference pr) { - if (!pr.Playable) return null; + if (!pr.Playable) + return null; + return new Session.Slot { PlayerReference = pr.Name, @@ -881,6 +1043,7 @@ LockFaction = pr.LockFaction, LockColor = pr.LockColor, LockTeam = pr.LockTeam, + LockHandicap = pr.LockHandicap, LockSpawn = pr.LockSpawn, Required = pr.Required, }; @@ -888,62 +1051,67 @@ public static void LoadMapSettings(S server, Session.Global gs, Ruleset rules) { - var options = rules.Actors["player"].TraitInfos() - .Concat(rules.Actors["world"].TraitInfos()) - .SelectMany(t => t.LobbyOptions(rules)); - - foreach (var o in options) - { - var value = o.DefaultValue; - var preferredValue = o.DefaultValue; - Session.LobbyOptionState state; - if (gs.LobbyOptions.TryGetValue(o.Id, out state)) + lock (server.LobbyInfo) + { + var options = rules.Actors["player"].TraitInfos() + .Concat(rules.Actors["world"].TraitInfos()) + .SelectMany(t => t.LobbyOptions(rules)); + + foreach (var o in options) { - // Propagate old state on map change - if (!o.IsLocked) + var value = o.DefaultValue; + var preferredValue = o.DefaultValue; + if (gs.LobbyOptions.TryGetValue(o.Id, out var state)) { - if (o.Values.Keys.Contains(state.PreferredValue)) - value = state.PreferredValue; - else if (o.Values.Keys.Contains(state.Value)) - value = state.Value; + // Propagate old state on map change + if (!o.IsLocked) + { + if (o.Values.Keys.Contains(state.PreferredValue)) + value = state.PreferredValue; + else if (o.Values.Keys.Contains(state.Value)) + value = state.Value; + } + + preferredValue = state.PreferredValue; } + else + state = new Session.LobbyOptionState(); - preferredValue = state.PreferredValue; - } - else - state = new Session.LobbyOptionState(); + state.IsLocked = o.IsLocked; + state.Value = value; + state.PreferredValue = preferredValue; + gs.LobbyOptions[o.Id] = state; - state.IsLocked = o.IsLocked; - state.Value = value; - state.PreferredValue = preferredValue; - gs.LobbyOptions[o.Id] = state; - - if (o.Id == "gamespeed") - { - var speed = server.ModData.Manifest.Get().Speeds[value]; - gs.Timestep = speed.Timestep; - gs.OrderLatency = speed.OrderLatency; + if (o.Id == "gamespeed") + { + var speed = server.ModData.Manifest.Get().Speeds[value]; + gs.Timestep = speed.Timestep; + gs.OrderLatency = speed.OrderLatency; + } } } } static Color SanitizePlayerColor(S server, Color askedColor, int playerIndex, Connection connectionToEcho = null) { - var validator = server.ModData.Manifest.Get(); - var askColor = askedColor; - - Action onError = message => + lock (server.LobbyInfo) { - if (connectionToEcho != null) - server.SendOrderTo(connectionToEcho, "Message", message); - }; + var validator = server.ModData.Manifest.Get(); + var askColor = askedColor; - var tileset = server.Map.Rules.TileSet; - var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color).ToList(); - var playerColors = server.LobbyInfo.Clients.Where(c => c.Index != playerIndex).Select(c => c.Color) - .Concat(server.Map.Players.Players.Values.Select(p => p.Color)).ToList(); + Action onError = message => + { + if (connectionToEcho != null) + server.SendOrderTo(connectionToEcho, "Message", message); + }; - return validator.MakeValid(askColor, server.Random, terrainColors, playerColors, onError); + var tileset = server.Map.Rules.TileSet; + var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color).ToList(); + var playerColors = server.LobbyInfo.Clients.Where(c => c.Index != playerIndex).Select(c => c.Color) + .Concat(server.Map.Players.Players.Values.Select(p => p.Color)).ToList(); + + return validator.MakeValid(askColor, server.Random, terrainColors, playerColors, onError); + } } static string MissionBriefingOrDefault(S server) @@ -957,33 +1125,39 @@ public void ClientJoined(S server, Connection conn) { - var client = server.GetClient(conn); + lock (server.LobbyInfo) + { + var client = server.GetClient(conn); - // Validate whether color is allowed and get an alternative if it isn't - if (client.Slot != null && !server.LobbyInfo.Slots[client.Slot].LockColor) - client.Color = SanitizePlayerColor(server, client.Color, client.Index); - - // Report any custom map details - // HACK: this isn't the best place for this to live, but if we move it somewhere else - // then we need a larger hack to hook the map change event. - var briefing = MissionBriefingOrDefault(server); - if (briefing != null) - server.SendOrderTo(conn, "Message", briefing); + // Validate whether color is allowed and get an alternative if it isn't + if (client.Slot != null && !server.LobbyInfo.Slots[client.Slot].LockColor) + client.Color = SanitizePlayerColor(server, client.Color, client.Index); + + // Report any custom map details + // HACK: this isn't the best place for this to live, but if we move it somewhere else + // then we need a larger hack to hook the map change event. + var briefing = MissionBriefingOrDefault(server); + if (briefing != null) + server.SendOrderTo(conn, "Message", briefing); + } } void INotifyServerEmpty.ServerEmpty(S server) { - // Expire any temporary bans - server.TempBans.Clear(); + lock (server.LobbyInfo) + { + // Expire any temporary bans + server.TempBans.Clear(); - // Re-enable spectators - server.LobbyInfo.GlobalSettings.AllowSpectators = true; + // Re-enable spectators + server.LobbyInfo.GlobalSettings.AllowSpectators = true; - // Reset player slots - server.LobbyInfo.Slots = server.Map.Players.Players - .Select(p => MakeSlotFromPlayerReference(p.Value)) - .Where(ss => ss != null) - .ToDictionary(ss => ss.PlayerReference, ss => ss); + // Reset player slots + server.LobbyInfo.Slots = server.Map.Players.Players + .Select(p => MakeSlotFromPlayerReference(p.Value)) + .Where(ss => ss != null) + .ToDictionary(ss => ss.PlayerReference, ss => ss); + } } public static PlayerReference PlayerReferenceForSlot(S server, Session.Slot slot) diff -Nru openra-20200503/OpenRA.Mods.Common/ServerTraits/LobbySettingsNotification.cs openra-20210321/OpenRA.Mods.Common/ServerTraits/LobbySettingsNotification.cs --- openra-20200503/OpenRA.Mods.Common/ServerTraits/LobbySettingsNotification.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/ServerTraits/LobbySettingsNotification.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Collections.Generic; using System.Linq; using OpenRA.Network; using OpenRA.Server; @@ -21,27 +20,22 @@ { public void ClientJoined(OpenRA.Server.Server server, Connection conn) { - if (server.LobbyInfo.ClientWithIndex(conn.PlayerIndex).IsAdmin) - return; - - var defaults = new Session.Global(); - LobbyCommands.LoadMapSettings(server, defaults, server.Map.Rules); - - var options = server.Map.Rules.Actors["player"].TraitInfos() - .Concat(server.Map.Rules.Actors["world"].TraitInfos()) - .SelectMany(t => t.LobbyOptions(server.Map.Rules)); - - var optionNames = new Dictionary(); - foreach (var o in options) - optionNames[o.Id] = o.Name; - - foreach (var kv in server.LobbyInfo.GlobalSettings.LobbyOptions) + lock (server.LobbyInfo) { - Session.LobbyOptionState def; - string optionName; - if (!defaults.LobbyOptions.TryGetValue(kv.Key, out def) || kv.Value.Value != def.Value) - if (optionNames.TryGetValue(kv.Key, out optionName)) - server.SendOrderTo(conn, "Message", optionName + ": " + kv.Value.Value); + var defaults = new Session.Global(); + LobbyCommands.LoadMapSettings(server, defaults, server.Map.Rules); + + var options = server.Map.Rules.Actors["player"].TraitInfos() + .Concat(server.Map.Rules.Actors["world"].TraitInfos()) + .SelectMany(t => t.LobbyOptions(server.Map.Rules)) + .ToDictionary(o => o.Id, o => o); + + foreach (var kv in server.LobbyInfo.GlobalSettings.LobbyOptions) + { + if (!defaults.LobbyOptions.TryGetValue(kv.Key, out var def) || kv.Value.Value != def.Value) + if (options.TryGetValue(kv.Key, out var option)) + server.SendOrderTo(conn, "Message", option.Name + ": " + option.Values[kv.Value.Value]); + } } } } diff -Nru openra-20200503/OpenRA.Mods.Common/ServerTraits/MasterServerPinger.cs openra-20210321/OpenRA.Mods.Common/ServerTraits/MasterServerPinger.cs --- openra-20200503/OpenRA.Mods.Common/ServerTraits/MasterServerPinger.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/ServerTraits/MasterServerPinger.cs 2021-03-21 11:10:05.000000000 +0000 @@ -82,7 +82,7 @@ public void ServerStarted(S server) { - if (!server.Ip.Equals(IPAddress.Loopback) && LanGameBeacon != null) + if (server.Type != ServerType.Local && LanGameBeacon != null) LanGameBeacon.Start(); } @@ -98,8 +98,7 @@ public void GameEnded(S server) { - if (LanGameBeacon != null) - LanGameBeacon.Stop(); + LanGameBeacon?.Stop(); lastChanged = Game.RunTime; } @@ -139,8 +138,7 @@ if (errorCode != 0) { // Hardcoded error messages take precedence over the server-provided messages - string message; - if (!MasterServerErrors.TryGetValue(errorCode, out message)) + if (!MasterServerErrors.TryGetValue(errorCode, out var message)) message = errorMessage; masterServerMessages.Enqueue("Warning: " + message); diff -Nru openra-20200503/OpenRA.Mods.Common/ServerTraits/PlayerPinger.cs openra-20210321/OpenRA.Mods.Common/ServerTraits/PlayerPinger.cs --- openra-20200503/OpenRA.Mods.Common/ServerTraits/PlayerPinger.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/ServerTraits/PlayerPinger.cs 2021-03-21 11:10:05.000000000 +0000 @@ -36,7 +36,11 @@ lastPing = Game.RunTime; // Ignore client timeout in singleplayer games to make debugging easier - if (server.LobbyInfo.NonBotClients.Count() < 2 && server.Type != ServerType.Dedicated) + var nonBotClientCount = 0; + lock (server.LobbyInfo) + nonBotClientCount = server.LobbyInfo.NonBotClients.Count(); + + if (nonBotClientCount < 2 && server.Type != ServerType.Dedicated) foreach (var c in server.Conns.ToList()) server.SendOrderTo(c, "Ping", Game.RunTime.ToString()); else diff -Nru openra-20200503/OpenRA.Mods.Common/ShroudExts.cs openra-20210321/OpenRA.Mods.Common/ShroudExts.cs --- openra-20200503/OpenRA.Mods.Common/ShroudExts.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/ShroudExts.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,18 +9,17 @@ */ #endregion -using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common { public static class ShroudExts { - public static bool AnyExplored(this Shroud shroud, Pair[] cells) + public static bool AnyExplored(this Shroud shroud, (CPos Cell, SubCell SubCell)[] cells) { // PERF: Avoid LINQ. foreach (var cell in cells) - if (shroud.IsExplored(cell.First)) + if (shroud.IsExplored(cell.Cell)) return true; return false; @@ -36,11 +35,11 @@ return false; } - public static bool AnyVisible(this Shroud shroud, Pair[] cells) + public static bool AnyVisible(this Shroud shroud, (CPos Cell, SubCell SubCell)[] cells) { // PERF: Avoid LINQ. foreach (var cell in cells) - if (shroud.IsVisible(cell.First)) + if (shroud.IsVisible(cell.Cell)) return true; return false; diff -Nru openra-20200503/OpenRA.Mods.Common/SpriteLoaders/PngSheetLoader.cs openra-20210321/OpenRA.Mods.Common/SpriteLoaders/PngSheetLoader.cs --- openra-20200503/OpenRA.Mods.Common/SpriteLoaders/PngSheetLoader.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/SpriteLoaders/PngSheetLoader.cs 2021-03-21 11:10:05.000000000 +0000 @@ -96,13 +96,17 @@ { regions = new List(); offsets = new List(); + var pngRectangle = new Rectangle(0, 0, png.Width, png.Height); - string frame; - for (var i = 0; png.EmbeddedData.TryGetValue("Frame[" + i + "]", out frame); i++) + for (var i = 0; png.EmbeddedData.TryGetValue("Frame[" + i + "]", out var frame); i++) { // Format: x,y,width,height;offsetX,offsetY var coords = frame.Split(';'); - regions.Add(FieldLoader.GetValue("Region", coords[0])); + var region = FieldLoader.GetValue("Region", coords[0]); + if (!pngRectangle.Contains(region)) + throw new InvalidDataException("Invalid frame regions {0} defined.".F(region)); + + regions.Add(region); offsets.Add(FieldLoader.GetValue("Offset", coords[1])); } } @@ -122,7 +126,7 @@ if (png.EmbeddedData.ContainsKey("FrameAmount")) frameAmount = FieldLoader.GetValue("FrameAmount", png.EmbeddedData["FrameAmount"]); else - frameAmount = png.Width / frameSize.Width * png.Height / frameSize.Height; + frameAmount = (png.Width / frameSize.Width) * (png.Height / frameSize.Height); } else if (png.EmbeddedData.ContainsKey("FrameAmount")) { @@ -141,6 +145,10 @@ var framesPerRow = png.Width / frameSize.Width; + var rows = (frameAmount + framesPerRow - 1) / framesPerRow; + if (png.Width < frameSize.Width * frameAmount / rows || png.Height < frameSize.Height * rows) + throw new InvalidDataException("Invalid frame size {0} and frame amount {1} defined.".F(frameSize, frameAmount)); + regions = new List(); offsets = new List(); diff -Nru openra-20200503/OpenRA.Mods.Common/TargetExtensions.cs openra-20210321/OpenRA.Mods.Common/TargetExtensions.cs --- openra-20200503/OpenRA.Mods.Common/TargetExtensions.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/TargetExtensions.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,8 +21,7 @@ /// /// public static Target RecalculateInvalidatingHiddenTargets(this Target t, Player viewer) { - bool targetIsHiddenActor; - var updated = t.Recalculate(viewer, out targetIsHiddenActor); + var updated = t.Recalculate(viewer, out bool targetIsHiddenActor); return targetIsHiddenActor ? Target.Invalid : updated; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/AcceptsDeliveredCash.cs openra-20210321/OpenRA.Mods.Common/Traits/AcceptsDeliveredCash.cs --- openra-20200503/OpenRA.Mods.Common/Traits/AcceptsDeliveredCash.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/AcceptsDeliveredCash.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,23 +15,23 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Tag trait for actors with `DeliversCash`.")] - public class AcceptsDeliveredCashInfo : ITraitInfo + public class AcceptsDeliveredCashInfo : TraitInfo { [Desc("Accepted `DeliversCash` types. Leave empty to accept all types.")] public readonly HashSet ValidTypes = new HashSet(); - [Desc("Stance the delivering actor needs to enter.")] - public readonly Stance ValidStances = Stance.Ally; + [Desc("Player relationships the owner of the delivering actor needs.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally; [Desc("Play a randomly selected sound from this list when accepting cash.")] public readonly string[] Sounds = { }; - public object Create(ActorInitializer init) { return new AcceptsDeliveredCash(init.Self, this); } + public override object Create(ActorInitializer init) { return new AcceptsDeliveredCash(init.Self, this); } } public class AcceptsDeliveredCash : INotifyCashTransfer { - AcceptsDeliveredCashInfo info; + readonly AcceptsDeliveredCashInfo info; public AcceptsDeliveredCash(Actor self, AcceptsDeliveredCashInfo info) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/AcceptsDeliveredExperience.cs openra-20210321/OpenRA.Mods.Common/Traits/AcceptsDeliveredExperience.cs --- openra-20200503/OpenRA.Mods.Common/Traits/AcceptsDeliveredExperience.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/AcceptsDeliveredExperience.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,15 +15,15 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Tag trait for actors with `DeliversExperience`.")] - public class AcceptsDeliveredExperienceInfo : ITraitInfo, Requires + public class AcceptsDeliveredExperienceInfo : TraitInfo, Requires { [Desc("Accepted `DeliversExperience` types. Leave empty to accept all types.")] public readonly HashSet ValidTypes = new HashSet(); - [Desc("Stance the delivering actor needs to enter.")] - public readonly Stance ValidStances = Stance.Ally; + [Desc("Player relationships the owner of the delivering actor needs.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally; - public object Create(ActorInitializer init) { return new AcceptsDeliveredExperience(init.Self, this); } + public override object Create(ActorInitializer init) { return new AcceptsDeliveredExperience(init.Self, this); } } public class AcceptsDeliveredExperience diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/AffectsShroud.cs openra-20210321/OpenRA.Mods.Common/Traits/AffectsShroud.cs --- openra-20200503/OpenRA.Mods.Common/Traits/AffectsShroud.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/AffectsShroud.cs 2021-03-21 11:10:05.000000000 +0000 @@ -72,7 +72,7 @@ { // PERF: Reuse collection to avoid allocations. footprint.UnionWith(self.OccupiesSpace.OccupiedCells() - .SelectMany(kv => Shroud.ProjectedCellsInRange(map, map.CenterOfCell(kv.First), minRange, maxRange, Info.MaxHeightDelta))); + .SelectMany(kv => Shroud.ProjectedCellsInRange(map, map.CenterOfCell(kv.Cell), minRange, maxRange, Info.MaxHeightDelta))); var cells = footprint.ToArray(); footprint.Clear(); return cells; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Air/Aircraft.cs openra-20210321/OpenRA.Mods.Common/Traits/Air/Aircraft.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Air/Aircraft.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Air/Aircraft.cs 2021-03-21 11:10:05.000000000 +0000 @@ -27,6 +27,7 @@ Land, ReturnToBase, LeaveMap, + LeaveMapAtClosestEdge } public class AircraftInfo : PausableConditionalTraitInfo, IPositionableInfo, IFacingInfo, IMoveInfo, ICruiseAltitudeInfo, @@ -47,15 +48,35 @@ [Desc("The speed at which the aircraft is repulsed from other aircraft. Specify -1 for normal movement speed.")] public readonly int RepulsionSpeed = -1; - public readonly int InitialFacing = 0; + public readonly WAngle InitialFacing = WAngle.Zero; - public readonly int TurnSpeed = 255; + [Desc("Speed at which the actor turns.")] + public readonly WAngle TurnSpeed = new WAngle(512); - [Desc("Turn speed to apply when aircraft flies in circles while idle. Defaults to TurnSpeed if negative.")] - public readonly int IdleTurnSpeed = -1; + [Desc("Turn speed to apply when aircraft flies in circles while idle. Defaults to TurnSpeed if undefined.")] + public readonly WAngle? IdleTurnSpeed = null; + [Desc("Maximum flight speed when cruising.")] public readonly int Speed = 1; + [Desc("If non-negative, force the aircraft to move in circles at this speed when idle (a speed of 0 means don't move), ignoring CanHover.")] + public readonly int IdleSpeed = -1; + + [Desc("Body pitch when flying forwards. Only relevant for voxel aircraft.")] + public readonly WAngle Pitch = WAngle.Zero; + + [Desc("Pitch steps to apply each tick when starting/stopping.")] + public readonly WAngle PitchSpeed = WAngle.Zero; + + [Desc("Body roll when turning. Only relevant for voxel aircraft.")] + public readonly WAngle Roll = WAngle.Zero; + + [Desc("Body roll to apply when aircraft flies in circles while idle. Defaults to Roll if undefined. Only relevant for voxel aircraft.")] + public readonly WAngle? IdleRoll = null; + + [Desc("Roll steps to apply each tick when turning.")] + public readonly WAngle RollSpeed = WAngle.Zero; + [Desc("Minimum altitude where this aircraft is considered airborne.")] public readonly int MinAirborneAltitude = 1; @@ -73,6 +94,9 @@ [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line for regular move orders.")] + public readonly Color TargetLineColor = Color.Green; + [GrantedConditionReference] [Desc("The condition to grant to self while airborne.")] public readonly string AirborneCondition = null; @@ -93,9 +117,6 @@ [Desc("Does this VTOL actor need to turn before landing (on terrain)?")] public readonly bool TurnToLand = false; - [Desc("Does this VTOL actor need to turn before landing on a resupplier?")] - public readonly bool TurnToDock = true; - [Desc("Does this actor automatically take off after resupplying?")] public readonly bool TakeOffOnResupply = false; @@ -130,7 +151,7 @@ public readonly int NumberOfTicksToVerifyAvailableAirport = 150; [Desc("Facing to use for actor previews (map editor, color picker, etc)")] - public readonly int PreviewFacing = 96; + public readonly WAngle PreviewFacing = new WAngle(384); [Desc("Display order for the facing slider in the map editor")] public readonly int EditorFacingDisplayOrder = 3; @@ -139,12 +160,19 @@ [Desc("Boolean expression defining the condition under which the regular (non-force) move cursor is disabled.")] public readonly BooleanExpression RequireForceMoveCondition = null; - public int GetInitialFacing() { return InitialFacing; } + [Desc("Cursor to display when able to land at target building.")] + public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to land at target building.")] + public readonly string EnterBlockedCursor = "enter-blocked"; + + public WAngle GetInitialFacing() { return InitialFacing; } public WDist GetCruiseAltitude() { return CruiseAltitude; } + public Color GetTargetLineColor() { return TargetLineColor; } public override object Create(ActorInitializer init) { return new Aircraft(init, this); } - IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) + IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) { yield return new FacingInit(PreviewFacing); } @@ -163,9 +191,6 @@ if (!LandableTerrainTypes.Contains(type)) return false; - if (world.WorldActor.Trait().GetBuildingAt(cell) != null) - return false; - if (check == BlockedByActor.None) return true; @@ -175,13 +200,13 @@ IEnumerable IEditorActorOptions.ActorOptions(ActorInfo ai, World world) { - yield return new EditorActorSlider("Facing", EditorFacingDisplayOrder, 0, 255, 8, + yield return new EditorActorSlider("Facing", EditorFacingDisplayOrder, 0, 1023, 8, actor => { - var init = actor.Init(); - return init != null ? init.Value(world) : InitialFacing; + var init = actor.GetInitOrDefault(this); + return (init != null ? init.Value : InitialFacing).Angle; }, - (actor, value) => actor.ReplaceInit(new FacingInit((int)value))); + (actor, value) => actor.ReplaceInit(new FacingInit(new WAngle((int)value)))); } } @@ -189,28 +214,49 @@ INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing, INotifyBecomingIdle, ICreationActivity, IActorPreviewInitModifier, IDeathActorInitModifier, IIssueDeployOrder, IIssueOrder, IResolveOrder, IOrderVoice { - static readonly Pair[] NoCells = { }; + static readonly (CPos, SubCell)[] NoCells = { }; readonly Actor self; Repairable repairable; Rearmable rearmable; IAircraftCenterPositionOffset[] positionOffsets; - ConditionManager conditionManager; IDisposable reservation; IEnumerable speedModifiers; INotifyMoving[] notifyMoving; INotifyVisualPositionChanged[] notifyVisualPositionChanged; IOverrideAircraftLanding overrideAircraftLanding; + WRot orientation; + [Sync] - public int Facing { get; set; } + public WAngle Facing + { + get { return orientation.Yaw; } + set { orientation = orientation.WithYaw(value); } + } + + public WAngle Pitch + { + get { return orientation.Pitch; } + set { orientation = orientation.WithPitch(value); } + } + + public WAngle Roll + { + get { return orientation.Roll; } + set { orientation = orientation.WithRoll(value); } + } + + public WRot Orientation { get { return orientation; } } [Sync] public WPos CenterPosition { get; private set; } public CPos TopLeft { get { return self.World.Map.CellContaining(CenterPosition); } } - public int TurnSpeed { get { return !IsTraitDisabled && !IsTraitPaused ? Info.TurnSpeed : 0; } } + public WAngle TurnSpeed { get { return !IsTraitDisabled && !IsTraitPaused ? Info.TurnSpeed : WAngle.Zero; } } + public WAngle? IdleTurnSpeed { get { return Info.IdleTurnSpeed; } } + public Actor ReservedActor { get; private set; } public bool MayYieldReservation { get; private set; } public bool ForceLanding { get; private set; } @@ -230,28 +276,28 @@ bool airborne; bool cruising; - int airborneToken = ConditionManager.InvalidConditionToken; - int cruisingToken = ConditionManager.InvalidConditionToken; + int airborneToken = Actor.InvalidConditionToken; + int cruisingToken = Actor.InvalidConditionToken; MovementType movementTypes; WPos cachedPosition; - int cachedFacing; + WAngle cachedFacing; public Aircraft(ActorInitializer init, AircraftInfo info) : base(info) { self = init.Self; - if (init.Contains()) - SetPosition(self, init.Get()); - - if (init.Contains()) - SetPosition(self, init.Get()); - - Facing = init.Contains() ? init.Get() : Info.InitialFacing; + var locationInit = init.GetOrDefault(); + if (locationInit != null) + SetPosition(self, locationInit.Value); + + var centerPositionInit = init.GetOrDefault(); + if (centerPositionInit != null) + SetPosition(self, centerPositionInit.Value); - if (init.Contains()) - creationActivityDelay = init.Get(); + Facing = init.GetValue(Info.InitialFacing); + creationActivityDelay = init.GetValue(0); } public WDist LandAltitude @@ -293,7 +339,6 @@ { repairable = self.TraitOrDefault(); rearmable = self.TraitOrDefault(); - conditionManager = self.TraitOrDefault(); speedModifiers = self.TraitsImplementing().ToArray().Select(sm => sm.GetSpeedModifier()); cachedPosition = self.CenterPosition; notifyMoving = self.TraitsImplementing().ToArray(); @@ -375,6 +420,15 @@ CurrentMovementTypes = newMovementTypes; + if (!CurrentMovementTypes.HasMovementType(MovementType.Horizontal)) + { + if (Info.Roll != WAngle.Zero && Roll != WAngle.Zero) + Roll = Util.TickFacing(Roll, WAngle.Zero, Info.RollSpeed); + + if (Info.Pitch != WAngle.Zero && Pitch != WAngle.Zero) + Pitch = Util.TickFacing(Pitch, WAngle.Zero, Info.PitchSpeed); + } + Repulse(); } @@ -389,7 +443,7 @@ // HACK: Prevent updating visibility twice per tick. We really shouldn't be // moving twice in a tick in the first place. notify = false; - SetPosition(self, CenterPosition + FlyStep(speed, repulsionForce.Yaw.Facing)); + SetPosition(self, CenterPosition + FlyStep(speed, repulsionForce.Yaw)); notify = true; } @@ -429,7 +483,7 @@ // The map bounds are in projected coordinates, which is technically wrong for this, // but we avoid the issues in practice by guessing the middle of the map instead of the edge var center = WPos.Lerp(self.World.Map.ProjectedTopLeft, self.World.Map.ProjectedBottomRight, 1, 2); - repulsionForce += new WVec(1024, 0, 0).Rotate(WRot.FromYaw((self.CenterPosition - center).Yaw)); + repulsionForce += new WVec(0, 1024, 0).Rotate(WRot.FromYaw((self.CenterPosition - center).Yaw)); } if (Info.CanSlide) @@ -546,22 +600,22 @@ get { return !IsTraitDisabled && !IsTraitPaused ? Util.ApplyPercentageModifiers(Info.Speed, speedModifiers) : 0; } } - public Pair[] OccupiedCells() + public (CPos Cell, SubCell SubCell)[] OccupiedCells() { if (!self.IsAtGroundLevel()) - return landingCells.Select(c => Pair.New(c, SubCell.FullCell)).ToArray(); + return landingCells.Select(c => (c, SubCell.FullCell)).ToArray(); - return new[] { Pair.New(TopLeft, SubCell.FullCell) }; + return new[] { (TopLeft, SubCell.FullCell) }; } - public WVec FlyStep(int facing) + public WVec FlyStep(WAngle facing) { return FlyStep(MovementSpeed, facing); } - public WVec FlyStep(int speed, int facing) + public WVec FlyStep(int speed, WAngle facing) { - var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing)); + var dir = new WVec(0, -1024, 0).Rotate(WRot.FromYaw(facing)); return speed * dir / 1024; } @@ -620,7 +674,7 @@ // We are not blocked by actors we can nudge out of the way // TODO: Generalize blocker checks and handling here and in Locomotor - if (!blockedByMobile && self.Owner.Stances[otherActor.Owner] == Stance.Ally && + if (!blockedByMobile && self.Owner.RelationshipWith(otherActor.Owner) == PlayerRelationship.Ally && otherActor.TraitOrDefault() != null && otherActor.CurrentActivity == null) return false; @@ -674,6 +728,12 @@ self.QueueActivity(new FlyOffMap(self)); self.QueueActivity(new RemoveSelf()); } + else if (Info.IdleBehavior == IdleBehaviorType.LeaveMapAtClosestEdge) + { + var edgeCell = self.World.Map.ChooseClosestEdgeCell(self.Location); + self.QueueActivity(new FlyOffMap(self, Target.FromCell(self.World, edgeCell))); + self.QueueActivity(new RemoveSelf()); + } else if (Info.IdleBehavior == IdleBehaviorType.ReturnToBase && GetActorBelow() == null) self.QueueActivity(new ReturnToBase(self, null, !Info.TakeOffOnResupply)); else @@ -819,20 +879,20 @@ return new Fly(self, Target.FromCell(self.World, cell), WDist.FromCells(nearEnough), targetLineColor: targetLineColor); } - public Activity MoveWithinRange(Target target, WDist range, + public Activity MoveWithinRange(in Target target, WDist range, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return new Fly(self, target, WDist.Zero, range, initialTargetPosition, targetLineColor); } - public Activity MoveWithinRange(Target target, WDist minRange, WDist maxRange, + public Activity MoveWithinRange(in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return new Fly(self, target, minRange, maxRange, initialTargetPosition, targetLineColor); } - public Activity MoveFollow(Actor self, Target target, WDist minRange, WDist maxRange, + public Activity MoveFollow(Actor self, in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return new FlyFollow(self, target, minRange, maxRange, @@ -878,13 +938,13 @@ } } - public Activity MoveToTarget(Actor self, Target target, + public Activity MoveToTarget(Actor self, in Target target, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return new Fly(self, target, initialTargetPosition, targetLineColor); } - public Activity MoveIntoTarget(Actor self, Target target) + public Activity MoveIntoTarget(Actor self, in Target target) { return new Land(self, target); } @@ -922,9 +982,11 @@ } } - public bool CanEnterTargetNow(Actor self, Target target) + public bool CanEnterTargetNow(Actor self, in Target target) { - if (target.Positions.Any(p => self.World.ActorMap.GetActorsAt(self.World.Map.CellContaining(p)).Any(a => a != self && a != target.Actor))) + // Lambdas can't use 'in' variables, so capture a copy for later + var targetActor = target; + if (target.Positions.Any(p => self.World.ActorMap.GetActorsAt(self.World.Map.CellContaining(p)).Any(a => a != self && a != targetActor.Actor))) return false; MakeReservation(target.Actor); @@ -939,11 +1001,19 @@ { get { - yield return new EnterAlliedActorTargeter("ForceEnter", 6, + yield return new EnterAlliedActorTargeter( + "ForceEnter", + 6, + Info.EnterCursor, + Info.EnterBlockedCursor, (target, modifiers) => Info.CanForceLand && modifiers.HasModifier(TargetModifiers.ForceMove) && AircraftCanEnter(target), target => Reservable.IsAvailableFor(target, self) && AircraftCanResupplyAt(target, true)); - yield return new EnterAlliedActorTargeter("Enter", 5, + yield return new EnterAlliedActorTargeter( + "Enter", + 5, + Info.EnterCursor, + Info.EnterBlockedCursor, AircraftCanEnter, target => Reservable.IsAvailableFor(target, self) && AircraftCanResupplyAt(target, !Info.TakeOffOnResupply)); @@ -951,7 +1021,7 @@ } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (!IsTraitDisabled && (order.OrderID == "Enter" || order.OrderID == "Move" || order.OrderID == "Land" || order.OrderID == "ForceEnter")) @@ -1016,7 +1086,7 @@ var target = Target.FromCell(self.World, cell); // TODO: this should scale with unit selection group size. - self.QueueActivity(order.Queued, new Fly(self, target, WDist.FromCells(8), targetLineColor: Color.Green)); + self.QueueActivity(order.Queued, new Fly(self, target, WDist.FromCells(8), targetLineColor: Info.TargetLineColor)); self.ShowTargetLines(); } else if (orderString == "Land") @@ -1030,7 +1100,7 @@ var target = Target.FromCell(self.World, cell); - self.QueueActivity(order.Queued, new Land(self, target, targetLineColor: Color.Green)); + self.QueueActivity(order.Queued, new Land(self, target, targetLineColor: Info.TargetLineColor)); self.ShowTargetLines(); } else if (orderString == "Enter" || orderString == "ForceEnter" || orderString == "Repair") @@ -1116,8 +1186,8 @@ return; airborne = true; - if (conditionManager != null && !string.IsNullOrEmpty(Info.AirborneCondition) && airborneToken == ConditionManager.InvalidConditionToken) - airborneToken = conditionManager.GrantCondition(self, Info.AirborneCondition); + if (airborneToken == Actor.InvalidConditionToken) + airborneToken = self.GrantCondition(Info.AirborneCondition); } void OnAirborneAltitudeLeft() @@ -1126,8 +1196,8 @@ return; airborne = false; - if (conditionManager != null && airborneToken != ConditionManager.InvalidConditionToken) - airborneToken = conditionManager.RevokeCondition(self, airborneToken); + if (airborneToken != Actor.InvalidConditionToken) + airborneToken = self.RevokeCondition(airborneToken); } #endregion @@ -1140,8 +1210,8 @@ return; cruising = true; - if (conditionManager != null && !string.IsNullOrEmpty(Info.CruisingCondition) && cruisingToken == ConditionManager.InvalidConditionToken) - cruisingToken = conditionManager.GrantCondition(self, Info.CruisingCondition); + if (cruisingToken == Actor.InvalidConditionToken) + cruisingToken = self.GrantCondition(Info.CruisingCondition); } void OnCruisingAltitudeLeft() @@ -1150,8 +1220,8 @@ return; cruising = false; - if (conditionManager != null && cruisingToken != ConditionManager.InvalidConditionToken) - cruisingToken = conditionManager.RevokeCondition(self, cruisingToken); + if (cruisingToken != Actor.InvalidConditionToken) + cruisingToken = self.RevokeCondition(cruisingToken); } #endregion @@ -1175,7 +1245,6 @@ public class AircraftMoveOrderTargeter : IOrderTargeter { readonly Aircraft aircraft; - readonly BuildingInfluence bi; public string OrderID { get; protected set; } public int OrderPriority { get { return 4; } } @@ -1184,11 +1253,10 @@ public AircraftMoveOrderTargeter(Aircraft aircraft) { this.aircraft = aircraft; - bi = aircraft.self.World.WorldActor.TraitOrDefault(); OrderID = "Move"; } - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { // Always prioritise orders over selecting other peoples actors or own actors that are already selected if (target.Type == TargetType.Actor && (target.Actor.Owner != self.Owner || self.World.Selection.Contains(target.Actor))) @@ -1197,7 +1265,7 @@ return modifiers.HasModifier(TargetModifiers.ForceMove); } - public virtual bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public virtual bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (target.Type != TargetType.Terrain || (aircraft.requireForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))) return false; @@ -1209,8 +1277,10 @@ // selection for left-mouse orders if (modifiers.HasModifier(TargetModifiers.ForceMove) && aircraft.Info.CanForceLand) { - var building = bi.GetBuildingAt(location); - if (building == null || building.TraitOrDefault() == null || aircraft.CanLand(location, blockedByMobile: false)) + var buildingAtLocation = self.World.ActorMap.GetActorsAt(location) + .Any(a => a.TraitOrDefault() != null && a.TraitOrDefault() != null); + + if (!buildingAtLocation || aircraft.CanLand(location, blockedByMobile: false)) OrderID = "Land"; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs openra-20210321/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Air/AttackAircraft.cs 2021-03-21 11:10:05.000000000 +0000 @@ -48,12 +48,12 @@ aircraftInfo = self.Info.TraitInfo(); } - public override Activity GetAttackActivity(Actor self, AttackSource source, Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null) + public override Activity GetAttackActivity(Actor self, AttackSource source, in Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null) { return new FlyAttack(self, source, newTarget, forceAttack, targetLineColor); } - protected override bool CanAttack(Actor self, Target target) + protected override bool CanAttack(Actor self, in Target target) { // Don't fire while landed or when outside the map. if (self.World.Map.DistanceAboveTerrain(self.CenterPosition).Length < aircraftInfo.MinAirborneAltitude @@ -63,7 +63,7 @@ if (!base.CanAttack(self, target)) return false; - return TargetInFiringArc(self, target, base.Info.FacingTolerance); + return TargetInFiringArc(self, target, Info.FacingTolerance); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs openra-20210321/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Air/AttackBomber.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,8 +19,8 @@ { public class AttackBomberInfo : AttackBaseInfo { - [Desc("Tolerance for attack angle. Range [0, 128], 128 covers 360 degrees.")] - public readonly new int FacingTolerance = 2; + [Desc("Tolerance for attack angle. Range [0, 512], 512 covers 360 degrees.")] + public readonly new WAngle FacingTolerance = new WAngle(8); public override object Create(ActorInitializer init) { return new AttackBomber(init.Self, this); } } @@ -50,27 +50,30 @@ void ITick.Tick(Actor self) { - var dat = self.World.Map.DistanceAboveTerrain(target.CenterPosition); - target = Target.FromPos(target.CenterPosition - new WVec(WDist.Zero, WDist.Zero, dat)); var wasInAttackRange = inAttackRange; - var wasFacingTarget = facingTarget; - inAttackRange = false; - facingTarget = TargetInFiringArc(self, target, info.FacingTolerance); - - foreach (var a in Armaments) + if (self.IsInWorld) { - if (!target.IsInRange(self.CenterPosition, a.MaxRange())) - continue; + var dat = self.World.Map.DistanceAboveTerrain(target.CenterPosition); + target = Target.FromPos(target.CenterPosition - new WVec(WDist.Zero, WDist.Zero, dat)); - inAttackRange = true; - a.CheckFire(self, facing, target); - } + var wasFacingTarget = facingTarget; + facingTarget = TargetInFiringArc(self, target, info.FacingTolerance); - // Actors without armaments may want to trigger an action when it passes the target - if (!Armaments.Any()) - inAttackRange = !wasInAttackRange && !facingTarget && wasFacingTarget; + foreach (var a in Armaments) + { + if (!target.IsInRange(self.CenterPosition, a.MaxRange())) + continue; + + inAttackRange = true; + a.CheckFire(self, facing, target); + } + + // Actors without armaments may want to trigger an action when it passes the target + if (!Armaments.Any()) + inAttackRange = !wasInAttackRange && !facingTarget && wasFacingTarget; + } if (inAttackRange && !wasInAttackRange) OnEnteredAttackRange(self); @@ -86,7 +89,7 @@ OnRemovedFromWorld(self); } - public override Activity GetAttackActivity(Actor self, AttackSource source, Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor) + public override Activity GetAttackActivity(Actor self, AttackSource source, in Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor) { throw new NotImplementedException("AttackBomber requires a scripted target"); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Air/FallsToEarth.cs openra-20210321/OpenRA.Mods.Common/Traits/Air/FallsToEarth.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Air/FallsToEarth.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Air/FallsToEarth.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,15 +16,15 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Causes aircraft husks that are spawned in the air to crash to the ground.")] - public class FallsToEarthInfo : ITraitInfo, IRulesetLoaded, Requires + public class FallsToEarthInfo : TraitInfo, IRulesetLoaded, Requires { [WeaponReference] [Desc("Explosion weapon that triggers when hitting ground.")] public readonly string Explosion = "UnitExplode"; - [Desc("Limit the maximum spin (in facing units per tick) that can be achieved while crashing.", - "0 disables spinning. Negative values imply no limit.")] - public readonly int MaximumSpinSpeed = -1; + [Desc("Limit the maximum spin (in angle units per tick) that can be achieved while crashing.", + "0 disables spinning. Leave undefined for no limit.")] + public readonly WAngle? MaximumSpinSpeed = null; [Desc("Does the aircraft (husk) move forward at aircraft speed?")] public readonly bool Moves = false; @@ -34,15 +34,14 @@ public WeaponInfo ExplosionWeapon { get; private set; } - public object Create(ActorInitializer init) { return new FallsToEarth(init, this); } + public override object Create(ActorInitializer init) { return new FallsToEarth(init, this); } public void RulesetLoaded(Ruleset rules, ActorInfo ai) { if (string.IsNullOrEmpty(Explosion)) return; - WeaponInfo weapon; var weaponToLower = Explosion.ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(weaponToLower, out weapon)) + if (!rules.Weapons.TryGetValue(weaponToLower, out var weapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); ExplosionWeapon = weapon; @@ -57,7 +56,7 @@ public FallsToEarth(ActorInitializer init, FallsToEarthInfo info) { this.info = info; - effectiveOwner = init.Contains() ? init.Get() : init.Self.Owner; + effectiveOwner = init.GetValue(info, init.Self.Owner); } // We return init.Self.Owner if there's no effective owner diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/AmmoPool.cs openra-20210321/OpenRA.Mods.Common/Traits/AmmoPool.cs --- openra-20200503/OpenRA.Mods.Common/Traits/AmmoPool.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/AmmoPool.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Actor has a limited amount of ammo, after using it all the actor must reload in some way.")] - public class AmmoPoolInfo : ITraitInfo + public class AmmoPoolInfo : TraitInfo { [Desc("Name of this ammo pool, used to link reload traits to this pool.")] public readonly string Name = "primary"; @@ -30,15 +30,6 @@ [Desc("Initial ammo the actor is created with. Defaults to Ammo.")] public readonly int InitialAmmo = -1; - [Desc("Defaults to value in Ammo. 0 means no visible pips.")] - public readonly int PipCount = -1; - - [Desc("PipType to use for loaded ammo.")] - public readonly PipType PipType = PipType.Green; - - [Desc("PipType to use for empty ammo.")] - public readonly PipType PipTypeEmpty = PipType.Transparent; - [Desc("How much ammo is reloaded after a certain period.")] public readonly int ReloadCount = 1; @@ -53,14 +44,13 @@ [Desc("The condition to grant to self for each ammo point in this pool.")] public readonly string AmmoCondition = null; - public object Create(ActorInitializer init) { return new AmmoPool(init.Self, this); } + public override object Create(ActorInitializer init) { return new AmmoPool(init.Self, this); } } - public class AmmoPool : INotifyCreated, INotifyAttack, IPips, ISync + public class AmmoPool : INotifyCreated, INotifyAttack, ISync { public readonly AmmoPoolInfo Info; readonly Stack tokens = new Stack(); - ConditionManager conditionManager; // HACK: Temporarily needed until Rearm activity is gone for good [Sync] @@ -100,40 +90,30 @@ void INotifyCreated.Created(Actor self) { - conditionManager = self.TraitOrDefault(); UpdateCondition(self); // HACK: Temporarily needed until Rearm activity is gone for good RemainingTicks = Info.ReloadDelay; } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (a != null && Info.Armaments.Contains(a.Info.Name)) TakeAmmo(self, 1); } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { } + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { } void UpdateCondition(Actor self) { - if (conditionManager == null || string.IsNullOrEmpty(Info.AmmoCondition)) + if (string.IsNullOrEmpty(Info.AmmoCondition)) return; while (CurrentAmmoCount > tokens.Count && tokens.Count < Info.Ammo) - tokens.Push(conditionManager.GrantCondition(self, Info.AmmoCondition)); + tokens.Push(self.GrantCondition(Info.AmmoCondition)); while (CurrentAmmoCount < tokens.Count && tokens.Count > 0) - conditionManager.RevokeCondition(self, tokens.Pop()); - } - - public IEnumerable GetPips(Actor self) - { - var pips = Info.PipCount >= 0 ? Info.PipCount : Info.Ammo; - - return Enumerable.Range(0, pips).Select(i => - (CurrentAmmoCount * pips) / Info.Ammo > i ? - Info.PipType : Info.PipTypeEmpty); + self.RevokeCondition(tokens.Pop()); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/AppearsOnMapPreview.cs openra-20210321/OpenRA.Mods.Common/Traits/AppearsOnMapPreview.cs --- openra-20200503/OpenRA.Mods.Common/Traits/AppearsOnMapPreview.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/AppearsOnMapPreview.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Collections.Generic; using System.Linq; -using OpenRA.Graphics; using OpenRA.Primitives; using OpenRA.Traits; @@ -27,7 +26,7 @@ "Overrides `Color` if both set.")] public readonly string Terrain = null; - void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List> destinationBuffer) + void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer) { var tileSet = map.Rules.TileSet; @@ -42,16 +41,16 @@ } else { - var owner = map.PlayerDefinitions.Where(p => s.InitDict.Get().PlayerName == p.Value.Nodes.First(k => k.Key == "Name").Value.Value).First(); + var owner = map.PlayerDefinitions.Single(p => s.Get().InternalName == p.Value.Nodes.Last(k => k.Key == "Name").Value.Value); var colorValue = owner.Value.Nodes.Where(n => n.Key == "Color"); var ownerColor = colorValue.Any() ? colorValue.First().Value.Value : "FFFFFF"; Color.TryParse(ownerColor, out color); } var ios = ai.TraitInfo(); - var cells = ios.OccupiedCells(ai, s.InitDict.Get().Value(null)); + var cells = ios.OccupiedCells(ai, s.Get().Value); foreach (var cell in cells) - destinationBuffer.Add(new Pair(cell.Key.ToMPos(map), color)); + destinationBuffer.Add((cell.Key.ToMPos(map), color)); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Armament.cs openra-20210321/OpenRA.Mods.Common/Traits/Armament.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Armament.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Armament.cs 2021-03-21 11:10:05.000000000 +0000 @@ -53,6 +53,7 @@ [Desc("Recoil recovery per-frame")] public readonly WDist RecoilRecovery = new WDist(9); + [SequenceReference] [Desc("Muzzle flash sequence to render")] public readonly string MuzzleSequence = null; @@ -60,9 +61,6 @@ [Desc("Palette to render Muzzle flash sequence in")] public readonly string MuzzlePalette = "effect"; - [Desc("Use multiple muzzle images if non-zero")] - public readonly int MuzzleSplitFacings = 0; - [GrantedConditionReference] [Desc("Condition to grant while reloading.")] public readonly string ReloadingCondition = null; @@ -70,25 +68,25 @@ public WeaponInfo WeaponInfo { get; private set; } public WDist ModifiedRange { get; private set; } - public readonly Stance TargetStances = Stance.Enemy; - public readonly Stance ForceTargetStances = Stance.Enemy | Stance.Neutral | Stance.Ally; + public readonly PlayerRelationship TargetRelationships = PlayerRelationship.Enemy; + public readonly PlayerRelationship ForceTargetRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral | PlayerRelationship.Ally; // TODO: instead of having multiple Armaments and unique AttackBase, // an actor should be able to have multiple AttackBases with // a single corresponding Armament each + [Desc("Cursor to display when hovering over a valid target.")] public readonly string Cursor = "attack"; // TODO: same as above + [Desc("Cursor to display when hovering over a valid target that is outside of range.")] public readonly string OutsideRangeCursor = "attackoutsiderange"; public override object Create(ActorInitializer init) { return new Armament(init.Self, this); } public override void RulesetLoaded(Ruleset rules, ActorInfo ai) { - WeaponInfo weaponInfo; - var weaponToLower = Weapon.ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(weaponToLower, out weaponInfo)) + if (!rules.Weapons.TryGetValue(weaponToLower, out var weaponInfo)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); WeaponInfo = weaponInfo; @@ -114,8 +112,7 @@ INotifyBurstComplete[] notifyBurstComplete; INotifyAttack[] notifyAttacks; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; IEnumerable rangeModifiers; IEnumerable reloadModifiers; @@ -126,7 +123,7 @@ int currentBarrel; int barrelCount; - List> delayedActions = new List>(); + List<(int Ticks, Action Func)> delayedActions = new List<(int, Action)>(); public WDist Recoil; public int FireDelay { get; protected set; } @@ -169,7 +166,6 @@ coords = self.Trait(); notifyBurstComplete = self.TraitsImplementing().ToArray(); notifyAttacks = self.TraitsImplementing().ToArray(); - conditionManager = self.TraitOrDefault(); rangeModifiers = self.TraitsImplementing().ToArray().Select(m => m.GetRangeModifier()); reloadModifiers = self.TraitsImplementing().ToArray().Select(m => m.GetReloadModifier()); @@ -181,15 +177,15 @@ void UpdateCondition(Actor self) { - if (string.IsNullOrEmpty(Info.ReloadingCondition) || conditionManager == null) + if (string.IsNullOrEmpty(Info.ReloadingCondition)) return; var enabled = !IsTraitDisabled && IsReloading; - if (enabled && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, Info.ReloadingCondition); - else if (!enabled && conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (enabled && conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(Info.ReloadingCondition); + else if (!enabled && conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); } protected virtual void Tick(Actor self) @@ -211,12 +207,12 @@ for (var i = 0; i < delayedActions.Count; i++) { var x = delayedActions[i]; - if (--x.First <= 0) - x.Second(); + if (--x.Ticks <= 0) + x.Func(); delayedActions[i] = x; } - delayedActions.RemoveAll(a => a.First <= 0); + delayedActions.RemoveAll(a => a.Ticks <= 0); } void ITick.Tick(Actor self) @@ -228,12 +224,12 @@ protected void ScheduleDelayedAction(int t, Action a) { if (t > 0) - delayedActions.Add(Pair.New(t, a)); + delayedActions.Add((t, a)); else a(); } - protected virtual bool CanFire(Actor self, Target target) + protected virtual bool CanFire(Actor self, in Target target) { if (IsReloading || IsTraitPaused) return false; @@ -253,7 +249,7 @@ // Note: facing is only used by the legacy positioning code // The world coordinate model uses Actor.Orientation - public virtual Barrel CheckFire(Actor self, IFacing facing, Target target) + public virtual Barrel CheckFire(Actor self, IFacing facing, in Target target) { if (!CanFire(self, target)) return null; @@ -275,14 +271,14 @@ return barrel; } - protected virtual void FireBarrel(Actor self, IFacing facing, Target target, Barrel barrel) + protected virtual void FireBarrel(Actor self, IFacing facing, in Target target, Barrel barrel) { foreach (var na in notifyAttacks) na.PreparingAttack(self, target, this, barrel); Func muzzlePosition = () => self.CenterPosition + MuzzleOffset(self, barrel); - var legacyFacing = MuzzleOrientation(self, barrel).Yaw.Angle / 4; - Func legacyMuzzleFacing = () => MuzzleOrientation(self, barrel).Yaw.Angle / 4; + Func muzzleFacing = () => MuzzleOrientation(self, barrel).Yaw; + var muzzleOrientation = WRot.FromYaw(muzzleFacing()); var passiveTarget = Weapon.TargetActorCenter ? target.CenterPosition : target.Positions.PositionClosestTo(muzzlePosition()); var initialOffset = Weapon.FirstBurstTargetOffset; @@ -290,7 +286,7 @@ { // We want this to match Armament.LocalOffset, so we need to convert it to forward, right, up initialOffset = new WVec(initialOffset.Y, -initialOffset.X, initialOffset.Z); - passiveTarget += initialOffset.Rotate(WRot.FromFacing(legacyFacing)); + passiveTarget += initialOffset.Rotate(muzzleOrientation); } var followingOffset = Weapon.FollowingBurstTargetOffset; @@ -298,14 +294,14 @@ { // We want this to match Armament.LocalOffset, so we need to convert it to forward, right, up followingOffset = new WVec(followingOffset.Y, -followingOffset.X, followingOffset.Z); - passiveTarget += ((Weapon.Burst - Burst) * followingOffset).Rotate(WRot.FromFacing(legacyFacing)); + passiveTarget += ((Weapon.Burst - Burst) * followingOffset).Rotate(muzzleOrientation); } var args = new ProjectileArgs { Weapon = Weapon, - Facing = legacyFacing, - CurrentMuzzleFacing = legacyMuzzleFacing, + Facing = muzzleFacing(), + CurrentMuzzleFacing = muzzleFacing, DamageModifiers = damageModifiers.ToArray(), @@ -320,6 +316,8 @@ GuidedTarget = target }; + // Lambdas can't use 'in' variables, so capture a copy for later + var delayedTarget = target; ScheduleDelayedAction(Info.FireDelay, () => { if (args.Weapon.Projectile != null) @@ -335,14 +333,14 @@ Game.Sound.Play(SoundType.World, args.Weapon.StartBurstReport, self.World, self.CenterPosition); foreach (var na in notifyAttacks) - na.Attacking(self, target, this, barrel); + na.Attacking(self, delayedTarget, this, barrel); Recoil = Info.Recoil; } }); } - protected virtual void UpdateBurst(Actor self, Target target) + protected virtual void UpdateBurst(Actor self, in Target target) { if (--Burst > 0) { @@ -374,19 +372,18 @@ protected virtual WVec CalculateMuzzleOffset(Actor self, Barrel b) { - var bodyOrientation = coords.QuantizeOrientation(self, self.Orientation); + // Weapon offset in turret coordinates var localOffset = b.Offset + new WVec(-Recoil, WDist.Zero, WDist.Zero); + + // Turret coordinates to body coordinates + var bodyOrientation = coords.QuantizeOrientation(self, self.Orientation); if (turret != null) - { - // WorldOrientation is quantized to satisfy the *Fudges. - // Need to then convert back to a pseudo-local coordinate space, apply offsets, - // then rotate back at the end - var turretOrientation = turret.WorldOrientation(self) - bodyOrientation; - localOffset = localOffset.Rotate(turretOrientation); - localOffset += turret.Offset; - } + localOffset = localOffset.Rotate(turret.WorldOrientation) + turret.Offset.Rotate(bodyOrientation); + else + localOffset = localOffset.Rotate(bodyOrientation); - return coords.LocalToWorld(localOffset.Rotate(bodyOrientation)); + // Body coordinates to world coordinates + return coords.LocalToWorld(localOffset); } public WRot MuzzleOrientation(Actor self, Barrel b) @@ -396,10 +393,7 @@ protected virtual WRot CalculateMuzzleOrientation(Actor self, Barrel b) { - var orientation = turret != null ? turret.WorldOrientation(self) : - coords.QuantizeOrientation(self, self.Orientation); - - return orientation + WRot.FromYaw(b.Yaw); + return WRot.FromYaw(b.Yaw).Rotate(turret != null ? turret.WorldOrientation : self.Orientation); } public Actor Actor { get { return self; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackBase.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,6 @@ using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Warheads; using OpenRA.Primitives; -using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -28,8 +27,10 @@ [Desc("Armament names")] public readonly string[] Armaments = { "primary", "secondary" }; + [Desc("Cursor to display when hovering over a valid target.")] public readonly string Cursor = null; + [Desc("Cursor to display when hovering over a valid target that is outside of range.")] public readonly string OutsideRangeCursor = null; [Desc("Color to use for the target line.")] @@ -51,14 +52,14 @@ public readonly string Voice = "Action"; [Desc("Tolerance for attack angle. Range [0, 128], 128 covers 360 degrees.")] - public readonly int FacingTolerance = 128; + public readonly WAngle FacingTolerance = new WAngle(512); public override void RulesetLoaded(Ruleset rules, ActorInfo ai) { base.RulesetLoaded(rules, ai); - if (FacingTolerance < 0 || FacingTolerance > 128) - throw new YamlException("Facing tolerance must be in range of [0, 128], 128 covers 360 degrees."); + if (FacingTolerance.Angle > 512) + throw new YamlException("Facing tolerance must be in range of [0, 512], 512 covers 360 degrees."); } public override abstract object Create(ActorInitializer init); @@ -125,7 +126,7 @@ return () => armaments; } - public bool TargetInFiringArc(Actor self, Target target, int facingTolerance) + public bool TargetInFiringArc(Actor self, in Target target, WAngle facingTolerance) { if (facing == null) return true; @@ -137,10 +138,10 @@ if (delta.HorizontalLengthSquared == 0) return true; - return Util.FacingWithinTolerance(facing.Facing, delta.Yaw.Facing, facingTolerance); + return Util.FacingWithinTolerance(facing.Facing, delta.Yaw, facingTolerance); } - protected virtual bool CanAttack(Actor self, Target target) + protected virtual bool CanAttack(Actor self, in Target target) { if (!self.IsInWorld || IsTraitDisabled || IsTraitPaused) return false; @@ -161,7 +162,7 @@ return true; } - public virtual void DoAttack(Actor self, Target target) + public virtual void DoAttack(Actor self, in Target target) { if (!CanAttack(self, target)) return; @@ -185,7 +186,7 @@ } } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order is AttackOrderTargeter) return new Order(order.OrderID, self, target, queued); @@ -225,9 +226,9 @@ return order.OrderString == attackOrderName || order.OrderString == forceAttackOrderName ? Info.Voice : null; } - public abstract Activity GetAttackActivity(Actor self, AttackSource source, Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null); + public abstract Activity GetAttackActivity(Actor self, AttackSource source, in Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null); - public bool HasAnyValidWeapons(Target t, bool checkForCenterTargetingWeapons = false) + public bool HasAnyValidWeapons(in Target t, bool checkForCenterTargetingWeapons = false) { if (IsTraitDisabled) return false; @@ -246,7 +247,7 @@ return false; } - public virtual WPos GetTargetPosition(WPos pos, Target target) + public virtual WPos GetTargetPosition(WPos pos, in Target target) { return HasAnyValidWeapons(target, true) ? target.CenterPosition : target.Positions.PositionClosestTo(pos); } @@ -297,7 +298,7 @@ return max; } - public WDist GetMinimumRangeVersusTarget(Target target) + public WDist GetMinimumRangeVersusTarget(in Target target) { if (IsTraitDisabled) return WDist.Zero; @@ -323,7 +324,7 @@ return min != WDist.MaxValue ? min : WDist.Zero; } - public WDist GetMaximumRangeVersusTarget(Target target) + public WDist GetMaximumRangeVersusTarget(in Target target) { if (IsTraitDisabled) return WDist.Zero; @@ -370,29 +371,17 @@ // (short-circuiting in the logical expression below) Player owner = null; if (t.Type == TargetType.FrozenActor) - { owner = t.FrozenActor.Owner; - } else if (t.Type == TargetType.Actor) - { - owner = t.Actor.EffectiveOwner != null && t.Actor.EffectiveOwner.Owner != null - ? t.Actor.EffectiveOwner.Owner - : t.Actor.Owner; - - // Special cases for spies so we don't kill friendly disguised spies - // and enable dogs to kill enemy disguised spies. - if (self.Owner.Stances[t.Actor.Owner] == Stance.Ally || self.Info.HasTraitInfo()) - owner = t.Actor.Owner; - } + owner = t.Actor.Owner; return Armaments.Where(a => !a.IsTraitDisabled - && (owner == null || (forceAttack ? a.Info.ForceTargetStances : a.Info.TargetStances) - .HasStance(self.Owner.Stances[owner])) + && (owner == null || (forceAttack ? a.Info.ForceTargetRelationships : a.Info.TargetRelationships).HasStance(self.Owner.RelationshipWith(owner))) && a.Weapon.IsValidAgainst(t, self.World, self)); } - public void AttackTarget(Target target, AttackSource source, bool queued, bool allowMove, bool forceAttack = false, Color? targetLineColor = null) + public void AttackTarget(in Target target, AttackSource source, bool queued, bool allowMove, bool forceAttack = false, Color? targetLineColor = null) { if (IsTraitDisabled) return; @@ -405,21 +394,21 @@ OnResolveAttackOrder(self, activity, target, queued, forceAttack); } - public virtual void OnResolveAttackOrder(Actor self, Activity activity, Target target, bool queued, bool forceAttack) { } + public virtual void OnResolveAttackOrder(Actor self, Activity activity, in Target target, bool queued, bool forceAttack) { } - public bool IsReachableTarget(Target target, bool allowMove) + public bool IsReachableTarget(in Target target, bool allowMove) { return HasAnyValidWeapons(target) && (target.IsInRange(self.CenterPosition, GetMaximumRangeVersusTarget(target)) || (allowMove && self.Info.HasTraitInfo())); } - public Stance UnforcedAttackTargetStances() + public PlayerRelationship UnforcedAttackTargetStances() { // PERF: Avoid LINQ. - var stances = Stance.None; + var stances = PlayerRelationship.None; foreach (var armament in Armaments) if (!armament.IsTraitDisabled) - stances |= armament.Info.TargetStances; + stances |= armament.Info.TargetRelationships; return stances; } @@ -437,9 +426,9 @@ public string OrderID { get; private set; } public int OrderPriority { get; private set; } - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } - bool CanTargetActor(Actor self, Target target, ref TargetModifiers modifiers, ref string cursor) + bool CanTargetActor(Actor self, in Target target, ref TargetModifiers modifiers, ref string cursor) { IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue); @@ -454,7 +443,7 @@ // targeting and attacking logic (which should be logically separate) // to use the same code if (target.Type == TargetType.Actor && target.Actor.EffectiveOwner != null && - target.Actor.EffectiveOwner.Disguised && self.Owner.Stances[target.Actor.Owner] == Stance.Enemy) + target.Actor.EffectiveOwner.Disguised && self.Owner.RelationshipWith(target.Actor.Owner) == PlayerRelationship.Enemy) modifiers |= TargetModifiers.ForceAttack; var forceAttack = modifiers.HasModifier(TargetModifiers.ForceAttack); @@ -515,7 +504,7 @@ return true; } - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { switch (target.Type) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackCharges.cs openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackCharges.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackCharges.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackCharges.cs 2021-03-21 11:10:05.000000000 +0000 @@ -35,8 +35,7 @@ public class AttackCharges : AttackOmni, INotifyAttack, INotifySold { readonly AttackChargesInfo info; - ConditionManager conditionManager; - int chargingToken = ConditionManager.InvalidConditionToken; + int chargingToken = Actor.InvalidConditionToken; bool charging; public int ChargeLevel { get; private set; } @@ -47,13 +46,6 @@ this.info = info; } - protected override void Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - - base.Created(self); - } - protected override void Tick(Actor self) { // Stop charging when we lose our target @@ -62,24 +54,23 @@ var delta = charging ? info.ChargeRate : -info.DischargeRate; ChargeLevel = (ChargeLevel + delta).Clamp(0, info.ChargeLevel); - if (ChargeLevel > 0 && conditionManager != null && !string.IsNullOrEmpty(info.ChargingCondition) - && chargingToken == ConditionManager.InvalidConditionToken) - chargingToken = conditionManager.GrantCondition(self, info.ChargingCondition); + if (ChargeLevel > 0 && chargingToken == Actor.InvalidConditionToken) + chargingToken = self.GrantCondition(info.ChargingCondition); - if (ChargeLevel == 0 && conditionManager != null && chargingToken != ConditionManager.InvalidConditionToken) - chargingToken = conditionManager.RevokeCondition(self, chargingToken); + if (ChargeLevel == 0 && chargingToken != Actor.InvalidConditionToken) + chargingToken = self.RevokeCondition(chargingToken); base.Tick(self); } - protected override bool CanAttack(Actor self, Target target) + protected override bool CanAttack(Actor self, in Target target) { charging = base.CanAttack(self, target) && IsReachableTarget(target, true); return ChargeLevel >= info.ChargeLevel && charging; } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) { ChargeLevel = 0; } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { } + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { ChargeLevel = 0; } + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { } void INotifySold.Selling(Actor self) { ChargeLevel = 0; } void INotifySold.Sold(Actor self) { } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs 2021-03-21 11:10:05.000000000 +0000 @@ -27,6 +27,9 @@ [Desc("Keep firing on targets even after attack order is cancelled")] public readonly bool PersistentTargeting = true; + [Desc("Range to stay away from min and max ranges to give some leeway if the target starts moving.")] + public readonly WDist RangeMargin = WDist.FromCells(1); + public override object Create(ActorInitializer init) { return new AttackFollow(init.Self, this); } } @@ -43,7 +46,7 @@ bool opportunityForceAttack; bool opportunityTargetIsPersistentTarget; - public void SetRequestedTarget(Actor self, Target target, bool isForceAttack = false) + public void SetRequestedTarget(Actor self, in Target target, bool isForceAttack = false) { RequestedTarget = target; requestedForceAttack = isForceAttack; @@ -76,7 +79,7 @@ base.Created(self); } - protected bool CanAimAtTarget(Actor self, Target target, bool forceAttack) + protected bool CanAimAtTarget(Actor self, in Target target, bool forceAttack) { if (target.Type == TargetType.Actor && !target.Actor.CanBeViewedByPlayer(self.Owner)) return false; @@ -108,8 +111,7 @@ // requestedTargetPresetForActivity will be cleared once the activity starts running and calls UpdateRequestedTarget if (self.CurrentActivity != null && self.CurrentActivity.NextActivity == requestedTargetPresetForActivity) { - bool targetIsHiddenActor; - RequestedTarget = RequestedTarget.Recalculate(self.Owner, out targetIsHiddenActor); + RequestedTarget = RequestedTarget.Recalculate(self.Owner, out _); } // Requested activity has been canceled @@ -152,12 +154,12 @@ base.Tick(self); } - public override Activity GetAttackActivity(Actor self, AttackSource source, Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null) + public override Activity GetAttackActivity(Actor self, AttackSource source, in Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null) { return new AttackActivity(self, newTarget, allowMove, forceAttack, targetLineColor); } - public override void OnResolveAttackOrder(Actor self, Activity activity, Target target, bool queued, bool forceAttack) + public override void OnResolveAttackOrder(Actor self, Activity activity, in Target target, bool queued, bool forceAttack) { // We can improve responsiveness for turreted actors by preempting // the last order (usually a move) and setting the target immediately @@ -226,7 +228,7 @@ bool wasMovingWithinRange; bool hasTicked; - public AttackActivity(Actor self, Target target, bool allowMove, bool forceAttack, Color? targetLineColor = null) + public AttackActivity(Actor self, in Target target, bool allowMove, bool forceAttack, Color? targetLineColor = null) { attack = self.Trait(); move = allowMove ? self.TraitOrDefault() : null; @@ -271,8 +273,7 @@ if (attack.IsTraitPaused) return false; - bool targetIsHiddenActor; - target = target.Recalculate(self.Owner, out targetIsHiddenActor); + target = target.Recalculate(self.Owner, out var targetIsHiddenActor); attack.SetRequestedTarget(self, target, forceAttack); hasTicked = true; @@ -284,12 +285,12 @@ lastVisibleOwner = target.Actor.Owner; lastVisibleTargetTypes = target.Actor.GetEnabledTargetTypes(); - // Try and sit at least one cell away from the min or max ranges to give some leeway if the target starts moving. - if (move != null && target.Actor.Info.HasTraitInfo()) + var leeway = attack.Info.RangeMargin.Length; + if (leeway != 0 && move != null && target.Actor.Info.HasTraitInfo()) { - var preferMinRange = Math.Min(lastVisibleMinimumRange.Length + 1024, lastVisibleMaximumRange.Length); - var preferMaxRange = Math.Max(lastVisibleMaximumRange.Length - 1024, lastVisibleMinimumRange.Length); - lastVisibleMaximumRange = new WDist((lastVisibleMaximumRange.Length - 1024).Clamp(preferMinRange, preferMaxRange)); + var preferMinRange = Math.Min(lastVisibleMinimumRange.Length + leeway, lastVisibleMaximumRange.Length); + var preferMaxRange = Math.Max(lastVisibleMaximumRange.Length - leeway, lastVisibleMinimumRange.Length); + lastVisibleMaximumRange = new WDist((lastVisibleMaximumRange.Length - leeway).Clamp(preferMinRange, preferMaxRange)); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackFrontal.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,8 +18,8 @@ [Desc("Unit got to face the target")] public class AttackFrontalInfo : AttackBaseInfo, Requires { - [Desc("Tolerance for attack angle. Range [0, 128], 128 covers 360 degrees.")] - public readonly new int FacingTolerance = 0; + [Desc("Tolerance for attack angle. Range [0, 512], 512 covers 360 degrees.")] + public readonly new WAngle FacingTolerance = WAngle.Zero; public override object Create(ActorInitializer init) { return new AttackFrontal(init.Self, this); } } @@ -34,7 +34,7 @@ Info = info; } - protected override bool CanAttack(Actor self, Target target) + protected override bool CanAttack(Actor self, in Target target) { if (!base.CanAttack(self, target)) return false; @@ -42,7 +42,7 @@ return TargetInFiringArc(self, target, Info.FacingTolerance); } - public override Activity GetAttackActivity(Actor self, AttackSource source, Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null) + public override Activity GetAttackActivity(Actor self, AttackSource source, in Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null) { return new Activities.Attack(self, newTarget, allowMove, forceAttack, targetLineColor); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackGarrisoned.cs 2021-03-21 11:10:05.000000000 +0000 @@ -123,7 +123,7 @@ FirePort SelectFirePort(Actor self, WAngle targetYaw) { // Pick a random port that faces the target - var bodyYaw = facing != null ? WAngle.FromFacing(facing.Facing) : WAngle.Zero; + var bodyYaw = facing != null ? facing.Facing : WAngle.Zero; var indices = Enumerable.Range(0, Info.Ports.Length).Shuffle(self.World.SharedRandom); foreach (var i in indices) { @@ -143,7 +143,7 @@ return coords.Value.LocalToWorld(p.Offset.Rotate(bodyOrientation)); } - public override void DoAttack(Actor self, Target target) + public override void DoAttack(Actor self, in Target target) { if (!CanAttack(self, target)) return; @@ -161,8 +161,7 @@ if (port == null) return; - var muzzleFacing = targetYaw.Angle / 4; - paxFacing[a.Actor].Facing = muzzleFacing; + paxFacing[a.Actor].Facing = targetYaw; paxPos[a.Actor].SetVisualPosition(a.Actor, pos + PortOffset(self, port)); var barrel = a.CheckFire(a.Actor, facing, target); @@ -172,12 +171,8 @@ if (a.Info.MuzzleSequence != null) { // Muzzle facing is fixed once the firing starts - var muzzleAnim = new Animation(self.World, paxRender[a.Actor].GetImage(a.Actor), () => muzzleFacing); + var muzzleAnim = new Animation(self.World, paxRender[a.Actor].GetImage(a.Actor), () => targetYaw); var sequence = a.Info.MuzzleSequence; - - if (a.Info.MuzzleSplitFacings > 0) - sequence += Util.QuantizeFacing(muzzleFacing, a.Info.MuzzleSplitFacings).ToString(); - var muzzleFlash = new AnimationWithOffset(muzzleAnim, () => PortOffset(self, port), () => false, diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackOmni.cs openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackOmni.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackOmni.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackOmni.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Collections.Generic; using OpenRA.Activities; -using OpenRA.Mods.Common.Activities; using OpenRA.Primitives; using OpenRA.Traits; @@ -27,7 +26,7 @@ public AttackOmni(Actor self, AttackOmniInfo info) : base(self, info) { } - public override Activity GetAttackActivity(Actor self, AttackSource source, Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null) + public override Activity GetAttackActivity(Actor self, AttackSource source, in Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor = null) { return new SetTarget(this, newTarget, allowMove, forceAttack, targetLineColor); } @@ -41,7 +40,7 @@ readonly Color? targetLineColor; Target target; - public SetTarget(AttackOmni attack, Target target, bool allowMove, bool forceAttack, Color? targetLineColor = null) + public SetTarget(AttackOmni attack, in Target target, bool allowMove, bool forceAttack, Color? targetLineColor = null) { this.target = target; this.targetLineColor = targetLineColor; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackTurreted.cs openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackTurreted.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Attack/AttackTurreted.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Attack/AttackTurreted.cs 2021-03-21 11:10:05.000000000 +0000 @@ -33,7 +33,7 @@ turrets = self.TraitsImplementing().Where(t => info.Turrets.Contains(t.Info.Turret)).ToArray(); } - protected override bool CanAttack(Actor self, Target target) + protected override bool CanAttack(Actor self, in Target target) { if (target.Type == TargetType.Invalid) return false; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/AttackMove.cs openra-20210321/OpenRA.Mods.Common/Traits/AttackMove.cs --- openra-20200503/OpenRA.Mods.Common/Traits/AttackMove.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/AttackMove.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Collections.Generic; using System.Linq; -using OpenRA.Graphics; using OpenRA.Mods.Common.Activities; using OpenRA.Orders; using OpenRA.Primitives; @@ -20,11 +19,14 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Provides access to the attack-move command, which will make the actor automatically engage viable targets while moving to the destination.")] - class AttackMoveInfo : ITraitInfo, Requires + class AttackMoveInfo : TraitInfo, Requires { [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.OrangeRed; + [GrantedConditionReference] [Desc("The condition to grant to self while an attack-move is active.")] public readonly string AttackMoveCondition = null; @@ -36,7 +38,7 @@ [Desc("Can the actor be ordered to move in to shroud?")] public readonly bool MoveIntoShroud = true; - public object Create(ActorInitializer init) { return new AttackMove(init.Self, this); } + public override object Create(ActorInitializer init) { return new AttackMove(init.Self, this); } } class AttackMove : IResolveOrder, IOrderVoice @@ -77,7 +79,7 @@ var assaultMoving = order.OrderString == "AssaultMove"; // TODO: this should scale with unit selection group size. - self.QueueActivity(order.Queued, new AttackMoveActivity(self, () => move.MoveTo(targetLocation, 8, targetLineColor: Color.OrangeRed), assaultMoving)); + self.QueueActivity(order.Queued, new AttackMoveActivity(self, () => move.MoveTo(targetLocation, 8, targetLineColor: Info.TargetLineColor), assaultMoving)); self.ShowTargetLines(); } } @@ -85,7 +87,8 @@ public class AttackMoveOrderGenerator : UnitOrderGenerator { - readonly TraitPair[] subjects; + TraitPair[] subjects; + readonly MouseButton expectedButton; public AttackMoveOrderGenerator(IEnumerable subjects, MouseButton button) @@ -117,14 +120,18 @@ // Cells outside the playable area should be clamped to the edge for consistency with move orders cell = world.Map.Clamp(cell); - foreach (var s in subjects) - yield return new Order(orderName, s.Actor, Target.FromCell(world, cell), queued); + yield return new Order(orderName, null, Target.FromCell(world, cell), queued, null, subjects.Select(s => s.Actor).ToArray()); } } - public override void Tick(World world) + public override void SelectionChanged(World world, IEnumerable selected) { - if (subjects.All(s => s.Actor.IsDead)) + subjects = selected.Where(s => !s.IsDead).SelectMany(a => a.TraitsImplementing() + .Select(am => new TraitPair(a, am))) + .ToArray(); + + // AttackMove doesn't work without AutoTarget, so require at least one unit in the selection to have it + if (!subjects.Any(s => s.Actor.Info.HasTraitInfo())) world.CancelInputMode(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/AutoCarryable.cs openra-20210321/OpenRA.Mods.Common/Traits/AutoCarryable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/AutoCarryable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/AutoCarryable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Linq; -using OpenRA.Activities; namespace OpenRA.Mods.Common.Traits { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/AutoTarget.cs openra-20210321/OpenRA.Mods.Common/Traits/AutoTarget.cs --- openra-20200503/OpenRA.Mods.Common/Traits/AutoTarget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/AutoTarget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Collections.Generic; using System.Linq; -using OpenRA.Activities; using OpenRA.Primitives; using OpenRA.Traits; @@ -119,11 +118,11 @@ yield return new EditorActorDropdown("Stance", EditorStanceDisplayOrder, labels, actor => { - var init = actor.Init(); - var stance = init != null ? init.Value(world) : InitialStance; + var init = actor.GetInitOrDefault(this); + var stance = init != null ? init.Value : InitialStance; return stances[(int)stance]; }, - (actor, value) => actor.ReplaceInit(new StanceInit((UnitStance)stances.IndexOf(value)))); + (actor, value) => actor.ReplaceInit(new StanceInit(this, (UnitStance)stances.IndexOf(value)))); } } @@ -145,11 +144,10 @@ public UnitStance PredictedStance; UnitStance stance; - ConditionManager conditionManager; IDisableAutoTarget[] disableAutoTarget; INotifyStanceChanged[] notifyStanceChanged; IEnumerable activeTargetPriorities; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; public void SetStance(Actor self, UnitStance value) { @@ -170,15 +168,11 @@ void ApplyStanceCondition(Actor self) { - if (conditionManager == null) - return; - - if (conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); - string condition; - if (Info.ConditionByStance.TryGetValue(stance, out condition)) - conditionToken = conditionManager.GrantCondition(self, condition); + if (Info.ConditionByStance.TryGetValue(stance, out var condition)) + conditionToken = self.GrantCondition(condition); } public AutoTarget(ActorInitializer init, AutoTargetInfo info) @@ -187,10 +181,7 @@ var self = init.Self; ActiveAttackBases = self.TraitsImplementing().ToArray().Where(Exts.IsTraitEnabled); - if (init.Contains()) - stance = init.Get(); - else - stance = self.Owner.IsBot || !self.Owner.Playable ? info.InitialStanceAI : info.InitialStance; + stance = init.GetValue(self.Owner.IsBot || !self.Owner.Playable ? info.InitialStanceAI : info.InitialStance); PredictedStance = stance; @@ -206,7 +197,6 @@ .OrderByDescending(ati => ati.Info.Priority).ToArray() .Where(Exts.IsTraitEnabled).Select(atp => atp.Info); - conditionManager = self.TraitOrDefault(); disableAutoTarget = self.TraitsImplementing().ToArray(); notifyStanceChanged = self.TraitsImplementing().ToArray(); ApplyStanceCondition(self); @@ -289,21 +279,22 @@ --nextScanTime; } - public Target ScanForTarget(Actor self, bool allowMove, bool allowTurn) + public Target ScanForTarget(Actor self, bool allowMove, bool allowTurn, bool ignoreScanInterval = false) { - if (nextScanTime <= 0 && ActiveAttackBases.Any()) + if ((ignoreScanInterval || nextScanTime <= 0) && ActiveAttackBases.Any()) { foreach (var dat in disableAutoTarget) if (dat.DisableAutoTarget(self)) return Target.Invalid; - nextScanTime = self.World.SharedRandom.Next(Info.MinimumScanTimeInterval, Info.MaximumScanTimeInterval); + if (!ignoreScanInterval) + nextScanTime = self.World.SharedRandom.Next(Info.MinimumScanTimeInterval, Info.MaximumScanTimeInterval); foreach (var ab in ActiveAttackBases) { // If we can't attack right now, there's no need to try and find a target. var attackStances = ab.UnforcedAttackTargetStances(); - if (attackStances != OpenRA.Traits.Stance.None) + if (attackStances != OpenRA.Traits.PlayerRelationship.None) { var range = Info.ScanRadius > 0 ? WDist.FromCells(Info.ScanRadius) : ab.GetMaximumRange(); return ChooseTarget(self, ab, attackStances, range, allowMove, allowTurn); @@ -321,7 +312,7 @@ Attack(self, target, allowMove); } - void Attack(Actor self, Target target, bool allowMove) + void Attack(Actor self, in Target target, bool allowMove) { foreach (var ab in ActiveAttackBases) ab.AttackTarget(target, AttackSource.AutoTarget, false, allowMove); @@ -335,7 +326,7 @@ return activeTargetPriorities.Any(ati => { // Incompatible stances - if (!ati.ValidStances.HasStance(self.Owner.Stances[owner])) + if (!ati.ValidRelationships.HasStance(self.Owner.RelationshipWith(owner))) return false; // Incompatible target types @@ -346,7 +337,7 @@ }); } - Target ChooseTarget(Actor self, AttackBase ab, Stance attackStances, WDist scanRange, bool allowMove, bool allowTurn) + Target ChooseTarget(Actor self, AttackBase ab, PlayerRelationship attackStances, WDist scanRange, bool allowMove, bool allowTurn) { var chosenTarget = Target.Invalid; var chosenTargetPriority = int.MinValue; @@ -357,8 +348,11 @@ return chosenTarget; var targetsInRange = self.World.FindActorsInCircle(self.CenterPosition, scanRange) - .Select(Target.FromActor) - .Concat(self.Owner.FrozenActorLayer.FrozenActorsInCircle(self.World, self.CenterPosition, scanRange) + .Select(Target.FromActor); + + if (allowMove || ab.Info.TargetFrozenActors) + targetsInRange = targetsInRange + .Concat(self.Owner.FrozenActorLayer.FrozenActorsInCircle(self.World, self.CenterPosition, scanRange) .Select(Target.FromFrozenActor)); foreach (var target in targetsInRange) @@ -371,7 +365,7 @@ // can bail early and avoid the more expensive targeting checks and armament selection. For groups of // allied units, this helps significantly reduce the cost of auto target scans. This is important as // these groups will continuously rescan their allies until an enemy finally comes into range. - if (attackStances == OpenRA.Traits.Stance.Enemy && !target.Actor.AppearsHostileTo(self)) + if (attackStances == PlayerRelationship.Enemy && !target.Actor.AppearsHostileTo(self)) continue; // Check whether we can auto-target this actor @@ -384,7 +378,7 @@ } else if (target.Type == TargetType.FrozenActor) { - if (attackStances == OpenRA.Traits.Stance.Enemy && self.Owner.Stances[target.FrozenActor.Owner] == OpenRA.Traits.Stance.Ally) + if (attackStances == PlayerRelationship.Enemy && self.Owner.RelationshipWith(target.FrozenActor.Owner) == PlayerRelationship.Ally) continue; targetTypes = target.FrozenActor.TargetTypes; @@ -400,7 +394,7 @@ return false; // Incompatible stances - if (!ati.ValidStances.HasStance(self.Owner.Stances[owner])) + if (!ati.ValidRelationships.HasStance(self.Owner.RelationshipWith(owner))) return false; // Incompatible target types @@ -453,13 +447,9 @@ } } - public class StanceInit : IActorInit + public class StanceInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - readonly UnitStance value = UnitStance.AttackAnything; - - public StanceInit() { } - public StanceInit(UnitStance init) { value = init; } - public UnitStance Value(World world) { return value; } + public StanceInit(TraitInfo info, UnitStance value) + : base(info, value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/AutoTargetPriority.cs openra-20210321/OpenRA.Mods.Common/Traits/AutoTargetPriority.cs --- openra-20200503/OpenRA.Mods.Common/Traits/AutoTargetPriority.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/AutoTargetPriority.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,8 +23,8 @@ [Desc("Target types that can't be AutoTargeted.", "Overrules ValidTargets.")] public readonly BitSet InvalidTargets; - [Desc("Stances between actor's and target's owner which can be AutoTargeted.")] - public readonly Stance ValidStances = Stance.Ally | Stance.Neutral | Stance.Enemy; + [Desc("Relationships between actor's and target's owner needed for AutoTargeting.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy; [Desc("ValidTargets with larger priorities will be AutoTargeted before lower priorities.")] public readonly int Priority = 1; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BodyOrientation.cs openra-20210321/OpenRA.Mods.Common/Traits/BodyOrientation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BodyOrientation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BodyOrientation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,50 +15,47 @@ namespace OpenRA.Mods.Common.Traits { - public class BodyOrientationInfo : ITraitInfo + public class BodyOrientationInfo : TraitInfo { - [Desc("Number of facings for gameplay calculations. -1 indicates auto-detection from another trait")] + [Desc("Number of facings for gameplay calculations. -1 indicates auto-detection from another trait.")] public readonly int QuantizedFacings = -1; - [Desc("Camera pitch for rotation calculations")] + [Desc("Camera pitch for rotation calculations.")] public readonly WAngle CameraPitch = WAngle.FromDegrees(40); - [Desc("Fudge the coordinate system angles like the early games.")] + [Desc("Fudge the coordinate system angles to simulate non-top-down perspective in mods with square cells.")] public readonly bool UseClassicPerspectiveFudge = true; - [Desc("Fudge the coordinate system angles like the early games.")] - public readonly bool UseClassicFacingFudge = false; - public WVec LocalToWorld(WVec vec) { // Rotate by 90 degrees if (!UseClassicPerspectiveFudge) return new WVec(vec.Y, -vec.X, vec.Z); - // RA's 2d perspective doesn't correspond to an orthonormal 3D + // The 2d perspective of older games with square cells doesn't correspond to an orthonormal 3D // coordinate system, so fudge the y axis to make things look good return new WVec(vec.Y, -CameraPitch.Sin() * vec.X / 1024, vec.Z); } - public WRot QuantizeOrientation(WRot orientation, int facings) + public WRot QuantizeOrientation(in WRot orientation, int facings) { // Quantization disabled if (facings == 0) return orientation; // Map yaw to the closest facing - var facing = QuantizeFacing(orientation.Yaw.Angle / 4, facings); + var facing = QuantizeFacing(orientation.Yaw, facings); // Roll and pitch are always zero if yaw is quantized - return new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing)); + return WRot.FromYaw(facing); } - public int QuantizeFacing(int facing, int facings) + public virtual WAngle QuantizeFacing(WAngle facing, int facings) { - return Util.QuantizeFacing(facing, facings, UseClassicFacingFudge) * (256 / facings); + return Util.QuantizeFacing(facing, facings); } - public object Create(ActorInitializer init) { return new BodyOrientation(init, this); } + public override object Create(ActorInitializer init) { return new BodyOrientation(init, this); } } public class BodyOrientation : ISync @@ -73,7 +70,7 @@ { this.info = info; var self = init.Self; - var faction = init.Contains() ? init.Get() : self.Owner.Faction.InternalName; + var faction = init.GetValue(self.Owner.Faction.InternalName); quantizedFacings = Exts.Lazy(() => { @@ -104,17 +101,17 @@ return info.LocalToWorld(vec); } - public WRot QuantizeOrientation(Actor self, WRot orientation) + public WRot QuantizeOrientation(Actor self, in WRot orientation) { return info.QuantizeOrientation(orientation, quantizedFacings.Value); } - public int QuantizeFacing(int facing) + public WAngle QuantizeFacing(WAngle facing) { return info.QuantizeFacing(facing, quantizedFacings.Value); } - public int QuantizeFacing(int facing, int facings) + public WAngle QuantizeFacing(WAngle facing, int facings) { return info.QuantizeFacing(facing, facings); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,11 +9,9 @@ */ #endregion -using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -69,6 +67,12 @@ [Desc("Increase maintained excess power by ExcessPowerIncrement for every N base buildings.")] public readonly int ExcessPowerIncreaseThreshold = 1; + [Desc("Number of refineries to build before building a barracks.")] + public readonly int InititalMinimumRefineryCount = 1; + + [Desc("Number of refineries to build additionally after building a barracks.")] + public readonly int AdditionalMinimumRefineryCount = 1; + [Desc("Additional delay (in ticks) between structure production checks when there is no active production.", "StructureProductionRandomBonusDelay is added to this.")] public readonly int StructureProductionInactiveDelay = 125; @@ -162,13 +166,9 @@ protected override void Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query player traits from self, which refers - // for bot modules always to the Player actor. - playerPower = self.TraitOrDefault(); - playerResources = self.Trait(); - positionsUpdatedModules = self.TraitsImplementing().ToArray(); + playerPower = self.Owner.PlayerActor.TraitOrDefault(); + playerResources = self.Owner.PlayerActor.Trait(); + positionsUpdatedModules = self.Owner.PlayerActor.TraitsImplementing().ToArray(); } protected override void TraitEnabled(Actor self) @@ -212,7 +212,7 @@ if (e.Attacker == null || e.Attacker.Disposed) return; - if (e.Attacker.Owner.Stances[self.Owner] != Stance.Enemy) + if (e.Attacker.Owner.RelationshipWith(self.Owner) != PlayerRelationship.Enemy) return; if (!e.Attacker.Info.HasTraitInfo()) @@ -249,7 +249,7 @@ if (!possibleRallyPoints.Any()) { - AIUtils.BotDebug("Bot Bug: No possible rallypoint near {0}", producer.Location); + AIUtils.BotDebug("{0} has no possible rallypoint near {1}", producer.Owner, producer.Location); return producer.Location; } @@ -266,7 +266,8 @@ get { // Require at least one refinery, unless we can't build it. - return AIUtils.CountBuildingByCommonName(Info.RefineryTypes, player) >= MinimumRefineryCount || + return !Info.RefineryTypes.Any() || + AIUtils.CountBuildingByCommonName(Info.RefineryTypes, player) >= MinimumRefineryCount || AIUtils.CountBuildingByCommonName(Info.PowerTypes, player) == 0 || AIUtils.CountBuildingByCommonName(Info.ConstructionYardTypes, player) == 0; } @@ -276,9 +277,7 @@ { get { - // Unless we have no barracks (higher priority), require a 2nd refinery. - // TODO: Possibly unhardcode this, at least the targeted minimum of 2 (the fallback can probably stay at 1). - return AIUtils.CountBuildingByCommonName(Info.BarracksTypes, player) > 0 ? 2 : 1; + return AIUtils.CountBuildingByCommonName(Info.BarracksTypes, player) > 0 ? Info.InititalMinimumRefineryCount + Info.AdditionalMinimumRefineryCount : Info.InititalMinimumRefineryCount; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/BaseBuilderQueueManager.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/BaseBuilderQueueManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/BaseBuilderQueueManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/BaseBuilderQueueManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -51,6 +51,8 @@ failRetryTicks = baseBuilder.Info.StructureProductionResumeDelay; minimumExcessPower = baseBuilder.Info.MinimumExcessPower; this.resourceTypeIndices = resourceTypeIndices; + if (!baseBuilder.Info.NavalProductionTypes.Any()) + waterState = WaterCheck.DontCheck; } public void Tick(IBot bot) @@ -134,17 +136,37 @@ // HACK: HACK HACK HACK // TODO: Derive this from BuildingCommonNames instead var type = BuildingType.Building; + CPos? location = null; + string orderString = "PlaceBuilding"; - // Check if Building is a defense and if we should place it towards the enemy or not. - if (world.Map.Rules.Actors[currentBuilding.Item].HasTraitInfo() && world.LocalRandom.Next(100) < baseBuilder.Info.PlaceDefenseTowardsEnemyChance) - type = BuildingType.Defense; - else if (baseBuilder.Info.RefineryTypes.Contains(world.Map.Rules.Actors[currentBuilding.Item].Name)) - type = BuildingType.Refinery; + // Check if Building is a plug for other Building + var actorInfo = world.Map.Rules.Actors[currentBuilding.Item]; + var plugInfo = actorInfo.TraitInfoOrDefault(); + if (plugInfo != null) + { + var possibleBuilding = world.ActorsWithTrait().FirstOrDefault(a => + a.Actor.Owner == player && a.Trait.AcceptsPlug(a.Actor, plugInfo.Type)); + + if (possibleBuilding != null) + { + orderString = "PlacePlug"; + location = possibleBuilding.Actor.Location + possibleBuilding.Trait.Info.Offset; + } + } + else + { + // Check if Building is a defense and if we should place it towards the enemy or not. + if (actorInfo.HasTraitInfo() && world.LocalRandom.Next(100) < baseBuilder.Info.PlaceDefenseTowardsEnemyChance) + type = BuildingType.Defense; + else if (baseBuilder.Info.RefineryTypes.Contains(actorInfo.Name)) + type = BuildingType.Refinery; + + location = ChooseBuildLocation(currentBuilding.Item, true, type); + } - var location = ChooseBuildLocation(currentBuilding.Item, true, type); if (location == null) { - AIUtils.BotDebug("AI: {0} has nowhere to place {1}".F(player, currentBuilding.Item)); + AIUtils.BotDebug("{0} has nowhere to place {1}".F(player, currentBuilding.Item)); bot.QueueOrder(Order.CancelProduction(queue.Actor, currentBuilding.Item, 1)); failCount += failCount; @@ -158,7 +180,8 @@ else { failCount = 0; - bot.QueueOrder(new Order("PlaceBuilding", player.PlayerActor, Target.FromCell(world, location.Value), false) + + bot.QueueOrder(new Order(orderString, player.PlayerActor, Target.FromCell(world, location.Value), false) { // Building to place TargetString = currentBuilding.Item, @@ -214,7 +237,7 @@ { if (power != null && power.TraitInfos().Where(i => i.EnabledByDefault).Sum(p => p.Amount) > 0) { - AIUtils.BotDebug("AI: {0} decided to build {1}: Priority override (low power)", queue.Actor.Owner, power.Name); + AIUtils.BotDebug("{0} decided to build {1}: Priority override (low power)", queue.Actor.Owner, power.Name); return power; } } @@ -225,7 +248,7 @@ var refinery = GetProducibleBuilding(baseBuilder.Info.RefineryTypes, buildableThings); if (refinery != null && HasSufficientPowerForActor(refinery)) { - AIUtils.BotDebug("AI: {0} decided to build {1}: Priority override (refinery)", queue.Actor.Owner, refinery.Name); + AIUtils.BotDebug("{0} decided to build {1}: Priority override (refinery)", queue.Actor.Owner, refinery.Name); return refinery; } @@ -242,7 +265,7 @@ var production = GetProducibleBuilding(baseBuilder.Info.ProductionTypes, buildableThings); if (production != null && HasSufficientPowerForActor(production)) { - AIUtils.BotDebug("AI: {0} decided to build {1}: Priority override (production)", queue.Actor.Owner, production.Name); + AIUtils.BotDebug("{0} decided to build {1}: Priority override (production)", queue.Actor.Owner, production.Name); return production; } @@ -261,7 +284,7 @@ var navalproduction = GetProducibleBuilding(baseBuilder.Info.NavalProductionTypes, buildableThings); if (navalproduction != null && HasSufficientPowerForActor(navalproduction)) { - AIUtils.BotDebug("AI: {0} decided to build {1}: Priority override (navalproduction)", queue.Actor.Owner, navalproduction.Name); + AIUtils.BotDebug("{0} decided to build {1}: Priority override (navalproduction)", queue.Actor.Owner, navalproduction.Name); return navalproduction; } @@ -278,7 +301,7 @@ var silo = GetProducibleBuilding(baseBuilder.Info.SiloTypes, buildableThings); if (silo != null && HasSufficientPowerForActor(silo)) { - AIUtils.BotDebug("AI: {0} decided to build {1}: Priority override (silo)", queue.Actor.Owner, silo.Name); + AIUtils.BotDebug("{0} decided to build {1}: Priority override (silo)", queue.Actor.Owner, silo.Name); return silo; } @@ -386,7 +409,7 @@ case BuildingType.Defense: // Build near the closest enemy structure - var closestEnemy = world.ActorsHavingTrait().Where(a => !a.Disposed && player.Stances[a.Owner] == Stance.Enemy) + var closestEnemy = world.ActorsHavingTrait().Where(a => !a.Disposed && player.RelationshipWith(a.Owner) == PlayerRelationship.Enemy) .ClosestTo(world.Map.CenterOfCell(baseBuilder.DefenseCenter)); var targetCell = closestEnemy != null ? closestEnemy.Location : baseCenter; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/SupportPowerDecision.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/SupportPowerDecision.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/SupportPowerDecision.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/BotModuleLogic/SupportPowerDecision.cs 2021-03-21 11:10:05.000000000 +0000 @@ -71,7 +71,7 @@ var checkActors = world.FindActorsInCircle(pos, radiusToUse); foreach (var scrutinized in checkActors) - answer += consideration.GetAttractiveness(scrutinized, firedBy.Stances[scrutinized.Owner], firedBy); + answer += consideration.GetAttractiveness(scrutinized, firedBy.RelationshipWith(scrutinized.Owner), firedBy); var delta = new WVec(radiusToUse, radiusToUse, WDist.Zero); var tl = world.Map.CellContaining(pos - delta); @@ -80,7 +80,7 @@ // IsValid check filters out Frozen Actors that have not initizialized their Owner foreach (var scrutinized in checkFrozen) - answer += consideration.GetAttractiveness(scrutinized, firedBy.Stances[scrutinized.Owner], firedBy); + answer += consideration.GetAttractiveness(scrutinized, firedBy.RelationshipWith(scrutinized.Owner), firedBy); } return answer; @@ -93,7 +93,7 @@ foreach (var consideration in Considerations) foreach (var scrutinized in actors) - answer += consideration.GetAttractiveness(scrutinized, firedBy.Stances[scrutinized.Owner], firedBy); + answer += consideration.GetAttractiveness(scrutinized, firedBy.RelationshipWith(scrutinized.Owner), firedBy); return answer; } @@ -105,7 +105,7 @@ foreach (var consideration in Considerations) foreach (var scrutinized in frozenActors) if (scrutinized.IsValid && scrutinized.Visible) - answer += consideration.GetAttractiveness(scrutinized, firedBy.Stances[scrutinized.Owner], firedBy); + answer += consideration.GetAttractiveness(scrutinized, firedBy.RelationshipWith(scrutinized.Owner), firedBy); return answer; } @@ -118,7 +118,7 @@ public enum DecisionMetric { Health, Value, None } [Desc("Against whom should this power be used?", "Allowed keywords: Ally, Neutral, Enemy")] - public readonly Stance Against = Stance.Enemy; + public readonly PlayerRelationship Against = PlayerRelationship.Enemy; [Desc("What types should the desired targets of this power be?")] public readonly BitSet Types = new BitSet("Air", "Ground", "Water"); @@ -138,7 +138,7 @@ } /// Evaluates a single actor according to the rules defined in this consideration - public int GetAttractiveness(Actor a, Stance stance, Player firedBy) + public int GetAttractiveness(Actor a, PlayerRelationship stance, Player firedBy) { if (stance != Against) return 0; @@ -174,7 +174,7 @@ return 0; } - public int GetAttractiveness(FrozenActor fa, Stance stance, Player firedBy) + public int GetAttractiveness(FrozenActor fa, PlayerRelationship stance, Player firedBy) { if (stance != Against) return 0; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/BuildingRepairBotModule.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/BuildingRepairBotModule.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/BuildingRepairBotModule.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/BuildingRepairBotModule.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,7 +29,7 @@ // HACK: We don't want D2k bots to repair all their buildings on placement // where half their HP is removed via neutral terrain damage. // TODO: Implement concrete placement for D2k bots and remove this hack. - if (e.Attacker.Owner.Stances[self.Owner] == Stance.Neutral) + if (self.Owner.RelationshipWith(e.Attacker.Owner) == PlayerRelationship.Neutral) return; var rb = self.TraitOrDefault(); @@ -37,8 +37,8 @@ { if (e.DamageState > DamageState.Light && e.PreviousDamageState <= DamageState.Light && !rb.RepairActive) { - AIUtils.BotDebug("Bot noticed damage {0} {1}->{2}, repairing.", - self, e.PreviousDamageState, e.DamageState); + AIUtils.BotDebug("{0} noticed damage {1} {2}->{3}, repairing.", + self.Owner, self, e.PreviousDamageState, e.DamageState); bot.QueueOrder(new Order("RepairBuilding", self.Owner.PlayerActor, Target.FromActor(self), false)); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/CaptureManagerBotModule.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/CaptureManagerBotModule.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/CaptureManagerBotModule.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/CaptureManagerBotModule.cs 2021-03-21 11:10:05.000000000 +0000 @@ -37,8 +37,8 @@ [Desc("Should visibility (Shroud, Fog, Cloak, etc) be considered when searching for capturable targets?")] public readonly bool CheckCaptureTargetsForVisibility = true; - [Desc("Player stances that capturers should attempt to target.")] - public readonly Stance CapturableStances = Stance.Enemy | Stance.Neutral; + [Desc("Player relationships that capturers should attempt to target.")] + public readonly PlayerRelationship CapturableRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral; public override object Create(ActorInitializer init) { return new CaptureManagerBotModule(init.Self, this); } } @@ -65,7 +65,7 @@ return; isEnemyUnit = unit => - player.Stances[unit.Owner] == Stance.Enemy + player.RelationshipWith(unit.Owner) == PlayerRelationship.Enemy && !unit.Info.HasTraitInfo() && unit.Info.HasTraitInfo(); @@ -133,7 +133,7 @@ return; var randPlayer = world.Players.Where(p => !p.Spectating - && Info.CapturableStances.HasStance(player.Stances[p])).Random(world.LocalRandom); + && Info.CapturableRelationships.HasStance(player.RelationshipWith(p))).Random(world.LocalRandom); var targetOptions = Info.CheckCaptureTargetsForVisibility ? GetVisibleActorsBelongingToPlayer(randPlayer) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs 2021-03-21 11:10:05.000000000 +0000 @@ -78,11 +78,7 @@ protected override void Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query player traits from self, which refers - // for bot modules always to the Player actor. - requestUnitProduction = self.TraitsImplementing().ToArray(); + requestUnitProduction = self.Owner.PlayerActor.TraitsImplementing().ToArray(); } protected override void TraitEnabled(Actor self) @@ -149,14 +145,14 @@ Target FindNextResource(Actor actor, HarvesterTraitWrapper harv) { Func isValidResource = cell => - domainIndex.IsPassable(actor.Location, cell, harv.Locomotor.Info) && + domainIndex.IsPassable(actor.Location, cell, harv.Locomotor) && harv.Harvester.CanHarvestCell(actor, cell) && claimLayer.CanClaimCell(actor, cell); var path = pathfinder.FindPath( PathSearch.Search(world, harv.Locomotor, actor, BlockedByActor.Stationary, isValidResource) .WithCustomCost(loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius) - .Where(u => !u.IsDead && actor.Owner.Stances[u.Owner] == Stance.Enemy) + .Where(u => !u.IsDead && actor.Owner.RelationshipWith(u.Owner) == PlayerRelationship.Enemy) .Sum(u => Math.Max(WDist.Zero.Length, Info.HarvesterEnemyAvoidanceRadius.Length - (world.Map.CenterOfCell(loc) - u.CenterPosition).Length))) .FromPoint(actor.Location)); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/McvManagerBotModule.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/McvManagerBotModule.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/McvManagerBotModule.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/McvManagerBotModule.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,10 +10,8 @@ #endregion using System; -using System.Collections; using System.Collections.Generic; using System.Linq; -using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -82,12 +80,8 @@ protected override void Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query player traits from self, which refers - // for bot modules always to the Player actor. - notifyPositionsUpdated = self.TraitsImplementing().ToArray(); - requestUnitProduction = self.TraitsImplementing().ToArray(); + notifyPositionsUpdated = self.Owner.PlayerActor.TraitsImplementing().ToArray(); + requestUnitProduction = self.Owner.PlayerActor.TraitsImplementing().ToArray(); } protected override void TraitEnabled(Actor self) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/SquadManagerBotModule.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/SquadManagerBotModule.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/SquadManagerBotModule.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/SquadManagerBotModule.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,11 +10,10 @@ #endregion using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using OpenRA.Mods.Common.Traits.BotModules.Squads; -using OpenRA.Support; +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -74,6 +73,17 @@ [Desc("Radius in cells that protecting squads should scan for enemies around their position.")] public readonly int ProtectionScanRadius = 8; + [Desc("Enemy target types to never target.")] + public readonly BitSet IgnoredEnemyTargetTypes = default(BitSet); + + public override void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + base.RulesetLoaded(rules, ai); + + if (DangerScanRadius <= 0) + throw new YamlException("DangerScanRadius must be greater than zero."); + } + public override object Create(ActorInitializer init) { return new SquadManagerBotModule(init.Self, this); } } @@ -92,6 +102,10 @@ public readonly Player Player; readonly Predicate unitCannotBeOrdered; + readonly List unitsHangingAroundTheBase = new List(); + + // Units that the bot already knows about. Any unit not on this list needs to be given a role. + readonly List activeUnits = new List(); public List Squads = new List(); @@ -100,10 +114,6 @@ IBotNotifyIdleBaseUnits[] notifyIdleBaseUnits; CPos initialBaseCenter; - List unitsHangingAroundTheBase = new List(); - - // Units that the bot already knows about. Any unit not on this list needs to be given a role. - List activeUnits = new List(); int rushTicks; int assignRolesTicks; @@ -119,21 +129,35 @@ unitCannotBeOrdered = a => a == null || a.Owner != Player || a.IsDead || !a.IsInWorld; } - public bool IsEnemyUnit(Actor a) + // Use for proactive targeting. + public bool IsPreferredEnemyUnit(Actor a) { - return a != null && !a.IsDead && Player.Stances[a.Owner] == Stance.Enemy - && !a.Info.HasTraitInfo() - && !a.GetEnabledTargetTypes().IsEmpty; + if (a == null || a.IsDead || Player.RelationshipWith(a.Owner) != PlayerRelationship.Enemy || a.Info.HasTraitInfo() || a.Info.HasTraitInfo()) + return false; + + var targetTypes = a.GetEnabledTargetTypes(); + return !targetTypes.IsEmpty && !targetTypes.Overlaps(Info.IgnoredEnemyTargetTypes); + } + + public bool IsNotHiddenUnit(Actor a) + { + var hasModifier = false; + var visModifiers = a.TraitsImplementing(); + foreach (var v in visModifiers) + { + if (v.IsVisible(a, Player)) + return true; + + hasModifier = true; + } + + return !hasModifier; } protected override void Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query player traits from self, which refers - // for bot modules always to the Player actor. - notifyPositionsUpdated = self.TraitsImplementing().ToArray(); - notifyIdleBaseUnits = self.TraitsImplementing().ToArray(); + notifyPositionsUpdated = self.Owner.PlayerActor.TraitsImplementing().ToArray(); + notifyIdleBaseUnits = self.Owner.PlayerActor.TraitsImplementing().ToArray(); } protected override void TraitEnabled(Actor self) @@ -160,12 +184,13 @@ internal Actor FindClosestEnemy(WPos pos) { - return World.Actors.Where(IsEnemyUnit).ClosestTo(pos); + var units = World.Actors.Where(IsPreferredEnemyUnit); + return units.Where(IsNotHiddenUnit).ClosestTo(pos) ?? units.ClosestTo(pos); } internal Actor FindClosestEnemy(WPos pos, WDist radius) { - return World.FindActorsInCircle(pos, radius).Where(IsEnemyUnit).ClosestTo(pos); + return World.FindActorsInCircle(pos, radius).Where(a => IsPreferredEnemyUnit(a) && IsNotHiddenUnit(a)).ClosestTo(pos); } void CleanSquads() @@ -232,8 +257,6 @@ foreach (var a in newUnits) { - unitsHangingAroundTheBase.Add(a); - if (a.Info.HasTraitInfo() && a.Info.HasTraitInfo()) { var air = GetSquadOfType(SquadType.Air); @@ -250,6 +273,8 @@ ships.Units.Add(a); } + else + unitsHangingAroundTheBase.Add(a); activeUnits.Add(a); } @@ -270,8 +295,7 @@ var attackForce = RegisterNewSquad(bot, SquadType.Assault); foreach (var a in unitsHangingAroundTheBase) - if (!a.Info.HasTraitInfo() && !Info.NavalUnitsTypes.Contains(a.Info.Name)) - attackForce.Units.Add(a); + attackForce.Units.Add(a); unitsHangingAroundTheBase.Clear(); foreach (var n in notifyIdleBaseUnits) @@ -295,7 +319,7 @@ { // Don't rush enemy aircraft! var enemies = World.FindActorsInCircle(b.CenterPosition, WDist.FromCells(Info.RushAttackScanRadius)) - .Where(unit => IsEnemyUnit(unit) && unit.Info.HasTraitInfo() && !unit.Info.HasTraitInfo() && !Info.NavalUnitsTypes.Contains(unit.Info.Name)).ToList(); + .Where(unit => IsPreferredEnemyUnit(unit) && unit.Info.HasTraitInfo() && !unit.Info.HasTraitInfo() && !Info.NavalUnitsTypes.Contains(unit.Info.Name)).ToList(); if (AttackOrFleeFuzzy.Rush.CanAttack(ownUnits, enemies)) { @@ -341,7 +365,7 @@ void IBotRespondToAttack.RespondToAttack(IBot bot, Actor self, AttackInfo e) { - if (!IsEnemyUnit(e.Attacker)) + if (!IsPreferredEnemyUnit(e.Attacker)) return; // Protected priority assets, MCVs, harvesters and buildings diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/AttackOrFleeFuzzy.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/AttackOrFleeFuzzy.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/AttackOrFleeFuzzy.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/AttackOrFleeFuzzy.cs 2021-03-21 11:10:05.000000000 +0000 @@ -243,7 +243,7 @@ return relative.Clamp(0.0f, 999.0f); } - static float SumOfValues(IEnumerable actors, Func getValue) where TTraitInfo : ITraitInfo + static float SumOfValues(IEnumerable actors, Func getValue) where TTraitInfo : ITraitInfoInterface { var sum = 0; foreach (var a in actors) @@ -253,7 +253,7 @@ return sum; } - static float Average(IEnumerable actors, Func getValue) where TTraitInfo : ITraitInfo + static float Average(IEnumerable actors, Func getValue) where TTraitInfo : ITraitInfoInterface { var sum = 0; var countActors = 0; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/StateMachine.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/StateMachine.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/StateMachine.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/StateMachine.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,8 +18,7 @@ public void Update(Squad squad) { - if (currentState != null) - currentState.Tick(squad); + currentState?.Tick(squad); } public void ChangeState(Squad squad, IState newState, bool rememberPrevious) @@ -27,14 +26,12 @@ if (rememberPrevious) previousState = currentState; - if (currentState != null) - currentState.Deactivate(squad); + currentState?.Deactivate(squad); if (newState != null) currentState = newState; - if (currentState != null) - currentState.Activate(squad); + currentState?.Activate(squad); } public void RevertToPreviousState(Squad squad, bool saveCurrentState) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/States/AirStates.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/States/AirStates.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/States/AirStates.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/States/AirStates.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Collections.Generic; using System.Linq; -using OpenRA.Mods.Common.Activities; using OpenRA.Primitives; using OpenRA.Traits; @@ -65,21 +64,21 @@ var map = owner.World.Map; var dangerRadius = owner.SquadManager.Info.DangerScanRadius; detectedEnemyTarget = null; - var x = (map.MapSize.X % dangerRadius) == 0 ? map.MapSize.X : map.MapSize.X + dangerRadius; - var y = (map.MapSize.Y % dangerRadius) == 0 ? map.MapSize.Y : map.MapSize.Y + dangerRadius; - for (var i = 0; i < x; i += dangerRadius * 2) + var columnCount = (map.MapSize.X + dangerRadius - 1) / dangerRadius; + var rowCount = (map.MapSize.Y + dangerRadius - 1) / dangerRadius; + + var checkIndices = Exts.MakeArray(columnCount * rowCount, i => i).Shuffle(owner.World.LocalRandom); + foreach (var i in checkIndices) { - for (var j = 0; j < y; j += dangerRadius * 2) + var pos = new MPos((i % columnCount) * dangerRadius + dangerRadius / 2, (i / columnCount) * dangerRadius + dangerRadius / 2).ToCPos(map); + + if (NearToPosSafely(owner, map.CenterOfCell(pos), out detectedEnemyTarget)) { - var pos = new CPos(i, j); - if (NearToPosSafely(owner, map.CenterOfCell(pos), out detectedEnemyTarget)) - { - if (needTarget && detectedEnemyTarget == null) - continue; + if (needTarget && detectedEnemyTarget == null) + continue; - return pos; - } + return pos; } } @@ -88,8 +87,7 @@ protected static bool NearToPosSafely(Squad owner, WPos loc) { - Actor a; - return NearToPosSafely(owner, loc, out a); + return NearToPosSafely(owner, loc, out _); } protected static bool NearToPosSafely(Squad owner, WPos loc, out Actor detectedEnemyTarget) @@ -97,7 +95,7 @@ detectedEnemyTarget = null; var dangerRadius = owner.SquadManager.Info.DangerScanRadius; var unitsAroundPos = owner.World.FindActorsInCircle(loc, WDist.FromCells(dangerRadius)) - .Where(owner.SquadManager.IsEnemyUnit).ToList(); + .Where(owner.SquadManager.IsPreferredEnemyUnit).ToList(); if (!unitsAroundPos.Any()) return true; @@ -111,49 +109,6 @@ return false; } - protected static bool FullAmmo(Actor a) - { - var ammoPools = a.TraitsImplementing(); - return ammoPools.All(x => x.HasFullAmmo); - } - - protected static bool HasAmmo(Actor a) - { - var ammoPools = a.TraitsImplementing(); - return ammoPools.All(x => x.HasAmmo); - } - - protected static bool ReloadsAutomatically(Actor a) - { - var ammoPools = a.TraitsImplementing(); - var rearmable = a.TraitOrDefault(); - if (rearmable == null) - return true; - - return ammoPools.All(ap => !rearmable.Info.AmmoPools.Contains(ap.Info.Name)); - } - - protected static bool IsRearm(Actor a) - { - if (a.IsIdle) - return false; - - var activity = a.CurrentActivity; - var type = activity.GetType(); - if (type == typeof(Resupply)) - return true; - - var next = activity.NextActivity; - if (next == null) - return false; - - var nextType = next.GetType(); - if (nextType == typeof(Resupply)) - return true; - - return false; - } - // Checks the number of anti air enemies around units protected virtual bool ShouldFlee(Squad owner) { @@ -220,12 +175,13 @@ if (BusyAttack(a)) continue; - if (!ReloadsAutomatically(a)) + var ammoPools = a.TraitsImplementing().ToArray(); + if (!ReloadsAutomatically(ammoPools, a.TraitOrDefault())) { - if (IsRearm(a)) + if (IsRearming(a)) continue; - if (!HasAmmo(a)) + if (!HasAmmo(ammoPools)) { owner.Bot.QueueOrder(new Order("ReturnToBase", a, false)); continue; @@ -251,9 +207,10 @@ foreach (var a in owner.Units) { - if (!ReloadsAutomatically(a) && !FullAmmo(a)) + var ammoPools = a.TraitsImplementing().ToArray(); + if (!ReloadsAutomatically(ammoPools, a.TraitOrDefault()) && !FullAmmo(ammoPools)) { - if (IsRearm(a)) + if (IsRearming(a)) continue; owner.Bot.QueueOrder(new Order("ReturnToBase", a, false)); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/States/GroundStates.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/States/GroundStates.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/States/GroundStates.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/States/GroundStates.cs 2021-03-21 11:10:05.000000000 +0000 @@ -46,15 +46,14 @@ } var enemyUnits = owner.World.FindActorsInCircle(owner.TargetActor.CenterPosition, WDist.FromCells(owner.SquadManager.Info.IdleScanRadius)) - .Where(owner.SquadManager.IsEnemyUnit).ToList(); + .Where(owner.SquadManager.IsPreferredEnemyUnit).ToList(); if (enemyUnits.Count == 0) return; if (AttackOrFleeFuzzy.Default.CanAttack(owner.Units, enemyUnits)) { - foreach (var u in owner.Units) - owner.Bot.QueueOrder(new Order("AttackMove", u, Target.FromCell(owner.World, owner.TargetActor.Location), false)); + owner.Bot.QueueOrder(new Order("AttackMove", null, Target.FromCell(owner.World, owner.TargetActor.Location), false, groupedActors: owner.Units.ToArray())); // We have gathered sufficient units. Attack the nearest enemy unit. owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsAttackMoveState(), true); @@ -68,6 +67,10 @@ class GroundUnitsAttackMoveState : GroundStateBase, IState { + int lastUpdatedTick; + CPos? lastLeaderLocation; + Actor lastTarget; + public void Activate(Squad owner) { } public void Tick(Squad owner) @@ -91,6 +94,27 @@ if (leader == null) return; + if (leader.Location != lastLeaderLocation) + { + lastLeaderLocation = leader.Location; + lastUpdatedTick = owner.World.WorldTick; + } + + if (owner.TargetActor != lastTarget) + { + lastTarget = owner.TargetActor; + lastUpdatedTick = owner.World.WorldTick; + } + + // HACK: Drop back to the idle state if we haven't moved in 2.5 seconds + // This works around the squad being stuck trying to attack-move to a location + // that they cannot path to, generating expensive pathfinding calls each tick. + if (owner.World.WorldTick > lastUpdatedTick + 63) + { + owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsIdleState(), true); + return; + } + var ownUnits = owner.World.FindActorsInCircle(leader.CenterPosition, WDist.FromCells(owner.Units.Count) / 3) .Where(a => a.Owner == owner.Units.First().Owner && owner.Units.Contains(a)).ToHashSet(); @@ -99,13 +123,14 @@ // Since units have different movement speeds, they get separated while approaching the target. // Let them regroup into tighter formation. owner.Bot.QueueOrder(new Order("Stop", leader, false)); - foreach (var unit in owner.Units.Where(a => !ownUnits.Contains(a))) - owner.Bot.QueueOrder(new Order("AttackMove", unit, Target.FromCell(owner.World, leader.Location), false)); + + var units = owner.Units.Where(a => !ownUnits.Contains(a)).ToArray(); + owner.Bot.QueueOrder(new Order("AttackMove", null, Target.FromCell(owner.World, leader.Location), false, groupedActors: units)); } else { var enemies = owner.World.FindActorsInCircle(leader.CenterPosition, WDist.FromCells(owner.SquadManager.Info.AttackScanRadius)) - .Where(owner.SquadManager.IsEnemyUnit); + .Where(owner.SquadManager.IsPreferredEnemyUnit); var target = enemies.ClosestTo(leader.CenterPosition); if (target != null) { @@ -113,8 +138,7 @@ owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsAttackState(), true); } else - foreach (var a in owner.Units) - owner.Bot.QueueOrder(new Order("AttackMove", a, Target.FromCell(owner.World, owner.TargetActor.Location), false)); + owner.Bot.QueueOrder(new Order("AttackMove", null, Target.FromCell(owner.World, owner.TargetActor.Location), false, groupedActors: owner.Units.ToArray())); } if (ShouldFlee(owner)) @@ -126,6 +150,10 @@ class GroundUnitsAttackState : GroundStateBase, IState { + int lastUpdatedTick; + CPos? lastLeaderLocation; + Actor lastTarget; + public void Activate(Squad owner) { } public void Tick(Squad owner) @@ -145,6 +173,28 @@ } } + var leader = owner.Units.ClosestTo(owner.TargetActor.CenterPosition); + if (leader.Location != lastLeaderLocation) + { + lastLeaderLocation = leader.Location; + lastUpdatedTick = owner.World.WorldTick; + } + + if (owner.TargetActor != lastTarget) + { + lastTarget = owner.TargetActor; + lastUpdatedTick = owner.World.WorldTick; + } + + // HACK: Drop back to the idle state if we haven't moved in 2.5 seconds + // This works around the squad being stuck trying to attack-move to a location + // that they cannot path to, generating expensive pathfinding calls each tick. + if (owner.World.WorldTick > lastUpdatedTick + 63) + { + owner.FuzzyStateMachine.ChangeState(owner, new GroundUnitsIdleState(), true); + return; + } + foreach (var a in owner.Units) if (!BusyAttack(a)) owner.Bot.QueueOrder(new Order("Attack", a, Target.FromActor(owner.TargetActor), false)); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/States/NavyStates.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/States/NavyStates.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/States/NavyStates.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/States/NavyStates.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,11 +29,11 @@ // (Way better than finding a nearest target which is likely to be on Ground) // You might be tempted to move these lookups into Activate() but that causes null reference exception. var domainIndex = first.World.WorldActor.Trait(); - var locomotorInfo = first.Info.TraitInfo().LocomotorInfo; + var locomotor = first.Trait().Locomotor; var navalProductions = owner.World.ActorsHavingTrait().Where(a => owner.SquadManager.Info.NavalProductionTypes.Contains(a.Info.Name) - && domainIndex.IsPassable(first.Location, a.Location, locomotorInfo) + && domainIndex.IsPassable(first.Location, a.Location, locomotor) && a.AppearsHostileTo(first)); if (navalProductions.Any()) @@ -71,15 +71,14 @@ } var enemyUnits = owner.World.FindActorsInCircle(owner.TargetActor.CenterPosition, WDist.FromCells(owner.SquadManager.Info.IdleScanRadius)) - .Where(owner.SquadManager.IsEnemyUnit).ToList(); + .Where(owner.SquadManager.IsPreferredEnemyUnit).ToList(); if (enemyUnits.Count == 0) return; if (AttackOrFleeFuzzy.Default.CanAttack(owner.Units, enemyUnits)) { - foreach (var u in owner.Units) - owner.Bot.QueueOrder(new Order("AttackMove", u, Target.FromCell(owner.World, owner.TargetActor.Location), false)); + owner.Bot.QueueOrder(new Order("AttackMove", null, Target.FromCell(owner.World, owner.TargetActor.Location), false, groupedActors: owner.Units.ToArray())); // We have gathered sufficient units. Attack the nearest enemy unit. owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsAttackMoveState(), true); @@ -93,6 +92,10 @@ class NavyUnitsAttackMoveState : NavyStateBase, IState { + int lastUpdatedTick; + CPos? lastLeaderLocation; + Actor lastTarget; + public void Activate(Squad owner) { } public void Tick(Squad owner) @@ -116,6 +119,27 @@ if (leader == null) return; + if (leader.Location != lastLeaderLocation) + { + lastLeaderLocation = leader.Location; + lastUpdatedTick = owner.World.WorldTick; + } + + if (owner.TargetActor != lastTarget) + { + lastTarget = owner.TargetActor; + lastUpdatedTick = owner.World.WorldTick; + } + + // HACK: Drop back to the idle state if we haven't moved in 2.5 seconds + // This works around the squad being stuck trying to attack-move to a location + // that they cannot path to, generating expensive pathfinding calls each tick. + if (owner.World.WorldTick > lastUpdatedTick + 63) + { + owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsIdleState(), true); + return; + } + var ownUnits = owner.World.FindActorsInCircle(leader.CenterPosition, WDist.FromCells(owner.Units.Count) / 3) .Where(a => a.Owner == owner.Units.First().Owner && owner.Units.Contains(a)).ToHashSet(); @@ -124,13 +148,14 @@ // Since units have different movement speeds, they get separated while approaching the target. // Let them regroup into tighter formation. owner.Bot.QueueOrder(new Order("Stop", leader, false)); - foreach (var unit in owner.Units.Where(a => !ownUnits.Contains(a))) - owner.Bot.QueueOrder(new Order("AttackMove", unit, Target.FromCell(owner.World, leader.Location), false)); + + var units = owner.Units.Where(a => !ownUnits.Contains(a)).ToArray(); + owner.Bot.QueueOrder(new Order("AttackMove", null, Target.FromCell(owner.World, leader.Location), false, groupedActors: units)); } else { var enemies = owner.World.FindActorsInCircle(leader.CenterPosition, WDist.FromCells(owner.SquadManager.Info.AttackScanRadius)) - .Where(owner.SquadManager.IsEnemyUnit); + .Where(owner.SquadManager.IsPreferredEnemyUnit); var target = enemies.ClosestTo(leader.CenterPosition); if (target != null) { @@ -138,8 +163,7 @@ owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsAttackState(), true); } else - foreach (var a in owner.Units) - owner.Bot.QueueOrder(new Order("AttackMove", a, Target.FromCell(owner.World, owner.TargetActor.Location), false)); + owner.Bot.QueueOrder(new Order("AttackMove", null, Target.FromCell(owner.World, owner.TargetActor.Location), false, groupedActors: owner.Units.ToArray())); } if (ShouldFlee(owner)) @@ -151,6 +175,10 @@ class NavyUnitsAttackState : NavyStateBase, IState { + int lastUpdatedTick; + CPos? lastLeaderLocation; + Actor lastTarget; + public void Activate(Squad owner) { } public void Tick(Squad owner) @@ -170,6 +198,28 @@ } } + var leader = owner.Units.ClosestTo(owner.TargetActor.CenterPosition); + if (leader.Location != lastLeaderLocation) + { + lastLeaderLocation = leader.Location; + lastUpdatedTick = owner.World.WorldTick; + } + + if (owner.TargetActor != lastTarget) + { + lastTarget = owner.TargetActor; + lastUpdatedTick = owner.World.WorldTick; + } + + // HACK: Drop back to the idle state if we haven't moved in 2.5 seconds + // This works around the squad being stuck trying to attack-move to a location + // that they cannot path to, generating expensive pathfinding calls each tick. + if (owner.World.WorldTick > lastUpdatedTick + 63) + { + owner.FuzzyStateMachine.ChangeState(owner, new NavyUnitsIdleState(), true); + return; + } + foreach (var a in owner.Units) if (!BusyAttack(a)) owner.Bot.QueueOrder(new Order("Attack", a, Target.FromActor(owner.TargetActor), false)); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/States/ProtectionStates.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/States/ProtectionStates.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/States/ProtectionStates.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/States/ProtectionStates.cs 2021-03-21 11:10:05.000000000 +0000 @@ -55,10 +55,7 @@ Backoff--; } else - { - foreach (var a in owner.Units) - owner.Bot.QueueOrder(new Order("AttackMove", a, Target.FromCell(owner.World, owner.TargetActor.Location), false)); - } + owner.Bot.QueueOrder(new Order("AttackMove", null, Target.FromCell(owner.World, owner.TargetActor.Location), false, groupedActors: owner.Units.ToArray())); } public void Deactivate(Squad owner) { } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/States/StateBase.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/States/StateBase.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/Squads/States/StateBase.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/Squads/States/StateBase.cs 2021-03-21 11:10:05.000000000 +0000 @@ -95,11 +95,60 @@ if (u.Owner == squad.Bot.Player && u.Info.HasTraitInfo()) return false; - var enemyAroundUnit = units.Where(unit => squad.SquadManager.IsEnemyUnit(unit) && unit.Info.HasTraitInfo()); + var enemyAroundUnit = units.Where(unit => squad.SquadManager.IsPreferredEnemyUnit(unit) && unit.Info.HasTraitInfo()); if (!enemyAroundUnit.Any()) return false; return flee(enemyAroundUnit); } + + protected static bool IsRearming(Actor a) + { + if (a.IsIdle) + return false; + + var activity = a.CurrentActivity; + if (activity.GetType() == typeof(Resupply)) + return true; + + var next = activity.NextActivity; + if (next == null) + return false; + + if (next.GetType() == typeof(Resupply)) + return true; + + return false; + } + + protected static bool FullAmmo(IEnumerable ammoPools) + { + foreach (var ap in ammoPools) + if (!ap.HasFullAmmo) + return false; + + return true; + } + + protected static bool HasAmmo(IEnumerable ammoPools) + { + foreach (var ap in ammoPools) + if (!ap.HasAmmo) + return false; + + return true; + } + + protected static bool ReloadsAutomatically(IEnumerable ammoPools, Rearmable rearmable) + { + if (rearmable == null) + return true; + + foreach (var ap in ammoPools) + if (!rearmable.Info.AmmoPools.Contains(ap.Info.Name)) + return false; + + return true; + } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/SupportPowerBotModule.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/SupportPowerBotModule.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/SupportPowerBotModule.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/SupportPowerBotModule.cs 2021-03-21 11:10:05.000000000 +0000 @@ -54,11 +54,7 @@ protected override void Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query player traits from self, which refers - // for bot modules always to the Player actor. - supportPowerManager = self.Trait(); + supportPowerManager = self.Owner.PlayerActor.Trait(); } protected override void TraitEnabled(Actor self) @@ -88,14 +84,14 @@ var powerDecision = powerDecisions[sp.Info.OrderName]; if (powerDecision == null) { - AIUtils.BotDebug("Bot Bug: FindAttackLocationToSupportPower, couldn't find powerDecision for {0}", sp.Info.OrderName); + AIUtils.BotDebug("{0} couldn't find powerDecision for {1}", player.PlayerName, sp.Info.OrderName); continue; } var attackLocation = FindCoarseAttackLocationToSupportPower(sp); if (attackLocation == null) { - AIUtils.BotDebug("AI: {1} can't find suitable coarse attack location for support power {0}. Delaying rescan.", sp.Info.OrderName, player.PlayerName); + AIUtils.BotDebug("{0} can't find suitable coarse attack location for support power {1}. Delaying rescan.", player.PlayerName, sp.Info.OrderName); waitingPowers[sp] += powerDecision.GetNextScanTime(world); continue; @@ -105,14 +101,14 @@ attackLocation = FindFineAttackLocationToSupportPower(sp, (CPos)attackLocation); if (attackLocation == null) { - AIUtils.BotDebug("AI: {1} can't find suitable final attack location for support power {0}. Delaying rescan.", sp.Info.OrderName, player.PlayerName); + AIUtils.BotDebug("{0} can't find suitable final attack location for support power {1}. Delaying rescan.", player.PlayerName, sp.Info.OrderName); waitingPowers[sp] += powerDecision.GetNextScanTime(world); continue; } // Valid target found, delay by a few ticks to avoid rescanning before power fires via order - AIUtils.BotDebug("AI: {2} found new target location {0} for support power {1}.", attackLocation, sp.Info.OrderName, player.PlayerName); + AIUtils.BotDebug("{0} found new target location {1} for support power {2}.", player.PlayerName, attackLocation, sp.Info.OrderName); waitingPowers[sp] += 10; bot.QueueOrder(new Order(sp.Key, supportPowerManager.Self, Target.FromCell(world, attackLocation.Value), false) { SuppressVisualFeedback = true }); } @@ -129,17 +125,18 @@ /// Scans the map in chunks, evaluating all actors in each. CPos? FindCoarseAttackLocationToSupportPower(SupportPowerInstance readyPower) { - CPos? bestLocation = null; - var bestAttractiveness = 0; var powerDecision = powerDecisions[readyPower.Info.OrderName]; if (powerDecision == null) { - AIUtils.BotDebug("Bot Bug: FindAttackLocationToSupportPower, couldn't find powerDecision for {0}", readyPower.Info.OrderName); + AIUtils.BotDebug("{0} couldn't find powerDecision for {1}", player.PlayerName, readyPower.Info.OrderName); return null; } var map = world.Map; var checkRadius = powerDecision.CoarseScanRadius; + var suitableLocations = new List<(MPos UV, int Attractiveness)>(); + var totalAttractiveness = 0; + for (var i = 0; i < map.MapSize.X; i += checkRadius) { for (var j = 0; j < map.MapSize.Y; j += checkRadius) @@ -155,15 +152,22 @@ var frozenTargets = player.FrozenActorLayer != null ? player.FrozenActorLayer.FrozenActorsInRegion(region) : Enumerable.Empty(); var consideredAttractiveness = powerDecision.GetAttractiveness(targets, player) + powerDecision.GetAttractiveness(frozenTargets, player); - if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness) + if (consideredAttractiveness < powerDecision.MinimumAttractiveness) continue; - bestAttractiveness = consideredAttractiveness; - bestLocation = new MPos(i, j).ToCPos(map); + suitableLocations.Add((tl, consideredAttractiveness)); + totalAttractiveness += consideredAttractiveness; } } - return bestLocation; + if (suitableLocations.Count == 0) + return null; + + // Pick a random location with above average attractiveness. + var averageAttractiveness = totalAttractiveness / suitableLocations.Count; + return suitableLocations.Shuffle(world.LocalRandom) + .First(x => x.Attractiveness >= averageAttractiveness) + .UV.ToCPos(map); } /// Detail scans an area, evaluating positions. @@ -174,7 +178,7 @@ var powerDecision = powerDecisions[readyPower.Info.OrderName]; if (powerDecision == null) { - AIUtils.BotDebug("Bot Bug: FindAttackLocationToSupportPower, couldn't find powerDecision for {0}", readyPower.Info.OrderName); + AIUtils.BotDebug("{0} couldn't find powerDecision for {1}", player.PlayerName, readyPower.Info.OrderName); return null; } @@ -227,8 +231,7 @@ { foreach (var n in waitingPowersNode.Value.Nodes) { - SupportPowerInstance instance; - if (supportPowerManager.Powers.TryGetValue(n.Key, out instance)) + if (supportPowerManager.Powers.TryGetValue(n.Key, out var instance)) waitingPowers[instance] = FieldLoader.GetValue("WaitingPowers", n.Value.Value); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/BotModules/UnitBuilderBotModule.cs openra-20210321/OpenRA.Mods.Common/Traits/BotModules/UnitBuilderBotModule.cs --- openra-20200503/OpenRA.Mods.Common/Traits/BotModules/UnitBuilderBotModule.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/BotModules/UnitBuilderBotModule.cs 2021-03-21 11:10:05.000000000 +0000 @@ -62,11 +62,7 @@ protected override void Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query player traits from self, which refers - // for bot modules always to the Player actor. - requestPause = self.TraitsImplementing().ToArray(); + requestPause = self.Owner.PlayerActor.TraitsImplementing().ToArray(); } void IBotNotifyIdleBaseUnits.UpdatedIdleBaseUnits(List idleUnits) @@ -159,7 +155,7 @@ if (queue != null) { bot.QueueOrder(Order.StartProduction(queue.Actor, name, 1)); - AIUtils.BotDebug("AI: {0} decided to build {1} (external request)", queue.Actor.Owner, name); + AIUtils.BotDebug("{0} decided to build {1} (external request)", queue.Actor.Owner, name); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildable.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -38,10 +38,13 @@ [Desc("Sequence of the actor that contains the icon.")] public readonly string Icon = "icon"; - [PaletteReference] + [PaletteReference(nameof(IconPaletteIsPlayerPalette))] [Desc("Palette used for the production icon.")] public readonly string IconPalette = "chrome"; + [Desc("Custom palette is a player palette BaseName")] + public readonly bool IconPaletteIsPlayerPalette = false; + [Desc("Base build time in frames (-1 indicates to use the unit's Value).")] public readonly int BuildDuration = -1; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/ActorPreviewPlaceBuildingPreview.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/ActorPreviewPlaceBuildingPreview.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/ActorPreviewPlaceBuildingPreview.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/ActorPreviewPlaceBuildingPreview.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,7 @@ [Desc("Enable the building's idle animation.")] public readonly bool Animated = true; - [PaletteReference("OverridePaletteIsPlayerPalette")] + [PaletteReference(nameof(OverridePaletteIsPlayerPalette))] [Desc("Custom palette name.")] public readonly string OverridePalette = null; @@ -68,8 +68,8 @@ if (!string.IsNullOrEmpty(info.OverridePalette)) { - var owner = init.Get().Value(wr.World); - palette = wr.Palette(info.OverridePaletteIsPlayerPalette ? info.OverridePalette + owner.InternalName : info.OverridePalette); + var ownerName = init.Get().InternalName; + palette = wr.Palette(info.OverridePaletteIsPlayerPalette ? info.OverridePalette + ownerName : info.OverridePalette); } } @@ -95,7 +95,7 @@ foreach (var r in RenderFootprint(wr, topLeft, footprint, info.FootprintUnderPreview)) yield return r; - foreach (var r in previewRenderables.OrderBy(WorldRenderer.RenderableScreenZPositionComparisonKey)) + foreach (var r in previewRenderables.OrderBy(WorldRenderer.RenderableZPositionComparisonKey)) yield return r; if (info.FootprintOverPreview != PlaceBuildingCellType.None) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/BaseProvider.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/BaseProvider.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/BaseProvider.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/BaseProvider.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,6 +24,21 @@ public readonly int Cooldown = 0; public readonly int InitialDelay = 0; + [Desc("Range circle color when operational.")] + public readonly Color CircleReadyColor = Color.FromArgb(128, Color.White); + + [Desc("Range circle color when inactive.")] + public readonly Color CircleBlockedColor = Color.FromArgb(128, Color.Red); + + [Desc("Range circle line width.")] + public readonly float CircleWidth = 1; + + [Desc("Range circle border color.")] + public readonly Color CircleBorderColor = Color.FromArgb(96, Color.Black); + + [Desc("Range circle border width.")] + public readonly float CircleBorderWidth = 3; + public override object Create(ActorInitializer init) { return new BaseProvider(init.Self, this); } } @@ -85,8 +100,10 @@ self.CenterPosition, Info.Range, 0, - Color.FromArgb(128, Ready() ? Color.White : Color.Red), - Color.FromArgb(96, Color.Black)); + Ready() ? Info.CircleReadyColor : Info.CircleBlockedColor, + Info.CircleWidth, + Info.CircleBorderColor, + Info.CircleBorderWidth); } IEnumerable IRenderAnnotationsWhenSelected.RenderAnnotations(Actor self, WorldRenderer wr) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/Bridge.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/Bridge.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/Bridge.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/Bridge.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Traits { - class BridgeInfo : ITraitInfo, IRulesetLoaded, Requires, Requires + class BridgeInfo : TraitInfo, IRulesetLoaded, Requires, Requires { public readonly bool Long = false; @@ -49,42 +49,41 @@ [Desc("Types of damage that this bridge causes to units over/in path of it while being destroyed/repaired. Leave empty for no damage types.")] public readonly BitSet DamageTypes = default(BitSet); - public object Create(ActorInitializer init) { return new Bridge(init.Self, this); } + public override object Create(ActorInitializer init) { return new Bridge(init.Self, this); } public void RulesetLoaded(Ruleset rules, ActorInfo ai) { if (string.IsNullOrEmpty(DemolishWeapon)) throw new YamlException("A value for DemolishWeapon of a Bridge trait is missing."); - WeaponInfo weapon; var weaponToLower = DemolishWeapon.ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(weaponToLower, out weapon)) + if (!rules.Weapons.TryGetValue(weaponToLower, out var weapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); DemolishWeaponInfo = weapon; } - public IEnumerable> Templates + public IEnumerable<(ushort Template, int Health)> Templates { get { if (Template != 0) - yield return Pair.New(Template, 100); + yield return (Template, 100); if (DamagedTemplate != 0) - yield return Pair.New(DamagedTemplate, 49); + yield return (DamagedTemplate, 49); if (DestroyedTemplate != 0) - yield return Pair.New(DestroyedTemplate, 0); + yield return (DestroyedTemplate, 0); if (DestroyedPlusNorthTemplate != 0) - yield return Pair.New(DestroyedPlusNorthTemplate, 0); + yield return (DestroyedPlusNorthTemplate, 0); if (DestroyedPlusSouthTemplate != 0) - yield return Pair.New(DestroyedPlusSouthTemplate, 0); + yield return (DestroyedPlusSouthTemplate, 0); if (DestroyedPlusBothTemplate != 0) - yield return Pair.New(DestroyedPlusBothTemplate, 0); + yield return (DestroyedPlusBothTemplate, 0); } } } @@ -200,7 +199,7 @@ return footprint.Select(c => (IRenderable)(new SpriteRenderable( wr.Theater.TileSprite(new TerrainTile(template, c.Value)), - wr.World.Map.CenterOfCell(c.Key), WVec.Zero, -offset, palette, 1f, true))).ToArray(); + wr.World.Map.CenterOfCell(c.Key), WVec.Zero, -offset, palette, 1f, true, false))).ToArray(); } bool initialized; @@ -212,7 +211,7 @@ var palette = wr.Palette(TileSet.TerrainPaletteInternalName); renderables = new Dictionary(); foreach (var t in info.Templates) - renderables.Add(t.First, TemplateRenderables(wr, palette, t.First)); + renderables.Add(t.Template, TemplateRenderables(wr, palette, t.Template)); initialized = true; } @@ -303,8 +302,7 @@ // If this bridge repair operation connects two pathfinding domains, // update the domain index. var domainIndex = self.World.WorldActor.TraitOrDefault(); - if (domainIndex != null) - domainIndex.UpdateCells(self.World, footprint.Keys); + domainIndex?.UpdateCells(self.World, footprint.Keys); if (LongBridgeSegmentIsDead() && !killedUnits) { @@ -370,7 +368,7 @@ return damage; } - public void Demolish(Actor saboteur, int direction) + public void Demolish(Actor saboteur, int direction, BitSet damageTypes) { var initialDamage = health.DamageState; self.World.AddFrameEndTask(w => @@ -378,7 +376,7 @@ // Use .FromPos since this actor is killed. Cannot use Target.FromActor info.DemolishWeaponInfo.Impact(Target.FromPos(self.CenterPosition), saboteur); - self.Kill(saboteur); + self.Kill(saboteur, damageTypes); }); // Destroy adjacent spans between (including) huts @@ -388,7 +386,7 @@ 0 : info.RepairPropagationDelay; self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () => - neighbours[direction].Demolish(saboteur, direction)))); + neighbours[direction].Demolish(saboteur, direction, damageTypes)))); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/BridgeHut.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/BridgeHut.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/BridgeHut.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/BridgeHut.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,12 +12,13 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Effects; +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Allows bridges to be targeted for demolition and repair.")] - class BridgeHutInfo : IDemolishableInfo, ITraitInfo + class BridgeHutInfo : TraitInfo, IDemolishableInfo { [Desc("Bridge types to act on")] public readonly string[] Types = { "GroundLevelBridge" }; @@ -36,7 +37,7 @@ public bool IsValidTarget(ActorInfo actorInfo, Actor saboteur) { return false; } // TODO: bridges don't support frozen under fog - public object Create(ActorInitializer init) { return new BridgeHut(init.World, this); } + public override object Create(ActorInitializer init) { return new BridgeHut(init.World, this); } } class BridgeHut : INotifyCreated, IDemolishable, ITick @@ -60,6 +61,7 @@ int demolishStep; int demolishDelay; Actor demolishSaboteur; + BitSet demolishDamageTypes; public BridgeHut(World world, BridgeHutInfo info) { @@ -170,7 +172,7 @@ return true; } - void IDemolishable.Demolish(Actor self, Actor saboteur, int delay) + void IDemolishable.Demolish(Actor self, Actor saboteur, int delay, BitSet damageTypes) { // TODO: Handle using ITick self.World.Add(new DelayedAction(delay, () => @@ -188,11 +190,12 @@ { demolishStep = 0; demolishSaboteur = saboteur; + demolishDamageTypes = damageTypes; DemolishStep(); } else foreach (var s in segments.Values) - s.Demolish(saboteur); + s.Demolish(saboteur, damageTypes); } })); } @@ -214,7 +217,7 @@ if (demolishStep < segmentLocations.Count) foreach (var c in segmentLocations[demolishStep]) - segments[c].Demolish(demolishSaboteur); + segments[c].Demolish(demolishSaboteur, demolishDamageTypes); demolishDelay = Info.DemolishPropagationDelay; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/BridgePlaceholder.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/BridgePlaceholder.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/BridgePlaceholder.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/BridgePlaceholder.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Placeholder actor used for dead segments and bridge end ramps.")] - class BridgePlaceholderInfo : ITraitInfo + class BridgePlaceholderInfo : TraitInfo { public readonly string Type = "GroundLevelBridge"; @@ -27,7 +27,7 @@ public readonly CVec[] NeighbourOffsets = { }; - public object Create(ActorInitializer init) { return new BridgePlaceholder(init.Self, this); } + public override object Create(ActorInitializer init) { return new BridgePlaceholder(init.Self, this); } } class BridgePlaceholder : IBridgeSegment, INotifyAddedToWorld, INotifyRemovedFromWorld @@ -70,7 +70,7 @@ }); } - void IBridgeSegment.Demolish(Actor saboteur) + void IBridgeSegment.Demolish(Actor saboteur, BitSet damageTypes) { // Do nothing } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/Building.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/Building.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/Building.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/Building.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,7 +13,6 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; -using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -27,7 +26,7 @@ OccupiedPassableTransitOnly = '+' } - public class BuildingInfo : ITraitInfo, IOccupySpaceInfo, IPlaceBuildingDecorationInfo + public class BuildingInfo : TraitInfo, IOccupySpaceInfo, IPlaceBuildingDecorationInfo { [Desc("Where you are allowed to place the building (Water, Clear, ...)")] public readonly HashSet TerrainTypes = new HashSet(); @@ -46,6 +45,8 @@ public readonly bool AllowInvalidPlacement = false; + public readonly bool AllowPlacementOnResources = false; + [Desc("Clear smudges from underneath the building footprint.")] public readonly bool RemoveSmudgesOnBuild = true; @@ -59,7 +60,7 @@ public readonly string[] UndeploySounds = { }; - public virtual object Create(ActorInitializer init) { return new Building(init, this); } + public override object Create(ActorInitializer init) { return new Building(init, this); } protected static object LoadFootprint(MiniYaml yaml) { @@ -166,7 +167,7 @@ foreach (var bp in world.ActorsWithTrait()) { - var validOwner = bp.Actor.Owner == p || (allyBuildEnabled && bp.Actor.Owner.Stances[p] == Stance.Ally); + var validOwner = bp.Actor.Owner == p || (allyBuildEnabled && bp.Actor.Owner.RelationshipWith(p) == PlayerRelationship.Ally); if (!validOwner || !bp.Trait.Ready()) continue; @@ -211,20 +212,19 @@ for (var x = scanStart.X; x < scanEnd.X; x++) { var pos = new CPos(x, y); - var buildingAtPos = bi.GetBuildingAt(pos); if (buildingAtPos == null) { var unitsAtPos = world.ActorMap.GetActorsAt(pos).Where(a => a.IsInWorld - && (a.Owner == p || (allyBuildEnabled && a.Owner.Stances[p] == Stance.Ally)) + && (a.Owner == p || (allyBuildEnabled && a.Owner.RelationshipWith(p) == PlayerRelationship.Ally)) && ActorGrantsValidArea(a, requiresBuildableArea)); if (unitsAtPos.Any()) nearnessCandidates.Add(pos); } else if (buildingAtPos.IsInWorld && ActorGrantsValidArea(buildingAtPos, requiresBuildableArea) - && (buildingAtPos.Owner == p || (allyBuildEnabled && buildingAtPos.Owner.Stances[p] == Stance.Ally))) + && (buildingAtPos.Owner == p || (allyBuildEnabled && buildingAtPos.Owner.RelationshipWith(p) == PlayerRelationship.Ally))) nearnessCandidates.Add(pos); } } @@ -266,8 +266,8 @@ readonly Actor self; readonly BuildingInfluence influence; - Pair[] occupiedCells; - Pair[] targetableCells; + (CPos, SubCell)[] occupiedCells; + (CPos, SubCell)[] targetableCells; CPos[] transitOnlyCells; public CPos TopLeft { get { return topLeft; } } @@ -276,26 +276,26 @@ public Building(ActorInitializer init, BuildingInfo info) { self = init.Self; - topLeft = init.Get(); + topLeft = init.GetValue(); Info = info; influence = self.World.WorldActor.Trait(); occupiedCells = Info.OccupiedTiles(TopLeft) - .Select(c => Pair.New(c, SubCell.FullCell)).ToArray(); + .Select(c => (c, SubCell.FullCell)).ToArray(); targetableCells = Info.FootprintTiles(TopLeft, FootprintCellType.Occupied) - .Select(c => Pair.New(c, SubCell.FullCell)).ToArray(); + .Select(c => (c, SubCell.FullCell)).ToArray(); transitOnlyCells = Info.TransitOnlyTiles(TopLeft).ToArray(); CenterPosition = init.World.Map.CenterOfCell(topLeft) + Info.CenterOffset(init.World); } - public Pair[] OccupiedCells() { return occupiedCells; } + public (CPos, SubCell)[] OccupiedCells() { return occupiedCells; } public CPos[] TransitOnlyCells() { return transitOnlyCells; } - Pair[] ITargetableCells.TargetableCells() { return targetableCells; } + (CPos, SubCell)[] ITargetableCells.TargetableCells() { return targetableCells; } void INotifyAddedToWorld.AddedToWorld(Actor self) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/BuildingInfluence.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/BuildingInfluence.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/BuildingInfluence.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/BuildingInfluence.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,9 +15,9 @@ namespace OpenRA.Mods.Common.Traits { [Desc("A dictionary of buildings placed on the map. Attach this to the world actor.")] - public class BuildingInfluenceInfo : ITraitInfo + public class BuildingInfluenceInfo : TraitInfo { - public object Create(ActorInitializer init) { return new BuildingInfluence(init.World); } + public override object Create(ActorInitializer init) { return new BuildingInfluence(init.World); } } public class BuildingInfluence diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,31 +22,64 @@ if (!world.Map.Contains(cell)) return false; - var building = world.WorldActor.Trait().GetBuildingAt(cell); - if (building != null) + if (!bi.AllowInvalidPlacement) { - if (ai == null) - return false; + // Replaceable actors are rare, so avoid initializing state unless we have to + var checkReplacements = ai != null && ai.HasTraitInfo(); + HashSet acceptedReplacements = null; - var replacementInfo = ai.TraitInfoOrDefault(); - if (replacementInfo == null) - return false; + var foundActors = false; + foreach (var a in world.ActorMap.GetActorsAt(cell)) + { + if (a == toIgnore) + continue; - if (!building.TraitsImplementing().Any(p => !p.IsTraitDisabled && - p.Info.Types.Overlaps(replacementInfo.ReplaceableTypes))) - return false; - } - else if (!bi.AllowInvalidPlacement && world.ActorMap.GetActorsAt(cell).Any(a => a != toIgnore)) - return false; + // If this is potentially a replacement actor we must check *all* cell occupants + // before we know the placement is invalid + // Otherwise, we can bail immediately + if (!checkReplacements) + return false; + + foundActors = true; + foreach (var r in a.TraitsImplementing()) + { + if (r.IsTraitDisabled) + continue; - var tile = world.Map.Tiles[cell]; - var tileInfo = world.Map.Rules.TileSet.GetTileInfo(tile); + if (acceptedReplacements == null) + acceptedReplacements = new HashSet(); - // TODO: This is bandaiding over bogus tilesets. - if (tileInfo != null && tileInfo.RampType > 0) - return false; + acceptedReplacements.UnionWith(r.Info.Types); + } + } + + // Replacements are enabled and the cell contained at least one (not ignored) actor or building bib + var building = world.WorldActor.Trait().GetBuildingAt(cell); + if (foundActors || building != null) + { + // The cell contains at least one actor, and none were replaceable + if (acceptedReplacements == null) + return false; + + // The cell contains at least one replaceable actor, but not of the types we accept + var foundReplacement = ai.TraitInfos() + .Any(r => r.ReplaceableTypes.Overlaps(acceptedReplacements)); + + if (!foundReplacement) + return false; + } + } + else + { + // HACK: To preserve legacy behaviour, AllowInvalidPlacement should display red placement indicators + // if (and only if) there is a building or bib in the cell + var building = world.WorldActor.Trait().GetBuildingAt(cell); + if (building != null) + return false; + } - return bi.TerrainTypes.Contains(world.Map.GetTerrainInfo(cell).Type); + // Buildings can never be placed on ramps + return world.Map.Ramp[cell] == 0 && bi.TerrainTypes.Contains(world.Map.GetTerrainInfo(cell).Type); } public static bool CanPlaceBuilding(this World world, CPos cell, ActorInfo ai, BuildingInfo bi, Actor toIgnore) @@ -55,18 +88,18 @@ return true; var res = world.WorldActor.TraitOrDefault(); - return bi.Tiles(cell).All( - t => world.Map.Contains(t) && (res == null || res.GetResourceType(t) == null) && + return bi.Tiles(cell).All(t => world.Map.Contains(t) && + (bi.AllowPlacementOnResources || res == null || res.GetResourceType(t) == null) && world.IsCellBuildable(t, ai, bi, toIgnore)); } - public static IEnumerable> GetLineBuildCells(World world, CPos cell, ActorInfo ai, BuildingInfo bi, Player owner) + public static IEnumerable<(CPos Cell, Actor Actor)> GetLineBuildCells(World world, CPos cell, ActorInfo ai, BuildingInfo bi, Player owner) { var lbi = ai.TraitInfo(); var topLeft = cell; // 1x1 assumption! if (world.IsCellBuildable(topLeft, ai, bi)) - yield return Pair.New(topLeft, null); + yield return (topLeft, null); // Start at place location, search outwards // TODO: First make it work, then make it nice @@ -97,7 +130,7 @@ // Place intermediate-line sections if (dirs[d] > 0) for (var i = 1; i < dirs[d]; i++) - yield return Pair.New(topLeft + i * vecs[d], connectors[d]); + yield return (topLeft + i * vecs[d], connectors[d]); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/Exit.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/Exit.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/Exit.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/Exit.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,7 +24,7 @@ [Desc("Cell offset where the exiting actor enters the ActorMap relative to the topleft cell of the producing actor.")] public readonly CVec ExitCell = CVec.Zero; - public readonly int Facing = -1; + public readonly WAngle? Facing = null; [Desc("Type tags on this exit.")] public readonly HashSet ProductionTypes = new HashSet(); @@ -46,16 +46,18 @@ public static class ExitExts { - public static Exit FirstExitOrDefault(this Actor actor, string productionType = null) + public static Exit NearestExitOrDefault(this Actor actor, WPos pos, string productionType = null, Func p = null) { - var all = actor.TraitsImplementing() - .Where(Exts.IsTraitEnabled) - .OrderBy(e => e.Info.Priority); + // The .ToList() is required to work around a bug/unexpected behaviour in mono, where + // the ThenBy clause makes the FirstOrDefault behave differently than under .NET. + // This is important because p may have side-effects that trigger a desync if not + // called on the same exits in the same order! + var all = Exits(actor, productionType) + .OrderByDescending(e => e.Info.Priority) + .ThenBy(e => (actor.World.Map.CenterOfCell(actor.Location + e.Info.ExitCell) - pos).LengthSquared) + .ToList(); - if (string.IsNullOrEmpty(productionType)) - return all.FirstOrDefault(); - - return all.FirstOrDefault(e => e.Info.ProductionTypes.Count == 0 || e.Info.ProductionTypes.Contains(productionType)); + return p != null ? all.FirstOrDefault(p) : all.FirstOrDefault(); } public static IEnumerable Exits(this Actor actor, string productionType = null) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/FootprintPlaceBuildingPreview.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/FootprintPlaceBuildingPreview.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/FootprintPlaceBuildingPreview.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/FootprintPlaceBuildingPreview.cs 2021-03-21 11:10:05.000000000 +0000 @@ -93,7 +93,7 @@ var pal = HasFlag(c.Value, PlaceBuildingCellType.LineBuild) ? linePalette : cellPalette; var pos = wr.World.Map.CenterOfCell(c.Key); var offset = new WVec(0, 0, topLeftPos.Z - pos.Z); - yield return new SpriteRenderable(tile, pos, offset, -511, pal, 1f, true); + yield return new SpriteRenderable(tile, pos, offset, -511, pal, 1f, true, true); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,7 +28,7 @@ public readonly CVec SpawnOffset = CVec.Zero; [Desc("Which direction the unit should face.")] - public readonly int Facing = 0; + public readonly WAngle Facing = WAngle.Zero; [Desc("Whether another actor should spawn upon re-enabling the trait.")] public readonly bool AllowRespawn = false; @@ -41,15 +41,15 @@ yield return new EditorActorCheckbox("Spawn Child Actor", EditorFreeActorDisplayOrder, actor => { - var init = actor.Init(); + var init = actor.GetInitOrDefault(this); if (init != null) - return init.Value(world); + return init.Value; return true; }, (actor, value) => { - actor.ReplaceInit(new FreeActorInit(value)); + actor.ReplaceInit(new FreeActorInit(this, value), this); }); } @@ -63,7 +63,7 @@ public FreeActor(ActorInitializer init, FreeActorInfo info) : base(info) { - allowSpawn = !init.Contains() || init.Get().ActorValue; + allowSpawn = init.GetValue(info, true); } protected override void TraitEnabled(Actor self) @@ -86,19 +86,15 @@ } } - public class FreeActorInit : IActorInit + public class FreeActorInit : ValueActorInit { - [FieldFromYamlKey] - public readonly bool ActorValue = true; - public FreeActorInit() { } - public FreeActorInit(bool init) { ActorValue = init; } - public bool Value(World world) { return ActorValue; } + public FreeActorInit(TraitInfo info, bool value) + : base(info, value) { } } - public class ParentActorInit : IActorInit + public class ParentActorInit : ValueActorInit, ISingleInstanceInit { - public readonly Actor ActorValue; - public ParentActorInit(Actor parent) { ActorValue = parent; } - public Actor Value(World world) { return ActorValue; } + public ParentActorInit(Actor value) + : base(value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/FreeActorWithDelivery.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/FreeActorWithDelivery.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/FreeActorWithDelivery.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/FreeActorWithDelivery.cs 2021-03-21 11:10:05.000000000 +0000 @@ -60,10 +60,7 @@ public void DoDelivery(CPos location, string actorName, string carrierActorName) { - Actor cargo; - Actor carrier; - - CreateActors(actorName, carrierActorName, out cargo, out carrier); + CreateActors(actorName, carrierActorName, out var cargo, out var carrier); var carryable = cargo.Trait(); carryable.Reserve(cargo, carrier); @@ -85,10 +82,10 @@ var spawn = self.World.Map.CenterOfCell(location); - var initialFacing = self.World.Map.FacingBetween(location, self.Location, 0); + var initialFacing = self.World.Map.FacingBetween(location, self.Location, WAngle.Zero); // If aircraft, spawn at cruise altitude - var aircraftInfo = self.World.Map.Rules.Actors[deliveringActorName.ToLower()].TraitInfoOrDefault(); + var aircraftInfo = self.World.Map.Rules.Actors[deliveringActorName.ToLowerInvariant()].TraitInfoOrDefault(); if (aircraftInfo != null) spawn += new WVec(0, 0, aircraftInfo.CruiseAltitude.Length); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/GroundLevelBridge.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/GroundLevelBridge.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/GroundLevelBridge.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/GroundLevelBridge.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Collections.Generic; -using System.Linq; using OpenRA.GameRules; using OpenRA.Primitives; using OpenRA.Traits; @@ -18,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Bridge actor that can't be passed underneath.")] - class GroundLevelBridgeInfo : ITraitInfo, IRulesetLoaded, Requires, Requires + class GroundLevelBridgeInfo : TraitInfo, IRulesetLoaded, Requires, Requires { public readonly string TerrainType = "Bridge"; @@ -37,15 +36,14 @@ public void RulesetLoaded(Ruleset rules, ActorInfo ai) { - WeaponInfo weapon; var weaponToLower = (DemolishWeapon ?? string.Empty).ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(weaponToLower, out weapon)) + if (!rules.Weapons.TryGetValue(weaponToLower, out var weapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); DemolishWeaponInfo = weapon; } - public object Create(ActorInitializer init) { return new GroundLevelBridge(init.Self, this); } + public override object Create(ActorInitializer init) { return new GroundLevelBridge(init.Self, this); } } class GroundLevelBridge : IBridgeSegment, INotifyAddedToWorld, INotifyRemovedFromWorld @@ -72,9 +70,7 @@ foreach (var cell in cells) self.World.Map.CustomTerrain[cell] = terrainIndex; - var domainIndex = self.World.WorldActor.TraitOrDefault(); - if (domainIndex != null) - domainIndex.UpdateCells(self.World, cells); + self.World.WorldActor.TraitOrDefault()?.UpdateCells(self.World, cells); } void INotifyAddedToWorld.AddedToWorld(Actor self) @@ -108,7 +104,7 @@ health.InflictDamage(self, repairer, new Damage(-health.MaxHP), true); } - void IBridgeSegment.Demolish(Actor saboteur) + void IBridgeSegment.Demolish(Actor saboteur, BitSet damageTypes) { self.World.AddFrameEndTask(w => { @@ -118,7 +114,7 @@ // Use .FromPos since this actor is dead. Cannot use Target.FromActor Info.DemolishWeaponInfo.Impact(Target.FromPos(self.CenterPosition), saboteur); - self.Kill(saboteur); + self.Kill(saboteur, damageTypes); }); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/LegacyBridgeHut.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/LegacyBridgeHut.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/LegacyBridgeHut.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/LegacyBridgeHut.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,31 +11,36 @@ using System.Linq; using OpenRA.Effects; +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Allows bridges to be targeted for demolition and repair.")] - class LegacyBridgeHutInfo : IDemolishableInfo, ITraitInfo + class LegacyBridgeHutInfo : TraitInfo, IDemolishableInfo { public bool IsValidTarget(ActorInfo actorInfo, Actor saboteur) { return false; } // TODO: bridges don't support frozen under fog - public object Create(ActorInitializer init) { return new LegacyBridgeHut(init); } + public override object Create(ActorInitializer init) { return new LegacyBridgeHut(init, this); } } class LegacyBridgeHut : IDemolishable { - public readonly Bridge FirstBridge; - public readonly Bridge Bridge; + public Bridge FirstBridge { get; private set; } + public Bridge Bridge { get; private set; } public DamageState BridgeDamageState { get { return Bridge.AggregateDamageState(); } } public bool Repairing { get { return repairDirections > 0; } } int repairDirections = 0; - public LegacyBridgeHut(ActorInitializer init) + public LegacyBridgeHut(ActorInitializer init, LegacyBridgeHutInfo info) { - Bridge = init.Get().ActorValue.Trait(); - Bridge.AddHut(this); - FirstBridge = Bridge.Enumerate(0, true).Last(); + var bridge = init.Get().Value; + init.World.AddFrameEndTask(_ => + { + Bridge = bridge.Actor(init.World).Value.Trait(); + Bridge.AddHut(this); + FirstBridge = Bridge.Enumerate(0, true).Last(); + }); } public void Repair(Actor repairer) @@ -49,7 +54,7 @@ return BridgeDamageState != DamageState.Dead; } - void IDemolishable.Demolish(Actor self, Actor saboteur, int delay) + void IDemolishable.Demolish(Actor self, Actor saboteur, int delay, BitSet damageTypes) { // TODO: Handle using ITick self.World.Add(new DelayedAction(delay, () => @@ -62,7 +67,7 @@ .Select(t => t.GetDamageModifier(self, null)); if (Util.ApplyPercentageModifiers(100, modifiers) > 0) - Bridge.Do((b, d) => b.Demolish(saboteur, d)); + Bridge.Do((b, d) => b.Demolish(saboteur, d, damageTypes)); })); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/LineBuild.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/LineBuild.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/LineBuild.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/LineBuild.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,32 +16,29 @@ namespace OpenRA.Mods.Common.Traits { public enum LineBuildDirection { Unset, X, Y } - public class LineBuildDirectionInit : IActorInit + public class LineBuildDirectionInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - readonly LineBuildDirection value = LineBuildDirection.Unset; - - public LineBuildDirectionInit() { } - public LineBuildDirectionInit(LineBuildDirection init) { value = init; } - public LineBuildDirection Value(World world) { return value; } + public LineBuildDirectionInit(LineBuildDirection value) + : base(value) { } } - public class LineBuildParentInit : IActorInit + public class LineBuildParentInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - public readonly string[] ParentNames = new string[0]; - readonly Actor[] parents = null; - public LineBuildParentInit() { } - public LineBuildParentInit(Actor[] init) { parents = init; } - public Actor[] Value(World world) + public LineBuildParentInit(Actor[] value) + : base(new string[0]) + { + parents = value; + } + + public Actor[] ActorValue(World world) { if (parents != null) return parents; var sma = world.WorldActor.Trait(); - return ParentNames.Select(n => sma.Actors[n]).ToArray(); + return value.Select(n => sma.Actors[n]).ToArray(); } } @@ -52,7 +49,7 @@ } [Desc("Place the second actor in line to build more of the same at once (used for walls).")] - public class LineBuildInfo : ITraitInfo + public class LineBuildInfo : TraitInfo { [Desc("The maximum allowed length of the line.")] public readonly int Range = 5; @@ -67,7 +64,7 @@ [Desc("Delete generated segments when destroyed or sold.")] public readonly bool SegmentsRequireNode = false; - public object Create(ActorInitializer init) { return new LineBuild(init, this); } + public override object Create(ActorInitializer init) { return new LineBuild(init, this); } } public class LineBuild : INotifyKilled, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyLineBuildSegmentsChanged @@ -79,8 +76,9 @@ public LineBuild(ActorInitializer init, LineBuildInfo info) { this.info = info; - if (init.Contains()) - parentNodes = init.Get().Value(init.World); + var lineBuildParentInit = init.GetOrDefault(); + if (lineBuildParentInit != null) + parentNodes = lineBuildParentInit.ActorValue(init.World); } void INotifyLineBuildSegmentsChanged.SegmentAdded(Actor self, Actor segment) @@ -93,10 +91,7 @@ void INotifyLineBuildSegmentsChanged.SegmentRemoved(Actor self, Actor segment) { - if (segments == null) - return; - - segments.Remove(segment); + segments?.Remove(segment); } void INotifyAddedToWorld.AddedToWorld(Actor self) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/PrimaryBuilding.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/PrimaryBuilding.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/PrimaryBuilding.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/PrimaryBuilding.cs 2021-03-21 11:10:05.000000000 +0000 @@ -47,20 +47,13 @@ { const string OrderID = "PrimaryProducer"; - ConditionManager conditionManager; - int primaryToken = ConditionManager.InvalidConditionToken; + int primaryToken = Actor.InvalidConditionToken; public bool IsPrimary { get; private set; } public PrimaryBuilding(Actor self, PrimaryBuildingInfo info) : base(info) { } - protected override void Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - base.Created(self); - } - IEnumerable IIssueOrder.Orders { get @@ -72,7 +65,7 @@ } } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == OrderID) return new Order(order.OrderID, self, false); @@ -109,13 +102,13 @@ b.Trait.SetPrimaryProducer(b.Actor, false); } - if (conditionManager != null && primaryToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.PrimaryCondition)) - primaryToken = conditionManager.GrantCondition(self, Info.PrimaryCondition); + if (primaryToken == Actor.InvalidConditionToken) + primaryToken = self.GrantCondition(Info.PrimaryCondition); Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", Info.SelectionNotification, self.Owner.Faction.InternalName); } - else if (primaryToken != ConditionManager.InvalidConditionToken) - primaryToken = conditionManager.RevokeCondition(self, primaryToken); + else if (primaryToken != Actor.InvalidConditionToken) + primaryToken = self.RevokeCondition(primaryToken); } protected override void TraitEnabled(Actor self) { } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/ProductionAirdrop.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/ProductionAirdrop.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/ProductionAirdrop.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/ProductionAirdrop.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,10 +9,8 @@ */ #endregion -using System; using System.Linq; using OpenRA.Activities; -using OpenRA.Mods.Common; using OpenRA.Mods.Common.Activities; using OpenRA.Primitives; using OpenRA.Traits; @@ -34,7 +32,7 @@ public readonly bool BaselineSpawn = false; [Desc("Direction the aircraft should face to land.")] - public readonly int Facing = 64; + public readonly WAngle Facing = new WAngle(256); public override object Create(ActorInitializer init) { return new ProductionAirdrop(init, this); } } @@ -44,7 +42,7 @@ public ProductionAirdrop(ActorInitializer init, ProductionAirdropInfo info) : base(init, info) { } - public override bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits) + public override bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits, int refundableValue) { if (IsTraitDisabled || IsTraitPaused) return false; @@ -53,22 +51,20 @@ var owner = self.Owner; var map = owner.World.Map; var aircraftInfo = self.World.Map.Rules.Actors[info.ActorType].TraitInfo(); - var mpStart = owner.World.WorldActor.TraitOrDefault(); CPos startPos; CPos endPos; - int spawnFacing; + WAngle spawnFacing; - if (info.BaselineSpawn && mpStart != null) + if (info.BaselineSpawn) { - var spawn = mpStart.Start[owner]; var bounds = map.Bounds; var center = new MPos(bounds.Left + bounds.Width / 2, bounds.Top + bounds.Height / 2).ToCPos(map); - var spawnVec = spawn - center; - startPos = spawn + spawnVec * (Exts.ISqrt((bounds.Height * bounds.Height + bounds.Width * bounds.Width) / (4 * spawnVec.LengthSquared))); + var spawnVec = owner.HomeLocation - center; + startPos = owner.HomeLocation + spawnVec * (Exts.ISqrt((bounds.Height * bounds.Height + bounds.Width * bounds.Width) / (4 * spawnVec.LengthSquared))); endPos = startPos; var spawnDirection = new WVec((self.Location - startPos).X, (self.Location - startPos).Y, 0); - spawnFacing = spawnDirection.Yaw.Facing; + spawnFacing = spawnDirection.Yaw; } else { @@ -89,7 +85,10 @@ owner.World.AddFrameEndTask(w => { if (!self.IsInWorld || self.IsDead) + { + owner.PlayerActor.Trait().GiveCash(refundableValue); return; + } var actor = w.CreateActor(info.ActorType, new TypeDictionary { @@ -103,7 +102,10 @@ actor.QueueActivity(new CallFunc(() => { if (!self.IsInWorld || self.IsDead) + { + owner.PlayerActor.Trait().GiveCash(refundableValue); return; + } foreach (var cargo in self.TraitsImplementing()) cargo.Delivered(self); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,22 +17,23 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Used to waypoint units after production or repair is finished.")] - public class RallyPointInfo : ITraitInfo + public class RallyPointInfo : TraitInfo { public readonly string Image = "rallypoint"; [Desc("Width (in pixels) of the rallypoint line.")] public readonly int LineWidth = 1; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] public readonly string FlagSequence = "flag"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] public readonly string CirclesSequence = "circles"; + [Desc("Cursor to display when rally point can be set.")] public readonly string Cursor = "ability"; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom indicator palette name")] public readonly string Palette = "player"; @@ -46,7 +47,7 @@ [Desc("The speech notification to play when setting a new rallypoint.")] public readonly string Notification = null; - public object Create(ActorInitializer init) { return new RallyPoint(init.Self, this); } + public override object Create(ActorInitializer init) { return new RallyPoint(init.Self, this); } } public class RallyPoint : IIssueOrder, IResolveOrder, INotifyOwnerChanged, INotifyCreated @@ -74,13 +75,7 @@ void INotifyCreated.Created(Actor self) { - // Display only the first level of priority - var priorityExits = self.Info.TraitInfos() - .GroupBy(e => e.Priority) - .FirstOrDefault(); - - var exits = priorityExits != null ? priorityExits.ToArray() : new ExitInfo[0]; - self.World.Add(new RallyPointIndicator(self, this, exits)); + self.World.Add(new RallyPointIndicator(self, this)); } public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) @@ -96,7 +91,7 @@ get { yield return new RallyPointOrderTargeter(Info.Cursor); } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == OrderID) { @@ -139,11 +134,11 @@ public string OrderID { get { return "SetRallyPoint"; } } public int OrderPriority { get { return 0; } } - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } public bool ForceSet { get; private set; } public bool IsQueued { get; protected set; } - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (target.Type != TargetType.Terrain) return false; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/Refinery.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/Refinery.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/Refinery.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/Refinery.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,10 +21,10 @@ namespace OpenRA.Mods.Common.Traits { - public class RefineryInfo : IAcceptResourcesInfo, Requires + public class RefineryInfo : TraitInfo, Requires, IAcceptResourcesInfo { - [Desc("Actual harvester facing when docking, 0-255 counter-clock-wise.")] - public readonly int DockAngle = 0; + [Desc("Actual harvester facing when docking.")] + public readonly WAngle DockAngle = WAngle.Zero; [Desc("Docking cell relative to top-left cell.")] public readonly CVec DockOffset = CVec.Zero; @@ -49,7 +49,7 @@ public readonly int TickVelocity = 2; public readonly int TickRate = 10; - public virtual object Create(ActorInitializer init) { return new Refinery(init.Self, this); } + public override object Create(ActorInitializer init) { return new Refinery(init.Self, this); } } public class Refinery : INotifyCreated, ITick, IAcceptResources, INotifySold, INotifyCapture, @@ -71,7 +71,7 @@ public bool AllowDocking { get { return !preventDock; } } public CVec DeliveryOffset { get { return info.DockOffset; } } - public int DeliveryAngle { get { return info.DockAngle; } } + public WAngle DeliveryAngle { get { return info.DockAngle; } } public bool IsDragRequired { get { return info.IsDragRequired; } } public WVec DragOffset { get { return info.DragOffset; } } public int DragLength { get { return info.DragLength; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/RepairableBuilding.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/RepairableBuilding.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/RepairableBuilding.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/RepairableBuilding.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -28,6 +29,9 @@ [Desc("The maximum amount of HP to repair each step.")] public readonly int RepairStep = 7; + [Desc("Damage types used for the repair.")] + public readonly BitSet RepairDamageTypes = default(BitSet); + [Desc("The percentage repair bonus applied with increasing numbers of repairers.")] public readonly int[] RepairBonuses = { 100, 150, 175, 200, 220, 240, 260, 280, 300 }; @@ -53,7 +57,6 @@ readonly IHealth health; readonly Predicate isNotActiveAlly; readonly Stack repairTokens = new Stack(); - ConditionManager conditionManager; int remainingTicks; public readonly List Repairers = new List(); @@ -63,13 +66,7 @@ : base(info) { health = self.Trait(); - isNotActiveAlly = player => player.WinState != WinState.Undefined || player.Stances[self.Owner] != Stance.Ally; - } - - protected override void Created(Actor self) - { - base.Created(self); - conditionManager = self.TraitOrDefault(); + isNotActiveAlly = player => player.WinState != WinState.Undefined || self.Owner.RelationshipWith(player) != PlayerRelationship.Ally; } [Sync] @@ -80,21 +77,21 @@ var hash = 0; foreach (var player in Repairers) hash ^= Sync.HashPlayer(player); + return hash; } } void UpdateCondition(Actor self) { - if (conditionManager == null || string.IsNullOrEmpty(Info.RepairCondition)) + if (string.IsNullOrEmpty(Info.RepairCondition)) return; - var currentRepairers = Repairers.Count; while (Repairers.Count > repairTokens.Count) - repairTokens.Push(conditionManager.GrantCondition(self, Info.RepairCondition)); + repairTokens.Push(self.GrantCondition(Info.RepairCondition)); while (Repairers.Count < repairTokens.Count && repairTokens.Count > 0) - conditionManager.RevokeCondition(self, repairTokens.Pop()); + self.RevokeCondition(repairTokens.Pop()); } public void RepairBuilding(Actor self, Player player) @@ -166,7 +163,7 @@ // activePlayers won't cause IndexOutOfRange because we capped the max amount of players // to the length of the array - self.InflictDamage(self, new Damage(-(hpToRepair * Info.RepairBonuses[activePlayers - 1] / 100))); + self.InflictDamage(self, new Damage(-(hpToRepair * Info.RepairBonuses[activePlayers - 1] / 100), Info.RepairDamageTypes)); if (health.DamageState == DamageState.Undamaged) { @@ -175,9 +172,7 @@ if (r == self.Owner) return; - var exp = r.PlayerActor.TraitOrDefault(); - if (exp != null) - exp.GiveExperience(Info.PlayerExperience); + r.PlayerActor.TraitOrDefault()?.GiveExperience(Info.PlayerExperience); }); Repairers.Clear(); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -84,9 +84,11 @@ { if (reservedForAircraft.GetActorBelow() == self) { + // HACK: Cache this in a local var, such that the inner activity of AttackMoveActivity can access the trait easily after reservedForAircraft was nulled + var aircraft = reservedForAircraft; if (rallyPoint != null && rallyPoint.Path.Count > 0) foreach (var cell in rallyPoint.Path) - reservedFor.QueueActivity(reservedForAircraft.MoveTo(cell, 1, targetLineColor: Color.Green)); + reservedFor.QueueActivity(new AttackMoveActivity(reservedFor, () => aircraft.MoveTo(cell, 1, targetLineColor: Color.OrangeRed))); else reservedFor.QueueActivity(new TakeOff(reservedFor)); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/SequencePlaceBuildingPreview.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/SequencePlaceBuildingPreview.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/SequencePlaceBuildingPreview.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/SequencePlaceBuildingPreview.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,7 @@ [Desc("Sequence name to use.")] public readonly string Sequence = "idle"; - [PaletteReference("SequencePaletteIsPlayerPalette")] + [PaletteReference(nameof(SequencePaletteIsPlayerPalette))] [Desc("Custom palette name.")] public readonly string SequencePalette = null; @@ -61,15 +61,15 @@ : base(wr, ai, info, init) { this.info = info; - var owner = init.Get().Value(wr.World); - var faction = init.Get().Value(wr.World); + var ownerName = init.Get().InternalName; + var faction = init.Get().Value; var rsi = ai.TraitInfo(); if (!string.IsNullOrEmpty(info.SequencePalette)) - palette = wr.Palette(info.SequencePaletteIsPlayerPalette ? info.SequencePalette + owner.InternalName : info.SequencePalette); + palette = wr.Palette(info.SequencePaletteIsPlayerPalette ? info.SequencePalette + ownerName : info.SequencePalette); else - palette = wr.Palette(rsi.Palette ?? rsi.PlayerPalette + owner.InternalName); + palette = wr.Palette(rsi.Palette ?? rsi.PlayerPalette + ownerName); preview = new Animation(wr.World, rsi.GetImage(ai, wr.World.Map.Rules.Sequences, faction)); preview.PlayRepeating(info.Sequence); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoAircraft.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoAircraft.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoAircraft.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoAircraft.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,10 +9,8 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; using OpenRA.Primitives; @@ -36,6 +34,15 @@ [Desc("Require the force-move modifier to display the move cursor.")] public readonly bool RequiresForceMove = false; + [Desc("Cursor to display when able to land at target building.")] + public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to land at target building.")] + public readonly string EnterBlockedCursor = "enter-blocked"; + + [Desc("Color to use for the target line for regular move orders.")] + public readonly Color TargetLineColor = Color.Green; + public override object Create(ActorInitializer init) { return new TransformsIntoAircraft(init, this); } } @@ -62,7 +69,12 @@ { if (!IsTraitDisabled) { - yield return new EnterAlliedActorTargeter("Enter", 5, AircraftCanEnter, + yield return new EnterAlliedActorTargeter( + "Enter", + 5, + Info.EnterCursor, + Info.EnterBlockedCursor, + AircraftCanEnter, target => Reservable.IsAvailableFor(target, self)); yield return new AircraftMoveOrderTargeter(self, this); @@ -84,7 +96,7 @@ } // Note: Returns a valid order even if the unit can't move to the target - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "Enter" || order.OrderID == "Move") return new Order(order.OrderID, self, target, queued); @@ -102,8 +114,6 @@ var cell = self.World.Map.Clamp(self.World.Map.CellContaining(order.Target.CenterPosition)); if (!Info.MoveIntoShroud && !self.Owner.Shroud.IsExplored(cell)) return; - - var target = Target.FromCell(self.World, cell); } else if (order.OrderString == "Enter") { @@ -112,8 +122,11 @@ if (order.Target.Type != TargetType.Actor) return; - var targetActor = order.Target.Actor; + if (!AircraftCanEnter(order.Target.Actor)) + return; } + else + return; var currentTransform = self.CurrentActivity as Transform; var transform = transforms.FirstOrDefault(t => !t.IsTraitDisabled && !t.IsTraitPaused); @@ -122,10 +135,10 @@ // Manually manage the inner activity queue var activity = currentTransform ?? transform.GetTransformActivity(self); - if (!order.Queued && activity.NextActivity != null) - activity.NextActivity.Cancel(self); + if (!order.Queued) + activity.NextActivity?.Cancel(self); - activity.Queue(new IssueOrderAfterTransform(order.OrderString, order.Target, Color.Green)); + activity.Queue(new IssueOrderAfterTransform(order.OrderString, order.Target, Info.TargetLineColor)); if (currentTransform == null) self.QueueActivity(order.Queued, activity); @@ -159,7 +172,7 @@ { readonly TransformsIntoAircraft aircraft; - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { // Always prioritise orders over selecting other peoples actors or own actors that are already selected if (target.Type == TargetType.Actor && (target.Actor.Owner != self.Owner || self.World.Selection.Contains(target.Actor))) @@ -177,7 +190,7 @@ public int OrderPriority { get { return 4; } } public bool IsQueued { get; protected set; } - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (target.Type != TargetType.Terrain || (aircraft.Info.RequiresForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))) return false; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoEntersTunnels.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoEntersTunnels.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoEntersTunnels.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoEntersTunnels.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,12 +9,9 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Activities; using OpenRA.Mods.Common.Activities; -using OpenRA.Mods.Common.Orders; using OpenRA.Primitives; using OpenRA.Traits; @@ -23,9 +20,15 @@ [Desc("Add to a building to expose a move cursor that triggers Transforms and issues an enter tunnel order to the transformed actor.")] public class TransformsIntoEntersTunnelsInfo : ConditionalTraitInfo, Requires { + [Desc("Cursor to display when able to enter target tunnel.")] public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to enter target tunnel.")] public readonly string EnterBlockedCursor = "enter-blocked"; + [Desc("Color to use for the target line while in tunnels.")] + public readonly Color TargetLineColor = Color.Green; + [VoiceReference] public readonly string Voice = "Action"; @@ -71,7 +74,7 @@ return self.CurrentActivity is Transform || transforms.Any(t => !t.IsTraitDisabled && !t.IsTraitPaused); } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "EnterTunnel") return new Order(order.OrderID, self, target, queued) { SuppressVisualFeedback = true }; @@ -95,10 +98,10 @@ // Manually manage the inner activity queue var activity = currentTransform ?? transform.GetTransformActivity(self); - if (!order.Queued && activity.NextActivity != null) - activity.NextActivity.Cancel(self); + if (!order.Queued) + activity.NextActivity?.Cancel(self); - activity.Queue(new IssueOrderAfterTransform(order.OrderString, order.Target, Color.Green)); + activity.Queue(new IssueOrderAfterTransform(order.OrderString, order.Target, Info.TargetLineColor)); if (currentTransform == null) self.QueueActivity(order.Queued, activity); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoMobile.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoMobile.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoMobile.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoMobile.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,10 +9,8 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Primitives; using OpenRA.Traits; @@ -27,12 +25,18 @@ [Desc("Locomotor used by the transformed actor. Must be defined on the World actor.")] public readonly string Locomotor = null; + [Desc("Cursor to display when a move order can be issued at target location.")] public readonly string Cursor = "move"; + + [Desc("Cursor to display when a move order cannot be issued at target location.")] public readonly string BlockedCursor = "move-blocked"; [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line for regular move orders.")] + public readonly Color TargetLineColor = Color.Green; + [Desc("Require the force-move modifier to display the move cursor.")] public readonly bool RequiresForceMove = false; @@ -83,7 +87,7 @@ } // Note: Returns a valid order even if the unit can't move to the target - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order is MoveOrderTargeter) return new Order("Move", self, target, queued); @@ -109,10 +113,10 @@ // Manually manage the inner activity queue var activity = currentTransform ?? transform.GetTransformActivity(self); - if (!order.Queued && activity.NextActivity != null) - activity.NextActivity.Cancel(self); + if (!order.Queued) + activity.NextActivity?.Cancel(self); - activity.Queue(new IssueOrderAfterTransform("Move", order.Target, Color.Green)); + activity.Queue(new IssueOrderAfterTransform("Move", order.Target, Info.TargetLineColor)); if (currentTransform == null) self.QueueActivity(order.Queued, activity); @@ -158,7 +162,7 @@ { readonly TransformsIntoMobile mobile; readonly bool rejectMove; - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { // Always prioritise orders over selecting other peoples actors or own actors that are already selected if (target.Type == TargetType.Actor && (target.Actor.Owner != self.Owner || self.World.Selection.Contains(target.Actor))) @@ -177,7 +181,7 @@ public int OrderPriority { get { return 4; } } public bool IsQueued { get; protected set; } - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (rejectMove || target.Type != TargetType.Terrain || (mobile.Info.RequiresForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))) return false; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoPassenger.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoPassenger.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoPassenger.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoPassenger.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,10 +9,8 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; using OpenRA.Primitives; @@ -29,9 +27,18 @@ [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Green; + [Desc("Require the force-move modifier to display the enter cursor.")] public readonly bool RequiresForceMove = false; + [Desc("Cursor to display when able to enter target actor.")] + public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to enter target actor.")] + public readonly string EnterBlockedCursor = "enter-blocked"; + public override object Create(ActorInitializer init) { return new TransformsIntoPassenger(init.Self, this); } } @@ -57,11 +64,17 @@ get { if (!IsTraitDisabled) - yield return new EnterAlliedActorTargeter("EnterTransport", 5, IsCorrectCargoType, CanEnter); + yield return new EnterAlliedActorTargeter( + "EnterTransport", + 5, + Info.EnterCursor, + Info.EnterBlockedCursor, + IsCorrectCargoType, + CanEnter); } } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "EnterTransport") return new Order(order.OrderID, self, target, queued); @@ -119,10 +132,10 @@ // Manually manage the inner activity queue var activity = currentTransform ?? transform.GetTransformActivity(self); - if (!order.Queued && activity.NextActivity != null) - activity.NextActivity.Cancel(self); + if (!order.Queued) + activity.NextActivity?.Cancel(self); - activity.Queue(new IssueOrderAfterTransform(order.OrderString, order.Target, Color.Green)); + activity.Queue(new IssueOrderAfterTransform(order.OrderString, order.Target, Info.TargetLineColor)); if (currentTransform == null) self.QueueActivity(order.Queued, activity); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoRepairable.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoRepairable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoRepairable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoRepairable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,10 +9,8 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; using OpenRA.Primitives; @@ -30,9 +28,18 @@ [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Green; + [Desc("Require the force-move modifier to display the enter cursor.")] public readonly bool RequiresForceMove = false; + [Desc("Cursor to display when able to be repaired at target actor.")] + public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to be repaired at target actor.")] + public readonly string EnterBlockedCursor = "enter-blocked"; + public override object Create(ActorInitializer init) { return new TransformsIntoRepairable(init.Self, this); } } @@ -60,7 +67,13 @@ get { if (!IsTraitDisabled) - yield return new EnterAlliedActorTargeter("Repair", 5, CanRepairAt, _ => CanRepair()); + yield return new EnterAlliedActorTargeter( + "Repair", + 5, + Info.EnterCursor, + Info.EnterBlockedCursor, + CanRepairAt, + _ => CanRepair()); } } @@ -85,7 +98,7 @@ return Info.RepairActors.Contains(target.Info.Name); } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "Repair") return new Order(order.OrderID, self, target, queued); @@ -113,10 +126,10 @@ // Manually manage the inner activity queue var activity = currentTransform ?? transform.GetTransformActivity(self); - if (!order.Queued && activity.NextActivity != null) - activity.NextActivity.Cancel(self); + if (!order.Queued) + activity.NextActivity?.Cancel(self); - activity.Queue(new IssueOrderAfterTransform(order.OrderString, order.Target, Color.Green)); + activity.Queue(new IssueOrderAfterTransform(order.OrderString, order.Target, Info.TargetLineColor)); if (currentTransform == null) self.QueueActivity(order.Queued, activity); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoTransforms.cs openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoTransforms.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoTransforms.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Buildings/TransformsIntoTransforms.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using OpenRA.Mods.Common.Activities; -using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -41,10 +40,10 @@ if (!order.Queued || currentTransform == null) return; - if (!order.Queued && currentTransform.NextActivity != null) - currentTransform.NextActivity.Cancel(self); + if (!order.Queued) + currentTransform.NextActivity?.Cancel(self); - currentTransform.Queue(new IssueOrderAfterTransform("DeployTransform", order.Target, Color.Green)); + currentTransform.Queue(new IssueOrderAfterTransform("DeployTransform", order.Target)); self.ShowTargetLines(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Burns.cs openra-20210321/OpenRA.Mods.Common/Traits/Burns.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Burns.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Burns.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using OpenRA.Graphics; -using OpenRA.Mods.Common.Traits.Render; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - [Desc("This actor will play a fire animation over its body and take damage over time.")] - class BurnsInfo : ITraitInfo, Requires - { - public readonly string Anim = "1"; - public readonly int Damage = 1; - public readonly int Interval = 8; - - public object Create(ActorInitializer init) { return new Burns(init.Self, this); } - } - - class Burns : ITick, ISync - { - readonly BurnsInfo info; - [Sync] - int ticks; - - public Burns(Actor self, BurnsInfo info) - { - this.info = info; - - var anim = new Animation(self.World, "fire", () => 0); - anim.IsDecoration = true; - anim.PlayRepeating(info.Anim); - self.Trait().Add(anim); - } - - void ITick.Tick(Actor self) - { - if (--ticks <= 0) - { - self.InflictDamage(self, new Damage(info.Damage)); - ticks = info.Interval; - } - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Capturable.cs openra-20210321/OpenRA.Mods.Common/Traits/Capturable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Capturable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Capturable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,9 +22,10 @@ [Desc("CaptureTypes (from the Captures trait) that are able to capture this.")] public readonly BitSet Types = default(BitSet); - [Desc("What diplomatic stances can be captured by this actor.")] - public readonly Stance ValidStances = Stance.Neutral | Stance.Enemy; + [Desc("What player relationships the target's owner needs to be captured by this actor.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy; + [Desc("Cancel the actor's current activity when getting captured.")] public readonly bool CancelActivity = false; public override object Create(ActorInitializer init) { return new Capturable(init.Self, this); } @@ -43,11 +44,7 @@ void INotifyCapture.OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner, BitSet captureTypes) { if (Info.CancelActivity) - { - var stop = new Order("Stop", self, false); - foreach (var t in self.TraitsImplementing()) - t.ResolveOrder(self, stop); - } + self.CancelActivity(); } protected override void TraitEnabled(Actor self) { captureManager.RefreshCapturable(self); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/CapturableProgressBar.cs openra-20210321/OpenRA.Mods.Common/Traits/CapturableProgressBar.cs --- openra-20200503/OpenRA.Mods.Common/Traits/CapturableProgressBar.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/CapturableProgressBar.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,7 +26,7 @@ class CapturableProgressBar : ConditionalTrait, ISelectionBar, ICaptureProgressWatcher { - Dictionary> progress = new Dictionary>(); + Dictionary progress = new Dictionary(); public CapturableProgressBar(Actor self, CapturableProgressBarInfo info) : base(info) { } @@ -39,7 +39,7 @@ if (total == 0) progress.Remove(captor); else - progress[captor] = Pair.New(current, total); + progress[captor] = (current, total); } float ISelectionBar.GetValue() @@ -47,7 +47,7 @@ if (IsTraitDisabled || !progress.Any()) return 0f; - return progress.Values.Max(p => (float)p.First / p.Second); + return progress.Values.Max(p => (float)p.Current / p.Total); } Color ISelectionBar.GetColor() { return Info.Color; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/CapturableProgressBlink.cs openra-20210321/OpenRA.Mods.Common/Traits/CapturableProgressBlink.cs --- openra-20200503/OpenRA.Mods.Common/Traits/CapturableProgressBlink.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/CapturableProgressBlink.cs 2021-03-21 11:10:05.000000000 +0000 @@ -54,7 +54,7 @@ if (IsTraitDisabled) return; - if (!captorOwners.Any()) + if (captorOwners.Count == 0) { tick = 0; return; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/CaptureManager.cs openra-20210321/OpenRA.Mods.Common/Traits/CaptureManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/CaptureManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/CaptureManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,7 @@ } [Desc("Manages Captures and Capturable traits on an actor.")] - public class CaptureManagerInfo : ITraitInfo + public class CaptureManagerInfo : TraitInfo { [GrantedConditionReference] [Desc("Condition granted when capturing an actor.")] @@ -38,7 +38,7 @@ [Desc("Should units friendly to the capturing actor auto-target this actor while it is being captured?")] public readonly bool PreventsAutoTarget = true; - public virtual object Create(ActorInitializer init) { return new CaptureManager(this); } + public override object Create(ActorInitializer init) { return new CaptureManager(this); } public bool CanBeTargetedBy(FrozenActor frozenActor, Actor captor, Captures captures) { @@ -48,17 +48,15 @@ // TODO: FrozenActors don't yet have a way of caching conditions, so we can't filter disabled traits // This therefore assumes that all Capturable traits are enabled, which is probably wrong. // Actors with FrozenUnderFog should therefore not disable the Capturable trait. - var stance = frozenActor.Owner.Stances[captor.Owner]; + var stance = captor.Owner.RelationshipWith(frozenActor.Owner); return frozenActor.Info.TraitInfos() - .Any(c => c.ValidStances.HasStance(stance) && - captures.Info.CaptureTypes.Overlaps(c.Types)); + .Any(c => c.ValidRelationships.HasStance(stance) && captures.Info.CaptureTypes.Overlaps(c.Types)); } } public class CaptureManager : INotifyCreated, INotifyCapture, ITick, IDisableEnemyAutoTarget { readonly CaptureManagerInfo info; - ConditionManager conditionManager; IMove move; ICaptureProgressWatcher[] progressWatchers; @@ -75,8 +73,8 @@ CaptureManager currentTargetManager; int currentTargetDelay; int currentTargetTotal; - int capturingToken = ConditionManager.InvalidConditionToken; - int beingCapturedToken = ConditionManager.InvalidConditionToken; + int capturingToken = Actor.InvalidConditionToken; + int beingCapturedToken = Actor.InvalidConditionToken; bool enteringCurrentTarget; HashSet currentCaptors = new HashSet(); @@ -90,7 +88,6 @@ void INotifyCreated.Created(Actor self) { - conditionManager = self.TraitOrDefault(); move = self.TraitOrDefault(); progressWatchers = self.TraitsImplementing().ToArray(); @@ -111,13 +108,13 @@ allyCapturableTypes = neutralCapturableTypes = enemyCapturableTypes = default(BitSet); foreach (var c in enabledCapturable) { - if (c.Info.ValidStances.HasStance(Stance.Ally)) + if (c.Info.ValidRelationships.HasStance(PlayerRelationship.Ally)) allyCapturableTypes = allyCapturableTypes.Union(c.Info.Types); - if (c.Info.ValidStances.HasStance(Stance.Neutral)) + if (c.Info.ValidRelationships.HasStance(PlayerRelationship.Neutral)) neutralCapturableTypes = neutralCapturableTypes.Union(c.Info.Types); - if (c.Info.ValidStances.HasStance(Stance.Enemy)) + if (c.Info.ValidRelationships.HasStance(PlayerRelationship.Enemy)) enemyCapturableTypes = enemyCapturableTypes.Union(c.Info.Types); } } @@ -131,14 +128,14 @@ public bool CanBeTargetedBy(Actor self, Actor captor, CaptureManager captorManager) { - var stance = self.Owner.Stances[captor.Owner]; - if (stance.HasStance(Stance.Enemy)) + var stance = captor.Owner.RelationshipWith(self.Owner); + if (stance.HasStance(PlayerRelationship.Enemy)) return captorManager.capturesTypes.Overlaps(enemyCapturableTypes); - if (stance.HasStance(Stance.Neutral)) + if (stance.HasStance(PlayerRelationship.Neutral)) return captorManager.capturesTypes.Overlaps(neutralCapturableTypes); - if (stance.HasStance(Stance.Ally)) + if (stance.HasStance(PlayerRelationship.Ally)) return captorManager.capturesTypes.Overlaps(allyCapturableTypes); return false; @@ -149,14 +146,14 @@ if (captures.IsTraitDisabled) return false; - var stance = self.Owner.Stances[captor.Owner]; - if (stance.HasStance(Stance.Enemy)) + var stance = captor.Owner.RelationshipWith(self.Owner); + if (stance.HasStance(PlayerRelationship.Enemy)) return captures.Info.CaptureTypes.Overlaps(enemyCapturableTypes); - if (stance.HasStance(Stance.Neutral)) + if (stance.HasStance(PlayerRelationship.Neutral)) return captures.Info.CaptureTypes.Overlaps(neutralCapturableTypes); - if (stance.HasStance(Stance.Ally)) + if (stance.HasStance(PlayerRelationship.Ally)) return captures.Info.CaptureTypes.Overlaps(allyCapturableTypes); return false; @@ -206,13 +203,11 @@ else currentTargetDelay += 1; - if (conditionManager != null && !string.IsNullOrEmpty(info.CapturingCondition) && - capturingToken == ConditionManager.InvalidConditionToken) - capturingToken = conditionManager.GrantCondition(self, info.CapturingCondition); - - if (targetManager.conditionManager != null && !string.IsNullOrEmpty(targetManager.info.BeingCapturedCondition) && - targetManager.beingCapturedToken == ConditionManager.InvalidConditionToken) - targetManager.beingCapturedToken = targetManager.conditionManager.GrantCondition(target, targetManager.info.BeingCapturedCondition); + if (capturingToken == Actor.InvalidConditionToken) + capturingToken = self.GrantCondition(info.CapturingCondition); + + if (targetManager.beingCapturedToken == Actor.InvalidConditionToken) + targetManager.beingCapturedToken = target.GrantCondition(targetManager.info.BeingCapturedCondition); captures = enabledCaptures .OrderBy(c => c.Info.CaptureDelay) @@ -262,11 +257,11 @@ foreach (var w in targetManager.progressWatchers) w.Update(target, self, target, 0, 0); - if (capturingToken != ConditionManager.InvalidConditionToken) - capturingToken = conditionManager.RevokeCondition(self, capturingToken); + if (capturingToken != Actor.InvalidConditionToken) + capturingToken = self.RevokeCondition(capturingToken); - if (targetManager.beingCapturedToken != ConditionManager.InvalidConditionToken) - targetManager.beingCapturedToken = targetManager.conditionManager.RevokeCondition(self, targetManager.beingCapturedToken); + if (targetManager.beingCapturedToken != Actor.InvalidConditionToken) + targetManager.beingCapturedToken = target.RevokeCondition(targetManager.beingCapturedToken); currentTarget = null; currentTargetManager = null; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Captures.cs openra-20210321/OpenRA.Mods.Common/Traits/Captures.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Captures.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Captures.cs 2021-03-21 11:10:05.000000000 +0000 @@ -43,16 +43,24 @@ [Desc("Experience granted to the capturing player.")] public readonly int PlayerExperience = 0; - [Desc("Stance that the structure's previous owner needs to have for the capturing player to receive Experience.")] - public readonly Stance PlayerExperienceStances = Stance.Enemy; + [Desc("Relationships that the structure's previous owner needs to have for the capturing player to receive Experience.")] + public readonly PlayerRelationship PlayerExperienceRelationships = PlayerRelationship.Enemy; + [Desc("Cursor to display when the health of the target actor is above the sabotage threshold.")] public readonly string SabotageCursor = "capture"; + + [Desc("Cursor to display when able to capture the target actor.")] public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to capture the target actor.")] public readonly string EnterBlockedCursor = "enter-blocked"; [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Crimson; + public override object Create(ActorInitializer init) { return new Captures(init.Self, this); } } @@ -77,7 +85,7 @@ } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID != "CaptureActor") return null; @@ -95,7 +103,7 @@ if (order.OrderString != "CaptureActor" || IsTraitDisabled) return; - self.QueueActivity(order.Queued, new CaptureActor(self, order.Target)); + self.QueueActivity(order.Queued, new CaptureActor(self, order.Target, Info.TargetLineColor)); self.ShowTargetLines(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Cargo.cs openra-20210321/OpenRA.Mods.Common/Traits/Cargo.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Cargo.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Cargo.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,14 +21,11 @@ namespace OpenRA.Mods.Common.Traits { [Desc("This actor can transport Passenger actors.")] - public class CargoInfo : ITraitInfo, Requires + public class CargoInfo : TraitInfo, Requires { [Desc("The maximum sum of Passenger.Weight that this actor can support.")] public readonly int MaxWeight = 0; - [Desc("Number of pips to display when this actor is selected.")] - public readonly int PipCount = 0; - [Desc("`Passenger.CargoType`s that can be loaded into this actor.")] public readonly HashSet Types = new HashSet(); @@ -52,7 +49,7 @@ public readonly WDist LoadRange = WDist.FromCells(5); [Desc("Which direction the passenger will face (relative to the transport) when unloading.")] - public readonly int PassengerFacing = 128; + public readonly WAngle PassengerFacing = new WAngle(512); [Desc("Delay (in ticks) before continuing after loading a passenger.")] public readonly int AfterLoadDelay = 8; @@ -78,6 +75,7 @@ "Condition can stack with multiple passengers.")] public readonly string LoadedCondition = null; + [ActorReference(dictionaryReference: LintDictionaryReference.Keys)] [Desc("Conditions to grant when specified actors are loaded inside the transport.", "A dictionary of [actor id]: [condition].")] public readonly Dictionary PassengerConditions = new Dictionary(); @@ -85,10 +83,10 @@ [GrantedConditionReference] public IEnumerable LinterPassengerConditions { get { return PassengerConditions.Values; } } - public object Create(ActorInitializer init) { return new Cargo(init, this); } + public override object Create(ActorInitializer init) { return new Cargo(init, this); } } - public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderVoice, INotifyCreated, INotifyKilled, + public class Cargo : IIssueOrder, IResolveOrder, IOrderVoice, INotifyCreated, INotifyKilled, INotifyOwnerChanged, INotifySold, INotifyActorDisposing, IIssueDeployOrder, ITransformActorInitModifier { @@ -103,8 +101,7 @@ int totalWeight = 0; int reservedWeight = 0; Aircraft aircraft; - ConditionManager conditionManager; - int loadingToken = ConditionManager.InvalidConditionToken; + int loadingToken = Actor.InvalidConditionToken; Stack loadedTokens = new Stack(); bool takeOffAfterLoad; bool initialised; @@ -133,14 +130,16 @@ return Util.AdjacentCells(self.World, Target.FromActor(self)).Where(c => loc != c); }); - if (init.Contains()) + var runtimeCargoInit = init.GetOrDefault(info); + var cargoInit = init.GetOrDefault(info); + if (runtimeCargoInit != null) { - cargo = new List(init.Get()); + cargo = runtimeCargoInit.Value.ToList(); totalWeight = cargo.Sum(c => GetWeight(c)); } - else if (init.Contains()) + else if (cargoInit != null) { - foreach (var u in init.Get()) + foreach (var u in cargoInit.Value) { var unit = self.World.CreateActor(false, u.ToLowerInvariant(), new TypeDictionary { new OwnerInit(self.Owner) }); @@ -169,19 +168,15 @@ void INotifyCreated.Created(Actor self) { aircraft = self.TraitOrDefault(); - conditionManager = self.TraitOrDefault(); - if (conditionManager != null && cargo.Any()) + if (cargo.Any()) { foreach (var c in cargo) - { - string passengerCondition; - if (Info.PassengerConditions.TryGetValue(c.Info.Name, out passengerCondition)) - passengerTokens.GetOrAdd(c.Info.Name).Push(conditionManager.GrantCondition(self, passengerCondition)); - } + if (Info.PassengerConditions.TryGetValue(c.Info.Name, out var passengerCondition)) + passengerTokens.GetOrAdd(c.Info.Name).Push(self.GrantCondition(passengerCondition)); if (!string.IsNullOrEmpty(Info.LoadedCondition)) - loadedTokens.Push(conditionManager.GrantCondition(self, Info.LoadedCondition)); + loadedTokens.Push(self.GrantCondition(Info.LoadedCondition)); } // Defer notifications until we are certain all traits on the transport are initialised @@ -213,7 +208,7 @@ } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "Unload") return new Order(order.OrderID, self, queued); @@ -267,8 +262,8 @@ if (!HasSpace(w)) return false; - if (conditionManager != null && loadingToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.LoadingCondition)) - loadingToken = conditionManager.GrantCondition(self, Info.LoadingCondition); + if (loadingToken == Actor.InvalidConditionToken) + loadingToken = self.GrantCondition(Info.LoadingCondition); reserves.Add(a); reservedWeight += w; @@ -286,8 +281,8 @@ reserves.Remove(a); ReleaseLock(self); - if (loadingToken != ConditionManager.InvalidConditionToken) - loadingToken = conditionManager.RevokeCondition(self, loadingToken); + if (loadingToken != Actor.InvalidConditionToken) + loadingToken = self.RevokeCondition(loadingToken); } // Prepare for transport pickup @@ -356,12 +351,11 @@ var p = passenger.Trait(); p.Transport = null; - Stack passengerToken; - if (passengerTokens.TryGetValue(passenger.Info.Name, out passengerToken) && passengerToken.Any()) - conditionManager.RevokeCondition(self, passengerToken.Pop()); + if (passengerTokens.TryGetValue(passenger.Info.Name, out var passengerToken) && passengerToken.Any()) + self.RevokeCondition(passengerToken.Pop()); if (loadedTokens.Any()) - conditionManager.RevokeCondition(self, loadedTokens.Pop()); + self.RevokeCondition(loadedTokens.Pop()); return passenger; } @@ -374,33 +368,6 @@ var passengerFacing = passenger.TraitOrDefault(); if (passengerFacing != null) passengerFacing.Facing = facing.Value.Facing + Info.PassengerFacing; - - foreach (var t in passenger.TraitsImplementing()) - t.TurretFacing = facing.Value.Facing + Info.PassengerFacing; - } - - public IEnumerable GetPips(Actor self) - { - var numPips = Info.PipCount; - - for (var i = 0; i < numPips; i++) - yield return GetPipAt(i); - } - - PipType GetPipAt(int i) - { - var n = i * Info.MaxWeight / Info.PipCount; - - foreach (var c in cargo) - { - var pi = c.Info.TraitInfo(); - if (n < pi.Weight) - return pi.PipType; - else - n -= pi.Weight; - } - - return PipType.Transparent; } public void Load(Actor self, Actor a) @@ -414,8 +381,8 @@ reserves.Remove(a); ReleaseLock(self); - if (loadingToken != ConditionManager.InvalidConditionToken) - loadingToken = conditionManager.RevokeCondition(self, loadingToken); + if (loadingToken != Actor.InvalidConditionToken) + loadingToken = self.RevokeCondition(loadingToken); } // Don't initialise (effectively twice) if this runs before the FrameEndTask from Created @@ -430,12 +397,11 @@ npe.OnPassengerEntered(self, a); } - string passengerCondition; - if (conditionManager != null && Info.PassengerConditions.TryGetValue(a.Info.Name, out passengerCondition)) - passengerTokens.GetOrAdd(a.Info.Name).Push(conditionManager.GrantCondition(self, passengerCondition)); + if (Info.PassengerConditions.TryGetValue(a.Info.Name, out var passengerCondition)) + passengerTokens.GetOrAdd(a.Info.Name).Push(self.GrantCondition(passengerCondition)); - if (conditionManager != null && !string.IsNullOrEmpty(Info.LoadedCondition)) - loadedTokens.Push(conditionManager.GrantCondition(self, Info.LoadedCondition)); + if (!string.IsNullOrEmpty(Info.LoadedCondition)) + loadedTokens.Push(self.GrantCondition(Info.LoadedCondition)); } void INotifyKilled.Killed(Actor self, AttackInfo e) @@ -506,25 +472,19 @@ void ITransformActorInitModifier.ModifyTransformActorInit(Actor self, TypeDictionary init) { - init.Add(new RuntimeCargoInit(Passengers.ToArray())); + init.Add(new RuntimeCargoInit(Info, Passengers.ToArray())); } } - public class RuntimeCargoInit : IActorInit, ISuppressInitExport + public class RuntimeCargoInit : ValueActorInit, ISuppressInitExport { - [FieldFromYamlKey] - readonly Actor[] value = { }; - public RuntimeCargoInit() { } - public RuntimeCargoInit(Actor[] init) { value = init; } - public Actor[] Value(World world) { return value; } + public RuntimeCargoInit(TraitInfo info, Actor[] value) + : base(info, value) { } } - public class CargoInit : IActorInit + public class CargoInit : ValueActorInit { - [FieldFromYamlKey] - readonly string[] value = { }; - public CargoInit() { } - public CargoInit(string[] init) { value = init; } - public string[] Value(World world) { return value; } + public CargoInit(TraitInfo info, string[] value) + : base(info, value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Carryable.cs openra-20210321/OpenRA.Mods.Common/Traits/Carryable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Carryable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Carryable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -44,10 +44,9 @@ public class Carryable : ConditionalTrait { - ConditionManager conditionManager; - int reservedToken = ConditionManager.InvalidConditionToken; - int carriedToken = ConditionManager.InvalidConditionToken; - int lockedToken = ConditionManager.InvalidConditionToken; + int reservedToken = Actor.InvalidConditionToken; + int carriedToken = Actor.InvalidConditionToken; + int lockedToken = Actor.InvalidConditionToken; Mobile mobile; IDelayCarryallPickup[] delayPickups; @@ -66,7 +65,6 @@ protected override void Created(Actor self) { - conditionManager = self.Trait(); mobile = self.TraitOrDefault(); delayPickups = self.TraitsImplementing().ToArray(); @@ -80,8 +78,8 @@ attached = true; - if (carriedToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.CarriedCondition)) - carriedToken = conditionManager.GrantCondition(self, Info.CarriedCondition); + if (carriedToken == Actor.InvalidConditionToken) + carriedToken = self.GrantCondition(Info.CarriedCondition); } // This gets called by carrier after we touched down @@ -92,8 +90,8 @@ attached = false; - if (carriedToken != ConditionManager.InvalidConditionToken) - carriedToken = conditionManager.RevokeCondition(self, carriedToken); + if (carriedToken != Actor.InvalidConditionToken) + carriedToken = self.RevokeCondition(carriedToken); } public virtual bool Reserve(Actor self, Actor carrier) @@ -104,8 +102,8 @@ state = State.Reserved; Carrier = carrier; - if (reservedToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.ReservedCondition)) - reservedToken = conditionManager.GrantCondition(self, Info.ReservedCondition); + if (reservedToken == Actor.InvalidConditionToken) + reservedToken = self.GrantCondition(Info.ReservedCondition); return true; } @@ -115,11 +113,11 @@ state = State.Free; Carrier = null; - if (reservedToken != ConditionManager.InvalidConditionToken) - reservedToken = conditionManager.RevokeCondition(self, reservedToken); + if (reservedToken != Actor.InvalidConditionToken) + reservedToken = self.RevokeCondition(reservedToken); - if (lockedToken != ConditionManager.InvalidConditionToken) - lockedToken = conditionManager.RevokeCondition(self, lockedToken); + if (lockedToken != Actor.InvalidConditionToken) + lockedToken = self.RevokeCondition(lockedToken); } // Prepare for transport pickup @@ -131,13 +129,16 @@ if (delayPickups.Any(d => d.IsTraitEnabled() && !d.TryLockForPickup(self, carrier))) return LockResponse.Pending; + if (mobile != null && !mobile.CanStayInCell(self.Location)) + return LockResponse.Pending; + if (state != State.Locked) { state = State.Locked; Carrier = carrier; - if (lockedToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.LockedCondition)) - lockedToken = conditionManager.GrantCondition(self, Info.LockedCondition); + if (lockedToken == Actor.InvalidConditionToken) + lockedToken = self.GrantCondition(Info.LockedCondition); } // Make sure we are not moving and at our normal position with respect to the cell grid diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/CarryableHarvester.cs openra-20210321/OpenRA.Mods.Common/Traits/CarryableHarvester.cs --- openra-20200503/OpenRA.Mods.Common/Traits/CarryableHarvester.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/CarryableHarvester.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,14 +10,13 @@ #endregion using System.Linq; -using OpenRA.Activities; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class CarryableHarvesterInfo : ITraitInfo + public class CarryableHarvesterInfo : TraitInfo { - public object Create(ActorInitializer init) { return new CarryableHarvester(); } + public override object Create(ActorInitializer init) { return new CarryableHarvester(); } } public class CarryableHarvester : INotifyCreated, INotifyHarvesterAction diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Carryall.cs openra-20210321/OpenRA.Mods.Common/Traits/Carryall.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Carryall.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Carryall.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,7 +21,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Transports actors with the `Carryable` trait.")] - public class CarryallInfo : ITraitInfo, Requires, Requires + public class CarryallInfo : TraitInfo, Requires, Requires { [Desc("Delay (in ticks) on the ground while attaching an actor to the carryall.")] public readonly int BeforeLoadDelay = 0; @@ -50,10 +50,20 @@ [Desc("Cursor to display when unable to drop off the passengers at location.")] public readonly string DropOffBlockedCursor = "move-blocked"; + [Desc("Cursor to display when picking up the passengers.")] + public readonly string PickUpCursor = "ability"; + + [GrantedConditionReference] + [Desc("Condition to grant to the Carryall while it is carrying something.")] + public readonly string CarryCondition = null; + [VoiceReference] public readonly string Voice = "Action"; - public virtual object Create(ActorInitializer init) { return new Carryall(init.Self, this); } + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Yellow; + + public override object Create(ActorInitializer init) { return new Carryall(init.Self, this); } } public class Carryall : INotifyKilled, ISync, ITick, IRender, INotifyActorDisposing, IIssueOrder, IResolveOrder, @@ -79,9 +89,10 @@ public Actor Carryable { get; private set; } public CarryallState State { get; private set; } - int cachedFacing; + WAngle cachedFacing; IActorPreview[] carryablePreview; HashSet landableTerrainTypes; + int carryConditionToken = Actor.InvalidConditionToken; /// Offset between the carryall's and the carried actor's CenterPositions public WVec CarryableOffset { get; private set; } @@ -174,6 +185,8 @@ Carryable = carryable; State = CarryallState.Carrying; self.World.ScreenMap.AddOrUpdate(self); + if (carryConditionToken == Actor.InvalidConditionToken) + carryConditionToken = self.GrantCondition(Info.CarryCondition); CarryableOffset = OffsetForCarryable(self, carryable); landableTerrainTypes = Carryable.Trait().Info.LocomotorInfo.TerrainSpeeds.Keys.ToHashSet(); @@ -185,6 +198,8 @@ { UnreserveCarryable(self); self.World.ScreenMap.AddOrUpdate(self); + if (carryConditionToken != Actor.InvalidConditionToken) + carryConditionToken = self.RevokeCondition(carryConditionToken); carryablePreview = null; landableTerrainTypes = null; @@ -237,7 +252,7 @@ var offset = body.LocalToWorld(CarryableOffset.Rotate(body.QuantizeOrientation(self, self.Orientation))); var previewRenderables = carryablePreview .SelectMany(p => p.Render(wr, self.CenterPosition + offset)) - .OrderBy(WorldRenderer.RenderableScreenZPositionComparisonKey); + .OrderBy(WorldRenderer.RenderableZPositionComparisonKey); foreach (var r in previewRenderables) yield return r; @@ -266,14 +281,14 @@ { get { - yield return new CarryallPickupOrderTargeter(); + yield return new CarryallPickupOrderTargeter(Info); yield return new DeployOrderTargeter("Unload", 10, () => CanUnload() ? Info.UnloadCursor : Info.UnloadBlockedCursor); yield return new CarryallDeliverUnitTargeter(aircraftInfo, Info); } } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "PickupUnit" || order.OrderID == "DeliverUnit" || order.OrderID == "Unload") return new Order(order.OrderID, self, target, queued); @@ -332,8 +347,8 @@ class CarryallPickupOrderTargeter : UnitOrderTargeter { - public CarryallPickupOrderTargeter() - : base("PickupUnit", 5, "ability", false, true) + public CarryallPickupOrderTargeter(CarryallInfo info) + : base("PickupUnit", 5, info.PickUpCursor, false, true) { } @@ -371,7 +386,7 @@ public string OrderID { get { return "DeliverUnit"; } } public int OrderPriority { get { return 6; } } public bool IsQueued { get; protected set; } - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } public CarryallDeliverUnitTargeter(AircraftInfo aircraftInfo, CarryallInfo info) { @@ -379,7 +394,7 @@ this.info = info; } - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (!info.AllowDropOff || !modifiers.HasModifier(TargetModifiers.ForceMove)) return false; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/CashTrickler.cs openra-20210321/OpenRA.Mods.Common/Traits/CashTrickler.cs --- openra-20200503/OpenRA.Mods.Common/Traits/CashTrickler.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/CashTrickler.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Lets the actor generate cash in a set periodic time.")] - public class CashTricklerInfo : PausableConditionalTraitInfo + public class CashTricklerInfo : PausableConditionalTraitInfo, IRulesetLoaded { [Desc("Number of ticks to wait between giving money.")] public readonly int Interval = 50; @@ -36,6 +36,12 @@ [Desc("Use resource storage for cash granted.")] public readonly bool UseResourceStorage = false; + void IRulesetLoaded.RulesetLoaded(Ruleset rules, ActorInfo info) + { + if (ShowTicks && !info.HasTraitInfo()) + throw new YamlException("CashTrickler is defined with ShowTicks 'true' but actor '{0}' occupies no space.".F(info.Name)); + } + public override object Create(ActorInitializer init) { return new CashTrickler(this); } } @@ -78,7 +84,7 @@ var cashTrickerModifier = self.TraitsImplementing().Select(x => x.GetCashTricklerModifier()); Ticks = info.Interval; - ModifyCash(self, self.Owner, Util.ApplyPercentageModifiers(info.Amount, cashTrickerModifier)); + ModifyCash(self, Util.ApplyPercentageModifiers(info.Amount, cashTrickerModifier)); } } @@ -88,7 +94,7 @@ new FloatingText(self.CenterPosition, self.Owner.Color, FloatingText.FormatCashTick(amount), info.DisplayDuration))); } - void ModifyCash(Actor self, Player newOwner, int amount) + void ModifyCash(Actor self, int amount) { if (info.UseResourceStorage) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ChangesHealth.cs openra-20210321/OpenRA.Mods.Common/Traits/ChangesHealth.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ChangesHealth.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ChangesHealth.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,90 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Attach this to actors which should regenerate or lose health points over time.")] + class ChangesHealthInfo : ConditionalTraitInfo, Requires + { + [Desc("Absolute amount of health points added in each step.", + "Use negative values to apply damage.")] + public readonly int Step = 5; + + [Desc("Relative percentages of health added in each step.", + "Use negative values to apply damage.", + "When both values are defined, their summary will be applied.")] + public readonly int PercentageStep = 0; + + [Desc("Time in ticks to wait between each health modification.")] + public readonly int Delay = 5; + + [Desc("Heal if current health is below this percentage of full health.")] + public readonly int StartIfBelow = 50; + + [Desc("Time in ticks to wait after taking damage.")] + public readonly int DamageCooldown = 0; + + [Desc("Apply the health change when encountering these damage types.")] + public readonly BitSet DamageTypes = default(BitSet); + + public override object Create(ActorInitializer init) { return new ChangesHealth(init.Self, this); } + } + + class ChangesHealth : ConditionalTrait, ITick, INotifyDamage + { + readonly IHealth health; + + [Sync] + int ticks; + + [Sync] + int damageTicks; + + public ChangesHealth(Actor self, ChangesHealthInfo info) + : base(info) + { + health = self.Trait(); + } + + void ITick.Tick(Actor self) + { + if (self.IsDead || IsTraitDisabled) + return; + + // Cast to long to avoid overflow when multiplying by the health + if (health.HP >= Info.StartIfBelow * (long)health.MaxHP / 100) + return; + + if (damageTicks > 0) + { + --damageTicks; + return; + } + + if (--ticks <= 0) + { + ticks = Info.Delay; + + // Cast to long to avoid overflow when multiplying by the health + self.InflictDamage(self, new Damage((int)-(Info.Step + Info.PercentageStep * (long)health.MaxHP / 100), Info.DamageTypes)); + } + } + + void INotifyDamage.Damaged(Actor self, AttackInfo e) + { + if (e.Damage.Value > 0) + damageTicks = Info.DamageCooldown; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ChangesTerrain.cs openra-20210321/OpenRA.Mods.Common/Traits/ChangesTerrain.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ChangesTerrain.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ChangesTerrain.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,12 +14,12 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Modifies the terrain type underneath the actors location.")] - class ChangesTerrainInfo : ITraitInfo, Requires + class ChangesTerrainInfo : TraitInfo, Requires { [FieldLoader.Require] public readonly string TerrainType = null; - public object Create(ActorInitializer init) { return new ChangesTerrain(this); } + public override object Create(ActorInitializer init) { return new ChangesTerrain(this); } } class ChangesTerrain : INotifyAddedToWorld, INotifyRemovedFromWorld diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Cloak.cs openra-20210321/OpenRA.Mods.Common/Traits/Cloak.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Cloak.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Cloak.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Activities; using OpenRA.Graphics; using OpenRA.Primitives; using OpenRA.Traits; @@ -46,14 +45,15 @@ [Desc("Measured in game ticks.")] public readonly int CloakDelay = 30; - [Desc("Events leading to the actor getting uncloaked. Possible values are: Attack, Move, Unload, Infiltrate, Demolish, Dock, Damage, Heal and SelfHeal.")] + [Desc("Events leading to the actor getting uncloaked. Possible values are: Attack, Move, Unload, Infiltrate, Demolish, Dock, Damage, Heal and SelfHeal.", + "'Dock' is triggered when docking to a refinery or resupplying.")] public readonly UncloakType UncloakOn = UncloakType.Attack | UncloakType.Unload | UncloakType.Infiltrate | UncloakType.Demolish | UncloakType.Dock; public readonly string CloakSound = null; public readonly string UncloakSound = null; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] public readonly string Palette = "cloak"; public readonly bool IsPlayerPalette = false; @@ -67,19 +67,18 @@ } public class Cloak : PausableConditionalTrait, IRenderModifier, INotifyDamage, INotifyUnload, INotifyDemolition, INotifyInfiltration, - INotifyAttack, ITick, IVisibilityModifier, IRadarColorModifier, INotifyCreated, INotifyHarvesterAction + INotifyAttack, ITick, IVisibilityModifier, IRadarColorModifier, INotifyCreated, INotifyHarvesterAction, INotifyBeingResupplied { [Sync] int remainingTime; bool isDocking; - ConditionManager conditionManager; Cloak[] otherCloaks; CPos? lastPos; bool wasCloaked = false; bool firstTick = true; - int cloakedToken = ConditionManager.InvalidConditionToken; + int cloakedToken = Actor.InvalidConditionToken; public Cloak(CloakInfo info) : base(info) @@ -89,7 +88,6 @@ protected override void Created(Actor self) { - conditionManager = self.TraitOrDefault(); otherCloaks = self.TraitsImplementing() .Where(c => c != this) .ToArray(); @@ -97,8 +95,8 @@ if (Cloaked) { wasCloaked = true; - if (conditionManager != null && cloakedToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.CloakedCondition)) - cloakedToken = conditionManager.GrantCondition(self, Info.CloakedCondition); + if (cloakedToken == Actor.InvalidConditionToken) + cloakedToken = self.GrantCondition(Info.CloakedCondition); } base.Created(self); @@ -110,9 +108,9 @@ public void Uncloak(int time) { remainingTime = Math.Max(remainingTime, time); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) { if (Info.UncloakOn.HasFlag(UncloakType.Attack)) Uncloak(); } + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (Info.UncloakOn.HasFlag(UncloakType.Attack)) Uncloak(); } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { } + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { } void INotifyDamage.Damaged(Actor self, AttackInfo e) { @@ -165,8 +163,8 @@ var isCloaked = Cloaked; if (isCloaked && !wasCloaked) { - if (conditionManager != null && cloakedToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.CloakedCondition)) - cloakedToken = conditionManager.GrantCondition(self, Info.CloakedCondition); + if (cloakedToken == Actor.InvalidConditionToken) + cloakedToken = self.GrantCondition(Info.CloakedCondition); // Sounds shouldn't play if the actor starts cloaked if (!(firstTick && Info.InitialDelay == 0) && !otherCloaks.Any(a => a.Cloaked)) @@ -174,8 +172,8 @@ } else if (!isCloaked && wasCloaked) { - if (cloakedToken != ConditionManager.InvalidConditionToken) - cloakedToken = conditionManager.RevokeCondition(self, cloakedToken); + if (cloakedToken != Actor.InvalidConditionToken) + cloakedToken = self.RevokeCondition(cloakedToken); if (!(firstTick && Info.InitialDelay == 0) && !otherCloaks.Any(a => a.Cloaked)) Game.Sound.Play(SoundType.World, Info.UncloakSound, self.CenterPosition); @@ -249,5 +247,20 @@ if (Info.UncloakOn.HasFlag(UncloakType.Infiltrate)) Uncloak(); } + + void INotifyBeingResupplied.StartingResupply(Actor self, Actor host) + { + if (Info.UncloakOn.HasFlag(UncloakType.Dock)) + { + isDocking = true; + Uncloak(); + } + } + + void INotifyBeingResupplied.StoppingResupply(Actor self, Actor host) + { + if (Info.UncloakOn.HasFlag(UncloakType.Dock)) + isDocking = false; + } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,9 +21,9 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Displays fireports, muzzle offsets, and hit areas in developer mode.")] - public class CombatDebugOverlayInfo : ITraitInfo + public class CombatDebugOverlayInfo : TraitInfo { - public object Create(ActorInitializer init) { return new CombatDebugOverlay(init.Self); } + public override object Create(ActorInitializer init) { return new CombatDebugOverlay(init.Self); } } public class CombatDebugOverlay : IRenderAnnotations, INotifyDamage, INotifyCreated @@ -55,13 +55,18 @@ IEnumerable IRenderAnnotations.RenderAnnotations(Actor self, WorldRenderer wr) { if (debugVis == null || !debugVis.CombatGeometry || self.World.FogObscures(self)) - yield break; + return Enumerable.Empty(); + + return RenderAnnotations(self, wr); + } + IEnumerable RenderAnnotations(Actor self, WorldRenderer wr) + { var blockers = allBlockers.Where(Exts.IsTraitEnabled).ToList(); if (blockers.Count > 0) { var height = new WVec(0, 0, blockers.Max(b => b.BlockingHeight.Length)); - yield return new LineAnnotationRenderable(self.CenterPosition, self.CenterPosition + height, 1, Color.Orange); + yield return new LineAnnotationRenderable(self.CenterPosition, self.CenterPosition + height, 1, Color.Orange); } var activeShapes = shapes.Where(Exts.IsTraitEnabled); @@ -110,9 +115,15 @@ foreach (var b in a.Barrels) { + var barrelEnd = new Barrel + { + Offset = b.Offset + new WVec(224, 0, 0), + Yaw = b.Yaw + }; + var muzzle = self.CenterPosition + a.MuzzleOffset(self, b); - var dirOffset = new WVec(0, -224, 0).Rotate(a.MuzzleOrientation(self, b)); - yield return new LineAnnotationRenderable(muzzle, muzzle + dirOffset, 1, Color.White); + var endMuzzle = self.CenterPosition + a.MuzzleOffset(self, barrelEnd); + yield return new LineAnnotationRenderable(muzzle, endMuzzle, 1, Color.White); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,14 +16,12 @@ namespace OpenRA.Mods.Common.Traits { /// Use as base class for *Info to subclass of ConditionalTrait. (See ConditionalTrait.) - public abstract class ConditionalTraitInfo : IObservesVariablesInfo, IRulesetLoaded + public abstract class ConditionalTraitInfo : TraitInfo, IObservesVariablesInfo, IRulesetLoaded { [ConsumedConditionReference] [Desc("Boolean expression defining the condition to enable this trait.")] public readonly BooleanExpression RequiresCondition = null; - public abstract object Create(ActorInitializer init); - // HACK: A shim for all the ActorPreview code that used to query UpgradeMinEnabledLevel directly // This can go away after we introduce an InitialConditions ActorInit and have the traits query the // condition directly diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,144 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - [Desc("Attach this to a unit to enable dynamic conditions by warheads, experience, crates, support powers, etc.")] - public class ConditionManagerInfo : TraitInfo, Requires { } - - public class ConditionManager : INotifyCreated - { - /// Value used to represent an invalid token. - public static readonly int InvalidConditionToken = -1; - - class ConditionState - { - /// Delegates that have registered to be notified when this condition changes. - public readonly List Notifiers = new List(); - - /// Unique integers identifying granted instances of the condition. - public readonly HashSet Tokens = new HashSet(); - } - - Dictionary state; - - /// Each granted condition receives a unique token that is used when revoking. - Dictionary tokens = new Dictionary(); - - int nextToken = 1; - - /// Cache of condition -> enabled state for quick evaluation of token counter conditions. - readonly Dictionary conditionCache = new Dictionary(); - - /// Read-only version of conditionCache that is passed to IConditionConsumers. - IReadOnlyDictionary readOnlyConditionCache; - - void INotifyCreated.Created(Actor self) - { - state = new Dictionary(); - readOnlyConditionCache = new ReadOnlyDictionary(conditionCache); - - var allObservers = new HashSet(); - - foreach (var provider in self.TraitsImplementing()) - { - foreach (var variableUser in provider.GetVariableObservers()) - { - allObservers.Add(variableUser.Notifier); - foreach (var variable in variableUser.Variables) - { - var cs = state.GetOrAdd(variable); - cs.Notifiers.Add(variableUser.Notifier); - conditionCache[variable] = 0; - } - } - } - - // Enable any conditions granted during trait setup - foreach (var kv in tokens) - { - ConditionState conditionState; - if (!state.TryGetValue(kv.Value, out conditionState)) - continue; - - conditionState.Tokens.Add(kv.Key); - conditionCache[kv.Value] = conditionState.Tokens.Count; - } - - // Update all traits with their initial condition state - foreach (var consumer in allObservers) - consumer(self, readOnlyConditionCache); - } - - void UpdateConditionState(Actor self, string condition, int token, bool isRevoke) - { - ConditionState conditionState; - if (!state.TryGetValue(condition, out conditionState)) - return; - - if (isRevoke) - conditionState.Tokens.Remove(token); - else - conditionState.Tokens.Add(token); - - conditionCache[condition] = conditionState.Tokens.Count; - - foreach (var notify in conditionState.Notifiers) - notify(self, readOnlyConditionCache); - } - - /// Grants a specified condition. - /// The token that is used to revoke this condition. - public int GrantCondition(Actor self, string condition) - { - var token = nextToken++; - tokens.Add(token, condition); - - // Conditions may be granted before the state is initialized. - // These conditions will be processed in INotifyCreated.Created. - if (state != null) - UpdateConditionState(self, condition, token, false); - - return token; - } - - /// - /// Revokes a previously granted condition. - /// - /// The actor to which this trait is attached. - /// The token ID returned by GrantCondition. - /// The invalid token ID. - public int RevokeCondition(Actor self, int token) - { - string condition; - if (!tokens.TryGetValue(token, out condition)) - throw new InvalidOperationException("Attempting to revoke condition with invalid token {0} for {1}.".F(token, self)); - - tokens.Remove(token); - - // Conditions may be granted and revoked before the state is initialized. - if (state != null) - UpdateConditionState(self, condition, token, true); - - return InvalidConditionToken; - } - - /// Returns whether the specified token is valid for RevokeCondition - public bool TokenValid(Actor self, int token) - { - return tokens.ContainsKey(token); - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,7 +23,7 @@ } [Desc("Allows a condition to be granted from an external source (Lua, warheads, etc).")] - public class ExternalConditionInfo : ITraitInfo, Requires + public class ExternalConditionInfo : TraitInfo { [GrantedConditionReference] [FieldLoader.Require] @@ -35,7 +35,7 @@ [Desc("If > 0, restrict the number of times that this condition can be granted by any source.")] public readonly int TotalCap = 0; - public object Create(ActorInitializer init) { return new ExternalCondition(init.Self, this); } + public override object Create(ActorInitializer init) { return new ExternalCondition(init.Self, this); } } public class ExternalCondition : ITick, INotifyCreated @@ -55,7 +55,6 @@ } public readonly ExternalConditionInfo Info; - readonly ConditionManager conditionManager; readonly Dictionary> permanentTokens = new Dictionary>(); // Tokens are sorted on insert/remove by ascending expiry time @@ -67,22 +66,18 @@ public ExternalCondition(Actor self, ExternalConditionInfo info) { Info = info; - conditionManager = self.Trait(); } public bool CanGrantCondition(Actor self, object source) { - if (conditionManager == null || source == null) + if (source == null) return false; // Timed tokens do not count towards the source cap: the condition with the shortest // remaining duration can always be revoked to make room. if (Info.SourceCap > 0) - { - HashSet permanentTokensForSource; - if (permanentTokens.TryGetValue(source, out permanentTokensForSource) && permanentTokensForSource.Count >= Info.SourceCap) + if (permanentTokens.TryGetValue(source, out var permanentTokensForSource) && permanentTokensForSource.Count >= Info.SourceCap) return false; - } if (Info.TotalCap > 0 && permanentTokens.Values.Sum(t => t.Count) >= Info.TotalCap) return false; @@ -93,11 +88,10 @@ public int GrantCondition(Actor self, object source, int duration = 0, int remaining = 0) { if (!CanGrantCondition(self, source)) - return ConditionManager.InvalidConditionToken; + return Actor.InvalidConditionToken; - var token = conditionManager.GrantCondition(self, Info.Condition); - HashSet permanent; - permanentTokens.TryGetValue(source, out permanent); + var token = self.GrantCondition(Info.Condition); + permanentTokens.TryGetValue(source, out var permanent); // Callers can override the amount of time remaining by passing a value // between 1 and the duration @@ -118,8 +112,8 @@ { var expireToken = timedTokens[expireIndex].Token; timedTokens.RemoveAt(expireIndex); - if (conditionManager.TokenValid(self, expireToken)) - conditionManager.RevokeCondition(self, expireToken); + if (self.TokenValid(expireToken)) + self.RevokeCondition(expireToken); } } } @@ -133,8 +127,8 @@ if (timedTokens.Count > 0) { var expire = timedTokens[0].Token; - if (conditionManager.TokenValid(self, expire)) - conditionManager.RevokeCondition(self, expire); + if (self.TokenValid(expire)) + self.RevokeCondition(expire); timedTokens.RemoveAt(0); } @@ -166,11 +160,10 @@ /// true if the now-revoked condition was originally granted by this trait. public bool TryRevokeCondition(Actor self, object source, int token) { - if (conditionManager == null || source == null) + if (source == null) return false; - HashSet permanentTokensForSource; - if (permanentTokens.TryGetValue(source, out permanentTokensForSource)) + if (permanentTokens.TryGetValue(source, out var permanentTokensForSource)) { if (!permanentTokensForSource.Remove(token)) return false; @@ -184,8 +177,8 @@ return false; } - if (conditionManager.TokenValid(self, token)) - conditionManager.RevokeCondition(self, token); + if (self.TokenValid(token)) + self.RevokeCondition(token); return true; } @@ -201,8 +194,8 @@ while (count < timedTokens.Count && timedTokens[count].Expires < worldTick) { var token = timedTokens[count].Token; - if (conditionManager.TokenValid(self, token)) - conditionManager.RevokeCondition(self, token); + if (self.TokenValid(token)) + self.RevokeCondition(token); count++; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantCondition.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantCondition.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantCondition.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantCondition.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,31 +29,23 @@ class GrantCondition : ConditionalTrait { - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; public GrantCondition(GrantConditionInfo info) : base(info) { } - protected override void Created(Actor self) - { - conditionManager = self.Trait(); - - base.Created(self); - } - protected override void TraitEnabled(Actor self) { - if (conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, Info.Condition); + if (conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(Info.Condition); } protected override void TraitDisabled(Actor self) { - if (Info.GrantPermanently || conditionToken == ConditionManager.InvalidConditionToken) + if (Info.GrantPermanently || conditionToken == Actor.InvalidConditionToken) return; - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + conditionToken = self.RevokeCondition(conditionToken); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnAttack.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnAttack.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnAttack.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnAttack.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,7 +52,6 @@ int cooldown = 0; int shotsFired = 0; - ConditionManager manager; // Only tracked when RevokeOnNewTarget is true. Target lastTarget = Target.Invalid; @@ -60,33 +59,26 @@ public GrantConditionOnAttack(ActorInitializer init, GrantConditionOnAttackInfo info) : base(info) { } - protected override void Created(Actor self) - { - base.Created(self); - - manager = self.TraitOrDefault(); - } - void GrantInstance(Actor self, string cond) { - if (manager == null || string.IsNullOrEmpty(cond)) + if (string.IsNullOrEmpty(cond)) return; - tokens.Push(manager.GrantCondition(self, cond)); + tokens.Push(self.GrantCondition(cond)); } void RevokeInstance(Actor self, bool revokeAll) { shotsFired = 0; - if (manager == null || tokens.Count == 0) + if (tokens.Count == 0) return; if (!revokeAll) - manager.RevokeCondition(self, tokens.Pop()); + self.RevokeCondition(tokens.Pop()); else while (tokens.Count > 0) - manager.RevokeCondition(self, tokens.Pop()); + self.RevokeCondition(tokens.Pop()); } void ITick.Tick(Actor self) @@ -98,7 +90,7 @@ } } - bool TargetChanged(Target lastTarget, Target target) + bool TargetChanged(in Target lastTarget, in Target target) { // Invalidate reveal changing the target. if (lastTarget.Type == TargetType.FrozenActor && target.Type == TargetType.Actor) @@ -128,7 +120,7 @@ return false; } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (IsTraitDisabled || IsTraitPaused) return; @@ -165,7 +157,7 @@ } } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { } + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { } protected override void TraitDisabled(Actor self) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnBotOwner.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnBotOwner.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnBotOwner.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnBotOwner.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Grants a condition to this actor when it is owned by an AI bot.")] - public class GrantConditionOnBotOwnerInfo : ITraitInfo + public class GrantConditionOnBotOwnerInfo : TraitInfo { [FieldLoader.Require] [GrantedConditionReference] @@ -26,15 +26,14 @@ [Desc("Bot types that trigger the condition.")] public readonly string[] Bots = { }; - public object Create(ActorInitializer init) { return new GrantConditionOnBotOwner(init, this); } + public override object Create(ActorInitializer init) { return new GrantConditionOnBotOwner(init, this); } } public class GrantConditionOnBotOwner : INotifyCreated, INotifyOwnerChanged { readonly GrantConditionOnBotOwnerInfo info; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; public GrantConditionOnBotOwner(ActorInitializer init, GrantConditionOnBotOwnerInfo info) { @@ -43,28 +42,17 @@ void INotifyCreated.Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.IsBot is set, so we - // must use a different method to enable this trait if - // it's defined on the PlayerActor. - self.World.AddFrameEndTask(w => - { - conditionManager = self.TraitOrDefault(); - if (conditionManager != null && self.Owner.IsBot && info.Bots.Contains(self.Owner.BotType)) - conditionToken = conditionManager.GrantCondition(self, info.Condition); - }); + if (self.Owner.IsBot && info.Bots.Contains(self.Owner.BotType)) + conditionToken = self.GrantCondition(info.Condition); } void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) { - if (conditionManager == null) - return; - - if (conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); if (info.Bots.Contains(newOwner.BotType)) - conditionToken = conditionManager.GrantCondition(self, info.Condition); + conditionToken = self.GrantCondition(info.Condition); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnCombatantOwner.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnCombatantOwner.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnCombatantOwner.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnCombatantOwner.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,53 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Grants a condition if the owner is a combatant.")] + public class GrantConditionOnCombatantOwnerInfo : TraitInfo + { + [FieldLoader.Require] + [GrantedConditionReference] + [Desc("The condition to grant.")] + public readonly string Condition = null; + + public override object Create(ActorInitializer init) { return new GrantConditionOnCombatantOwner(init.Self, this); } + } + + public class GrantConditionOnCombatantOwner : INotifyCreated, INotifyOwnerChanged + { + readonly GrantConditionOnCombatantOwnerInfo info; + + int conditionToken = Actor.InvalidConditionToken; + + public GrantConditionOnCombatantOwner(Actor self, GrantConditionOnCombatantOwnerInfo info) + { + this.info = info; + } + + void INotifyCreated.Created(Actor self) + { + if (!self.Owner.NonCombatant) + conditionToken = self.GrantCondition(info.Condition); + } + + void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) + { + if (conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); + + if (!newOwner.NonCombatant) + conditionToken = self.GrantCondition(info.Condition); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDamageState.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDamageState.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDamageState.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDamageState.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Applies a condition to the actor at specified damage states.")] - public class GrantConditionOnDamageStateInfo : ITraitInfo, Requires + public class GrantConditionOnDamageStateInfo : TraitInfo, Requires { [FieldLoader.Require] [GrantedConditionReference] @@ -33,7 +33,7 @@ [Desc("Is the condition irrevocable once it has been activated?")] public readonly bool GrantPermanently = false; - public object Create(ActorInitializer init) { return new GrantConditionOnDamageState(init.Self, this); } + public override object Create(ActorInitializer init) { return new GrantConditionOnDamageState(init.Self, this); } } public class GrantConditionOnDamageState : INotifyDamageStateChanged, INotifyCreated @@ -41,8 +41,7 @@ readonly GrantConditionOnDamageStateInfo info; readonly IHealth health; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; public GrantConditionOnDamageState(Actor self, GrantConditionOnDamageStateInfo info) { @@ -52,16 +51,15 @@ void INotifyCreated.Created(Actor self) { - conditionManager = self.Trait(); GrantConditionOnValidDamageState(self, health.DamageState); } void GrantConditionOnValidDamageState(Actor self, DamageState state) { - if (!info.ValidDamageStates.HasFlag(state) || conditionToken != ConditionManager.InvalidConditionToken) + if (!info.ValidDamageStates.HasFlag(state) || conditionToken != Actor.InvalidConditionToken) return; - conditionToken = conditionManager.GrantCondition(self, info.Condition); + conditionToken = self.GrantCondition(info.Condition); var sound = info.EnabledSounds.RandomOrDefault(Game.CosmeticRandom); Game.Sound.Play(SoundType.World, sound, self.CenterPosition); @@ -69,7 +67,7 @@ void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) { - var granted = conditionToken != ConditionManager.InvalidConditionToken; + var granted = conditionToken != Actor.InvalidConditionToken; if (granted && info.GrantPermanently) return; @@ -77,7 +75,7 @@ GrantConditionOnValidDamageState(self, health.DamageState); else if (granted && !info.ValidDamageStates.HasFlag(e.DamageState) && info.ValidDamageStates.HasFlag(e.PreviousDamageState)) { - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + conditionToken = self.RevokeCondition(conditionToken); var sound = info.DisabledSounds.RandomOrDefault(Game.CosmeticRandom); Game.Sound.Play(SoundType.World, sound, self.CenterPosition); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs 2021-03-21 11:10:05.000000000 +0000 @@ -43,8 +43,8 @@ [Desc("Cursor to display when unable to (un)deploy the actor.")] public readonly string DeployBlockedCursor = "deploy-blocked"; - [Desc("Facing that the actor must face before deploying. Set to -1 to deploy regardless of facing.")] - public readonly int Facing = -1; + [Desc("Facing that the actor must face before deploying. Leave undefined to deploy regardless of facing.")] + public readonly WAngle? Facing = null; [Desc("Play a randomly selected sound from this list when deploying.")] public readonly string[] DeploySounds = null; @@ -72,9 +72,9 @@ yield return new EditorActorCheckbox("Deployed", EditorDeployedDisplayOrder, actor => { - var init = actor.Init(); + var init = actor.GetInitOrDefault(); if (init != null) - return init.Value(world) == DeployState.Deployed; + return init.Value == DeployState.Deployed; return false; }, @@ -94,14 +94,11 @@ { readonly Actor self; readonly bool checkTerrainType; - readonly bool canTurn; - readonly IMove move; DeployState deployState; - ConditionManager conditionManager; INotifyDeployTriggered[] notify; - int deployedToken = ConditionManager.InvalidConditionToken; - int undeployedToken = ConditionManager.InvalidConditionToken; + int deployedToken = Actor.InvalidConditionToken; + int undeployedToken = Actor.InvalidConditionToken; public DeployState DeployState { get { return deployState; } } @@ -110,39 +107,33 @@ { self = init.Self; checkTerrainType = info.AllowedTerrainTypes.Count > 0; - canTurn = self.Info.HasTraitInfo(); - move = self.TraitOrDefault(); - if (init.Contains()) - deployState = init.Get(); + deployState = init.GetValue(DeployState.Undeployed); } protected override void Created(Actor self) { - conditionManager = self.TraitOrDefault(); notify = self.TraitsImplementing().ToArray(); base.Created(self); + if (Info.Facing.HasValue && deployState != DeployState.Undeployed) + { + var facing = self.TraitOrDefault(); + if (facing != null) + facing.Facing = Info.Facing.Value; + } + switch (deployState) { case DeployState.Undeployed: OnUndeployCompleted(); break; case DeployState.Deploying: - if (canTurn) - self.Trait().Facing = Info.Facing; - Deploy(true); break; case DeployState.Deployed: - if (canTurn) - self.Trait().Facing = Info.Facing; - OnDeployCompleted(); break; case DeployState.Undeploying: - if (canTurn) - self.Trait().Facing = Info.Facing; - Undeploy(true); break; } @@ -181,7 +172,7 @@ } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "GrantConditionOnDeploy") return new Order(order.OrderID, self, target, queued); @@ -243,16 +234,8 @@ if (Info.CanDeployOnRamps) return true; - var ramp = 0; - if (self.World.Map.Contains(location)) - { - var tile = self.World.Map.Tiles[location]; - var ti = self.World.Map.Rules.TileSet.GetTileInfo(tile); - if (ti != null) - ramp = ti.RampType; - } - - return ramp == 0; + var map = self.World.Map; + return !map.Ramp.Contains(location) || map.Ramp[location] == 0; } void INotifyDeployComplete.FinishedDeploy(Actor self) @@ -317,43 +300,40 @@ void OnDeployStarted() { - if (undeployedToken != ConditionManager.InvalidConditionToken) - undeployedToken = conditionManager.RevokeCondition(self, undeployedToken); + if (undeployedToken != Actor.InvalidConditionToken) + undeployedToken = self.RevokeCondition(undeployedToken); deployState = DeployState.Deploying; } void OnDeployCompleted() { - if (conditionManager != null && !string.IsNullOrEmpty(Info.DeployedCondition) && deployedToken == ConditionManager.InvalidConditionToken) - deployedToken = conditionManager.GrantCondition(self, Info.DeployedCondition); + if (deployedToken == Actor.InvalidConditionToken) + deployedToken = self.GrantCondition(Info.DeployedCondition); deployState = DeployState.Deployed; } void OnUndeployStarted() { - if (deployedToken != ConditionManager.InvalidConditionToken) - deployedToken = conditionManager.RevokeCondition(self, deployedToken); + if (deployedToken != Actor.InvalidConditionToken) + deployedToken = self.RevokeCondition(deployedToken); deployState = DeployState.Deploying; } void OnUndeployCompleted() { - if (conditionManager != null && !string.IsNullOrEmpty(Info.UndeployedCondition) && undeployedToken == ConditionManager.InvalidConditionToken) - undeployedToken = conditionManager.GrantCondition(self, Info.UndeployedCondition); + if (undeployedToken == Actor.InvalidConditionToken) + undeployedToken = self.GrantCondition(Info.UndeployedCondition); deployState = DeployState.Undeployed; } } - public class DeployStateInit : IActorInit + public class DeployStateInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - readonly DeployState value = DeployState.Deployed; - public DeployStateInit() { } - public DeployStateInit(DeployState init) { value = init; } - public DeployState Value(World world) { return value; } + public DeployStateInit(DeployState value) + : base(value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnFaction.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnFaction.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnFaction.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnFaction.cs 2021-03-21 11:10:05.000000000 +0000 @@ -33,21 +33,13 @@ class GrantConditionOnFaction : ConditionalTrait, INotifyOwnerChanged { - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; string faction; public GrantConditionOnFaction(ActorInitializer init, GrantConditionOnFactionInfo info) : base(info) { - faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName; - } - - protected override void Created(Actor self) - { - conditionManager = self.Trait(); - - base.Created(self); + faction = init.GetValue(init.Self.Owner.Faction.InternalName); } public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) @@ -63,16 +55,16 @@ protected override void TraitEnabled(Actor self) { - if (conditionToken == ConditionManager.InvalidConditionToken && Info.Factions.Contains(faction)) - conditionToken = conditionManager.GrantCondition(self, Info.Condition); + if (conditionToken == Actor.InvalidConditionToken && Info.Factions.Contains(faction)) + conditionToken = self.GrantCondition(Info.Condition); } protected override void TraitDisabled(Actor self) { - if (conditionToken == ConditionManager.InvalidConditionToken) + if (conditionToken == Actor.InvalidConditionToken) return; - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + conditionToken = self.RevokeCondition(conditionToken); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnHealth.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnHealth.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnHealth.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnHealth.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Applies a condition to the actor at when its health is between 2 specific values.")] - public class GrantConditionOnHealthInfo : ITraitInfo, IRulesetLoaded, Requires + public class GrantConditionOnHealthInfo : TraitInfo, IRulesetLoaded, Requires { [FieldLoader.Require] [GrantedConditionReference] @@ -37,7 +37,7 @@ [Desc("Is the condition irrevokable once it has been granted?")] public readonly bool GrantPermanently = false; - public object Create(ActorInitializer init) { return new GrantConditionOnHealth(init.Self, this); } + public override object Create(ActorInitializer init) { return new GrantConditionOnHealth(init.Self, this); } public void RulesetLoaded(Ruleset rules, ActorInfo ai) { @@ -53,8 +53,7 @@ readonly IHealth health; readonly int maxHP; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; public GrantConditionOnHealth(Actor self, GrantConditionOnHealthInfo info) { @@ -65,16 +64,15 @@ void INotifyCreated.Created(Actor self) { - conditionManager = self.Trait(); GrantConditionOnValidHealth(self, health.HP); } void GrantConditionOnValidHealth(Actor self, int hp) { - if (info.MinHP > hp || maxHP < hp || conditionToken != ConditionManager.InvalidConditionToken) + if (info.MinHP > hp || maxHP < hp || conditionToken != Actor.InvalidConditionToken) return; - conditionToken = conditionManager.GrantCondition(self, info.Condition); + conditionToken = self.GrantCondition(info.Condition); var sound = info.EnabledSounds.RandomOrDefault(Game.CosmeticRandom); Game.Sound.Play(SoundType.World, sound, self.CenterPosition); @@ -82,7 +80,7 @@ void INotifyDamage.Damaged(Actor self, AttackInfo e) { - var granted = conditionToken != ConditionManager.InvalidConditionToken; + var granted = conditionToken != Actor.InvalidConditionToken; if (granted && info.GrantPermanently) return; @@ -90,7 +88,7 @@ GrantConditionOnValidHealth(self, health.HP); else if (granted && (info.MinHP > health.HP || maxHP < health.HP)) { - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + conditionToken = self.RevokeCondition(conditionToken); var sound = info.DisabledSounds.RandomOrDefault(Game.CosmeticRandom); Game.Sound.Play(SoundType.World, sound, self.CenterPosition); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnJumpjetLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnJumpjetLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnJumpjetLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnJumpjetLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -40,16 +40,16 @@ protected override void UpdateConditions(Actor self, byte oldLayer, byte newLayer) { - if (!jumpjetInAir && newLayer == ValidLayerType && oldLayer != ValidLayerType && conditionToken == ConditionManager.InvalidConditionToken) + if (!jumpjetInAir && newLayer == ValidLayerType && oldLayer != ValidLayerType && conditionToken == Actor.InvalidConditionToken) { - conditionToken = conditionManager.GrantCondition(self, Info.Condition); + conditionToken = self.GrantCondition(Info.Condition); jumpjetInAir = true; } // By the time the condition is meant to be revoked, the 'oldLayer' is already no longer the Jumpjet layer, either - if (jumpjetInAir && newLayer != ValidLayerType && oldLayer != ValidLayerType && conditionToken != ConditionManager.InvalidConditionToken) + if (jumpjetInAir && newLayer != ValidLayerType && oldLayer != ValidLayerType && conditionToken != Actor.InvalidConditionToken) { - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + conditionToken = self.RevokeCondition(conditionToken); jumpjetInAir = false; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,8 +24,7 @@ public abstract class GrantConditionOnLayer : ConditionalTrait, INotifyCustomLayerChanged where InfoType : GrantConditionOnLayerInfo { protected readonly byte ValidLayerType; - protected ConditionManager conditionManager; - protected int conditionToken = ConditionManager.InvalidConditionToken; + protected int conditionToken = Actor.InvalidConditionToken; public GrantConditionOnLayer(Actor self, InfoType info, byte validLayer) : base(info) @@ -33,40 +32,31 @@ ValidLayerType = validLayer; } - protected override void Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - base.Created(self); - } - void INotifyCustomLayerChanged.CustomLayerChanged(Actor self, byte oldLayer, byte newLayer) { - if (conditionManager == null) - return; - UpdateConditions(self, oldLayer, newLayer); } protected virtual void UpdateConditions(Actor self, byte oldLayer, byte newLayer) { - if (newLayer == ValidLayerType && oldLayer != ValidLayerType && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, Info.Condition); - else if (newLayer != ValidLayerType && oldLayer == ValidLayerType && conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (newLayer == ValidLayerType && oldLayer != ValidLayerType && conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(Info.Condition); + else if (newLayer != ValidLayerType && oldLayer == ValidLayerType && conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); } protected override void TraitEnabled(Actor self) { - if (self.Location.Layer == ValidLayerType && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, Info.Condition); + if (self.Location.Layer == ValidLayerType && conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(Info.Condition); } protected override void TraitDisabled(Actor self) { - if (conditionToken == ConditionManager.InvalidConditionToken) + if (conditionToken == Actor.InvalidConditionToken) return; - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + conditionToken = self.RevokeCondition(conditionToken); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnLineBuildDirection.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnLineBuildDirection.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnLineBuildDirection.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnLineBuildDirection.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,7 +13,7 @@ namespace OpenRA.Mods.Common.Traits { - public class GrantConditionOnLineBuildDirectionInfo : ITraitInfo, Requires + public class GrantConditionOnLineBuildDirectionInfo : TraitInfo, Requires { [FieldLoader.Require] [GrantedConditionReference] @@ -24,7 +24,7 @@ [Desc("Line build direction to trigger the condition.")] public readonly LineBuildDirection Direction = LineBuildDirection.X; - public object Create(ActorInitializer init) { return new GrantConditionOnLineBuildDirection(init, this); } + public override object Create(ActorInitializer init) { return new GrantConditionOnLineBuildDirection(init, this); } } public class GrantConditionOnLineBuildDirection : INotifyCreated @@ -35,17 +35,13 @@ public GrantConditionOnLineBuildDirection(ActorInitializer init, GrantConditionOnLineBuildDirectionInfo info) { this.info = info; - direction = init.Get().Value(init.World); + direction = init.GetValue(); } void INotifyCreated.Created(Actor self) { - if (direction != info.Direction) - return; - - var conditionManager = self.TraitOrDefault(); - if (conditionManager != null && !string.IsNullOrEmpty(info.Condition)) - conditionManager.GrantCondition(self, info.Condition); + if (direction == info.Direction) + self.GrantCondition(info.Condition); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnMovement.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnMovement.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnMovement.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnMovement.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,8 +29,7 @@ public class GrantConditionOnMovement : ConditionalTrait, INotifyMoving { readonly IMove movement; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; public GrantConditionOnMovement(Actor self, GrantConditionOnMovementInfo info) : base(info) @@ -38,23 +37,14 @@ movement = self.Trait(); } - protected override void Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - base.Created(self); - } - void UpdateCondition(Actor self, MovementType types) { - if (conditionManager == null) - return; - var validMovement = !IsTraitDisabled && (types & Info.ValidMovementTypes) != 0; - if (!validMovement && conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); - else if (validMovement && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, Info.Condition); + if (!validMovement && conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); + else if (validMovement && conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(Info.Condition); } void INotifyMoving.MovementTypeChanged(Actor self, MovementType types) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPlayerResources.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPlayerResources.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPlayerResources.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPlayerResources.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,13 +9,12 @@ */ #endregion -using System.Linq; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Grants a condition to this actor when the player has stored resources.")] - public class GrantConditionOnPlayerResourcesInfo : ITraitInfo + public class GrantConditionOnPlayerResourcesInfo : TraitInfo { [FieldLoader.Require] [GrantedConditionReference] @@ -25,7 +24,7 @@ [Desc("Enable condition when the amount of stored resources is greater than this.")] public readonly int Threshold = 0; - public object Create(ActorInitializer init) { return new GrantConditionOnPlayerResources(this); } + public override object Create(ActorInitializer init) { return new GrantConditionOnPlayerResources(this); } } public class GrantConditionOnPlayerResources : INotifyCreated, INotifyOwnerChanged, ITick @@ -33,8 +32,7 @@ readonly GrantConditionOnPlayerResourcesInfo info; PlayerResources playerResources; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; public GrantConditionOnPlayerResources(GrantConditionOnPlayerResourcesInfo info) { @@ -43,13 +41,7 @@ void INotifyCreated.Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query other player traits from self, knowing that - // it refers to the same actor as self.Owner.PlayerActor - var playerActor = self.Info.Name == "player" ? self : self.Owner.PlayerActor; - playerResources = playerActor.Trait(); - conditionManager = self.TraitOrDefault(); + playerResources = self.Owner.PlayerActor.Trait(); } void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) @@ -59,14 +51,14 @@ void ITick.Tick(Actor self) { - if (string.IsNullOrEmpty(info.Condition) || conditionManager == null) + if (string.IsNullOrEmpty(info.Condition)) return; var enabled = playerResources.Resources > info.Threshold; - if (enabled && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, info.Condition); - else if (!enabled && conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (enabled && conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(info.Condition); + else if (!enabled && conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPowerState.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPowerState.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPowerState.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPowerState.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,8 +31,7 @@ public class GrantConditionOnPowerState : ConditionalTrait, INotifyOwnerChanged, INotifyPowerLevelChanged { PowerManager playerPower; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; bool validPowerState; @@ -46,8 +45,6 @@ { base.Created(self); - conditionManager = self.TraitOrDefault(); - Update(self); } @@ -63,15 +60,12 @@ void Update(Actor self) { - if (conditionManager == null) - return; - validPowerState = !IsTraitDisabled && Info.ValidPowerStates.HasFlag(playerPower.PowerState); - if (validPowerState && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, Info.Condition); - else if (!validPowerState && conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (validPowerState && conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(Info.Condition); + else if (!validPowerState && conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); } void INotifyPowerLevelChanged.PowerLevelChanged(Actor self) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPrerequisite.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPrerequisite.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPrerequisite.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnPrerequisite.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Grants a condition to the actor this is attached to when prerequisites are available.")] - public class GrantConditionOnPrerequisiteInfo : ITraitInfo + public class GrantConditionOnPrerequisiteInfo : TraitInfo { [FieldLoader.Require] [GrantedConditionReference] @@ -26,7 +26,7 @@ [Desc("List of required prerequisites.")] public readonly string[] Prerequisites = { }; - public object Create(ActorInitializer init) { return new GrantConditionOnPrerequisite(init.Self, this); } + public override object Create(ActorInitializer init) { return new GrantConditionOnPrerequisite(init.Self, this); } } public class GrantConditionOnPrerequisite : INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyOwnerChanged @@ -34,9 +34,8 @@ readonly GrantConditionOnPrerequisiteInfo info; bool wasAvailable; - ConditionManager conditionManager; GrantConditionOnPrerequisiteManager globalManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; public GrantConditionOnPrerequisite(Actor self, GrantConditionOnPrerequisiteInfo info) { @@ -45,14 +44,7 @@ void INotifyCreated.Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query other player traits from self, knowing that - // it refers to the same actor as self.Owner.PlayerActor - var playerActor = self.Info.Name == "player" ? self : self.Owner.PlayerActor; - - globalManager = playerActor.Trait(); - conditionManager = self.TraitOrDefault(); + globalManager = self.Owner.PlayerActor.Trait(); } void INotifyAddedToWorld.AddedToWorld(Actor self) @@ -74,13 +66,13 @@ public void PrerequisitesUpdated(Actor self, bool available) { - if (available == wasAvailable || conditionManager == null) + if (available == wasAvailable) return; - if (available && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, info.Condition); - else if (!available && conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (available && conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(info.Condition); + else if (!available && conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); wasAvailable = available; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnProduction.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnProduction.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnProduction.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnProduction.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Grants a condition when this actor produces a specific actor.")] - public class GrantConditionOnProductionInfo : ITraitInfo + public class GrantConditionOnProductionInfo : TraitInfo { [FieldLoader.Require] [GrantedConditionReference] @@ -35,15 +35,14 @@ public readonly bool ShowSelectionBar = true; public readonly Color SelectionBarColor = Color.Magenta; - public object Create(ActorInitializer init) { return new GrantConditionOnProduction(init.Self, this); } + public override object Create(ActorInitializer init) { return new GrantConditionOnProduction(init.Self, this); } } - public class GrantConditionOnProduction : INotifyCreated, INotifyProduction, ITick, ISync, ISelectionBar + public class GrantConditionOnProduction : INotifyProduction, ITick, ISync, ISelectionBar { readonly GrantConditionOnProductionInfo info; - ConditionManager conditionManager; - int token = ConditionManager.InvalidConditionToken; + int token = Actor.InvalidConditionToken; [Sync] int ticks; @@ -54,31 +53,26 @@ ticks = info.Duration; } - void INotifyCreated.Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - } - void INotifyProduction.UnitProduced(Actor self, Actor other, CPos exit) { if (info.Actors.Any() && !info.Actors.Select(a => a.ToLowerInvariant()).Contains(other.Info.Name)) return; - if (conditionManager != null && token == ConditionManager.InvalidConditionToken) - token = conditionManager.GrantCondition(self, info.Condition); + if (token == Actor.InvalidConditionToken) + token = self.GrantCondition(info.Condition); ticks = info.Duration; } void ITick.Tick(Actor self) { - if (info.Duration >= 0 && token != ConditionManager.InvalidConditionToken && --ticks < 0) - token = conditionManager.RevokeCondition(self, token); + if (info.Duration >= 0 && token != Actor.InvalidConditionToken && --ticks < 0) + token = self.RevokeCondition(token); } float ISelectionBar.GetValue() { - if (!info.ShowSelectionBar || info.Duration < 0 || token == ConditionManager.InvalidConditionToken) + if (!info.ShowSelectionBar || info.Duration < 0 || token == Actor.InvalidConditionToken) return 0; return (float)ticks / info.Duration; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnSubterraneanLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnSubterraneanLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnSubterraneanLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnSubterraneanLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,7 +20,7 @@ [Desc("Dig animation image to play when transitioning.")] public readonly string SubterraneanTransitionImage = null; - [SequenceReference("SubterraneanTransitionImage")] + [SequenceReference(nameof(SubterraneanTransitionImage))] [Desc("Dig animation sequence to play when transitioning.")] public readonly string SubterraneanTransitionSequence = null; @@ -74,11 +74,11 @@ // Grant condition when new layer is Subterranean and depth is lower than transition depth, // revoke condition when new layer is not Subterranean and depth is at or higher than transition depth. - if (newLayer == ValidLayerType && depth < transitionDepth && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, Info.Condition); - else if (newLayer != ValidLayerType && depth > transitionDepth && conditionToken != ConditionManager.InvalidConditionToken) + if (newLayer == ValidLayerType && depth < transitionDepth && conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(Info.Condition); + else if (newLayer != ValidLayerType && depth > transitionDepth && conditionToken != Actor.InvalidConditionToken) { - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + conditionToken = self.RevokeCondition(conditionToken); PlayTransitionAudioVisuals(self, self.Location); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnTerrain.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnTerrain.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnTerrain.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnTerrain.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits { - public class GrantConditionOnTerrainInfo : ITraitInfo + public class GrantConditionOnTerrainInfo : TraitInfo { [FieldLoader.Require] [GrantedConditionReference] @@ -25,16 +25,15 @@ [Desc("Terrain names to trigger the condition.")] public readonly string[] TerrainTypes = { }; - public object Create(ActorInitializer init) { return new GrantConditionOnTerrain(init, this); } + public override object Create(ActorInitializer init) { return new GrantConditionOnTerrain(init, this); } } - public class GrantConditionOnTerrain : INotifyCreated, ITick + public class GrantConditionOnTerrain : ITick { readonly GrantConditionOnTerrainInfo info; readonly TileSet tileSet; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; string cachedTerrain; public GrantConditionOnTerrain(ActorInitializer init, GrantConditionOnTerrainInfo info) @@ -43,28 +42,23 @@ tileSet = init.World.Map.Rules.TileSet; } - void INotifyCreated.Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - } - void ITick.Tick(Actor self) { - var loc = self.Location; - if (conditionManager == null) + var cell = self.Location; + if (!self.World.Map.Contains(cell)) return; // The terrain type may change between ticks without the actor moving - var currentTerrain = loc.Layer == 0 ? self.World.Map.GetTerrainInfo(loc).Type : - tileSet[self.World.GetCustomMovementLayers()[loc.Layer].GetTerrainIndex(loc)].Type; + var currentTerrain = cell.Layer == 0 ? self.World.Map.GetTerrainInfo(cell).Type : + tileSet[self.World.GetCustomMovementLayers()[cell.Layer].GetTerrainIndex(cell)].Type; var wantsGranted = info.TerrainTypes.Contains(currentTerrain); if (currentTerrain != cachedTerrain) { - if (wantsGranted && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, info.Condition); - else if (!wantsGranted && conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (wantsGranted && conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(info.Condition); + else if (!wantsGranted && conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); } cachedTerrain = currentTerrain; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionWhileAiming.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionWhileAiming.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantConditionWhileAiming.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantConditionWhileAiming.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,43 +13,37 @@ namespace OpenRA.Mods.Common.Traits { - public class GrantConditionWhileAimingInfo : ITraitInfo + public class GrantConditionWhileAimingInfo : TraitInfo { [FieldLoader.Require] [GrantedConditionReference] [Desc("The condition to grant while aiming.")] public readonly string Condition = null; - object ITraitInfo.Create(ActorInitializer init) { return new GrantConditionWhileAiming(this); } + public override object Create(ActorInitializer init) { return new GrantConditionWhileAiming(this); } } - public class GrantConditionWhileAiming : INotifyCreated, INotifyAiming + public class GrantConditionWhileAiming : INotifyAiming { readonly GrantConditionWhileAimingInfo info; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; public GrantConditionWhileAiming(GrantConditionWhileAimingInfo info) { this.info = info; } - void INotifyCreated.Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - } - void INotifyAiming.StartedAiming(Actor self, AttackBase attack) { - if (conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, info.Condition); + if (conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(info.Condition); } void INotifyAiming.StoppedAiming(Actor self, AttackBase attack) { - if (conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantExternalConditionToCrusher.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantExternalConditionToCrusher.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantExternalConditionToCrusher.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantExternalConditionToCrusher.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Grant a condition to the crushing actor.")] - public class GrantExternalConditionToCrusherInfo : ITraitInfo + public class GrantExternalConditionToCrusherInfo : TraitInfo { [Desc("The condition to apply on a crush attempt. Must be included among the crusher actor's ExternalCondition traits.")] public readonly string WarnCrushCondition = null; @@ -30,7 +30,7 @@ [Desc("Duration of the condition applied on a successful crush (in ticks). Set to 0 for a permanent condition.")] public readonly int OnCrushDuration = 0; - public virtual object Create(ActorInitializer init) { return new GrantExternalConditionToCrusher(init.Self, this); } + public override object Create(ActorInitializer init) { return new GrantExternalConditionToCrusher(init.Self, this); } } public class GrantExternalConditionToCrusher : INotifyCrushed @@ -44,20 +44,16 @@ void INotifyCrushed.OnCrush(Actor self, Actor crusher, BitSet crushClasses) { - var external = crusher.TraitsImplementing() - .FirstOrDefault(t => t.Info.Condition == Info.OnCrushCondition && t.CanGrantCondition(crusher, self)); - - if (external != null) - external.GrantCondition(crusher, self, Info.OnCrushDuration); + crusher.TraitsImplementing() + .FirstOrDefault(t => t.Info.Condition == Info.OnCrushCondition && t.CanGrantCondition(crusher, self)) + ?.GrantCondition(crusher, self, Info.OnCrushDuration); } void INotifyCrushed.WarnCrush(Actor self, Actor crusher, BitSet crushClasses) { - var external = crusher.TraitsImplementing() - .FirstOrDefault(t => t.Info.Condition == Info.WarnCrushCondition && t.CanGrantCondition(crusher, self)); - - if (external != null) - external.GrantCondition(crusher, self, Info.WarnCrushDuration); + crusher.TraitsImplementing() + .FirstOrDefault(t => t.Info.Condition == Info.WarnCrushCondition && t.CanGrantCondition(crusher, self)) + ?.GrantCondition(crusher, self, Info.WarnCrushDuration); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantExternalConditionToProduced.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantExternalConditionToProduced.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantExternalConditionToProduced.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantExternalConditionToProduced.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Linq; -using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { @@ -37,11 +36,9 @@ if (IsTraitDisabled || other.IsDead) return; - var external = other.TraitsImplementing() - .FirstOrDefault(t => t.Info.Condition == Info.Condition && t.CanGrantCondition(other, self)); - - if (external != null) - external.GrantCondition(other, self, Info.Duration); + other.TraitsImplementing() + .FirstOrDefault(t => t.Info.Condition == Info.Condition && t.CanGrantCondition(other, self)) + ?.GrantCondition(other, self, Info.Duration); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantRandomCondition.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantRandomCondition.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/GrantRandomCondition.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/GrantRandomCondition.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,14 +15,14 @@ namespace OpenRA.Mods.Common.Traits.Conditions { [Desc("Grants a random condition from a predefined list to the actor when created.")] - public class GrantRandomConditionInfo : ITraitInfo + public class GrantRandomConditionInfo : TraitInfo { [FieldLoader.Require] [GrantedConditionReference] [Desc("List of conditions to grant from.")] public readonly string[] Conditions = null; - public object Create(ActorInitializer init) { return new GrantRandomCondition(init.Self, this); } + public override object Create(ActorInitializer init) { return new GrantRandomCondition(init.Self, this); } } public class GrantRandomCondition : INotifyCreated @@ -40,8 +40,7 @@ return; var condition = info.Conditions.Random(self.World.SharedRandom); - var conditionManager = self.Trait(); - conditionManager.GrantCondition(self, condition); + self.GrantCondition(condition); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/LineBuildSegmentExternalCondition.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/LineBuildSegmentExternalCondition.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/LineBuildSegmentExternalCondition.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/LineBuildSegmentExternalCondition.cs 2021-03-21 11:10:05.000000000 +0000 @@ -47,8 +47,7 @@ void RevokeCondition(Actor self, Actor segment) { - int token; - if (!tokens.TryGetValue(segment, out token)) + if (!tokens.TryGetValue(segment, out var token)) return; tokens.Remove(segment); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/ProximityExternalCondition.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/ProximityExternalCondition.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/ProximityExternalCondition.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/ProximityExternalCondition.cs 2021-03-21 11:10:05.000000000 +0000 @@ -30,8 +30,8 @@ "Ignored if 0 (actors are selected regardless of vertical distance).")] public readonly WDist MaximumVerticalOffset = WDist.Zero; - [Desc("What diplomatic stances are affected.")] - public readonly Stance ValidStances = Stance.Ally; + [Desc("What player relationships are affected.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally; [Desc("Condition is applied permanently to this actor.")] public readonly bool AffectsParent = false; @@ -110,8 +110,8 @@ if (tokens.ContainsKey(a)) return; - var stance = self.Owner.Stances[a.Owner]; - if (!Info.ValidStances.HasStance(stance)) + var stance = self.Owner.RelationshipWith(a.Owner); + if (!Info.ValidRelationships.HasStance(stance)) return; var external = a.TraitsImplementing() @@ -134,8 +134,8 @@ // Work around for actors produced within the region not triggering until the second tick if ((produced.CenterPosition - self.CenterPosition).HorizontalLengthSquared <= Info.Range.LengthSquared) { - var stance = self.Owner.Stances[produced.Owner]; - if (!Info.ValidStances.HasStance(stance)) + var stance = self.Owner.RelationshipWith(produced.Owner); + if (!Info.ValidRelationships.HasStance(stance)) return; var external = produced.TraitsImplementing() @@ -151,8 +151,7 @@ if (a.Disposed) return; - int token; - if (!tokens.TryGetValue(a, out token)) + if (!tokens.TryGetValue(a, out var token)) return; tokens.Remove(a); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Conditions/ToggleConditionOnOrder.cs openra-20210321/OpenRA.Mods.Common/Traits/Conditions/ToggleConditionOnOrder.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Conditions/ToggleConditionOnOrder.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Conditions/ToggleConditionOnOrder.cs 2021-03-21 11:10:05.000000000 +0000 @@ -42,8 +42,7 @@ public class ToggleConditionOnOrder : PausableConditionalTrait, IResolveOrder { - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; // If the trait is paused this may be true with no condition granted [Sync] @@ -52,21 +51,11 @@ public ToggleConditionOnOrder(Actor self, ToggleConditionOnOrderInfo info) : base(info) { } - protected override void Created(Actor self) - { - base.Created(self); - - conditionManager = self.TraitOrDefault(); - } - void SetCondition(Actor self, bool granted) { - if (conditionManager == null) - return; - - if (granted && conditionToken == ConditionManager.InvalidConditionToken) + if (granted && conditionToken == Actor.InvalidConditionToken) { - conditionToken = conditionManager.GrantCondition(self, Info.Condition); + conditionToken = self.GrantCondition(Info.Condition); if (Info.EnabledSound != null) Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Sounds", Info.EnabledSound, self.Owner.Faction.InternalName); @@ -74,9 +63,9 @@ if (Info.EnabledSpeech != null) Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", Info.EnabledSpeech, self.Owner.Faction.InternalName); } - else if (!granted && conditionToken != ConditionManager.InvalidConditionToken) + else if (!granted && conditionToken != Actor.InvalidConditionToken) { - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + conditionToken = self.RevokeCondition(conditionToken); if (Info.DisabledSound != null) Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Sounds", Info.DisabledSound, self.Owner.Faction.InternalName); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Contrail.cs openra-20210321/OpenRA.Mods.Common/Traits/Contrail.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Contrail.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Contrail.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Draw a colored contrail behind this actor when they move.")] - class ContrailInfo : ITraitInfo, Requires + class ContrailInfo : TraitInfo, Requires { [Desc("Position relative to body")] public readonly WVec Offset = WVec.Zero; @@ -38,7 +38,7 @@ [Desc("Use player remap color instead of a custom color?")] public readonly bool UsePlayerColor = true; - public object Create(ActorInitializer init) { return new Contrail(init.Self, this); } + public override object Create(ActorInitializer init) { return new Contrail(init.Self, this); } } class Contrail : ITick, IRender, INotifyAddedToWorld diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Crates/CrateAction.cs openra-20210321/OpenRA.Mods.Common/Traits/Crates/CrateAction.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Crates/CrateAction.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Crates/CrateAction.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,7 +23,7 @@ [Desc("Image containing the crate effect animation sequence.")] public readonly string Image = "crate-effects"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Animation sequence played when collected. Leave empty for no effect.")] public readonly string Sequence = null; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Crates/Crate.cs openra-20210321/OpenRA.Mods.Common/Traits/Crates/Crate.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Crates/Crate.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Crates/Crate.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { - public class CrateInfo : ITraitInfo, IPositionableInfo, Requires + public class CrateInfo : TraitInfo, IPositionableInfo, Requires { [Desc("Length of time (in seconds) until the crate gets removed automatically. " + "A value of zero disables auto-removal.")] @@ -30,7 +30,7 @@ [Desc("Define actors that can collect crates by setting this into the Crushes field from the Mobile trait.")] public readonly string CrushClass = "crate"; - public object Create(ActorInitializer init) { return new Crate(init, this); } + public override object Create(ActorInitializer init) { return new Crate(init, this); } public IReadOnlyDictionary OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any) { @@ -63,9 +63,6 @@ if (!CanExistInCell(world, cell)) return SubCell.Invalid; - if (world.WorldActor.Trait().GetBuildingAt(cell) != null) - return SubCell.Invalid; - if (check == BlockedByActor.None) return SubCell.FullCell; @@ -93,8 +90,9 @@ self = init.Self; this.info = info; - if (init.Contains()) - SetPosition(self, init.Get()); + var locationInit = init.GetOrDefault(); + if (locationInit != null) + SetPosition(self, locationInit.Value); } void INotifyCreated.Created(Actor self) @@ -154,20 +152,20 @@ if (crateActions.Any()) { - var shares = crateActions.Select(a => Pair.New(a, a.GetSelectionSharesOuter(crusher))); + var shares = crateActions.Select(a => (Action: a, Shares: a.GetSelectionSharesOuter(crusher))); - var totalShares = shares.Sum(a => a.Second); + var totalShares = shares.Sum(a => a.Shares); var n = self.World.SharedRandom.Next(totalShares); foreach (var s in shares) { - if (n < s.Second) + if (n < s.Shares) { - s.First.Activate(crusher); + s.Action.Activate(crusher); return; } - n -= s.Second; + n -= s.Shares; } } } @@ -179,7 +177,7 @@ } public CPos TopLeft { get { return Location; } } - public Pair[] OccupiedCells() { return new[] { Pair.New(Location, SubCell.FullCell) }; } + public (CPos, SubCell)[] OccupiedCells() { return new[] { (Location, SubCell.FullCell) }; } public WPos CenterPosition { get; private set; } @@ -247,9 +245,7 @@ { self.World.AddToMaps(self, this); - var cs = self.World.WorldActor.TraitOrDefault(); - if (cs != null) - cs.IncrementCrates(); + self.World.WorldActor.TraitOrDefault()?.IncrementCrates(); if (self.World.Map.DistanceAboveTerrain(CenterPosition) > WDist.Zero && self.TraitOrDefault() != null) self.QueueActivity(new Parachute(self)); @@ -259,9 +255,7 @@ { self.World.RemoveFromMaps(self, this); - var cs = self.World.WorldActor.TraitOrDefault(); - if (cs != null) - cs.DecrementCrates(); + self.World.WorldActor.TraitOrDefault()?.DecrementCrates(); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Crates/ExplodeCrateAction.cs openra-20210321/OpenRA.Mods.Common/Traits/Crates/ExplodeCrateAction.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Crates/ExplodeCrateAction.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Crates/ExplodeCrateAction.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Linq; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Crates/HealActorsCrateAction.cs openra-20210321/OpenRA.Mods.Common/Traits/Crates/HealActorsCrateAction.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Crates/HealActorsCrateAction.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Crates/HealActorsCrateAction.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,46 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Heals all actors that belong to the owner of the collector.")] + class HealActorsCrateActionInfo : CrateActionInfo + { + [Desc("The target type(s) of the actors this crate action will heal. Leave empty to heal all actors.")] + public readonly BitSet TargetTypes = default(BitSet); + + public override object Create(ActorInitializer init) { return new HealActorsCrateAction(init.Self, this); } + } + + class HealActorsCrateAction : CrateAction + { + readonly HealActorsCrateActionInfo info; + + public HealActorsCrateAction(Actor self, HealActorsCrateActionInfo info) + : base(self, info) + { + this.info = info; + } + + public override void Activate(Actor collector) + { + foreach (var healable in collector.World.ActorsWithTrait().Where(tp => tp.Actor.Owner == collector.Owner)) + if (!healable.Trait.IsDead && (info.TargetTypes.IsEmpty || info.TargetTypes.Overlaps(healable.Actor.GetEnabledTargetTypes()))) + healable.Trait.InflictDamage(healable.Actor, healable.Actor, new Damage(-(healable.Trait.MaxHP - healable.Trait.HP)), true); + + base.Activate(collector); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Crates/HealUnitsCrateAction.cs openra-20210321/OpenRA.Mods.Common/Traits/Crates/HealUnitsCrateAction.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Crates/HealUnitsCrateAction.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Crates/HealUnitsCrateAction.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - [Desc("Heals all actors that belong to the owner of the collector.")] - class HealUnitsCrateActionInfo : CrateActionInfo - { - public override object Create(ActorInitializer init) { return new HealUnitsCrateAction(init.Self, this); } - } - - class HealUnitsCrateAction : CrateAction - { - public HealUnitsCrateAction(Actor self, HealUnitsCrateActionInfo info) - : base(self, info) { } - - public override void Activate(Actor collector) - { - foreach (var healable in collector.World.ActorsWithTrait().Where(tp => tp.Actor.Owner == collector.Owner)) - if (!healable.Trait.IsDead) - healable.Trait.InflictDamage(healable.Actor, healable.Actor, new Damage(-(healable.Trait.MaxHP - healable.Trait.HP)), true); - - base.Activate(collector); - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Crates/LevelUpCrateAction.cs openra-20210321/OpenRA.Mods.Common/Traits/Crates/LevelUpCrateAction.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Crates/LevelUpCrateAction.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Crates/LevelUpCrateAction.cs 2021-03-21 11:10:05.000000000 +0000 @@ -72,9 +72,7 @@ var recipient = actor; // loop variable in closure hazard recipient.World.AddFrameEndTask(w => { - var gainsExperience = recipient.TraitOrDefault(); - if (gainsExperience != null) - gainsExperience.GiveLevels(info.Levels); + recipient.TraitOrDefault()?.GiveLevels(info.Levels); }); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/CreatesShroud.cs openra-20210321/OpenRA.Mods.Common/Traits/CreatesShroud.cs --- openra-20200503/OpenRA.Mods.Common/Traits/CreatesShroud.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/CreatesShroud.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,6 +9,7 @@ */ #endregion +using System.Collections.Generic; using System.Linq; using OpenRA.Traits; @@ -16,8 +17,8 @@ { public class CreatesShroudInfo : AffectsShroudInfo { - [Desc("Stance the watching player needs to see the generated shroud.")] - public readonly Stance ValidStances = Stance.Neutral | Stance.Enemy; + [Desc("Relationship the watching player needs to see the generated shroud.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy; public override object Create(ActorInitializer init) { return new CreatesShroud(init.Self, this); } } @@ -25,7 +26,7 @@ public class CreatesShroud : AffectsShroud { readonly CreatesShroudInfo info; - ICreatesShroudModifier[] rangeModifiers; + IEnumerable rangeModifiers; public CreatesShroud(Actor self, CreatesShroudInfo info) : base(self, info) @@ -37,12 +38,12 @@ { base.Created(self); - rangeModifiers = self.TraitsImplementing().ToArray(); + rangeModifiers = self.TraitsImplementing().ToArray().Select(x => x.GetCreatesShroudModifier()); } protected override void AddCellsToPlayerShroud(Actor self, Player p, PPos[] uv) { - if (!info.ValidStances.HasStance(p.Stances[self.Owner])) + if (!info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p))) return; p.Shroud.AddSource(this, Shroud.SourceType.Shroud, uv); @@ -57,8 +58,7 @@ if (CachedTraitDisabled) return WDist.Zero; - var revealsShroudModifier = rangeModifiers.Select(x => x.GetCreatesShroudModifier()); - var range = Util.ApplyPercentageModifiers(Info.Range.Length, revealsShroudModifier); + var range = Util.ApplyPercentageModifiers(Info.Range.Length, rangeModifiers); return new WDist(range); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Crushable.cs openra-20210321/OpenRA.Mods.Common/Traits/Crushable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Crushable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Crushable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -70,7 +70,7 @@ if (IsTraitDisabled || !self.IsAtGroundLevel() || !Info.CrushClasses.Overlaps(crushClasses)) return self.World.NoPlayersMask; - return Info.CrushedByFriendlies ? self.World.AllPlayersMask : self.Owner.EnemyPlayersMask; + return Info.CrushedByFriendlies ? self.World.AllPlayersMask : ~self.Owner.AlliedPlayersMask; } bool CrushableInner(BitSet crushClasses, Player crushOwner) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/DamagedByTerrain.cs openra-20210321/OpenRA.Mods.Common/Traits/DamagedByTerrain.cs --- openra-20200503/OpenRA.Mods.Common/Traits/DamagedByTerrain.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/DamagedByTerrain.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("This actor receives damage from the given weapon when on the specified terrain type.")] - class DamagedByTerrainInfo : ConditionalTraitInfo, Requires + public class DamagedByTerrainInfo : ConditionalTraitInfo, Requires, Requires { [FieldLoader.Require] [Desc("Amount of damage received per DamageInterval ticks.")] @@ -32,60 +32,19 @@ [Desc("Terrain types where the actor will take damage.")] public readonly string[] Terrain = { }; - [Desc("Percentage health below which the actor will not receive further damage.")] - public readonly int DamageThreshold = 0; - - [Desc("Inflict damage down to the DamageThreshold when the actor gets created on damaging terrain.")] - public readonly bool StartOnThreshold = false; - - public override object Create(ActorInitializer init) { return new DamagedByTerrain(init.Self, this); } + public override object Create(ActorInitializer init) { return new DamagedByTerrain(this); } } - class DamagedByTerrain : ConditionalTrait, ITick, ISync, INotifyAddedToWorld + public class DamagedByTerrain : ConditionalTrait, ITick, ISync { - readonly IHealth health; - - [Sync] int damageTicks; - [Sync] - int damageThreshold; - - public DamagedByTerrain(Actor self, DamagedByTerrainInfo info) - : base(info) - { - health = self.Trait(); - } - - void INotifyAddedToWorld.AddedToWorld(Actor self) - { - if (!Info.StartOnThreshold) - return; - - var safeTiles = 0; - var totalTiles = 0; - foreach (var kv in self.OccupiesSpace.OccupiedCells()) - { - totalTiles++; - if (!Info.Terrain.Contains(self.World.Map.GetTerrainInfo(kv.First).Type)) - safeTiles++; - } - - if (totalTiles == 0) - return; - - // Cast to long to avoid overflow when multiplying by the health - damageThreshold = (int)((Info.DamageThreshold * (long)health.MaxHP + (100 - Info.DamageThreshold) * safeTiles * (long)health.MaxHP / totalTiles) / 100); - - // Actors start with maximum damage applied - var delta = health.HP - damageThreshold; - if (delta > 0) - self.InflictDamage(self.World.WorldActor, new Damage(delta, Info.DamageTypes)); - } + public DamagedByTerrain(DamagedByTerrainInfo info) + : base(info) { } void ITick.Tick(Actor self) { - if (IsTraitDisabled || health.HP <= damageThreshold || --damageTicks > 0) + if (IsTraitDisabled || --damageTicks > 0) return; // Prevents harming cargo. diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/DeliversCash.cs openra-20210321/OpenRA.Mods.Common/Traits/DeliversCash.cs --- openra-20200503/OpenRA.Mods.Common/Traits/DeliversCash.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/DeliversCash.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Donate money to actors with the `AcceptsDeliveredCash` trait.")] - class DeliversCashInfo : ITraitInfo + class DeliversCashInfo : TraitInfo { [Desc("The amount of cash the owner receives.")] public readonly int Payload = 500; @@ -32,10 +32,16 @@ [Desc("Sound to play when delivering cash")] public readonly string[] Sounds = { }; + [Desc("Cursor to display when hovering over a valid actor to deliver cash to.")] + public readonly string Cursor = "enter"; + [VoiceReference] public readonly string Voice = "Action"; - public object Create(ActorInitializer init) { return new DeliversCash(this); } + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Yellow; + + public override object Create(ActorInitializer init) { return new DeliversCash(this); } } class DeliversCash : IIssueOrder, IResolveOrder, IOrderVoice, INotifyCashTransfer @@ -49,10 +55,10 @@ public IEnumerable Orders { - get { yield return new DeliversCashOrderTargeter(); } + get { yield return new DeliversCashOrderTargeter(info); } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID != "DeliverCash") return null; @@ -73,7 +79,7 @@ if (order.OrderString != "DeliverCash") return; - self.QueueActivity(order.Queued, new DonateCash(self, order.Target, info.Payload, info.PlayerExperience)); + self.QueueActivity(order.Queued, new DonateCash(self, order.Target, info.Payload, info.PlayerExperience, info.TargetLineColor)); self.ShowTargetLines(); } @@ -87,27 +93,33 @@ public class DeliversCashOrderTargeter : UnitOrderTargeter { - public DeliversCashOrderTargeter() - : base("DeliverCash", 5, "enter", false, true) { } + public DeliversCashOrderTargeter(DeliversCashInfo info) + : base("DeliverCash", 5, info.Cursor, false, true) { } public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor) { - var type = self.Info.TraitInfo().Type; var targetInfo = target.Info.TraitInfoOrDefault(); - return targetInfo != null - && targetInfo.ValidStances.HasStance(target.Owner.Stances[self.Owner]) - && (targetInfo.ValidTypes.Count == 0 - || (!string.IsNullOrEmpty(type) && targetInfo.ValidTypes.Contains(type))); + if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner))) + return false; + + if (targetInfo.ValidTypes.Count == 0) + return true; + + var type = self.Info.TraitInfo().Type; + return !string.IsNullOrEmpty(type) && targetInfo.ValidTypes.Contains(type); } public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor) { - var type = self.Info.TraitInfo().Type; var targetInfo = target.Info.TraitInfoOrDefault(); - return targetInfo != null - && targetInfo.ValidStances.HasStance(target.Owner.Stances[self.Owner]) - && (targetInfo.ValidTypes.Count == 0 - || (!string.IsNullOrEmpty(type) && targetInfo.ValidTypes.Contains(type))); + if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner))) + return false; + + if (targetInfo.ValidTypes.Count == 0) + return true; + + var type = self.Info.TraitInfo().Type; + return !string.IsNullOrEmpty(type) && targetInfo.ValidTypes.Contains(type); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/DeliversExperience.cs openra-20210321/OpenRA.Mods.Common/Traits/DeliversExperience.cs --- openra-20200503/OpenRA.Mods.Common/Traits/DeliversExperience.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/DeliversExperience.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("This actor can grant experience levels equal to it's own current level via entering to other actors with the `AcceptsDeliveredExperience` trait.")] - class DeliversExperienceInfo : ITraitInfo, Requires + class DeliversExperienceInfo : TraitInfo, Requires { [Desc("The amount of experience the donating player receives.")] public readonly int PlayerExperience = 0; @@ -26,10 +26,16 @@ [Desc("Identifier checked against AcceptsDeliveredExperience.ValidTypes. Only needed if the latter is not empty.")] public readonly string Type = null; + [Desc("Cursor to display when hovering over a valid actor to deliver experience to.")] + public readonly string Cursor = "enter"; + [VoiceReference] public readonly string Voice = "Action"; - public object Create(ActorInitializer init) { return new DeliversExperience(init, this); } + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Yellow; + + public override object Create(ActorInitializer init) { return new DeliversExperience(init, this); } } class DeliversExperience : IIssueOrder, IResolveOrder, IOrderVoice @@ -50,11 +56,11 @@ get { if (gainsExperience.Level != 0) - yield return new DeliversExperienceOrderTargeter(); + yield return new DeliversExperienceOrderTargeter(info); } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID != "DeliverExperience") return null; @@ -84,33 +90,33 @@ else if (order.Target.Type != TargetType.FrozenActor) return; - self.QueueActivity(order.Queued, new DonateExperience(self, order.Target, gainsExperience.Level, info.PlayerExperience)); + self.QueueActivity(order.Queued, new DonateExperience(self, order.Target, gainsExperience.Level, info.PlayerExperience, info.TargetLineColor)); self.ShowTargetLines(); } public class DeliversExperienceOrderTargeter : UnitOrderTargeter { - public DeliversExperienceOrderTargeter() - : base("DeliverExperience", 5, "enter", true, true) { } + public DeliversExperienceOrderTargeter(DeliversExperienceInfo info) + : base("DeliverExperience", 5, info.Cursor, true, true) { } public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor) { if (target == self) return false; - var type = self.Info.TraitInfo().Type; - var targetInfo = target.Info.TraitInfoOrDefault(); var targetGainsExperience = target.TraitOrDefault(); - - if (targetGainsExperience == null || targetInfo == null) + if (targetGainsExperience == null || targetGainsExperience.Level == targetGainsExperience.MaxLevel) return false; - if (targetGainsExperience.Level == targetGainsExperience.MaxLevel) + var targetInfo = target.Info.TraitInfoOrDefault(); + if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner))) return false; - return targetInfo.ValidStances.HasStance(target.Owner.Stances[self.Owner]) - && (targetInfo.ValidTypes.Count == 0 - || (!string.IsNullOrEmpty(type) && targetInfo.ValidTypes.Contains(type))); + if (targetInfo.ValidTypes.Count == 0) + return true; + + var type = self.Info.TraitInfo().Type; + return !string.IsNullOrEmpty(type) && targetInfo.ValidTypes.Contains(type); } public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor) @@ -118,19 +124,19 @@ if (target.Actor == null || target.Actor == self) return false; - var type = self.Info.TraitInfo().Type; - var targetInfo = target.Info.TraitInfoOrDefault(); var targetGainsExperience = target.Actor.TraitOrDefault(); - - if (targetGainsExperience == null || targetInfo == null) + if (targetGainsExperience == null || targetGainsExperience.Level == targetGainsExperience.MaxLevel) return false; - if (targetGainsExperience.Level == targetGainsExperience.MaxLevel) + var targetInfo = target.Info.TraitInfoOrDefault(); + if (targetInfo == null || !targetInfo.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner))) return false; - return targetInfo.ValidStances.HasStance(target.Owner.Stances[self.Owner]) - && (targetInfo.ValidTypes.Count == 0 - || (!string.IsNullOrEmpty(type) && targetInfo.ValidTypes.Contains(type))); + if (targetInfo.ValidTypes.Count == 0) + return true; + + var type = self.Info.TraitInfo().Type; + return !string.IsNullOrEmpty(type) && targetInfo.ValidTypes.Contains(type); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Demolishable.cs openra-20210321/OpenRA.Mods.Common/Traits/Demolishable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Demolishable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Demolishable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,12 +11,13 @@ using System.Collections.Generic; using System.Linq; +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Handle demolitions from C4 explosives.")] - public class DemolishableInfo : ConditionalTraitInfo, IDemolishableInfo, ITraitInfo + public class DemolishableInfo : ConditionalTraitInfo, IDemolishableInfo { public bool IsValidTarget(ActorInfo actorInfo, Actor saboteur) { return true; } @@ -34,43 +35,35 @@ public readonly Actor Saboteur; public readonly int Token; public int Delay; + public readonly BitSet DamageTypes; - public DemolishAction(Actor saboteur, int delay, int token) + public DemolishAction(Actor saboteur, int delay, int token, BitSet damageTypes) { Saboteur = saboteur; Delay = delay; Token = token; + DamageTypes = damageTypes; } } - ConditionManager conditionManager; List actions = new List(); List removeActions = new List(); public Demolishable(DemolishableInfo info) : base(info) { } - protected override void Created(Actor self) - { - base.Created(self); - conditionManager = self.TraitOrDefault(); - } - bool IDemolishable.IsValidTarget(Actor self, Actor saboteur) { return !IsTraitDisabled; } - void IDemolishable.Demolish(Actor self, Actor saboteur, int delay) + void IDemolishable.Demolish(Actor self, Actor saboteur, int delay, BitSet damageTypes) { if (IsTraitDisabled) return; - var token = ConditionManager.InvalidConditionToken; - if (conditionManager != null && !string.IsNullOrEmpty(Info.Condition)) - token = conditionManager.GrantCondition(self, Info.Condition); - - actions.Add(new DemolishAction(saboteur, delay, token)); + var token = self.GrantCondition(Info.Condition); + actions.Add(new DemolishAction(saboteur, delay, token, damageTypes)); } void ITick.Tick(Actor self) @@ -87,10 +80,10 @@ .Select(t => t.GetDamageModifier(self, null)); if (Util.ApplyPercentageModifiers(100, modifiers) > 0) - self.Kill(a.Saboteur); - else if (a.Token != ConditionManager.InvalidConditionToken) + self.Kill(a.Saboteur, a.DamageTypes); + else if (a.Token != Actor.InvalidConditionToken) { - conditionManager.RevokeCondition(self, a.Token); + self.RevokeCondition(a.Token); removeActions.Add(a); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Demolition.cs openra-20210321/OpenRA.Mods.Common/Traits/Demolition.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Demolition.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Demolition.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { - class DemolitionInfo : ITraitInfo + class DemolitionInfo : TraitInfo { [Desc("Delay to demolish the target once the explosive device is planted. " + "Measured in game ticks. Default is 1.8 seconds.")] @@ -37,16 +37,23 @@ "Possible values are Exit, Suicide, Dispose.")] public readonly EnterBehaviour EnterBehaviour = EnterBehaviour.Exit; + [Desc("Types of damage that this trait causes. Leave empty for no damage types.")] + public readonly BitSet DamageTypes = default(BitSet); + [VoiceReference] [Desc("Voice string when planting explosive charges.")] public readonly string Voice = "Action"; - public readonly Stance TargetStances = Stance.Enemy | Stance.Neutral; - public readonly Stance ForceTargetStances = Stance.Enemy | Stance.Neutral | Stance.Ally; + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Crimson; + + public readonly PlayerRelationship TargetRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral; + public readonly PlayerRelationship ForceTargetRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral | PlayerRelationship.Ally; + [Desc("Cursor to display when hovering over a demolishable target.")] public readonly string Cursor = "c4"; - public object Create(ActorInitializer init) { return new Demolition(this); } + public override object Create(ActorInitializer init) { return new Demolition(this); } } class Demolition : IIssueOrder, IResolveOrder, IOrderVoice @@ -63,7 +70,7 @@ get { yield return new DemolitionOrderTargeter(info); } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID != "C4") return null; @@ -84,7 +91,7 @@ } self.QueueActivity(order.Queued, new Demolish(self, order.Target, info.EnterBehaviour, info.DetonationDelay, - info.Flashes, info.FlashesDelay, info.FlashInterval)); + info.Flashes, info.FlashesDelay, info.FlashInterval, info.DamageTypes, info.TargetLineColor)); self.ShowTargetLines(); } @@ -110,11 +117,11 @@ if (modifiers.HasModifier(TargetModifiers.ForceMove)) return false; - var stance = self.Owner.Stances[target.Owner]; - if (!info.TargetStances.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack)) + var stance = target.Owner.RelationshipWith(self.Owner); + if (!info.TargetRelationships.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack)) return false; - if (!info.ForceTargetStances.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack)) + if (!info.ForceTargetRelationships.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack)) return false; return target.TraitsImplementing().Any(i => i.IsValidTarget(target, self)); @@ -122,11 +129,11 @@ public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor) { - var stance = self.Owner.Stances[target.Owner]; - if (!info.TargetStances.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack)) + var stance = target.Owner.RelationshipWith(self.Owner); + if (!info.TargetRelationships.HasStance(stance) && !modifiers.HasModifier(TargetModifiers.ForceAttack)) return false; - if (!info.ForceTargetStances.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack)) + if (!info.ForceTargetRelationships.HasStance(stance) && modifiers.HasModifier(TargetModifiers.ForceAttack)) return false; return target.Info.TraitInfos().Any(i => i.IsValidTarget(target.Info, self)); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/DetectCloaked.cs openra-20210321/OpenRA.Mods.Common/Traits/DetectCloaked.cs --- openra-20200503/OpenRA.Mods.Common/Traits/DetectCloaked.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/DetectCloaked.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Linq; using OpenRA.Primitives; -using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/EjectOnDeath.cs openra-20210321/OpenRA.Mods.Common/Traits/EjectOnDeath.cs --- openra-20200503/OpenRA.Mods.Common/Traits/EjectOnDeath.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/EjectOnDeath.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using OpenRA.Mods.Common.Activities; using OpenRA.Primitives; using OpenRA.Traits; @@ -91,11 +90,7 @@ var pilot = self.World.CreateActor(true, Info.PilotActor.ToLowerInvariant(), td); if (!inAir) - { - var pilotMobile = pilot.TraitOrDefault(); - if (pilotMobile != null) - pilotMobile.Nudge(pilot); - } + pilot.TraitOrDefault()?.Nudge(pilot); else Game.Sound.Play(SoundType.World, Info.ChuteSound, cp); }); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/EngineerRepairable.cs openra-20210321/OpenRA.Mods.Common/Traits/EngineerRepairable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/EngineerRepairable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/EngineerRepairable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,18 +10,23 @@ #endregion using OpenRA.Primitives; -using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { public class EngineerRepairType { } [Desc("Eligible for instant repair.")] - class EngineerRepairableInfo : TraitInfo + class EngineerRepairableInfo : ConditionalTraitInfo { [Desc("Actors with these Types under EngineerRepair trait can repair me.")] public readonly BitSet Types = default(BitSet); + + public override object Create(ActorInitializer init) { return new EngineerRepairable(init, this); } } - class EngineerRepairable { } + class EngineerRepairable : ConditionalTrait + { + public EngineerRepairable(ActorInitializer init, EngineerRepairableInfo info) + : base(info) { } + } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/EngineerRepair.cs openra-20210321/OpenRA.Mods.Common/Traits/EngineerRepair.cs --- openra-20200503/OpenRA.Mods.Common/Traits/EngineerRepair.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/EngineerRepair.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Collections.Generic; -using System.Linq; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; using OpenRA.Primitives; @@ -27,20 +26,23 @@ [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Yellow; + [Desc("Behaviour when entering the structure.", "Possible values are Exit, Suicide, Dispose.")] public readonly EnterBehaviour EnterBehaviour = EnterBehaviour.Dispose; - [Desc("What diplomatic stances allow target to be repaired by this actor.")] - public readonly Stance ValidStances = Stance.Ally; + [Desc("What player relationship the target's owner needs to be repaired by this actor.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally; [Desc("Sound to play when repairing is done.")] public readonly string RepairSound = null; - [Desc("Cursor to show when hovering over a valid actor to repair.")] + [Desc("Cursor to display when hovering over a valid actor to repair.")] public readonly string Cursor = "goldwrench"; - [Desc("Cursor to show when target actor has full health so it can't be repaired.")] + [Desc("Cursor to display when target actor has full health so it can't be repaired.")] public readonly string RepairBlockedCursor = "goldwrench-blocked"; public override object Create(ActorInitializer init) { return new EngineerRepair(init, this); } @@ -62,7 +64,7 @@ } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID != "EngineerRepair") return null; @@ -108,14 +110,14 @@ public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor) { - var engineerRepairable = target.Info.TraitInfoOrDefault(); - if (engineerRepairable == null) + var engineerRepairable = target.TraitOrDefault(); + if (engineerRepairable == null || engineerRepairable.IsTraitDisabled) return false; - if (!engineerRepairable.Types.IsEmpty && !engineerRepairable.Types.Overlaps(info.Types)) + if (!engineerRepairable.Info.Types.IsEmpty && !engineerRepairable.Info.Types.Overlaps(info.Types)) return false; - if (!info.ValidStances.HasStance(self.Owner.Stances[target.Owner])) + if (!info.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner))) return false; if (target.GetDamageState() == DamageState.Undamaged) @@ -126,6 +128,10 @@ public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor) { + // TODO: FrozenActors don't yet have a way of caching conditions, so we can't filter disabled traits + // This therefore assumes that all EngineerRepairable traits are enabled, which is probably wrong. + // Actors with FrozenUnderFog should therefore not disable the EngineerRepairable trait if + // ValidStances includes Enemy actors. var engineerRepairable = target.Info.TraitInfoOrDefault(); if (engineerRepairable == null) return false; @@ -133,7 +139,7 @@ if (!engineerRepairable.Types.IsEmpty && !engineerRepairable.Types.Overlaps(info.Types)) return false; - if (!info.ValidStances.HasStance(self.Owner.Stances[target.Owner])) + if (!info.ValidRelationships.HasStance(target.Owner.RelationshipWith(self.Owner))) return false; if (target.DamageState == DamageState.Undamaged) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/EntersTunnels.cs openra-20210321/OpenRA.Mods.Common/Traits/EntersTunnels.cs --- openra-20200503/OpenRA.Mods.Common/Traits/EntersTunnels.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/EntersTunnels.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,31 +20,39 @@ namespace OpenRA.Mods.Common.Traits { [Desc("This actor can interact with TunnelEntrances to move through TerrainTunnels.")] - public class EntersTunnelsInfo : ITraitInfo, Requires, IObservesVariablesInfo + public class EntersTunnelsInfo : TraitInfo, Requires, IObservesVariablesInfo { + [Desc("Cursor to display when able to enter target tunnel.")] public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to enter target tunnel.")] public readonly string EnterBlockedCursor = "enter-blocked"; [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line while in tunnels.")] + public readonly Color TargetLineColor = Color.Green; + [ConsumedConditionReference] [Desc("Boolean expression defining the condition under which the regular (non-force) enter cursor is disabled.")] public readonly BooleanExpression RequireForceMoveCondition = null; - public object Create(ActorInitializer init) { return new EntersTunnels(init.Self, this); } + public override object Create(ActorInitializer init) { return new EntersTunnels(init.Self, this); } } public class EntersTunnels : IIssueOrder, IResolveOrder, IOrderVoice, IObservesVariables { readonly EntersTunnelsInfo info; readonly IMove move; + readonly IMoveInfo moveInfo; bool requireForceMove; public EntersTunnels(Actor self, EntersTunnelsInfo info) { this.info = info; move = self.Trait(); + moveInfo = self.Info.TraitInfo(); } public IEnumerable Orders @@ -60,7 +68,7 @@ return !requireForceMove || modifiers.HasModifier(TargetModifiers.ForceMove); } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID != "EnterTunnel") return null; @@ -82,8 +90,8 @@ if (tunnel == null || !tunnel.Exit.HasValue) return; - self.QueueActivity(order.Queued, move.MoveTo(tunnel.Entrance, tunnel.NearEnough, targetLineColor: Color.Green)); - self.QueueActivity(move.MoveTo(tunnel.Exit.Value, tunnel.NearEnough, targetLineColor: Color.Green)); + self.QueueActivity(order.Queued, move.MoveTo(tunnel.Entrance, tunnel.NearEnough, targetLineColor: moveInfo.GetTargetLineColor())); + self.QueueActivity(move.MoveTo(tunnel.Exit.Value, tunnel.NearEnough, targetLineColor: info.TargetLineColor)); self.ShowTargetLines(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ExitsDebugOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/ExitsDebugOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ExitsDebugOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ExitsDebugOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Displays `Exit` data for factories.")] - public class ExitsDebugOverlayInfo : ITraitInfo, Requires + public class ExitsDebugOverlayInfo : TraitInfo, Requires { [Desc("Should cell vectors be drawn for each perimeter cell?")] public readonly bool DrawPerimiterCellVectors = true; @@ -30,7 +30,7 @@ [Desc("Should lines be drawn for each exit (from spawn offset to the center of the exit cell)?")] public readonly bool DrawSpawnOffsetLines = true; - object ITraitInfo.Create(ActorInitializer init) { return new ExitsDebugOverlay(init.Self, this); } + public override object Create(ActorInitializer init) { return new ExitsDebugOverlay(init.Self, this); } } public class ExitsDebugOverlay : IRenderAnnotationsWhenSelected @@ -70,7 +70,7 @@ if (info.DrawPerimiterCellVectors) { - var occupiedCells = self.OccupiesSpace.OccupiedCells().Select(p => p.First).ToArray(); + var occupiedCells = self.OccupiesSpace.OccupiedCells().Select(p => p.Cell).ToArray(); perimeterCells = Util.ExpandFootprint(occupiedCells, true).Except(occupiedCells).ToArray(); foreach (var perimCell in perimeterCells) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Explodes.cs openra-20210321/OpenRA.Mods.Common/Traits/Explodes.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Explodes.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Explodes.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,6 +52,9 @@ "Footprint (explosion on each occupied cell).")] public readonly ExplosionType Type = ExplosionType.CenterPosition; + [Desc("Offset of the explosion from the center of the exploding actor (or cell).")] + public readonly WVec Offset = WVec.Zero; + public WeaponInfo WeaponInfo { get; private set; } public WeaponInfo EmptyWeaponInfo { get; private set; } @@ -60,18 +63,16 @@ { if (!string.IsNullOrEmpty(Weapon)) { - WeaponInfo weapon; var weaponToLower = Weapon.ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(weaponToLower, out weapon)) + if (!rules.Weapons.TryGetValue(weaponToLower, out var weapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); WeaponInfo = weapon; } if (!string.IsNullOrEmpty(EmptyWeapon)) { - WeaponInfo emptyWeapon; var emptyWeaponToLower = EmptyWeapon.ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(emptyWeaponToLower, out emptyWeapon)) + if (!rules.Weapons.TryGetValue(emptyWeaponToLower, out var emptyWeapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(emptyWeaponToLower)); EmptyWeaponInfo = emptyWeapon; } @@ -84,6 +85,7 @@ { readonly IHealth health; BuildingInfo buildingInfo; + Armament[] armaments; public Explodes(ExplodesInfo info, Actor self) : base(info) @@ -94,6 +96,8 @@ protected override void Created(Actor self) { buildingInfo = self.Info.TraitInfoOrDefault(); + armaments = self.TraitsImplementing().ToArray(); + base.Created(self); } @@ -120,33 +124,33 @@ { var cells = buildingInfo.OccupiedTiles(self.Location); foreach (var c in cells) - weapon.Impact(Target.FromPos(self.World.Map.CenterOfCell(c)), source); + weapon.Impact(Target.FromPos(self.World.Map.CenterOfCell(c) + Info.Offset), source); return; } // Use .FromPos since this actor is killed. Cannot use Target.FromActor - weapon.Impact(Target.FromPos(self.CenterPosition), source); + weapon.Impact(Target.FromPos(self.CenterPosition + Info.Offset), source); } WeaponInfo ChooseWeaponForExplosion(Actor self) { - var armaments = self.TraitsImplementing(); - if (!armaments.Any()) + if (armaments.Length == 0) return Info.WeaponInfo; + else if (self.World.SharedRandom.Next(100) > Info.LoadedChance) + return Info.EmptyWeaponInfo; + + // PERF: Avoid LINQ + foreach (var a in armaments) + if (!a.IsReloading) + return Info.WeaponInfo; - // TODO: EmptyWeapon should be removed in favour of conditions - var shouldExplode = !armaments.All(a => a.IsReloading); - var useFullExplosion = self.World.SharedRandom.Next(100) <= Info.LoadedChance; - return (shouldExplode && useFullExplosion) ? Info.WeaponInfo : Info.EmptyWeaponInfo; + return Info.EmptyWeaponInfo; } void INotifyDamage.Damaged(Actor self, AttackInfo e) { - if (IsTraitDisabled || !self.IsInWorld) - return; - - if (Info.DamageThreshold == 0) + if (Info.DamageThreshold == 0 || IsTraitDisabled || !self.IsInWorld) return; if (!Info.DeathTypes.IsEmpty && !e.Damage.DamageTypes.Overlaps(Info.DeathTypes)) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ExplosionOnDamageTransition.cs openra-20210321/OpenRA.Mods.Common/Traits/ExplosionOnDamageTransition.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ExplosionOnDamageTransition.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ExplosionOnDamageTransition.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,14 +9,13 @@ */ #endregion -using System.Linq; using OpenRA.GameRules; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("This actor triggers an explosion on itself when transitioning to a specific damage state.")] - public class ExplosionOnDamageTransitionInfo : ITraitInfo, IRulesetLoaded, Requires + public class ExplosionOnDamageTransitionInfo : TraitInfo, IRulesetLoaded, Requires { [WeaponReference] [FieldLoader.Require] @@ -31,16 +30,15 @@ public WeaponInfo WeaponInfo { get; private set; } - public object Create(ActorInitializer init) { return new ExplosionOnDamageTransition(this, init.Self); } + public override object Create(ActorInitializer init) { return new ExplosionOnDamageTransition(this, init.Self); } public void RulesetLoaded(Ruleset rules, ActorInfo ai) { if (string.IsNullOrEmpty(Weapon)) return; - WeaponInfo weapon; var weaponToLower = Weapon.ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(weaponToLower, out weapon)) + if (!rules.Weapons.TryGetValue(weaponToLower, out var weapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); WeaponInfo = weapon; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/GainsExperience.cs openra-20210321/OpenRA.Mods.Common/Traits/GainsExperience.cs --- openra-20200503/OpenRA.Mods.Common/Traits/GainsExperience.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/GainsExperience.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("This actor's experience increases when it has killed a GivesExperience actor.")] - public class GainsExperienceInfo : ITraitInfo + public class GainsExperienceInfo : TraitInfo { [FieldLoader.Require] [Desc("Condition to grant at each level.", @@ -32,8 +32,8 @@ [Desc("Image for the level up sprite.")] public readonly string LevelUpImage = null; - [SequenceReference("Image")] - [Desc("Sequence for the level up sprite. Needs to be present on Image.")] + [SequenceReference(nameof(LevelUpImage), allowNullImage: true)] + [Desc("Sequence for the level up sprite. Needs to be present on LevelUpImage.")] public readonly string LevelUpSequence = "levelup"; [PaletteReference] @@ -49,21 +49,20 @@ [NotificationReference("Sounds")] public readonly string LevelUpNotification = null; - public object Create(ActorInitializer init) { return new GainsExperience(init, this); } + public override object Create(ActorInitializer init) { return new GainsExperience(init, this); } } - public class GainsExperience : INotifyCreated, ISync, IResolveOrder + public class GainsExperience : INotifyCreated, ISync, IResolveOrder, ITransformActorInitModifier { readonly Actor self; readonly GainsExperienceInfo info; readonly int initialExperience; - readonly List> nextLevel = new List>(); - ConditionManager conditionManager; + readonly List<(int RequiredExperience, string Condition)> nextLevel = new List<(int, string)>(); // Stored as a percentage of our value [Sync] - int experience = 0; + public int Experience { get; private set; } [Sync] public int Level { get; private set; } @@ -74,10 +73,9 @@ self = init.Self; this.info = info; + Experience = 0; MaxLevel = info.Conditions.Count; - - if (init.Contains()) - initialExperience = init.Get(); + initialExperience = init.GetValue(info, 0); } void INotifyCreated.Created(Actor self) @@ -85,9 +83,8 @@ var valued = self.Info.TraitInfoOrDefault(); var requiredExperience = info.ExperienceModifier < 0 ? (valued != null ? valued.Cost : 1) : info.ExperienceModifier; foreach (var kv in info.Conditions) - nextLevel.Add(Pair.New(kv.Key * requiredExperience, kv.Value)); + nextLevel.Add((kv.Key * requiredExperience, kv.Value)); - conditionManager = self.TraitOrDefault(); if (initialExperience > 0) GiveExperience(initialExperience, info.SuppressLevelupAnimation); } @@ -100,7 +97,7 @@ return; var newLevel = Math.Min(Level + numLevels, MaxLevel); - GiveExperience(nextLevel[newLevel - 1].First - experience, silent); + GiveExperience(nextLevel[newLevel - 1].RequiredExperience - Experience, silent); } public void GiveExperience(int amount, bool silent = false) @@ -111,12 +108,11 @@ if (MaxLevel == 0) return; - experience = (experience + amount).Clamp(0, nextLevel[MaxLevel - 1].First); + Experience = (Experience + amount).Clamp(0, nextLevel[MaxLevel - 1].RequiredExperience); - while (Level < MaxLevel && experience >= nextLevel[Level].First) + while (Level < MaxLevel && Experience >= nextLevel[Level].RequiredExperience) { - if (conditionManager != null) - conditionManager.GrantCondition(self, nextLevel[Level].Second); + self.GrantCondition(nextLevel[Level].Condition); Level++; @@ -143,15 +139,16 @@ GiveLevels(1); } } + + void ITransformActorInitModifier.ModifyTransformActorInit(Actor self, TypeDictionary init) + { + init.Add(new ExperienceInit(info, Experience)); + } } - class ExperienceInit : IActorInit + class ExperienceInit : ValueActorInit { - [FieldFromYamlKey] - readonly int value; - - public ExperienceInit() { } - public ExperienceInit(int init) { value = init; } - public int Value(World world) { return value; } + public ExperienceInit(TraitInfo info, int value) + : base(info, value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/GivesBounty.cs openra-20210321/OpenRA.Mods.Common/Traits/GivesBounty.cs --- openra-20200503/OpenRA.Mods.Common/Traits/GivesBounty.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/GivesBounty.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,8 +23,8 @@ [Desc("Percentage of the killed actor's Cost or CustomSellValue to be given.")] public readonly int Percentage = 10; - [Desc("Stance the attacking player needs to receive the bounty.")] - public readonly Stance ValidStances = Stance.Neutral | Stance.Enemy; + [Desc("Player relationships the attacking player needs to receive the bounty.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy; [Desc("Whether to show a floating text announcing the won bounty.")] public readonly bool ShowBounty = true; @@ -64,7 +64,7 @@ if (e.Attacker == null || e.Attacker.Disposed || IsTraitDisabled) return; - if (!Info.ValidStances.HasStance(e.Attacker.Owner.Stances[self.Owner])) + if (!Info.ValidRelationships.HasStance(e.Attacker.Owner.RelationshipWith(self.Owner))) return; if (!Info.DeathTypes.IsEmpty && !e.Damage.DamageTypes.Overlaps(Info.DeathTypes)) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/GivesExperience.cs openra-20210321/OpenRA.Mods.Common/Traits/GivesExperience.cs --- openra-20200503/OpenRA.Mods.Common/Traits/GivesExperience.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/GivesExperience.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,19 +9,20 @@ */ #endregion +using System.Collections.Generic; using System.Linq; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("This actor gives experience to a GainsExperience actor when they are killed.")] - class GivesExperienceInfo : ITraitInfo + class GivesExperienceInfo : TraitInfo { [Desc("If -1, use the value of the unit cost.")] public readonly int Experience = -1; - [Desc("Stance the attacking player needs to receive the experience.")] - public readonly Stance ValidStances = Stance.Neutral | Stance.Enemy; + [Desc("Player relationships the attacking player needs to receive the experience.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy; [Desc("Percentage of the `Experience` value that is being granted to the killing actor.")] public readonly int ActorExperienceModifier = 10000; @@ -29,34 +30,39 @@ [Desc("Percentage of the `Experience` value that is being granted to the player owning the killing actor.")] public readonly int PlayerExperienceModifier = 0; - public object Create(ActorInitializer init) { return new GivesExperience(init.Self, this); } + public override object Create(ActorInitializer init) { return new GivesExperience(init.Self, this); } } - class GivesExperience : INotifyKilled + class GivesExperience : INotifyKilled, INotifyCreated { readonly GivesExperienceInfo info; + int exp; + IEnumerable experienceModifiers; + public GivesExperience(Actor self, GivesExperienceInfo info) { this.info = info; } + void INotifyCreated.Created(Actor self) + { + var valued = self.Info.TraitInfoOrDefault(); + exp = info.Experience >= 0 ? info.Experience + : valued != null ? valued.Cost : 0; + + experienceModifiers = self.TraitsImplementing().ToArray().Select(m => m.GetGivesExperienceModifier()); + } + void INotifyKilled.Killed(Actor self, AttackInfo e) { - if (e.Attacker == null || e.Attacker.Disposed) + if (exp == 0 || e.Attacker == null || e.Attacker.Disposed) return; - if (!info.ValidStances.HasStance(e.Attacker.Owner.Stances[self.Owner])) + if (!info.ValidRelationships.HasStance(e.Attacker.Owner.RelationshipWith(self.Owner))) return; - var valued = self.Info.TraitInfoOrDefault(); - - var exp = info.Experience >= 0 - ? info.Experience - : valued != null ? valued.Cost : 0; - - var experienceModifier = self.TraitsImplementing().Select(x => x.GetGivesExperienceModifier()); - exp = Util.ApplyPercentageModifiers(exp, experienceModifier); + exp = Util.ApplyPercentageModifiers(exp, experienceModifiers); var killer = e.Attacker.TraitOrDefault(); if (killer != null) @@ -66,9 +72,8 @@ killer.GiveExperience(Util.ApplyPercentageModifiers(exp, killerExperienceModifier)); } - var attackerExp = e.Attacker.Owner.PlayerActor.TraitOrDefault(); - if (attackerExp != null) - attackerExp.GiveExperience(Util.ApplyPercentageModifiers(exp, new[] { info.PlayerExperienceModifier })); + e.Attacker.Owner.PlayerActor.TraitOrDefault() + ?.GiveExperience(Util.ApplyPercentageModifiers(exp, new[] { info.PlayerExperienceModifier })); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Guard.cs openra-20210321/OpenRA.Mods.Common/Traits/Guard.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Guard.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Guard.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,12 +16,15 @@ namespace OpenRA.Mods.Common.Traits { [Desc("The player can give this unit the order to follow and protect friendly units with the Guardable trait.")] - public class GuardInfo : ITraitInfo, Requires + public class GuardInfo : TraitInfo, Requires { [VoiceReference] public readonly string Voice = "Action"; - public object Create(ActorInitializer init) { return new Guard(this); } + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.OrangeRed; + + public override object Create(ActorInitializer init) { return new Guard(this); } } public class Guard : IResolveOrder, IOrderVoice, INotifyCreated @@ -51,7 +54,7 @@ return; var range = target.Actor.Info.TraitInfo().Range; - self.QueueActivity(queued, new AttackMoveActivity(self, () => move.MoveFollow(self, target, WDist.Zero, range, targetLineColor: Color.OrangeRed))); + self.QueueActivity(queued, new AttackMoveActivity(self, () => move.MoveFollow(self, target, WDist.Zero, range, targetLineColor: info.TargetLineColor))); self.ShowTargetLines(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Harvester.cs openra-20210321/OpenRA.Mods.Common/Traits/Harvester.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Harvester.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Harvester.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,7 +21,7 @@ namespace OpenRA.Mods.Common.Traits { - public class HarvesterInfo : ITraitInfo, Requires + public class HarvesterInfo : TraitInfo, Requires { public readonly HashSet DeliveryBuildings = new HashSet(); @@ -42,9 +42,6 @@ [Desc("How many bales can it dump at once.")] public readonly int BaleUnloadAmount = 1; - [Desc("How many squares to show the fill level.")] - public readonly int PipCount = 7; - public readonly int HarvestFacings = 0; [Desc("Which resources it can harvest.")] @@ -87,20 +84,32 @@ [VoiceReference] public readonly string DeliverVoice = "Action"; - public object Create(ActorInitializer init) { return new Harvester(init.Self, this); } + [Desc("Color to use for the target line of harvest orders.")] + public readonly Color HarvestLineColor = Color.Crimson; + + [Desc("Color to use for the target line of harvest orders.")] + public readonly Color DeliverLineColor = Color.Green; + + [Desc("Cursor to display when able to unload at target actor.")] + public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to unload at target actor.")] + public readonly string EnterBlockedCursor = "enter-blocked"; + + public override object Create(ActorInitializer init) { return new Harvester(init.Self, this); } } - public class Harvester : IIssueOrder, IResolveOrder, IPips, IOrderVoice, + public class Harvester : IIssueOrder, IResolveOrder, IOrderVoice, ISpeedModifier, ISync, INotifyCreated { public readonly HarvesterInfo Info; + public readonly IReadOnlyDictionary Contents; + readonly Mobile mobile; readonly ResourceLayer resLayer; readonly ResourceClaimLayer claimLayer; readonly Dictionary contents = new Dictionary(); - INotifyHarvesterAction[] notifyHarvesterAction; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; HarvesterResourceMultiplier[] resourceMultipliers; [Sync] @@ -127,6 +136,8 @@ public Harvester(Actor self, HarvesterInfo info) { Info = info; + Contents = new ReadOnlyDictionary(contents); + mobile = self.Trait(); resLayer = self.World.WorldActor.Trait(); claimLayer = self.World.WorldActor.Trait(); @@ -134,9 +145,7 @@ void INotifyCreated.Created(Actor self) { - notifyHarvesterAction = self.TraitsImplementing().ToArray(); resourceMultipliers = self.TraitsImplementing().ToArray(); - conditionManager = self.TraitOrDefault(); UpdateCondition(self); self.QueueActivity(new CallFunc(() => ChooseNewProc(self, null))); @@ -172,25 +181,25 @@ public Actor ClosestProc(Actor self, Actor ignore) { // Find all refineries and their occupancy count: - var refs = self.World.ActorsWithTrait() + var refineries = self.World.ActorsWithTrait() .Where(r => r.Actor != ignore && r.Actor.Owner == self.Owner && IsAcceptableProcType(r.Actor)) .Select(r => new { Location = r.Actor.Location + r.Trait.DeliveryOffset, Actor = r.Actor, Occupancy = self.World.ActorsHavingTrait(h => h.LinkedProc == r.Actor).Count() - }).ToDictionary(r => r.Location); + }).ToLookup(r => r.Location); // Start a search from each refinery's delivery location: List path; - using (var search = PathSearch.FromPoints(self.World, mobile.Locomotor, self, refs.Values.Select(r => r.Location), self.Location, BlockedByActor.None) - .WithCustomCost(loc => + using (var search = PathSearch.FromPoints(self.World, mobile.Locomotor, self, refineries.Select(r => r.Key), self.Location, BlockedByActor.None) + .WithCustomCost(location => { - if (!refs.ContainsKey(loc)) + if (!refineries.Contains(location)) return 0; - var occupancy = refs[loc].Occupancy; + var occupancy = refineries[location].First().Occupancy; // Too many harvesters clogs up the refinery's delivery location: if (occupancy >= Info.MaxUnloadQueue) @@ -202,7 +211,7 @@ path = self.World.WorldActor.Trait().FindPath(search); if (path.Count != 0) - return refs[path.Last()].Actor; + return refineries[path.Last()].First().Actor; return null; } @@ -213,15 +222,15 @@ void UpdateCondition(Actor self) { - if (string.IsNullOrEmpty(Info.EmptyCondition) || conditionManager == null) + if (string.IsNullOrEmpty(Info.EmptyCondition)) return; var enabled = IsEmpty; - if (enabled && conditionToken == ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.GrantCondition(self, Info.EmptyCondition); - else if (!enabled && conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (enabled && conditionToken == Actor.InvalidConditionToken) + conditionToken = self.GrantCondition(Info.EmptyCondition); + else if (!enabled && conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); } public void AcceptResource(Actor self, ResourceType type) @@ -281,14 +290,18 @@ { get { - yield return new EnterAlliedActorTargeter("Deliver", 5, + yield return new EnterAlliedActorTargeter( + "Deliver", + 5, + Info.EnterCursor, + Info.EnterBlockedCursor, (proc, _) => IsAcceptableProcType(proc), proc => proc.Trait().AllowDocking); yield return new HarvestOrderTargeter(); } } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "Deliver" || order.OrderID == "Harvest") return new Order(order.OrderID, self, target, queued); @@ -348,27 +361,6 @@ } } - PipType GetPipAt(int i) - { - var n = i * Info.Capacity / Info.PipCount; - - foreach (var rt in contents) - if (n < rt.Value) - return rt.Key.PipColor; - else - n -= rt.Value; - - return PipType.Transparent; - } - - IEnumerable IPips.GetPips(Actor self) - { - var numPips = Info.PipCount; - - for (var i = 0; i < numPips; i++) - yield return GetPipAt(i); - } - int ISpeedModifier.GetSpeedModifier() { return 100 - (100 - Info.FullyLoadedSpeed) * contents.Values.Sum() / Info.Capacity; @@ -379,9 +371,9 @@ public string OrderID { get { return "Harvest"; } } public int OrderPriority { get { return 10; } } public bool IsQueued { get; protected set; } - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (target.Type != TargetType.Terrain) return false; @@ -395,10 +387,12 @@ if (!self.Owner.Shroud.IsExplored(location)) return false; - var res = self.World.WorldActor.Trait().GetRenderedResourceType(location); var info = self.Info.TraitInfo(); + var res = self.World.WorldActor.TraitsImplementing() + .Select(r => r.GetRenderedResourceType(location)) + .FirstOrDefault(r => r != null && info.Resources.Contains(r.Info.Type)); - if (res == null || !info.Resources.Contains(res.Info.Type)) + if (res == null) return false; cursor = "harvest"; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Health.cs openra-20210321/OpenRA.Mods.Common/Traits/Health.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Health.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Health.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { - public class HealthInfo : IHealthInfo, IRulesetLoaded, IEditorActorOptions + public class HealthInfo : TraitInfo, IHealthInfo, IRulesetLoaded, IEditorActorOptions { [Desc("HitPoints")] public readonly int HP = 0; @@ -27,7 +27,7 @@ [Desc("Display order for the health slider in the map editor")] public readonly int EditorHealthDisplayOrder = 2; - public virtual object Create(ActorInitializer init) { return new Health(init, this); } + public override object Create(ActorInitializer init) { return new Health(init, this); } public void RulesetLoaded(Ruleset rules, ActorInfo ai) { @@ -42,8 +42,8 @@ yield return new EditorActorSlider("Health", EditorHealthDisplayOrder, 0, 100, 5, actor => { - var init = actor.Init(); - return init != null ? init.Value(world) : 100; + var init = actor.GetInitOrDefault(); + return init != null ? init.Value : 100; }, (actor, value) => actor.ReplaceInit(new HealthInit((int)value))); } @@ -68,10 +68,12 @@ public Health(ActorInitializer init, HealthInfo info) { Info = info; - MaxHP = info.HP > 0 ? info.HP : 1; + MaxHP = hp = info.HP > 0 ? info.HP : 1; // Cast to long to avoid overflow when multiplying by the health - hp = init.Contains() ? (int)(init.Get() * (long)MaxHP / 100) : MaxHP; + var healthInit = init.GetOrDefault(); + if (healthInit != null) + hp = (int)(healthInit.Value * (long)MaxHP / 100); DisplayHP = hp; } @@ -231,28 +233,22 @@ } } - public class HealthInit : IActorInit + public class HealthInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - readonly int value = 100; - readonly bool allowZero; - public HealthInit() { } - public HealthInit(int init) - : this(init, false) { } - public HealthInit(int init, bool allowZero) - { - this.allowZero = allowZero; - value = init; - } + public HealthInit(int value, bool allowZero = false) + : base(value) { this.allowZero = allowZero; } - public int Value(World world) + public override int Value { - if (value < 0 || (value == 0 && !allowZero)) - return 1; + get + { + if (value < 0 || (value == 0 && !allowZero)) + return 1; - return value; + return value; + } } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/HitShape.cs openra-20210321/OpenRA.Mods.Common/Traits/HitShape.cs --- openra-20200503/OpenRA.Mods.Common/Traits/HitShape.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/HitShape.cs 2021-03-21 11:10:05.000000000 +0000 @@ -35,6 +35,7 @@ public readonly BitSet ArmorTypes = default(BitSet); [FieldLoader.LoadUsing("LoadShape")] + [Desc("Engine comes with support for `Circle`, `Capsule`, `Polygon` and `Rectangle`. Defaults to `Circle` when left empty.")] public readonly IHitShape Type; static object LoadShape(MiniYaml yaml) @@ -89,11 +90,16 @@ IEnumerable ITargetablePositions.TargetablePositions(Actor self) { if (IsTraitDisabled) - yield break; + return Enumerable.Empty(); + return TargetablePositions(self); + } + + IEnumerable TargetablePositions(Actor self) + { if (Info.UseTargetableCellsOffsets && targetableCells != null) foreach (var c in targetableCells.TargetableCells()) - yield return self.World.Map.CenterOfCell(c.First); + yield return self.World.Map.CenterOfCell(c.Cell); foreach (var o in Info.TargetableOffsets) { @@ -109,11 +115,7 @@ if (turret != null) { - // WorldOrientation is quantized to satisfy the *Fudges. - // Need to then convert back to a pseudo-local coordinate space, apply offsets, - // then rotate back at the end - var turretOrientation = turret.WorldOrientation(self) - quantizedBodyOrientation; - localOffset = localOffset.Rotate(turretOrientation); + localOffset = localOffset.Rotate(turret.LocalOrientation); localOffset += turret.Offset; } @@ -122,27 +124,15 @@ public WDist DistanceFromEdge(Actor self, WPos pos) { - var origin = self.CenterPosition; - var orientation = self.Orientation; - if (turret != null) - { - origin += turret.Position(self); - orientation = turret.WorldOrientation(self); - } - + var origin = turret != null ? self.CenterPosition + turret.Position(self) : self.CenterPosition; + var orientation = turret != null ? turret.WorldOrientation : self.Orientation; return Info.Type.DistanceFromEdge(pos, origin, orientation); } public IEnumerable RenderDebugOverlay(Actor self, WorldRenderer wr) { - var origin = self.CenterPosition; - var orientation = self.Orientation; - if (turret != null) - { - origin += turret.Position(self); - orientation = turret.WorldOrientation(self); - } - + var origin = turret != null ? self.CenterPosition + turret.Position(self) : self.CenterPosition; + var orientation = turret != null ? turret.WorldOrientation : self.Orientation; return Info.Type.RenderDebugOverlay(wr, origin, orientation); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Husk.cs openra-20210321/OpenRA.Mods.Common/Traits/Husk.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Husk.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Husk.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,21 +18,21 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Spawns remains of a husk actor with the correct facing.")] - public class HuskInfo : ITraitInfo, IPositionableInfo, IFacingInfo, IActorPreviewInitInfo + public class HuskInfo : TraitInfo, IPositionableInfo, IFacingInfo, IActorPreviewInitInfo { public readonly HashSet AllowedTerrain = new HashSet(); [Desc("Facing to use for actor previews (map editor, color picker, etc)")] - public readonly int PreviewFacing = 96; + public readonly WAngle PreviewFacing = new WAngle(384); - IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) + IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) { yield return new FacingInit(PreviewFacing); } - public object Create(ActorInitializer init) { return new Husk(init, this); } + public override object Create(ActorInitializer init) { return new Husk(init, this); } - public int GetInitialFacing() { return 128; } + public WAngle GetInitialFacing() { return new WAngle(512); } public IReadOnlyDictionary OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any) { @@ -68,24 +68,32 @@ [Sync] public WPos CenterPosition { get; private set; } + WRot orientation; + [Sync] - public int Facing { get; set; } + public WAngle Facing + { + get { return orientation.Yaw; } + set { orientation = orientation.WithYaw(value); } + } - public int TurnSpeed { get { return 0; } } + public WRot Orientation { get { return orientation; } } + + public WAngle TurnSpeed { get { return WAngle.Zero; } } public Husk(ActorInitializer init, HuskInfo info) { this.info = info; self = init.Self; - TopLeft = init.Get(); - CenterPosition = init.Contains() ? init.Get() : init.World.Map.CenterOfCell(TopLeft); - Facing = init.Contains() ? init.Get() : 128; + TopLeft = init.GetValue(); + CenterPosition = init.GetValue(init.World.Map.CenterOfCell(TopLeft)); + Facing = init.GetValue(info.GetInitialFacing()); - dragSpeed = init.Contains() ? init.Get() : 0; + dragSpeed = init.GetValue(0); finalPosition = init.World.Map.CenterOfCell(TopLeft); - effectiveOwner = init.Contains() ? init.Get() : self.Owner; + effectiveOwner = init.GetValue(info, self.Owner); } void INotifyCreated.Created(Actor self) @@ -108,7 +116,7 @@ return true; } - public Pair[] OccupiedCells() { return new[] { Pair.New(TopLeft, SubCell.FullCell) }; } + public (CPos, SubCell)[] OccupiedCells() { return new[] { (TopLeft, SubCell.FullCell) }; } public bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any) { return false; } public SubCell GetValidSubCell(SubCell preferred = SubCell.Any) { return SubCell.FullCell; } public SubCell GetAvailableSubCell(CPos cell, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All) @@ -171,13 +179,9 @@ Player IEffectiveOwner.Owner { get { return effectiveOwner; } } } - public class HuskSpeedInit : IActorInit + public class HuskSpeedInit : ValueActorInit, ISingleInstanceInit { - [FieldFromYamlKey] - readonly int value = 0; - - public HuskSpeedInit() { } - public HuskSpeedInit(int init) { value = init; } - public int Value(World world) { return value; } + public HuskSpeedInit(int value) + : base(value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Immobile.cs openra-20210321/OpenRA.Mods.Common/Traits/Immobile.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Immobile.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Immobile.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,10 +15,10 @@ namespace OpenRA.Mods.Common.Traits { - class ImmobileInfo : ITraitInfo, IOccupySpaceInfo + class ImmobileInfo : TraitInfo, IOccupySpaceInfo { public readonly bool OccupiesSpace = true; - public object Create(ActorInitializer init) { return new Immobile(init, this); } + public override object Create(ActorInitializer init) { return new Immobile(init, this); } public IReadOnlyDictionary OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any) { @@ -39,22 +39,22 @@ [Sync] readonly WPos position; - readonly Pair[] occupied; + readonly (CPos, SubCell)[] occupied; public Immobile(ActorInitializer init, ImmobileInfo info) { - location = init.Get(); + location = init.GetValue(); position = init.World.Map.CenterOfCell(location); if (info.OccupiesSpace) - occupied = new[] { Pair.New(TopLeft, SubCell.FullCell) }; + occupied = new[] { (TopLeft, SubCell.FullCell) }; else - occupied = new Pair[0]; + occupied = new (CPos, SubCell)[0]; } public CPos TopLeft { get { return location; } } public WPos CenterPosition { get { return position; } } - public Pair[] OccupiedCells() { return occupied; } + public (CPos, SubCell)[] OccupiedCells() { return occupied; } void INotifyAddedToWorld.AddedToWorld(Actor self) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Infantry/ScaredyCat.cs openra-20210321/OpenRA.Mods.Common/Traits/Infantry/ScaredyCat.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Infantry/ScaredyCat.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Infantry/ScaredyCat.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,26 +9,34 @@ */ #endregion +using System; +using System.Collections.Generic; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Makes the unit automatically run around when taking damage.")] - class ScaredyCatInfo : ITraitInfo, Requires + class ScaredyCatInfo : TraitInfo, Requires { + [Desc("Chance (out of 100) the unit has to enter panic mode when attacked.")] + public readonly int PanicChance = 100; + [Desc("How long (in ticks) the actor should panic for.")] public readonly int PanicLength = 25 * 10; [Desc("Panic movement speed as a percentage of the normal speed.")] public readonly int PanicSpeedModifier = 200; - [Desc("Chance (out of 100) the unit has to enter panic mode when attacked.")] + [Desc("Chance (out of 100) the unit has to enter panic mode when attacking.")] public readonly int AttackPanicChance = 20; - [SequenceReference(null, true)] + [Desc("The terrain types that this actor should avoid running on to while panicking.")] + public readonly HashSet AvoidTerrainTypes = new HashSet(); + + [SequenceReference(prefix: true)] public readonly string PanicSequencePrefix = "panic-"; - public object Create(ActorInitializer init) { return new ScaredyCat(init.Self, this); } + public override object Create(ActorInitializer init) { return new ScaredyCat(init.Self, this); } } class ScaredyCat : ITick, INotifyIdle, INotifyDamage, INotifyAttack, ISpeedModifier, ISync, IRenderInfantrySequenceModifier @@ -36,6 +44,7 @@ readonly ScaredyCatInfo info; readonly Mobile mobile; readonly Actor self; + readonly Func avoidTerrainFilter; [Sync] int panicStartedTick; @@ -49,9 +58,12 @@ this.self = self; this.info = info; mobile = self.Trait(); + + if (info.AvoidTerrainTypes.Count > 0) + avoidTerrainFilter = c => info.AvoidTerrainTypes.Contains(self.World.Map.GetTerrainInfo(c).Type); } - void Panic() + public void Panic() { if (!Panicking) self.CancelActivity(); @@ -76,22 +88,25 @@ if (!Panicking) return; - mobile.Nudge(self); + // Note: This is just a modified copy of Mobile.Nudge + var cell = mobile.GetAdjacentCell(self.Location, avoidTerrainFilter); + if (cell != null) + self.QueueActivity(false, mobile.MoveTo(cell.Value, 0)); } void INotifyDamage.Damaged(Actor self, AttackInfo e) { - if (e.Damage.Value > 0) + if (e.Damage.Value > 0 && self.World.SharedRandom.Next(100) < info.PanicChance) Panic(); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { - if (self.World.SharedRandom.Next(100 / info.AttackPanicChance) == 0) + if (self.World.SharedRandom.Next(100) < info.AttackPanicChance) Panic(); } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { } + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { } int ISpeedModifier.GetSpeedModifier() { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Infantry/TakeCover.cs openra-20210321/OpenRA.Mods.Common/Traits/Infantry/TakeCover.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Infantry/TakeCover.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Infantry/TakeCover.cs 2021-03-21 11:10:05.000000000 +0000 @@ -36,7 +36,7 @@ [Desc("Muzzle offset modifier to apply while prone.")] public readonly WVec ProneOffset = new WVec(500, 0, 0); - [SequenceReference(null, true)] + [SequenceReference(prefix: true)] [Desc("Sequence prefix to apply while prone.")] public readonly string ProneSequencePrefix = "prone-"; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Infantry/TerrainModifiesDamage.cs openra-20210321/OpenRA.Mods.Common/Traits/Infantry/TerrainModifiesDamage.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Infantry/TerrainModifiesDamage.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Infantry/TerrainModifiesDamage.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits { - public class TerrainModifiesDamageInfo : ITraitInfo + public class TerrainModifiesDamageInfo : TraitInfo { [FieldLoader.Require] [Desc("Damage percentage for specific terrain types. 120 = 120%, 80 = 80%, etc.")] @@ -23,7 +23,7 @@ [Desc("Modify healing damage? For example: A friendly medic.")] public readonly bool ModifyHealing = false; - public object Create(ActorInitializer init) { return new TerrainModifiesDamage(init.Self, this); } + public override object Create(ActorInitializer init) { return new TerrainModifiesDamage(init.Self, this); } } public class TerrainModifiesDamage : IDamageModifier diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Interactable.cs openra-20210321/OpenRA.Mods.Common/Traits/Interactable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Interactable.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Interactable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,80 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Used to enable mouse interaction on actors that are not Selectable.")] + public class InteractableInfo : TraitInfo, IMouseBoundsInfo + { + [Desc("Defines a custom rectangle for mouse interaction with the actor.", + "If null, the engine will guess an appropriate size based on the With*Body trait.", + "The first two numbers define the width and height of the rectangle.", + "The (optional) second two numbers define an x and y offset from the actor center.")] + public readonly int[] Bounds = null; + + [Desc("Defines a custom rectangle for Decorations (e.g. the selection box).", + "If null, Bounds will be used instead")] + public readonly int[] DecorationBounds = null; + + public override object Create(ActorInitializer init) { return new Interactable(this); } + } + + public class Interactable : INotifyCreated, IMouseBounds + { + readonly InteractableInfo info; + IAutoMouseBounds[] autoBounds; + + public Interactable(InteractableInfo info) + { + this.info = info; + } + + void INotifyCreated.Created(Actor self) + { + autoBounds = self.TraitsImplementing().ToArray(); + } + + Rectangle AutoBounds(Actor self, WorldRenderer wr) + { + return autoBounds.Select(s => s.AutoMouseoverBounds(self, wr)).FirstOrDefault(r => !r.IsEmpty); + } + + Polygon Bounds(Actor self, WorldRenderer wr, int[] bounds) + { + if (bounds == null) + return new Polygon(AutoBounds(self, wr)); + + var size = new int2(bounds[0], bounds[1]); + + var offset = -size / 2; + if (bounds.Length > 2) + offset += new int2(bounds[2], bounds[3]); + + var xy = wr.ScreenPxPosition(self.CenterPosition) + offset; + return new Polygon(new Rectangle(xy.X, xy.Y, size.X, size.Y)); + } + + Polygon IMouseBounds.MouseoverBounds(Actor self, WorldRenderer wr) + { + return Bounds(self, wr, info.Bounds); + } + + public Rectangle DecorationBounds(Actor self, WorldRenderer wr) + { + return Bounds(self, wr, info.DecorationBounds ?? info.Bounds).BoundingRect; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/IsometricSelectable.cs openra-20210321/OpenRA.Mods.Common/Traits/IsometricSelectable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/IsometricSelectable.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/IsometricSelectable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,141 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using OpenRA.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("This actor is selectable. Defines bounds of selectable area, selection class, selection priority and selection priority modifiers.")] + public class IsometricSelectableInfo : TraitInfo, IMouseBoundsInfo, ISelectableInfo, IRulesetLoaded, Requires + { + [Desc("Defines a custom rectangle for mouse interaction with the actor.", + "If null, the engine will guess an appropriate size based on the building's footprint.", + "The first two numbers define the width and depth of the footprint rectangle.", + "The (optional) second two numbers define an x and y offset from the actor center.")] + public readonly int[] Bounds = null; + + [Desc("Height above the footprint for the top of the interaction rectangle.")] + public readonly int Height = 24; + + [Desc("Defines a custom rectangle for Decorations (e.g. the selection box).", + "If null, Bounds will be used instead.")] + public readonly int[] DecorationBounds = null; + + [Desc("Defines a custom height for Decorations (e.g. the selection box).", + "If < 0, Height will be used instead.", + "If Height is 0, this must be defined with a value greater than 0.")] + public readonly int DecorationHeight = -1; + + public readonly int Priority = 10; + + [Desc("Allow selection priority to be modified using a hotkey.", + "Valid values are None (priority is not affected by modifiers)", + "Ctrl (priority is raised when Ctrl pressed) and", + "Alt (priority is raised when Alt pressed).")] + public readonly SelectionPriorityModifiers PriorityModifiers = SelectionPriorityModifiers.None; + + [Desc("All units having the same selection class specified will be selected with select-by-type commands (e.g. double-click). ", + "Defaults to the actor name when not defined or inherited.")] + public readonly string Class = null; + + [VoiceReference] + public readonly string Voice = "Select"; + + public override object Create(ActorInitializer init) { return new IsometricSelectable(init.Self, this); } + + int ISelectableInfo.Priority { get { return Priority; } } + SelectionPriorityModifiers ISelectableInfo.PriorityModifiers { get { return PriorityModifiers; } } + string ISelectableInfo.Voice { get { return Voice; } } + + public virtual void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + var grid = Game.ModData.Manifest.Get(); + if (grid.Type != MapGridType.RectangularIsometric) + throw new YamlException("IsometricSelectable can only be used in mods that use the RectangularIsometric MapGrid type."); + + if (Height == 0 && DecorationHeight <= 0) + throw new YamlException("DecorationHeight must be defined and greater than 0 if Height is 0."); + } + } + + public class IsometricSelectable : IMouseBounds, ISelectable + { + readonly IsometricSelectableInfo info; + readonly string selectionClass = null; + readonly BuildingInfo buildingInfo; + + public IsometricSelectable(Actor self, IsometricSelectableInfo info) + { + this.info = info; + selectionClass = string.IsNullOrEmpty(info.Class) ? self.Info.Name : info.Class; + buildingInfo = self.Info.TraitInfo(); + } + + Polygon Bounds(Actor self, WorldRenderer wr, int[] bounds, int height) + { + int2 left, right, top, bottom; + if (bounds != null) + { + var offset = bounds.Length >= 4 ? new int2(bounds[2], bounds[3]) : int2.Zero; + var center = wr.ScreenPxPosition(self.CenterPosition) + offset; + left = center - new int2(bounds[0] / 2, 0); + right = left + new int2(bounds[0], 0); + top = center - new int2(0, bounds[1] / 2); + bottom = top + new int2(0, bounds[1]); + } + else + { + var xMin = int.MaxValue; + var xMax = int.MinValue; + var yMin = int.MaxValue; + var yMax = int.MinValue; + foreach (var c in buildingInfo.OccupiedTiles(self.Location)) + { + xMin = Math.Min(xMin, c.X); + xMax = Math.Max(xMax, c.X); + yMin = Math.Min(yMin, c.Y); + yMax = Math.Max(yMax, c.Y); + } + + left = wr.ScreenPxPosition(self.World.Map.CenterOfCell(new CPos(xMin, yMax)) - new WVec(768, 0, 0)); + right = wr.ScreenPxPosition(self.World.Map.CenterOfCell(new CPos(xMax, yMin)) + new WVec(768, 0, 0)); + top = wr.ScreenPxPosition(self.World.Map.CenterOfCell(new CPos(xMin, yMin)) - new WVec(0, 768, 0)); + bottom = wr.ScreenPxPosition(self.World.Map.CenterOfCell(new CPos(xMax, yMax)) + new WVec(0, 768, 0)); + } + + if (height == 0) + return new Polygon(new[] { top, left, bottom, right }); + + var h = new int2(0, height); + return new Polygon(new[] { top - h, left - h, left, bottom, right, right - h }); + } + + public Polygon Bounds(Actor self, WorldRenderer wr) + { + return Bounds(self, wr, info.Bounds, info.Height); + } + + public Polygon DecorationBounds(Actor self, WorldRenderer wr) + { + return Bounds(self, wr, info.DecorationBounds ?? info.Bounds, info.DecorationHeight >= 0 ? info.DecorationHeight : info.Height); + } + + Polygon IMouseBounds.MouseoverBounds(Actor self, WorldRenderer wr) + { + return Bounds(self, wr); + } + + string ISelectable.Class { get { return selectionClass; } } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/JamsMissiles.cs openra-20210321/OpenRA.Mods.Common/Traits/JamsMissiles.cs --- openra-20200503/OpenRA.Mods.Common/Traits/JamsMissiles.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/JamsMissiles.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,8 +19,8 @@ [Desc("Range of the deflection.")] public readonly WDist Range = WDist.Zero; - [Desc("What diplomatic stances are affected.")] - public readonly Stance DeflectionStances = Stance.Ally | Stance.Neutral | Stance.Enemy; + [Desc("What player relationships are affected.")] + public readonly PlayerRelationship DeflectionRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy; [Desc("Chance of deflecting missiles.")] public readonly int Chance = 100; @@ -31,7 +31,7 @@ public class JamsMissiles : ConditionalTrait { public WDist Range { get { return IsTraitDisabled ? WDist.Zero : Info.Range; } } - public Stance DeflectionStances { get { return Info.DeflectionStances; } } + public PlayerRelationship DeflectionStances { get { return Info.DeflectionRelationships; } } public int Chance { get { return Info.Chance; } } public JamsMissiles(JamsMissilesInfo info) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/KillsSelf.cs openra-20210321/OpenRA.Mods.Common/Traits/KillsSelf.cs --- openra-20200503/OpenRA.Mods.Common/Traits/KillsSelf.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/KillsSelf.cs 2021-03-21 11:10:05.000000000 +0000 @@ -35,7 +35,6 @@ class KillsSelf : ConditionalTrait, INotifyAddedToWorld, ITick { int lifetime; - ConditionManager conditionManager; public KillsSelf(Actor self, KillsSelfInfo info) : base(info) @@ -51,12 +50,6 @@ self.World.AddFrameEndTask(w => Kill(self)); } - protected override void Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - base.Created(self); - } - void INotifyAddedToWorld.AddedToWorld(Actor self) { if (!IsTraitDisabled) @@ -80,8 +73,7 @@ if (self.IsDead) return; - if (conditionManager != null && !string.IsNullOrEmpty(Info.GrantsCondition)) - conditionManager.GrantCondition(self, Info.GrantsCondition); + self.GrantCondition(Info.GrantsCondition); if (Info.RemoveInstead || !self.Info.HasTraitInfo()) self.Dispose(); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/LintAttributes.cs openra-20210321/OpenRA.Mods.Common/Traits/LintAttributes.cs --- openra-20200503/OpenRA.Mods.Common/Traits/LintAttributes.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/LintAttributes.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,37 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; + +namespace OpenRA.Mods.Common.Traits +{ + [AttributeUsage(AttributeTargets.Field)] + public sealed class VoiceSetReferenceAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Field)] + public sealed class VoiceReferenceAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Field)] + public sealed class LocomotorReferenceAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Field)] + public sealed class NotificationReferenceAttribute : Attribute + { + public readonly string NotificationTypeFieldName = null; + public readonly string NotificationType = null; + + public NotificationReferenceAttribute(string type = null, string typeFromField = null) + { + NotificationType = type; + NotificationTypeFieldName = typeFromField; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Mobile.cs openra-20210321/OpenRA.Mods.Common/Traits/Mobile.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Mobile.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Mobile.cs 2021-03-21 11:10:05.000000000 +0000 @@ -30,21 +30,30 @@ [Desc("Which Locomotor does this trait use. Must be defined on the World actor.")] public readonly string Locomotor = null; - public readonly int InitialFacing = 0; + public readonly WAngle InitialFacing = WAngle.Zero; [Desc("Speed at which the actor turns.")] - public readonly int TurnSpeed = 255; + public readonly WAngle TurnSpeed = new WAngle(512); public readonly int Speed = 1; + [Desc("If set to true, this unit will always turn in place instead of following a curved trajectory (like infantry).")] + public readonly bool AlwaysTurnInPlace = false; + + [Desc("Cursor to display when a move order can be issued at target location.")] public readonly string Cursor = "move"; + + [Desc("Cursor to display when a move order cannot be issued at target location.")] public readonly string BlockedCursor = "move-blocked"; [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line for regular move orders.")] + public readonly Color TargetLineColor = Color.Green; + [Desc("Facing to use for actor previews (map editor, color picker, etc)")] - public readonly int PreviewFacing = 96; + public readonly WAngle PreviewFacing = new WAngle(384); [Desc("Display order for the facing slider in the map editor")] public readonly int EditorFacingDisplayOrder = 3; @@ -57,11 +66,13 @@ [Desc("Boolean expression defining the condition under which this actor cannot be nudged by other actors.")] public readonly BooleanExpression ImmovableCondition = null; - IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) + IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) { yield return new FacingInit(PreviewFacing); } + public Color GetTargetLineColor() { return TargetLineColor; } + public override object Create(ActorInitializer init) { return new Mobile(init, this); } public LocomotorInfo LocomotorInfo { get; private set; } @@ -81,7 +92,7 @@ base.RulesetLoaded(rules, ai); } - public int GetInitialFacing() { return InitialFacing; } + public WAngle GetInitialFacing() { return InitialFacing; } // initialized and used by CanEnterCell Locomotor locomotor; @@ -124,37 +135,13 @@ IEnumerable IEditorActorOptions.ActorOptions(ActorInfo ai, World world) { - yield return new EditorActorSlider("Facing", EditorFacingDisplayOrder, 0, 255, 8, + yield return new EditorActorSlider("Facing", EditorFacingDisplayOrder, 0, 1023, 8, actor => { - var init = actor.Init(); - return init != null ? init.Value(world) : InitialFacing; + var init = actor.GetInitOrDefault(this); + return (init != null ? init.Value : InitialFacing).Angle; }, - (actor, value) => - { - // TODO: This can all go away once turrets are properly defined as a relative facing - var turretInit = actor.Init(); - var turretsInit = actor.Init(); - var facingInit = actor.Init(); - - var oldFacing = facingInit != null ? facingInit.Value(world) : InitialFacing; - var newFacing = (int)value; - - if (turretInit != null) - { - var newTurretFacing = (turretInit.Value(world) + newFacing - oldFacing + 255) % 255; - actor.ReplaceInit(new TurretFacingInit(newTurretFacing)); - } - - if (turretsInit != null) - { - var newTurretFacings = turretsInit.Value(world) - .ToDictionary(kv => kv.Key, kv => (kv.Value + newFacing - oldFacing + 255) % 255); - actor.ReplaceInit(new TurretFacingsInit(newTurretFacings)); - } - - actor.ReplaceInit(new FacingInit(newFacing)); - }); + (actor, value) => actor.ReplaceInit(new FacingInit(new WAngle((int)value)))); } } @@ -191,10 +178,12 @@ } #endregion - int oldFacing, facing; + WAngle oldFacing; + WRot orientation; WPos oldPos; CPos fromCell, toCell; public SubCell FromSubCell, ToSubCell; + INotifyCustomLayerChanged[] notifyCustomLayerChanged; INotifyVisualPositionChanged[] notifyVisualPositionChanged; INotifyMoving[] notifyMoving; @@ -212,14 +201,17 @@ } #region IFacing + [Sync] - public int Facing + public WAngle Facing { - get { return facing; } - set { facing = value; } + get { return orientation.Yaw; } + set { orientation = orientation.WithYaw(value); } } - public int TurnSpeed { get { return Info.TurnSpeed; } } + public WRot Orientation { get { return orientation; } } + + public WAngle TurnSpeed { get { return Info.TurnSpeed; } } #endregion [Sync] @@ -242,16 +234,16 @@ public CPos TopLeft { get { return ToCell; } } - public Pair[] OccupiedCells() + public (CPos, SubCell)[] OccupiedCells() { if (FromCell == ToCell) - return new[] { Pair.New(FromCell, FromSubCell) }; + return new[] { (FromCell, FromSubCell) }; // HACK: Should be fixed properly, see https://github.com/OpenRA/OpenRA/pull/17292 for an explanation if (Info.LocomotorInfo.SharesCell) - return new[] { Pair.New(ToCell, ToSubCell) }; + return new[] { (ToCell, ToSubCell) }; - return new[] { Pair.New(FromCell, FromSubCell), Pair.New(ToCell, ToSubCell) }; + return new[] { (FromCell, FromSubCell), (ToCell, ToSubCell) }; } #endregion @@ -263,31 +255,34 @@ speedModifiers = Exts.Lazy(() => self.TraitsImplementing().ToArray().Select(x => x.GetSpeedModifier())); ToSubCell = FromSubCell = info.LocomotorInfo.SharesCell ? init.World.Map.Grid.DefaultSubCell : SubCell.FullCell; - if (init.Contains()) + + var subCellInit = init.GetOrDefault(); + if (subCellInit != null) { - FromSubCell = ToSubCell = init.Get(); + FromSubCell = ToSubCell = subCellInit.Value; returnToCellOnCreationRecalculateSubCell = false; } - if (init.Contains()) + var locationInit = init.GetOrDefault(); + if (locationInit != null) { - fromCell = toCell = init.Get(); + fromCell = toCell = locationInit.Value; SetVisualPosition(self, init.World.Map.CenterOfSubCell(FromCell, FromSubCell)); } - Facing = oldFacing = init.Contains() ? init.Get() : info.InitialFacing; + Facing = oldFacing = init.GetValue(info.InitialFacing); // Sets the initial visual position // Unit will move into the cell grid (defined by LocationInit) as its initial activity - if (init.Contains()) + var centerPositionInit = init.GetOrDefault(); + if (centerPositionInit != null) { - oldPos = init.Get(); + oldPos = centerPositionInit.Value; SetVisualPosition(self, oldPos); returnToCellOnCreation = true; } - if (init.Contains()) - creationActivityDelay = init.Get(); + creationActivityDelay = init.GetValue(0); } protected override void Created(Actor self) @@ -369,14 +364,14 @@ self.QueueActivity(false, MoveTo(cell.Value, 0)); } - public CPos? GetAdjacentCell(CPos nextCell) + public CPos? GetAdjacentCell(CPos nextCell, Func preferToAvoid = null) { var availCells = new List(); var notStupidCells = new List(); foreach (CVec direction in CVec.Directions) { var p = ToCell + direction; - if (CanEnterCell(p) && CanStayInCell(p)) + if (CanEnterCell(p) && CanStayInCell(p) && (preferToAvoid == null || !preferToAvoid(p))) availCells.Add(p); else if (p != nextCell && p != ToCell) notStupidCells.Add(p); @@ -412,10 +407,10 @@ public bool IsLeaving() { - if (CurrentMovementTypes.HasFlag(MovementType.Horizontal)) + if (CurrentMovementTypes.HasMovementType(MovementType.Horizontal)) return true; - if (CurrentMovementTypes.HasFlag(MovementType.Turn)) + if (CurrentMovementTypes.HasMovementType(MovementType.Turn)) return TurnToMove; return false; @@ -429,8 +424,7 @@ if (ToCell.Layer == 0) return true; - ICustomMovementLayer layer; - if (self.World.GetCustomMovementLayers().TryGetValue(ToCell.Layer, out layer)) + if (self.World.GetCustomMovementLayers().TryGetValue(ToCell.Layer, out var layer)) return layer.InteractsWithDefaultLayer; return true; @@ -613,19 +607,19 @@ return WrapMove(new Move(self, cell, WDist.FromCells(nearEnough), ignoreActor, evaluateNearestMovableCell, targetLineColor)); } - public Activity MoveWithinRange(Target target, WDist range, + public Activity MoveWithinRange(in Target target, WDist range, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return WrapMove(new MoveWithinRange(self, target, WDist.Zero, range, initialTargetPosition, targetLineColor)); } - public Activity MoveWithinRange(Target target, WDist minRange, WDist maxRange, + public Activity MoveWithinRange(in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return WrapMove(new MoveWithinRange(self, target, minRange, maxRange, initialTargetPosition, targetLineColor)); } - public Activity MoveFollow(Actor self, Target target, WDist minRange, WDist maxRange, + public Activity MoveFollow(Actor self, in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null) { return WrapMove(new Follow(self, target, minRange, maxRange, initialTargetPosition, targetLineColor)); @@ -668,7 +662,7 @@ subCell = mobile.ToSubCell; if (recalculateSubCell) - subCell = mobile.Info.LocomotorInfo.SharesCell ? self.World.ActorMap.FreeSubCell(cell, subCell) : SubCell.FullCell; + subCell = mobile.Info.LocomotorInfo.SharesCell ? self.World.ActorMap.FreeSubCell(cell, subCell, a => a != self) : SubCell.FullCell; // TODO: solve/reduce cell is full problem if (subCell == SubCell.Invalid) @@ -684,19 +678,9 @@ QueueChild(mobile.VisualMove(self, pos, self.World.Map.CenterOfSubCell(cell, subCell))); return true; } - - public override void Cancel(Actor self, bool keepQueue = false) - { - // If we are forbidden from stopping in this cell, use evaluateNearestMovableCell - // to nudge us to the nearest cell that we can stop in. - if (!mobile.CanStayInCell(cell)) - QueueChild(new Move(self, cell, WDist.Zero, null, true)); - - base.Cancel(self, keepQueue); - } } - public Activity MoveToTarget(Actor self, Target target, + public Activity MoveToTarget(Actor self, in Target target, WPos? initialTargetPosition = null, Color? targetLineColor = null) { if (target.Type == TargetType.Invalid) @@ -705,7 +689,7 @@ return WrapMove(new MoveAdjacentTo(self, target, initialTargetPosition, targetLineColor)); } - public Activity MoveIntoTarget(Actor self, Target target) + public Activity MoveIntoTarget(Actor self, in Target target) { if (target.Type == TargetType.Invalid) return null; @@ -732,7 +716,7 @@ return NearestMoveableCell(target, 1, 10); } - public bool CanEnterTargetNow(Actor self, Target target) + public bool CanEnterTargetNow(Actor self, in Target target) { if (target.Type == TargetType.FrozenActor && !target.FrozenActor.IsValid) return false; @@ -746,16 +730,7 @@ public int MovementSpeedForCell(Actor self, CPos cell) { - var index = cell.Layer == 0 ? self.World.Map.GetTerrainIndex(cell) : - self.World.GetCustomMovementLayers()[cell.Layer].GetTerrainIndex(cell); - - if (index == byte.MaxValue) - return 0; - - var terrainSpeed = Info.LocomotorInfo.TilesetTerrainInfo[self.World.Map.Rules.TileSet][index].Speed; - if (terrainSpeed == 0) - return 0; - + var terrainSpeed = Locomotor.MovementSpeedForCell(cell); var modifiers = speedModifiers.Value.Append(terrainSpeed); return Util.ApplyPercentageModifiers(Info.Speed, modifiers); @@ -822,7 +797,7 @@ var length = speed > 0 ? (toPos - fromPos).Length / speed : 0; var delta = toPos - fromPos; - var facing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : Facing; + var facing = delta.HorizontalLengthSquared != 0 ? delta.Yaw : Facing; return new Drag(self, fromPos, toPos, length, facing); } @@ -851,12 +826,12 @@ void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits) { if (!inits.Contains() && !inits.Contains()) - inits.Add(new DynamicFacingInit(() => facing)); + inits.Add(new DynamicFacingInit(() => Facing)); } void IDeathActorInitModifier.ModifyDeathActorInit(Actor self, TypeDictionary init) { - init.Add(new FacingInit(facing)); + init.Add(new FacingInit(Facing)); // Allows the husk to drag to its final position if (CanEnterCell(self.Location, self, BlockedByActor.Stationary)) @@ -934,7 +909,7 @@ } // Note: Returns a valid order even if the unit can't move to the target - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order is MoveOrderTargeter) return new Order("Move", self, target, queued); @@ -953,7 +928,7 @@ if (!Info.LocomotorInfo.MoveIntoShroud && !self.Owner.Shroud.IsExplored(cell)) return; - self.QueueActivity(order.Queued, WrapMove(new Move(self, cell, WDist.FromCells(8), null, true, Color.Green))); + self.QueueActivity(order.Queued, WrapMove(new Move(self, cell, WDist.FromCells(8), null, true, Info.TargetLineColor))); self.ShowTargetLines(); } @@ -998,7 +973,7 @@ readonly Mobile mobile; readonly LocomotorInfo locomotorInfo; readonly bool rejectMove; - public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) + public bool TargetOverridesSelection(Actor self, in Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { // Always prioritise orders over selecting other peoples actors or own actors that are already selected if (target.Type == TargetType.Actor && (target.Actor.Owner != self.Owner || self.World.Selection.Contains(target.Actor))) @@ -1018,7 +993,7 @@ public int OrderPriority { get { return 4; } } public bool IsQueued { get; protected set; } - public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) + public bool CanTarget(Actor self, in Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (rejectMove || target.Type != TargetType.Terrain || (mobile.requireForceMove && !modifiers.HasModifier(TargetModifiers.ForceMove))) return false; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs openra-20210321/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; @@ -19,12 +18,12 @@ namespace OpenRA.Mods.Common.Traits { [Desc("This actor will remain visible (but not updated visually) under fog, once discovered.")] - public class FrozenUnderFogInfo : ITraitInfo, Requires, IDefaultVisibilityInfo + public class FrozenUnderFogInfo : TraitInfo, Requires, IDefaultVisibilityInfo { - [Desc("Players with these stances can always see the actor.")] - public readonly Stance AlwaysVisibleStances = Stance.Ally; + [Desc("Players with these relationships can always see the actor.")] + public readonly PlayerRelationship AlwaysVisibleRelationships = PlayerRelationship.Ally; - public object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); } + public override object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); } } public class FrozenUnderFog : ICreatesFrozenActors, IRenderModifier, IDefaultVisibility, ITick, ITickRender, ISync, INotifyCreated, INotifyOwnerChanged, INotifyActorDisposing @@ -106,8 +105,8 @@ if (byPlayer == null) return true; - var stance = self.Owner.Stances[byPlayer]; - return info.AlwaysVisibleStances.HasStance(stance) || IsVisibleInner(self, byPlayer); + var stance = self.Owner.RelationshipWith(byPlayer); + return info.AlwaysVisibleRelationships.HasStance(stance) || IsVisibleInner(self, byPlayer); } void ITick.Tick(Actor self) @@ -145,7 +144,7 @@ { IRenderable[] renderables = null; Rectangle[] bounds = null; - Rectangle mouseBounds = Rectangle.Empty; + var mouseBounds = Polygon.Empty; for (var playerIndex = 0; playerIndex < frozenStates.Count; playerIndex++) { var frozen = frozenStates[playerIndex].FrozenActor; @@ -195,5 +194,5 @@ } } - public class HiddenUnderFogInit : IActorInit { } + public class HiddenUnderFogInit : RuntimeFlagInit, ISingleInstanceInit { } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderShroud.cs openra-20210321/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderShroud.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderShroud.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderShroud.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,16 +17,16 @@ namespace OpenRA.Mods.Common.Traits { [Desc("The actor stays invisible under the shroud.")] - public class HiddenUnderShroudInfo : ITraitInfo, IDefaultVisibilityInfo + public class HiddenUnderShroudInfo : TraitInfo, IDefaultVisibilityInfo { - [Desc("Players with these stances can always see the actor.")] - public readonly Stance AlwaysVisibleStances = Stance.Ally; + [Desc("Players with these relationships can always see the actor.")] + public readonly PlayerRelationship AlwaysVisibleRelationships = PlayerRelationship.Ally; [Desc("Possible values are CenterPosition (reveal when the center is visible) and ", "Footprint (reveal when any footprint cell is visible).")] public readonly VisibilityType Type = VisibilityType.Footprint; - public virtual object Create(ActorInitializer init) { return new HiddenUnderShroud(this); } + public override object Create(ActorInitializer init) { return new HiddenUnderShroud(this); } } public class HiddenUnderShroud : IDefaultVisibility, IRenderModifier @@ -55,8 +55,8 @@ if (byPlayer == null) return true; - var stance = self.Owner.Stances[byPlayer]; - return Info.AlwaysVisibleStances.HasStance(stance) || IsVisibleInner(self, byPlayer); + var stance = self.Owner.RelationshipWith(byPlayer); + return Info.AlwaysVisibleRelationships.HasStance(stance) || IsVisibleInner(self, byPlayer); } IEnumerable IRenderModifier.ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Multipliers/HandicapDamageMultiplier.cs openra-20210321/OpenRA.Mods.Common/Traits/Multipliers/HandicapDamageMultiplier.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Multipliers/HandicapDamageMultiplier.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Multipliers/HandicapDamageMultiplier.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,40 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Modifies the damage applied to this actor based on the owner's handicap.")] + public class HandicapDamageMultiplierInfo : TraitInfo + { + public override object Create(ActorInitializer init) { return new HandicapDamageMultiplier(init.Self); } + } + + public class HandicapDamageMultiplier : IDamageModifier + { + readonly Actor self; + + public HandicapDamageMultiplier(Actor self) + { + this.self = self; + } + + int IDamageModifier.GetDamageModifier(Actor attacker, Damage damage) + { + // Equivalent to the health handicap from C&C3: + // 5% handicap = 95% health = 105% damage + // 50% handicap = 50% health = 200% damage + // 95% handicap = 5% health = 2000% damage + return 10000 / (100 - self.Owner.Handicap); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Multipliers/HandicapFirepowerMultiplier.cs openra-20210321/OpenRA.Mods.Common/Traits/Multipliers/HandicapFirepowerMultiplier.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Multipliers/HandicapFirepowerMultiplier.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Multipliers/HandicapFirepowerMultiplier.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,40 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Modifies the damage applied by this actor based on the owner's handicap.")] + public class HandicapFirepowerMultiplierInfo : TraitInfo + { + public override object Create(ActorInitializer init) { return new HandicapFirepowerMultiplier(init.Self); } + } + + public class HandicapFirepowerMultiplier : IFirepowerModifier + { + readonly Actor self; + + public HandicapFirepowerMultiplier(Actor self) + { + this.self = self; + } + + int IFirepowerModifier.GetFirepowerModifier() + { + // Equivalent to the firepower handicap from C&C3: + // 5% handicap = 95% firepower + // 50% handicap = 50% firepower + // 95% handicap = 5% firepower + return 100 - self.Owner.Handicap; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Multipliers/HandicapProductionTimeMultiplier.cs openra-20210321/OpenRA.Mods.Common/Traits/Multipliers/HandicapProductionTimeMultiplier.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Multipliers/HandicapProductionTimeMultiplier.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Multipliers/HandicapProductionTimeMultiplier.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,32 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Modifies the production time of this actor based on the producer's handicap.")] + public class HandicapProductionTimeMultiplierInfo : TraitInfo, IProductionTimeModifierInfo + { + int IProductionTimeModifierInfo.GetProductionTimeModifier(TechTree techTree, string queue) + { + // Equivalent to the build speed handicap from C&C3: + // 5% handicap = 105% build time + // 50% handicap = 150% build time + // 95% handicap = 195% build time + return 100 + techTree.Owner.Handicap; + } + } + + public class HandicapProductionTimeMultiplier { } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Multipliers/ProductionCostMultiplier.cs openra-20210321/OpenRA.Mods.Common/Traits/Multipliers/ProductionCostMultiplier.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Multipliers/ProductionCostMultiplier.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Multipliers/ProductionCostMultiplier.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Collections.Generic; using System.Linq; -using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Multipliers/ProductionTimeMultiplier.cs openra-20210321/OpenRA.Mods.Common/Traits/Multipliers/ProductionTimeMultiplier.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Multipliers/ProductionTimeMultiplier.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Multipliers/ProductionTimeMultiplier.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Collections.Generic; using System.Linq; -using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/MustBeDestroyed.cs openra-20210321/OpenRA.Mods.Common/Traits/MustBeDestroyed.cs --- openra-20200503/OpenRA.Mods.Common/Traits/MustBeDestroyed.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/MustBeDestroyed.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,12 +14,12 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Actors with this trait must be destroyed for a game to end.")] - public class MustBeDestroyedInfo : ITraitInfo + public class MustBeDestroyedInfo : TraitInfo { [Desc("In a short game only actors that have this value set to true need to be destroyed.")] public bool RequiredForShortGame = false; - public object Create(ActorInitializer init) { return new MustBeDestroyed(this); } + public override object Create(ActorInitializer init) { return new MustBeDestroyed(this); } } public class MustBeDestroyed diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/PaletteEffects/FlashPaletteEffect.cs openra-20210321/OpenRA.Mods.Common/Traits/PaletteEffects/FlashPaletteEffect.cs --- openra-20200503/OpenRA.Mods.Common/Traits/PaletteEffects/FlashPaletteEffect.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/PaletteEffects/FlashPaletteEffect.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,7 +19,7 @@ using GUtil = OpenRA.Graphics.Util; [Desc("Used for bursted one-colored whole screen effects. Add this to the world actor.")] - public class FlashPaletteEffectInfo : ITraitInfo + public class FlashPaletteEffectInfo : TraitInfo { public readonly HashSet ExcludePalettes = new HashSet { "cursor", "chrome", "colorpicker", "fog", "shroud" }; @@ -31,7 +31,7 @@ [Desc("Set this when using multiple independent flash effects.")] public readonly string Type = null; - public object Create(ActorInitializer init) { return new FlashPaletteEffect(this); } + public override object Create(ActorInitializer init) { return new FlashPaletteEffect(this); } } public class FlashPaletteEffect : IPaletteModifier, ITick diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/PaletteEffects/GlobalLightingPaletteEffect.cs openra-20210321/OpenRA.Mods.Common/Traits/PaletteEffects/GlobalLightingPaletteEffect.cs --- openra-20200503/OpenRA.Mods.Common/Traits/PaletteEffects/GlobalLightingPaletteEffect.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/PaletteEffects/GlobalLightingPaletteEffect.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Used for day/night effects.")] - class GlobalLightingPaletteEffectInfo : ITraitInfo, ILobbyCustomRulesIgnore + public class GlobalLightingPaletteEffectInfo : TraitInfo, ILobbyCustomRulesIgnore { [Desc("Do not modify graphics that use any palette in this list.")] public readonly HashSet ExcludePalettes = new HashSet { "cursor", "chrome", "colorpicker", "fog", "shroud", "alpha" }; @@ -30,10 +30,10 @@ public readonly float Blue = 1f; public readonly float Ambient = 1f; - public object Create(ActorInitializer init) { return new GlobalLightingPaletteEffect(this); } + public override object Create(ActorInitializer init) { return new GlobalLightingPaletteEffect(this); } } - class GlobalLightingPaletteEffect : IPaletteModifier + public class GlobalLightingPaletteEffect : IPaletteModifier { readonly GlobalLightingPaletteEffectInfo info; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/PaletteEffects/MenuPaletteEffect.cs openra-20210321/OpenRA.Mods.Common/Traits/PaletteEffects/MenuPaletteEffect.cs --- openra-20200503/OpenRA.Mods.Common/Traits/PaletteEffects/MenuPaletteEffect.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/PaletteEffects/MenuPaletteEffect.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Fades the world from/to black at the start/end of the game, and can (optionally) desaturate the world")] - public class MenuPaletteEffectInfo : ITraitInfo + public class MenuPaletteEffectInfo : TraitInfo { [Desc("Time (in ticks) to fade between states")] public readonly int FadeLength = 10; @@ -28,7 +28,7 @@ [Desc("Effect style to fade to when opening the in-game menu. Accepts values of None, Black or Desaturated.")] public readonly MenuPaletteEffect.EffectType MenuEffect = MenuPaletteEffect.EffectType.None; - public object Create(ActorInitializer init) { return new MenuPaletteEffect(this); } + public override object Create(ActorInitializer init) { return new MenuPaletteEffect(this); } } public class MenuPaletteEffect : IPaletteModifier, IRender, IWorldLoaded, INotifyGameLoaded diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/PaletteEffects/RotationPaletteEffect.cs openra-20210321/OpenRA.Mods.Common/Traits/PaletteEffects/RotationPaletteEffect.cs --- openra-20200503/OpenRA.Mods.Common/Traits/PaletteEffects/RotationPaletteEffect.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/PaletteEffects/RotationPaletteEffect.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Palette effect used for sprinkle \"animations\".")] - class RotationPaletteEffectInfo : ITraitInfo + class RotationPaletteEffectInfo : TraitInfo { [Desc("Defines to which palettes this effect should be applied to.", "If none specified, it applies to all palettes not explicitly excluded.")] @@ -41,7 +41,7 @@ [Desc("Step towards next color index per tick.")] public readonly float RotationStep = .25f; - public object Create(ActorInitializer init) { return new RotationPaletteEffect(init.World, this); } + public override object Create(ActorInitializer init) { return new RotationPaletteEffect(init.World, this); } } class RotationPaletteEffect : ITick, IPaletteModifier diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Parachutable.cs openra-20210321/OpenRA.Mods.Common/Traits/Parachutable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Parachutable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Parachutable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Can be paradropped by a ParaDrop actor.")] - public class ParachutableInfo : ITraitInfo, Requires + public class ParachutableInfo : TraitInfo, Requires { [Desc("If we land on invalid terrain for my actor type should we be killed?")] public readonly bool KilledOnImpassableTerrain = true; @@ -29,7 +29,7 @@ [Desc("Image where Ground/WaterCorpseSequence is looked up.")] public readonly string Image = "explosion"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] public readonly string GroundCorpseSequence = null; [PaletteReference] @@ -37,7 +37,7 @@ public readonly string GroundImpactSound = null; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] public readonly string WaterCorpseSequence = null; [PaletteReference] @@ -54,18 +54,17 @@ [Desc("The condition to grant to self while parachuting.")] public readonly string ParachutingCondition = null; - public object Create(ActorInitializer init) { return new Parachutable(init.Self, this); } + public override object Create(ActorInitializer init) { return new Parachutable(init.Self, this); } } - public class Parachutable : INotifyCreated, INotifyParachute + public class Parachutable : INotifyParachute { readonly ParachutableInfo info; readonly IPositionable positionable; public Actor IgnoreActor; - ConditionManager conditionManager; - int parachutingToken = ConditionManager.InvalidConditionToken; + int parachutingToken = Actor.InvalidConditionToken; public Parachutable(Actor self, ParachutableInfo info) { @@ -75,17 +74,12 @@ public bool IsInAir { get; private set; } - void INotifyCreated.Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - } - void INotifyParachute.OnParachute(Actor self) { IsInAir = true; - if (conditionManager != null && parachutingToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(info.ParachutingCondition)) - parachutingToken = conditionManager.GrantCondition(self, info.ParachutingCondition); + if (parachutingToken == Actor.InvalidConditionToken) + parachutingToken = self.GrantCondition(info.ParachutingCondition); self.NotifyBlocker(self.Location); } @@ -94,8 +88,8 @@ { IsInAir = false; - if (parachutingToken != ConditionManager.InvalidConditionToken) - parachutingToken = conditionManager.RevokeCondition(self, parachutingToken); + if (parachutingToken != Actor.InvalidConditionToken) + parachutingToken = self.RevokeCondition(parachutingToken); if (!info.KilledOnImpassableTerrain) return; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ParaDrop.cs openra-20210321/OpenRA.Mods.Common/Traits/ParaDrop.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ParaDrop.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ParaDrop.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,14 +10,12 @@ #endregion using System; -using System.Collections.Generic; -using OpenRA.Mods.Common.Activities; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("This unit can spawn and eject other actors while flying.")] - public class ParaDropInfo : ITraitInfo, Requires + public class ParaDropInfo : TraitInfo, Requires { [Desc("Distance around the drop-point to unload troops.")] public readonly WDist DropRange = WDist.FromCells(4); @@ -28,7 +26,7 @@ [Desc("Sound to play when dropping.")] public readonly string ChuteSound = null; - public object Create(ActorInitializer init) { return new ParaDrop(init.Self, this); } + public override object Create(ActorInitializer init) { return new ParaDrop(init.Self, this); } } public class ParaDrop : ITick, ISync, INotifyRemovedFromWorld diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Passenger.cs openra-20210321/OpenRA.Mods.Common/Traits/Passenger.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Passenger.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Passenger.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Collections.Generic; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; @@ -20,16 +19,20 @@ namespace OpenRA.Mods.Common.Traits { [Desc("This actor can enter Cargo actors.")] - public class PassengerInfo : ITraitInfo, IObservesVariablesInfo + public class PassengerInfo : TraitInfo, IObservesVariablesInfo { public readonly string CargoType = null; - public readonly PipType PipType = PipType.Green; + + [Desc("If defined, use a custom pip type defined on the transport's WithCargoPipsDecoration.CustomPipSequences list.")] + public readonly string CustomPipType = null; + public readonly int Weight = 1; [GrantedConditionReference] [Desc("The condition to grant to when this actor is loaded inside any transport.")] public readonly string CargoCondition = null; + [ActorReference(dictionaryReference: LintDictionaryReference.Keys)] [Desc("Conditions to grant when this actor is loaded inside specified transport.", "A dictionary of [actor id]: [condition].")] public readonly Dictionary CargoConditions = new Dictionary(); @@ -40,22 +43,30 @@ [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Green; + [ConsumedConditionReference] [Desc("Boolean expression defining the condition under which the regular (non-force) enter cursor is disabled.")] public readonly BooleanExpression RequireForceMoveCondition = null; - public object Create(ActorInitializer init) { return new Passenger(this); } + [Desc("Cursor to display when able to enter target actor.")] + public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to enter target actor.")] + public readonly string EnterBlockedCursor = "enter-blocked"; + + public override object Create(ActorInitializer init) { return new Passenger(this); } } - public class Passenger : INotifyCreated, IIssueOrder, IResolveOrder, IOrderVoice, INotifyRemovedFromWorld, INotifyEnteredCargo, INotifyExitedCargo, INotifyKilled, IObservesVariables + public class Passenger : IIssueOrder, IResolveOrder, IOrderVoice, INotifyRemovedFromWorld, INotifyEnteredCargo, INotifyExitedCargo, INotifyKilled, IObservesVariables { public readonly PassengerInfo Info; public Actor Transport; bool requireForceMove; - ConditionManager conditionManager; - int anyCargoToken = ConditionManager.InvalidConditionToken; - int specificCargoToken = ConditionManager.InvalidConditionToken; + int anyCargoToken = Actor.InvalidConditionToken; + int specificCargoToken = Actor.InvalidConditionToken; public Passenger(PassengerInfo info) { @@ -68,16 +79,17 @@ { get { - yield return new EnterAlliedActorTargeter("EnterTransport", 5, IsCorrectCargoType, CanEnter); + yield return new EnterAlliedActorTargeter( + "EnterTransport", + 5, + Info.EnterCursor, + Info.EnterBlockedCursor, + IsCorrectCargoType, + CanEnter); } } - void INotifyCreated.Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - } - - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "EnterTransport") return new Order(order.OrderID, self, target, queued); @@ -122,15 +134,11 @@ void INotifyEnteredCargo.OnEnteredCargo(Actor self, Actor cargo) { - string specificCargoCondition; - if (conditionManager != null) - { - if (anyCargoToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.CargoCondition)) - anyCargoToken = conditionManager.GrantCondition(self, Info.CargoCondition); + if (anyCargoToken == Actor.InvalidConditionToken) + anyCargoToken = self.GrantCondition(Info.CargoCondition); - if (specificCargoToken == ConditionManager.InvalidConditionToken && Info.CargoConditions.TryGetValue(cargo.Info.Name, out specificCargoCondition)) - specificCargoToken = conditionManager.GrantCondition(self, specificCargoCondition); - } + if (specificCargoToken == Actor.InvalidConditionToken && Info.CargoConditions.TryGetValue(cargo.Info.Name, out var specificCargoCondition)) + specificCargoToken = self.GrantCondition(specificCargoCondition); // Allow scripted / initial actors to move from the unload point back into the cell grid on unload // This is handled by the RideTransport activity for player-loaded cargo @@ -145,11 +153,11 @@ void INotifyExitedCargo.OnExitedCargo(Actor self, Actor cargo) { - if (anyCargoToken != ConditionManager.InvalidConditionToken) - anyCargoToken = conditionManager.RevokeCondition(self, anyCargoToken); + if (anyCargoToken != Actor.InvalidConditionToken) + anyCargoToken = self.RevokeCondition(anyCargoToken); - if (specificCargoToken != ConditionManager.InvalidConditionToken) - specificCargoToken = conditionManager.RevokeCondition(self, specificCargoToken); + if (specificCargoToken != Actor.InvalidConditionToken) + specificCargoToken = self.RevokeCondition(specificCargoToken); } void IResolveOrder.ResolveOrder(Actor self, Order order) @@ -169,7 +177,7 @@ if (!IsCorrectCargoType(targetActor)) return; - self.QueueActivity(order.Queued, new RideTransport(self, order.Target)); + self.QueueActivity(order.Queued, new RideTransport(self, order.Target, Info.TargetLineColor)); self.ShowTargetLines(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/AllyRepair.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/AllyRepair.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/AllyRepair.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/AllyRepair.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,9 +26,7 @@ if (!building.AppearsFriendlyTo(self)) return; - var rb = building.TraitOrDefault(); - if (rb != null) - rb.RepairBuilding(building, self.Owner); + building.TraitOrDefault()?.RepairBuilding(building, self.Owner); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/BaseAttackNotifier.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/BaseAttackNotifier.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/BaseAttackNotifier.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/BaseAttackNotifier.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ { [Desc("Plays an audio notification and shows a radar ping when a building is attacked.", "Attach this to the player actor.")] - public class BaseAttackNotifierInfo : ITraitInfo + public class BaseAttackNotifierInfo : TraitInfo { [Desc("Minimum duration (in seconds) between notification events.")] public readonly int NotifyInterval = 30; @@ -35,7 +35,7 @@ "Won't play a notification to allies if this is null.")] public string AllyNotification = null; - public object Create(ActorInitializer init) { return new BaseAttackNotifier(init.Self, this); } + public override object Create(ActorInitializer init) { return new BaseAttackNotifier(init.Self, this); } } public class BaseAttackNotifier : INotifyDamage @@ -80,8 +80,7 @@ if (p != self.Owner && p.IsAlliedWith(self.Owner) && p != e.Attacker.Owner) Game.Sound.PlayNotification(rules, p, "Speech", info.AllyNotification, p.Faction.InternalName); - if (radarPings != null) - radarPings.Add(() => self.Owner.IsAlliedWith(self.World.RenderPlayer), self.CenterPosition, info.RadarPingColor, info.RadarPingDuration); + radarPings?.Add(() => self.Owner.IsAlliedWith(self.World.RenderPlayer), self.CenterPosition, info.RadarPingColor, info.RadarPingDuration); } lastAttackTime = self.World.WorldTick; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/ClassicParallelProductionQueue.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/ClassicParallelProductionQueue.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/ClassicParallelProductionQueue.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/ClassicParallelProductionQueue.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,225 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Attach this to the player actor (not a building!) to define a new shared build queue.", + "Will only work together with the Production: trait on the actor that actually does the production.", + "You will also want to add PrimaryBuildings: to let the user choose where new units should exit.", + "The production speed depends on the number of production buildings and units queued at the same time.")] + public class ClassicParallelProductionQueueInfo : ProductionQueueInfo, Requires, Requires + { + [Desc("If you build more actors of the same type,", "the same queue will get its build time lowered for every actor produced there.")] + public readonly bool SpeedUp = false; + + [Desc("Every time another production building of the same queue is", + "constructed, the build times of all actors in the queue", + "modified by a percentage of the original time.")] + public readonly int[] BuildingCountBuildTimeMultipliers = { 100, 85, 75, 65, 60, 55, 50 }; + + [Desc("Build time modifier multiplied by the number of parallel production for producing different actors at the same time.")] + public readonly int[] ParallelPenaltyBuildTimeMultipliers = { 100, 116, 133, 150, 166, 183, 200, 216, 233, 250 }; + + public override object Create(ActorInitializer init) { return new ClassicParallelProductionQueue(init, this); } + } + + public class ClassicParallelProductionQueue : ProductionQueue + { + static readonly ActorInfo[] NoItems = { }; + + readonly Actor self; + readonly ClassicParallelProductionQueueInfo info; + + int penalty; + + public ClassicParallelProductionQueue(ActorInitializer init, ClassicParallelProductionQueueInfo info) + : base(init, init.Self, info) + { + self = init.Self; + this.info = info; + } + + protected override void Tick(Actor self) + { + // PERF: Avoid LINQ. + Enabled = false; + var isActive = false; + foreach (var x in self.World.ActorsWithTrait()) + { + if (x.Trait.IsTraitDisabled) + continue; + + if (x.Actor.Owner != self.Owner || !x.Trait.Info.Produces.Contains(Info.Type)) + continue; + + Enabled |= IsValidFaction; + isActive |= !x.Trait.IsTraitPaused; + } + + if (!Enabled) + ClearQueue(); + + TickInner(self, !isActive); + } + + protected override void TickInner(Actor self, bool allProductionPaused) + { + CancelUnbuildableItems(); + + if (allProductionPaused) + return; + + var item = Queue.FirstOrDefault(i => !i.Paused); + if (item == null) + return; + + var parallelBuilds = Queue.FindAll(i => !i.Paused && !i.Done) + .GroupBy(i => i.Item) + .ToList() + .Count - 1; + + if (parallelBuilds > 0 && !developerMode.FastBuild) + { + penalty -= 100; + if (penalty < 0) + penalty = info.ParallelPenaltyBuildTimeMultipliers[Math.Min(parallelBuilds, info.ParallelPenaltyBuildTimeMultipliers.Length - 1)]; + else + return; + } + + var before = item.RemainingTime; + item.Tick(playerResources); + + if (item.RemainingTime == before) + return; + + // As we have progressed this actor type, we will move all queued items of this actor to the end. + foreach (var other in Queue.FindAll(a => a.Item == item.Item)) + { + Queue.Remove(other); + Queue.Add(other); + } + } + + public override IEnumerable AllItems() + { + return Enabled ? base.AllItems() : NoItems; + } + + public override IEnumerable BuildableItems() + { + return Enabled ? base.BuildableItems() : NoItems; + } + + public override bool IsProducing(ProductionItem item) + { + return Queue.Contains(item); + } + + public override TraitPair MostLikelyProducer() + { + var productionActors = self.World.ActorsWithTrait() + .Where(x => x.Actor.Owner == self.Owner + && !x.Trait.IsTraitDisabled && x.Trait.Info.Produces.Contains(Info.Type)) + .OrderByDescending(x => x.Actor.IsPrimaryBuilding()) + .ThenByDescending(x => x.Actor.ActorID) + .ToList(); + + var unpaused = productionActors.FirstOrDefault(a => !a.Trait.IsTraitPaused); + return unpaused.Trait != null ? unpaused : productionActors.FirstOrDefault(); + } + + protected override bool BuildUnit(ActorInfo unit) + { + // Find a production structure to build this actor + var bi = unit.TraitInfo(); + + // Some units may request a specific production type, which is ignored if the AllTech cheat is enabled + var type = developerMode.AllTech ? Info.Type : (bi.BuildAtProductionType ?? Info.Type); + + var producers = self.World.ActorsWithTrait() + .Where(x => x.Actor.Owner == self.Owner + && !x.Trait.IsTraitDisabled + && x.Trait.Info.Produces.Contains(type)) + .OrderByDescending(x => x.Actor.IsPrimaryBuilding()) + .ThenByDescending(x => x.Actor.ActorID); + + if (!producers.Any()) + { + CancelProduction(unit.Name, 1); + return false; + } + + foreach (var p in producers) + { + if (p.Trait.IsTraitPaused) + continue; + + var inits = new TypeDictionary + { + new OwnerInit(self.Owner), + new FactionInit(BuildableInfo.GetInitialFaction(unit, p.Trait.Faction)) + }; + + var item = Queue.First(i => i.Done && i.Item == unit.Name); + if (p.Trait.Produce(p.Actor, unit, type, inits, item.TotalCost)) + { + EndProduction(item); + return true; + } + } + + return false; + } + + protected override void BeginProduction(ProductionItem item, bool hasPriority) + { + // Ignore `hasPriority` as it's not relevant in parallel production context. + base.BeginProduction(item, false); + } + + public override int GetBuildTime(ActorInfo unit, BuildableInfo bi) + { + if (developerMode.FastBuild) + return 0; + + var time = base.GetBuildTime(unit, bi); + + if (info.SpeedUp) + { + var type = bi.BuildAtProductionType ?? info.Type; + + var selfsameProductionsCount = self.World.ActorsWithTrait() + .Count(p => !p.Trait.IsTraitDisabled && !p.Trait.IsTraitPaused && p.Actor.Owner == self.Owner && p.Trait.Info.Produces.Contains(type)); + + var speedModifier = selfsameProductionsCount.Clamp(1, info.BuildingCountBuildTimeMultipliers.Length) - 1; + time = (time * info.BuildingCountBuildTimeMultipliers[speedModifier]) / 100; + } + + return time; + } + + public override int RemainingTimeActual(ProductionItem item) + { + var parallelBuilds = Queue.FindAll(i => !i.Paused && !i.Done) + .GroupBy(i => i.Item) + .ToList() + .Count; + return item.RemainingTimeActual * parallelBuilds * info.ParallelPenaltyBuildTimeMultipliers[Math.Min(parallelBuilds - 1, info.ParallelPenaltyBuildTimeMultipliers.Length - 1)] / 100; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/ClassicProductionQueue.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/ClassicProductionQueue.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/ClassicProductionQueue.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/ClassicProductionQueue.cs 2021-03-21 11:10:05.000000000 +0000 @@ -124,9 +124,10 @@ new FactionInit(BuildableInfo.GetInitialFaction(unit, p.Trait.Faction)) }; - if (p.Trait.Produce(p.Actor, unit, type, inits)) + var item = Queue.First(i => i.Done && i.Item == unit.Name); + if (p.Trait.Produce(p.Actor, unit, type, inits, item.TotalCost)) { - EndProduction(Queue.FirstOrDefault(i => i.Done && i.Item == unit.Name)); + EndProduction(item); return true; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/ConquestVictoryConditions.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/ConquestVictoryConditions.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/ConquestVictoryConditions.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/ConquestVictoryConditions.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { - public class ConquestVictoryConditionsInfo : ITraitInfo, Requires + public class ConquestVictoryConditionsInfo : TraitInfo, Requires { [Desc("Delay for the end game notification in milliseconds.")] public readonly int NotificationDelay = 1500; @@ -28,7 +28,7 @@ [Desc("Disable the win/loss messages and audio notifications?")] public readonly bool SuppressNotifications = false; - public object Create(ActorInitializer init) { return new ConquestVictoryConditions(init.Self, this); } + public override object Create(ActorInitializer init) { return new ConquestVictoryConditions(init.Self, this); } } public class ConquestVictoryConditions : ITick, INotifyWinStateChanged, INotifyTimeLimit @@ -78,12 +78,12 @@ var myTeam = self.World.LobbyInfo.ClientWithIndex(self.Owner.ClientIndex).Team; var teams = self.World.Players.Where(p => !p.NonCombatant && p.Playable) - .Select(p => new Pair(p, p.PlayerActor.TraitOrDefault())) - .OrderByDescending(p => p.Second != null ? p.Second.Experience : 0) - .GroupBy(p => (self.World.LobbyInfo.ClientWithIndex(p.First.ClientIndex) ?? new Session.Client()).Team) - .OrderByDescending(g => g.Sum(gg => gg.Second != null ? gg.Second.Experience : 0)); + .Select(p => (Player: p, PlayerStatistics: p.PlayerActor.TraitOrDefault())) + .OrderByDescending(p => p.PlayerStatistics != null ? p.PlayerStatistics.Experience : 0) + .GroupBy(p => (self.World.LobbyInfo.ClientWithIndex(p.Player.ClientIndex) ?? new Session.Client()).Team) + .OrderByDescending(g => g.Sum(gg => gg.PlayerStatistics != null ? gg.PlayerStatistics.Experience : 0)); - if (teams.First().Key == myTeam && (myTeam != 0 || teams.First().First().First == self.Owner)) + if (teams.First().Key == myTeam && (myTeam != 0 || teams.First().First().Player == self.Owner)) { mo.MarkCompleted(self.Owner, objectiveID); return; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/DeveloperMode.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/DeveloperMode.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/DeveloperMode.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/DeveloperMode.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Attach this to the player actor.")] - public class DeveloperModeInfo : ITraitInfo, ILobbyOptions + public class DeveloperModeInfo : TraitInfo, ILobbyOptions { [Translate] [Desc("Descriptive label for the developer mode checkbox in the lobby.")] @@ -68,7 +68,7 @@ yield return new LobbyBooleanOption("cheats", CheckboxLabel, CheckboxDescription, CheckboxVisible, CheckboxDisplayOrder, CheckboxEnabled, CheckboxLocked); } - public object Create(ActorInitializer init) { return new DeveloperMode(this); } + public override object Create(ActorInitializer init) { return new DeveloperMode(this); } } public class DeveloperMode : IResolveOrder, ISync, INotifyCreated, IUnlocksRenderPlayer @@ -244,10 +244,7 @@ case "DevPlayerExperience": { - var playerExperience = self.Owner.PlayerActor.TraitOrDefault(); - if (playerExperience != null) - playerExperience.GiveExperience((int)order.ExtraData); - + self.Owner.PlayerActor.TraitOrDefault()?.GiveExperience((int)order.ExtraData); break; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/DummyBot.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/DummyBot.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/DummyBot.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/DummyBot.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("A placeholder bot that doesn't do anything.")] - public sealed class DummyBotInfo : ITraitInfo, IBotInfo + public sealed class DummyBotInfo : TraitInfo, IBotInfo { [Desc("Human-readable name this bot uses.")] public readonly string Name = "Unnamed Bot"; @@ -27,7 +27,7 @@ string IBotInfo.Name { get { return Name; } } - public object Create(ActorInitializer init) { return new DummyBot(this); } + public override object Create(ActorInitializer init) { return new DummyBot(this); } } public sealed class DummyBot : IBot diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/EnemyWatcher.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/EnemyWatcher.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/EnemyWatcher.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/EnemyWatcher.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ { [Desc("Tracks neutral and enemy actors' visibility and notifies the player.", "Attach this to the player actor. The actors to track need the 'AnnounceOnSeen' trait.")] - class EnemyWatcherInfo : ITraitInfo + class EnemyWatcherInfo : TraitInfo { [Desc("Interval in ticks between scanning for enemies.")] public readonly int ScanInterval = 25; @@ -25,7 +25,7 @@ [Desc("Minimal ticks in-between notifications.")] public readonly int NotificationInterval = 750; - public object Create(ActorInitializer init) { return new EnemyWatcher(this); } + public override object Create(ActorInitializer init) { return new EnemyWatcher(this); } } class EnemyWatcher : ITick diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/GrantConditionOnPrerequisiteManager.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/GrantConditionOnPrerequisiteManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/GrantConditionOnPrerequisiteManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/GrantConditionOnPrerequisiteManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,15 +17,15 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Attach this to the player actor.")] - public class GrantConditionOnPrerequisiteManagerInfo : ITraitInfo, Requires + public class GrantConditionOnPrerequisiteManagerInfo : TraitInfo, Requires { - public object Create(ActorInitializer init) { return new GrantConditionOnPrerequisiteManager(init); } + public override object Create(ActorInitializer init) { return new GrantConditionOnPrerequisiteManager(init); } } public class GrantConditionOnPrerequisiteManager : ITechTreeElement { readonly Actor self; - readonly Dictionary>> upgradables = new Dictionary>>(); + readonly Dictionary> upgradables = new Dictionary>(); readonly TechTree techTree; public GrantConditionOnPrerequisiteManager(ActorInitializer init) @@ -44,11 +44,11 @@ var key = MakeKey(prerequisites); if (!upgradables.ContainsKey(key)) { - upgradables.Add(key, new List>()); + upgradables.Add(key, new List<(Actor, GrantConditionOnPrerequisite)>()); techTree.Add(key, prerequisites, 0, this); } - upgradables[key].Add(Pair.New(actor, u)); + upgradables[key].Add((actor, u)); // Notify the current state u.PrerequisitesUpdated(actor, techTree.HasPrerequisites(prerequisites)); @@ -59,7 +59,7 @@ var key = MakeKey(prerequisites); var list = upgradables[key]; - list.RemoveAll(x => x.First == actor && x.Second == u); + list.RemoveAll(x => x.Actor == actor && x.GrantConditionOnPrerequisite == u); if (!list.Any()) { upgradables.Remove(key); @@ -69,22 +69,20 @@ public void PrerequisitesAvailable(string key) { - List> list; - if (!upgradables.TryGetValue(key, out list)) + if (!upgradables.TryGetValue(key, out var list)) return; foreach (var u in list) - u.Second.PrerequisitesUpdated(u.First, true); + u.GrantConditionOnPrerequisite.PrerequisitesUpdated(u.Actor, true); } public void PrerequisitesUnavailable(string key) { - List> list; - if (!upgradables.TryGetValue(key, out list)) + if (!upgradables.TryGetValue(key, out var list)) return; foreach (var u in list) - u.Second.PrerequisitesUpdated(u.First, false); + u.GrantConditionOnPrerequisite.PrerequisitesUpdated(u.Actor, false); } public void PrerequisitesItemHidden(string key) { } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/HarvesterAttackNotifier.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/HarvesterAttackNotifier.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/HarvesterAttackNotifier.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/HarvesterAttackNotifier.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ { [Desc("Plays an audio notification and shows a radar ping when a harvester is attacked.", "Attach this to the player actor.")] - public class HarvesterAttackNotifierInfo : ITraitInfo + public class HarvesterAttackNotifierInfo : TraitInfo { [Desc("Minimum duration (in seconds) between notification events.")] public readonly int NotifyInterval = 30; @@ -30,7 +30,7 @@ [Desc("The audio notification type to play.")] public string Notification = "HarvesterAttack"; - public object Create(ActorInitializer init) { return new HarvesterAttackNotifier(init.Self, this); } + public override object Create(ActorInitializer init) { return new HarvesterAttackNotifier(init.Self, this); } } public class HarvesterAttackNotifier : INotifyDamage @@ -61,8 +61,7 @@ { Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.Notification, self.Owner.Faction.InternalName); - if (radarPings != null) - radarPings.Add(() => self.Owner.IsAlliedWith(self.World.RenderPlayer), self.CenterPosition, info.RadarPingColor, info.RadarPingDuration); + radarPings?.Add(() => self.Owner.IsAlliedWith(self.World.RenderPlayer), self.CenterPosition, info.RadarPingColor, info.RadarPingDuration); } lastAttackTime = self.World.WorldTick; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/MissionObjectives.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/MissionObjectives.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/MissionObjectives.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/MissionObjectives.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -34,7 +35,7 @@ } } - public class MissionObjectivesInfo : ITraitInfo + public class MissionObjectivesInfo : TraitInfo { [Desc("Set this to true if multiple cooperative players have a distinct set of " + "objectives that each of them has to complete to win the game. This is mainly " + @@ -58,15 +59,19 @@ [NotificationReference("Speech")] public readonly string LeaveNotification = null; - public object Create(ActorInitializer init) { return new MissionObjectives(init.World, this); } + public override object Create(ActorInitializer init) { return new MissionObjectives(init.Self.Owner, this); } } - public class MissionObjectives : INotifyWinStateChanged, ISync, IResolveOrder + public class MissionObjectives : INotifyWinStateChanged, ISync, IResolveOrder, IWorldLoaded { public readonly MissionObjectivesInfo Info; readonly List objectives = new List(); + readonly Player player; public ReadOnlyList Objectives; + Player[] enemies; + Player[] allies; + [Sync] public int ObjectivesHash { @@ -83,12 +88,21 @@ // The player's WinState is only updated when his allies have all completed their objective as well. public WinState WinStateCooperative { get; private set; } - public MissionObjectives(World world, MissionObjectivesInfo info) + public MissionObjectives(Player player, MissionObjectivesInfo info) { Info = info; + this.player = player; Objectives = new ReadOnlyList(objectives); } + void IWorldLoaded.WorldLoaded(World w, WorldRenderer wr) + { + // Players and NonCombatants are fixed once the game starts, but the result of IsAlliedWith + // may change once players are marked as spectators, so cache these + allies = player.World.Players.Where(p => !p.NonCombatant && player.IsAlliedWith(p)).ToArray(); + enemies = player.World.Players.Where(p => !p.NonCombatant && player.RelationshipWith(p) == PlayerRelationship.Enemy).ToArray(); + } + public int Add(Player player, string description, string type, bool required = true, bool inhibitAnnouncement = false) { var newID = objectives.Count; @@ -140,10 +154,9 @@ void CheckIfGameIsOver(Player player) { - var players = player.World.Players.Where(p => !p.NonCombatant); - - var gameOver = players.All(p => p.WinState != WinState.Undefined || !p.HasObjectives); + var gameOver = player.World.Players.All(p => p.NonCombatant || p.WinState != WinState.Undefined || !p.HasObjectives); if (gameOver) + { Game.RunAfterDelay(Info.GameOverDelay, () => { if (!Game.IsCurrentWorld(player.World)) @@ -153,17 +166,14 @@ player.World.SetPauseState(true); player.World.PauseStateLocked = true; }); + } } void INotifyWinStateChanged.OnPlayerWon(Player player) { - var players = player.World.Players.Where(p => !p.NonCombatant); - var enemies = players.Where(p => !p.IsAlliedWith(player)); - if (Info.Cooperative) { WinStateCooperative = WinState.Won; - var allies = players.Where(p => p.IsAlliedWith(player)); if (allies.All(p => p.PlayerActor.Trait().WinStateCooperative == WinState.Won)) { @@ -193,13 +203,9 @@ void INotifyWinStateChanged.OnPlayerLost(Player player) { - var players = player.World.Players.Where(p => !p.NonCombatant); - var enemies = players.Where(p => !p.IsAlliedWith(player)); - if (Info.Cooperative) { WinStateCooperative = WinState.Lost; - var allies = players.Where(p => p.IsAlliedWith(player)); if (allies.Any(p => p.PlayerActor.Trait().WinStateCooperative == WinState.Lost)) { @@ -249,24 +255,21 @@ public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "Surrender") - { ForceDefeat(self.Owner); - self.Owner.Spectating = true; - } } } [Desc("Provides game mode progress information for players.", "Goes on WorldActor - observers don't have a player it can live on.", "Current options for PanelName are 'SKIRMISH_STATS' and 'MISSION_OBJECTIVES'.")] - public class ObjectivesPanelInfo : ITraitInfo + public class ObjectivesPanelInfo : TraitInfo { public string PanelName = null; [Desc("in ms")] public int ExitDelay = 1400; - public object Create(ActorInitializer init) { return new ObjectivesPanel(this); } + public override object Create(ActorInitializer init) { return new ObjectivesPanel(this); } } public class ObjectivesPanel : IObjectivesPanel diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/ModularBot.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/ModularBot.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/ModularBot.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/ModularBot.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using OpenRA.Support; @@ -19,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Bot that uses BotModules.")] - public sealed class ModularBotInfo : IBotInfo, ITraitInfo + public sealed class ModularBotInfo : TraitInfo, IBotInfo { [FieldLoader.Require] [Desc("Internal id for this bot.")] @@ -35,7 +34,7 @@ string IBotInfo.Name { get { return Name; } } - public object Create(ActorInitializer init) { return new ModularBot(this, init); } + public override object Create(ActorInitializer init) { return new ModularBot(this, init); } } public sealed class ModularBot : ITick, IBot, INotifyDamage diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/PlaceBeacon.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/PlaceBeacon.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/PlaceBeacon.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/PlaceBeacon.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("A beacon that is constructed from a circle sprite that is animated once and a moving arrow sprite.")] - public class PlaceBeaconInfo : ITraitInfo + public class PlaceBeaconInfo : TraitInfo { public readonly int Duration = 30 * 25; @@ -26,21 +26,21 @@ public readonly bool IsPlayerPalette = true; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] public readonly string Palette = "player"; public readonly string BeaconImage = "beacon"; - [SequenceReference("BeaconImage")] + [SequenceReference(nameof(BeaconImage))] public readonly string BeaconSequence = null; - [SequenceReference("BeaconImage")] + [SequenceReference(nameof(BeaconImage))] public readonly string ArrowSequence = "arrow"; - [SequenceReference("BeaconImage")] + [SequenceReference(nameof(BeaconImage))] public readonly string CircleSequence = "circles"; - public object Create(ActorInitializer init) { return new PlaceBeacon(init.Self, this); } + public override object Create(ActorInitializer init) { return new PlaceBeacon(init.Self, this); } } public class PlaceBeacon : IResolveOrder diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,10 +16,10 @@ namespace OpenRA.Mods.Common.Traits { // Allows third party mods to detect whether an actor was created by PlaceBuilding. - public class PlaceBuildingInit : IActorInit { } + public class PlaceBuildingInit : RuntimeFlagInit { } [Desc("Allows the player to execute build orders.", " Attach this to the player actor.")] - public class PlaceBuildingInfo : ITraitInfo + public class PlaceBuildingInfo : TraitInfo { [Desc("Play NewOptionsNotification this many ticks after building placement.")] public readonly int NewOptionsNotificationDelay = 10; @@ -34,7 +34,7 @@ [Desc("Hotkey to toggle between PlaceBuildingVariants when placing a structure.")] public HotkeyReference ToggleVariantKey = new HotkeyReference(); - public object Create(ActorInitializer init) { return new PlaceBuilding(this); } + public override object Create(ActorInitializer init) { return new PlaceBuilding(this); } } public class PlaceBuilding : IResolveOrder, ITick @@ -119,43 +119,42 @@ foreach (var t in BuildingUtils.GetLineBuildCells(w, targetLocation, actorInfo, buildingInfo, order.Player)) { - if (t.First == targetLocation) + if (t.Cell == targetLocation) continue; - w.CreateActor(t.First == targetLocation ? actorInfo.Name : segmentType, new TypeDictionary + w.CreateActor(t.Cell == targetLocation ? actorInfo.Name : segmentType, new TypeDictionary { - new LocationInit(t.First), + new LocationInit(t.Cell), new OwnerInit(order.Player), new FactionInit(faction), - new LineBuildDirectionInit(t.First.X == targetLocation.X ? LineBuildDirection.Y : LineBuildDirection.X), - new LineBuildParentInit(new[] { t.Second, placed }), + new LineBuildDirectionInit(t.Cell.X == targetLocation.X ? LineBuildDirection.Y : LineBuildDirection.X), + new LineBuildParentInit(new[] { t.Actor, placed }), new PlaceBuildingInit() }); } } else if (os == "PlacePlug") { - var host = self.World.WorldActor.Trait().GetBuildingAt(targetLocation); - if (host == null) - return; - var plugInfo = actorInfo.TraitInfoOrDefault(); if (plugInfo == null) return; - var location = host.Location; - var pluggableLocations = host.TraitsImplementing() - .Where(p => p.AcceptsPlug(host, plugInfo.Type)); - - var pluggable = pluggableLocations.FirstOrDefault(p => location + p.Info.Offset == targetLocation) - ?? pluggableLocations.FirstOrDefault(); - - if (pluggable == null) - return; - - pluggable.EnablePlug(host, plugInfo.Type); - foreach (var s in buildingInfo.BuildSounds) - Game.Sound.PlayToPlayer(SoundType.World, order.Player, s, host.CenterPosition); + foreach (var a in self.World.ActorMap.GetActorsAt(targetLocation)) + { + var pluggables = a.TraitsImplementing() + .Where(p => p.AcceptsPlug(a, plugInfo.Type)) + .ToList(); + + var pluggable = pluggables.FirstOrDefault(p => a.Location + p.Info.Offset == targetLocation) + ?? pluggables.FirstOrDefault(); + + if (pluggable == null) + return; + + pluggable.EnablePlug(a, plugInfo.Type); + foreach (var s in buildingInfo.BuildSounds) + Game.Sound.PlayToPlayer(SoundType.World, order.Player, s, a.CenterPosition); + } } else { @@ -163,17 +162,15 @@ || !buildingInfo.IsCloseEnoughToBase(self.World, order.Player, actorInfo, targetLocation)) return; - var replacementInfo = actorInfo.TraitInfoOrDefault(); - if (replacementInfo != null) - { - var buildingInfluence = self.World.WorldActor.Trait(); + var replaceableTypes = actorInfo.TraitInfos() + .SelectMany(r => r.ReplaceableTypes) + .ToHashSet(); + + if (replaceableTypes.Any()) foreach (var t in buildingInfo.Tiles(targetLocation)) - { - var host = buildingInfluence.GetBuildingAt(t); - if (host != null) - host.World.Remove(host); - } - } + foreach (var a in self.World.ActorMap.GetActorsAt(t)) + if (a.TraitsImplementing().Any(r => !r.IsTraitDisabled && r.Info.Types.Overlaps(replaceableTypes))) + self.World.Remove(a); var building = w.CreateActor(actorInfo.Name, new TypeDictionary { @@ -193,14 +190,10 @@ queue.EndProduction(item); + // FindBaseProvider may return null if the build anywhere cheat is active + // BuildingInfo.IsCloseEnoughToBase has already verified that this is a valid build location if (buildingInfo.RequiresBaseProvider) - { - // May be null if the build anywhere cheat is active - // BuildingInfo.IsCloseEnoughToBase has already verified that this is a valid build location - var provider = buildingInfo.FindBaseProvider(w, self.Owner, targetLocation); - if (provider != null) - provider.BeginCooldown(); - } + buildingInfo.FindBaseProvider(w, self.Owner, targetLocation)?.BeginCooldown(); if (GetNumBuildables(self.Owner) > prevItems) triggerNotification = true; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/PlayerExperience.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/PlayerExperience.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/PlayerExperience.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/PlayerExperience.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,9 +16,9 @@ [Desc("This trait can be used to track player experience based on units killed with the `GivesExperience` trait.", "It can also be used as a point score system in scripted maps, for example.", "Attach this to the player actor.")] - public class PlayerExperienceInfo : ITraitInfo + public class PlayerExperienceInfo : TraitInfo { - public object Create(ActorInitializer init) { return new PlayerExperience(); } + public override object Create(ActorInitializer init) { return new PlayerExperience(); } } public class PlayerExperience : ISync diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/PlayerRadarTerrain.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/PlayerRadarTerrain.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/PlayerRadarTerrain.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/PlayerRadarTerrain.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,16 +10,15 @@ #endregion using System; -using System.Collections.Generic; using OpenRA.Graphics; using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class PlayerRadarTerrainInfo : ITraitInfo, Requires + public class PlayerRadarTerrainInfo : TraitInfo, Requires { - public object Create(ActorInitializer init) + public override object Create(ActorInitializer init) { return new PlayerRadarTerrain(init.Self); } @@ -30,7 +29,7 @@ public bool IsInitialized { get; private set; } readonly World world; - CellLayer> terrainColor; + CellLayer<(int, int)> terrainColor; readonly Shroud shroud; public event Action CellTerrainColorChanged = null; @@ -62,13 +61,12 @@ { terrainColor[uv] = GetColor(world.Map, uv); - if (CellTerrainColorChanged != null) - CellTerrainColorChanged(uv); + CellTerrainColorChanged?.Invoke(uv); } public void WorldLoaded(World w, WorldRenderer wr) { - terrainColor = new CellLayer>(w.Map); + terrainColor = new CellLayer<(int, int)>(w.Map); w.AddFrameEndTask(_ => { @@ -83,25 +81,22 @@ }); } - public Pair this[MPos uv] + public (int Left, int Right) this[MPos uv] { get { return terrainColor[uv]; } } - public static Pair GetColor(Map map, MPos uv) + public static (int Left, int Right) GetColor(Map map, MPos uv) { var custom = map.CustomTerrain[uv]; - int leftColor, rightColor; - if (custom == byte.MaxValue) + if (custom != byte.MaxValue) { - var type = map.Rules.TileSet.GetTileInfo(map.Tiles[uv]); - leftColor = type != null ? type.LeftColor.ToArgb() : Color.Black.ToArgb(); - rightColor = type != null ? type.RightColor.ToArgb() : Color.Black.ToArgb(); + var c = map.Rules.TileSet[custom].Color.ToArgb(); + return (c, c); } - else - leftColor = rightColor = map.Rules.TileSet[custom].Color.ToArgb(); - return Pair.New(leftColor, rightColor); + var tc = map.GetTerrainColorPair(uv); + return (tc.Left.ToArgb(), tc.Right.ToArgb()); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/PlayerResources.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/PlayerResources.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/PlayerResources.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/PlayerResources.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { - public class PlayerResourcesInfo : ITraitInfo, ILobbyOptions + public class PlayerResourcesInfo : TraitInfo, ILobbyOptions { [Translate] [Desc("Descriptive label for the starting cash option in the lobby.")] @@ -63,7 +63,7 @@ new ReadOnlyDictionary(startingCash), DefaultCash.ToString(), DefaultCashDropdownLocked); } - public object Create(ActorInitializer init) { return new PlayerResources(init.Self, this); } + public override object Create(ActorInitializer init) { return new PlayerResources(init.Self, this); } } public class PlayerResources : ISync diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/PlayerStatistics.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/PlayerStatistics.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/PlayerStatistics.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/PlayerStatistics.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Collections.Generic; using System.Linq; -using OpenRA; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits.Render; using OpenRA.Primitives; @@ -20,9 +19,9 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Attach this to the player actor to collect observer stats.")] - public class PlayerStatisticsInfo : ITraitInfo + public class PlayerStatisticsInfo : TraitInfo { - public object Create(ActorInitializer init) { return new PlayerStatistics(init.Self); } + public override object Create(ActorInitializer init) { return new PlayerStatistics(init.Self); } } public class PlayerStatistics : ITick, IResolveOrder, INotifyCreated, IWorldLoaded @@ -57,6 +56,7 @@ public int BuildingsDead; public int ArmyValue; + public int AssetsValue; // High resolution (every second) record of earnings, limited to the last minute readonly Queue earnedSeconds = new Queue(60); @@ -122,27 +122,9 @@ public void ResolveOrder(Actor self, Order order) { - switch (order.OrderString) - { - case "Chat": - case "HandshakeResponse": - case "PauseGame": - case "StartGame": - case "Disconnected": - case "ServerError": - case "AuthenticationError": - case "SyncLobbyInfo": - case "SyncClientInfo": - case "SyncLobbySlots": - case "SyncLobbyGlobalSettings": - case "SyncClientPing": - case "Ping": - case "Pong": - return; - } - if (order.OrderString.StartsWith("Dev")) return; + OrderCount++; } @@ -164,6 +146,7 @@ public readonly ActorInfo ActorInfo; public readonly Animation Icon; public readonly string IconPalette; + public readonly bool IconPaletteIsPlayerPalette; public readonly int ProductionQueueOrder; public readonly int BuildPaletteOrder; public readonly TooltipInfo TooltipInfo; @@ -189,6 +172,7 @@ Icon = new Animation(owner.World, image); Icon.Play(BuildableInfo.Icon); IconPalette = BuildableInfo.IconPalette; + IconPaletteIsPlayerPalette = BuildableInfo.IconPaletteIsPlayerPalette; BuildPaletteOrder = BuildableInfo.BuildPaletteOrder; ProductionQueueOrder = queues.Where(q => BuildableInfo.Queue.Contains(q.Type)) .Select(q => q.DisplayOrder) @@ -198,16 +182,19 @@ } [Desc("Attach this to a unit to update observer stats.")] - public class UpdatesPlayerStatisticsInfo : ITraitInfo + public class UpdatesPlayerStatisticsInfo : TraitInfo { [Desc("Add to army value in statistics")] public bool AddToArmyValue = false; + [Desc("Add to assets value in statistics")] + public bool AddToAssetsValue = true; + [ActorReference] [Desc("Count this actor as a different type in the spectator army display.")] public string OverrideActor = null; - public object Create(ActorInitializer init) { return new UpdatesPlayerStatistics(this, init.Self); } + public override object Create(ActorInitializer init) { return new UpdatesPlayerStatistics(this, init.Self); } } public class UpdatesPlayerStatistics : INotifyKilled, INotifyCreated, INotifyOwnerChanged, INotifyActorDisposing @@ -218,6 +205,7 @@ PlayerStatistics playerStats; bool includedInArmyValue = false; + bool includedInAssetsValue = false; public UpdatesPlayerStatistics(UpdatesPlayerStatisticsInfo info, Actor self) { @@ -234,37 +222,45 @@ return; var attackerStats = e.Attacker.Owner.PlayerActor.Trait(); - var defenderStats = self.Owner.PlayerActor.Trait(); if (self.Info.HasTraitInfo()) { attackerStats.BuildingsKilled++; - defenderStats.BuildingsDead++; + playerStats.BuildingsDead++; } else if (self.Info.HasTraitInfo()) { attackerStats.UnitsKilled++; - defenderStats.UnitsDead++; + playerStats.UnitsDead++; } attackerStats.KillsCost += cost; - defenderStats.DeathsCost += cost; + playerStats.DeathsCost += cost; if (includedInArmyValue) { - defenderStats.ArmyValue -= cost; + playerStats.ArmyValue -= cost; includedInArmyValue = false; playerStats.Units[actorName].Count--; } + + if (includedInAssetsValue) + { + playerStats.AssetsValue -= cost; + includedInAssetsValue = false; + } } void INotifyCreated.Created(Actor self) { includedInArmyValue = info.AddToArmyValue; - if (includedInArmyValue) { playerStats.ArmyValue += cost; playerStats.Units[actorName].Count++; } + + includedInAssetsValue = info.AddToAssetsValue; + if (includedInAssetsValue) + playerStats.AssetsValue += cost; } void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) @@ -278,6 +274,12 @@ newOwnerStats.Units[actorName].Count++; } + if (includedInAssetsValue) + { + playerStats.AssetsValue -= cost; + newOwnerStats.AssetsValue += cost; + } + playerStats = newOwnerStats; } @@ -289,6 +291,12 @@ includedInArmyValue = false; playerStats.Units[actorName].Count--; } + + if (includedInAssetsValue) + { + playerStats.AssetsValue -= cost; + includedInAssetsValue = false; + } } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,7 +20,7 @@ [Desc("Attach this to an actor (usually a building) to let it produce units or construct buildings.", "If one builds another actor of this type, he will get a separate queue to create two actors", "at the same time. Will only work together with the Production: trait.")] - public class ProductionQueueInfo : ITraitInfo + public class ProductionQueueInfo : TraitInfo { [FieldLoader.Require] [Desc("What kind of production will be added (e.g. Building, Infantry, Vehicle, ...)")] @@ -88,7 +88,7 @@ "The filename of the audio is defined per faction in notifications.yaml.")] public readonly string CancelledAudio = null; - public virtual object Create(ActorInitializer init) { return new ProductionQueue(init, init.Self.Owner.PlayerActor, this); } + public override object Create(ActorInitializer init) { return new ProductionQueue(init, init.Self.Owner.PlayerActor, this); } public void RulesetLoaded(Ruleset rules, ActorInfo ai) { @@ -131,7 +131,7 @@ self = init.Self; Info = info; - Faction = init.Contains() ? init.Get() : self.Owner.Faction.InternalName; + Faction = init.GetValue(self.Owner.Faction.InternalName); IsValidFaction = !info.Factions.Any() || info.Factions.Contains(Faction); Enabled = IsValidFaction; @@ -141,19 +141,13 @@ void INotifyCreated.Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query other player traits from self, knowing that - // it refers to the same actor as self.Owner.PlayerActor - var playerActor = self.Info.Name == "player" ? self : self.Owner.PlayerActor; - - playerPower = playerActor.TraitOrDefault(); - playerResources = playerActor.Trait(); - developerMode = playerActor.Trait(); - techTree = playerActor.Trait(); + playerPower = self.Owner.PlayerActor.TraitOrDefault(); + playerResources = self.Owner.PlayerActor.Trait(); + developerMode = self.Owner.PlayerActor.Trait(); + techTree = self.Owner.PlayerActor.Trait(); productionTraits = self.TraitsImplementing().Where(p => p.Info.Produces.Contains(Info.Type)).ToArray(); - CacheProducibles(playerActor); + CacheProducibles(self.Owner.PlayerActor); } protected void ClearQueue() @@ -276,8 +270,7 @@ public bool CanBuild(ActorInfo actor) { - ProductionState ps; - if (!Producible.TryGetValue(actor, out ps)) + if (!Producible.TryGetValue(actor, out var ps)) return false; return ps.Buildable || developerMode.AllTech; @@ -316,7 +309,10 @@ protected void CancelUnbuildableItems() { - var buildableNames = BuildableItems().Select(b => b.Name).ToList(); + if (Queue.Count == 0) + return; + + var buildableNames = BuildableItems().Select(b => b.Name).ToHashSet(); // EndProduction removes the item from the queue, so we enumerate // by index in reverse to avoid issues with index reassignment @@ -416,8 +412,11 @@ var hasPlayedSound = false; BeginProduction(new ProductionItem(this, order.TargetString, cost, playerPower, () => self.World.AddFrameEndTask(_ => { - var isBuilding = unit.HasTraitInfo(); + // Make sure the item hasn't been invalidated between the ProductionItem ticking and this FrameEndTask running + if (!Queue.Any(i => i.Done && i.Item == unit.Name)) + return; + var isBuilding = unit.HasTraitInfo(); if (isBuilding && !hasPlayedSound) hasPlayedSound = Game.Sound.PlayNotification(rules, self.Owner, "Speech", Info.ReadyAudio, self.Owner.Faction.InternalName); else if (!isBuilding) @@ -472,9 +471,7 @@ protected void PauseProduction(string itemName, bool paused) { - var item = Queue.FirstOrDefault(a => a.Item == itemName); - if (item != null) - item.Pause(paused); + Queue.FirstOrDefault(a => a.Item == itemName)?.Pause(paused); } protected void CancelProduction(string itemName, uint numberToCancel) @@ -579,10 +576,10 @@ var bi = unit.TraitInfo(); var type = developerMode.AllTech ? Info.Type : (bi.BuildAtProductionType ?? Info.Type); - - if (!mostLikelyProducerTrait.IsTraitPaused && mostLikelyProducerTrait.Produce(self, unit, type, inits)) + var item = Queue.First(i => i.Done && i.Item == unit.Name); + if (!mostLikelyProducerTrait.IsTraitPaused && mostLikelyProducerTrait.Produce(self, unit, type, inits, item.TotalCost)) { - EndProduction(Queue.FirstOrDefault(i => i.Done && i.Item == unit.Name)); + EndProduction(item); return true; } @@ -653,8 +650,7 @@ if (Done) { - if (OnComplete != null) - OnComplete(); + OnComplete?.Invoke(); return; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/ProvidesPrerequisite.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/ProvidesPrerequisite.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/ProvidesPrerequisite.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/ProvidesPrerequisite.cs 2021-03-21 11:10:05.000000000 +0000 @@ -53,7 +53,7 @@ if (string.IsNullOrEmpty(prerequisite)) prerequisite = init.Self.Info.Name; - faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName; + faction = init.GetValue(init.Self.Owner.Faction.InternalName); } public IEnumerable ProvidesPrerequisites @@ -69,13 +69,7 @@ protected override void Created(Actor self) { - // Special case handling is required for the Player actor. - // Created is called before Player.PlayerActor is assigned, - // so we must query other player traits from self, knowing that - // it refers to the same actor as self.Owner.PlayerActor - var playerActor = self.Info.Name == "player" ? self : self.Owner.PlayerActor; - - techTree = playerActor.Trait(); + techTree = self.Owner.PlayerActor.Trait(); Update(); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/ProvidesTechPrerequisite.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/ProvidesTechPrerequisite.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/ProvidesTechPrerequisite.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/ProvidesTechPrerequisite.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,10 +10,11 @@ #endregion using System.Collections.Generic; +using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class ProvidesTechPrerequisiteInfo : ITechTreePrerequisiteInfo + public class ProvidesTechPrerequisiteInfo : TraitInfo, ITechTreePrerequisiteInfo { [Desc("Internal id for this tech level.")] public readonly string Id; @@ -27,7 +28,7 @@ IEnumerable ITechTreePrerequisiteInfo.Prerequisites(ActorInfo info) { return Prerequisites; } - public object Create(ActorInitializer init) { return new ProvidesTechPrerequisite(this, init); } + public override object Create(ActorInitializer init) { return new ProvidesTechPrerequisite(this, init); } } public class ProvidesTechPrerequisite : ITechTreePrerequisite diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/ResourceStorageWarning.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/ResourceStorageWarning.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/ResourceStorageWarning.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/ResourceStorageWarning.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Provides the player with an audible warning when their storage is nearing full.")] - public class ResourceStorageWarningInfo : ITraitInfo, Requires + public class ResourceStorageWarningInfo : TraitInfo, Requires { [Desc("Interval, in seconds, at which to check if more storage is needed.")] public readonly int AdviceInterval = 20; @@ -26,7 +26,7 @@ [Desc("The speech to play for the warning.")] public readonly string Notification = "SilosNeeded"; - public object Create(ActorInitializer init) { return new ResourceStorageWarning(init.Self, this); } + public override object Create(ActorInitializer init) { return new ResourceStorageWarning(init.Self, this); } } public class ResourceStorageWarning : ITick diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/StrategicVictoryConditions.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/StrategicVictoryConditions.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/StrategicVictoryConditions.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/StrategicVictoryConditions.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,7 +22,7 @@ public class StrategicPoint { } [Desc("Allows King of the Hill (KotH) style gameplay.")] - public class StrategicVictoryConditionsInfo : ITraitInfo, Requires + public class StrategicVictoryConditionsInfo : TraitInfo, Requires { [Desc("Amount of time (in game ticks) that the player has to hold all the strategic points.", "Defaults to 7500 ticks (5 minutes at default speed).")] public readonly int HoldDuration = 7500; @@ -43,7 +43,7 @@ [Desc("Disable the win/loss messages and audio notifications?")] public readonly bool SuppressNotifications = false; - public object Create(ActorInitializer init) { return new StrategicVictoryConditions(init.Self, this); } + public override object Create(ActorInitializer init) { return new StrategicVictoryConditions(init.Self, this); } } public class StrategicVictoryConditions : ITick, ISync, INotifyWinStateChanged, INotifyTimeLimit @@ -73,7 +73,7 @@ } public int Total { get { return AllPoints.Count(); } } - int Owned { get { return AllPoints.Count(a => WorldUtils.AreMutualAllies(player, a.Owner)); } } + int Owned { get { return AllPoints.Count(a => a.Owner.RelationshipWith(player) == PlayerRelationship.Ally); } } public bool Holding { get { return Owned >= info.RatioRequired * Total / 100; } } @@ -119,12 +119,12 @@ var myTeam = self.World.LobbyInfo.ClientWithIndex(self.Owner.ClientIndex).Team; var teams = self.World.Players.Where(p => !p.NonCombatant && p.Playable) - .Select(p => new Pair(p, p.PlayerActor.TraitOrDefault())) - .OrderByDescending(p => p.Second != null ? p.Second.Experience : 0) - .GroupBy(p => (self.World.LobbyInfo.ClientWithIndex(p.First.ClientIndex) ?? new Session.Client()).Team) - .OrderByDescending(g => g.Sum(gg => gg.Second != null ? gg.Second.Experience : 0)); + .Select(p => (Player: p, PlayerStatistics: p.PlayerActor.TraitOrDefault())) + .OrderByDescending(p => p.PlayerStatistics != null ? p.PlayerStatistics.Experience : 0) + .GroupBy(p => (self.World.LobbyInfo.ClientWithIndex(p.Player.ClientIndex) ?? new Session.Client()).Team) + .OrderByDescending(g => g.Sum(gg => gg.PlayerStatistics != null ? gg.PlayerStatistics.Experience : 0)); - if (teams.First().Key == myTeam && (myTeam != 0 || teams.First().First().First == self.Owner)) + if (teams.First().Key == myTeam && (myTeam != 0 || teams.First().First().Player == self.Owner)) { mo.MarkCompleted(self.Owner, objectiveID); return; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/TechTree.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/TechTree.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/TechTree.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/TechTree.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,9 +18,9 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Manages build limits and pre-requisites.", " Attach this to the player actor.")] - public class TechTreeInfo : ITraitInfo + public class TechTreeInfo : TraitInfo { - public object Create(ActorInitializer init) { return new TechTree(init); } + public override object Create(ActorInitializer init) { return new TechTree(init); } } public class TechTree @@ -106,6 +106,8 @@ return ret; } + public Player Owner { get { return player; } } + class Watcher { public readonly string Key; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Player/TimeLimitManager.cs openra-20210321/OpenRA.Mods.Common/Traits/Player/TimeLimitManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Player/TimeLimitManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Player/TimeLimitManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,18 +9,16 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; using OpenRA.Mods.Common.Widgets; -using OpenRA.Primitives; using OpenRA.Traits; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Traits { [Desc("This trait allows setting a time limit on matches. Attach this to the World actor.")] - public class TimeLimitManagerInfo : ITraitInfo, ILobbyOptions, IRulesetLoaded + public class TimeLimitManagerInfo : TraitInfo, ILobbyOptions, IRulesetLoaded { [Desc("Label that will be shown for the time limit option in the lobby.")] public readonly string TimeLimitLabel = "Time Limit"; @@ -89,7 +87,7 @@ new ReadOnlyDictionary(timelimits), TimeLimitDefault.ToString(), TimeLimitLocked); } - public object Create(ActorInitializer init) { return new TimeLimitManager(init.Self, this); } + public override object Create(ActorInitializer init) { return new TimeLimitManager(init.Self, this); } } public class TimeLimitManager : INotifyTimeLimit, ITick, IWorldLoaded diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Pluggable.cs openra-20210321/OpenRA.Mods.Common/Traits/Pluggable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Pluggable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Pluggable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { - public class PluggableInfo : ITraitInfo + public class PluggableInfo : TraitInfo, IEditorActorOptions { [Desc("Footprint cell offset where a plug can be placed.")] public readonly CVec Offset = CVec.Zero; @@ -32,6 +32,17 @@ "Value is the condition expression defining the requirements to place the plug.")] public readonly Dictionary Requirements = new Dictionary(); + [Desc("Options to display in the map editor.", + "Key is the plug type that the requirements applies to.", + "Value is the label that is displayed in the actor editor dropdown.")] + public readonly Dictionary EditorOptions = new Dictionary(); + + [Desc("Label to use for an empty plug socket.")] + public readonly string EmptyOption = "Empty"; + + [Desc("Display order for the dropdown in the map editor")] + public readonly int EditorDisplayOrder = 5; + [GrantedConditionReference] public IEnumerable LinterConditions { get { return Conditions.Values; } } @@ -41,7 +52,29 @@ get { return Requirements.Values.SelectMany(r => r.Variables).Distinct(); } } - public object Create(ActorInitializer init) { return new Pluggable(init, this); } + IEnumerable IEditorActorOptions.ActorOptions(ActorInfo ai, World world) + { + if (!EditorOptions.Any()) + yield break; + + // Make sure the no-plug option is always available + EditorOptions[""] = EmptyOption; + yield return new EditorActorDropdown("Plug", EditorDisplayOrder, EditorOptions, + actor => + { + var init = actor.GetInitOrDefault(this); + return init != null ? init.Value : ""; + }, + (actor, value) => + { + if (string.IsNullOrEmpty(value)) + actor.RemoveInit(this); + else + actor.ReplaceInit(new PlugInit(this, value), this); + }); + } + + public override object Create(ActorInitializer init) { return new Pluggable(init, this); } } public class Pluggable : IObservesVariables, INotifyCreated @@ -49,8 +82,7 @@ public readonly PluggableInfo Info; readonly string initialPlug; - ConditionManager conditionManager; - int conditionToken = ConditionManager.InvalidConditionToken; + int conditionToken = Actor.InvalidConditionToken; Dictionary plugTypesAvailability = null; string active; @@ -59,9 +91,7 @@ { Info = info; - var plugInit = init.Contains() ? init.Get>() : new Dictionary(); - if (plugInit.ContainsKey(Info.Offset)) - initialPlug = plugInit[Info.Offset]; + initialPlug = init.GetValue(info, null); if (info.Requirements.Count > 0) { @@ -73,8 +103,6 @@ void INotifyCreated.Created(Actor self) { - conditionManager = self.TraitOrDefault(); - if (!string.IsNullOrEmpty(initialPlug)) EnablePlug(self, initialPlug); } @@ -92,14 +120,13 @@ public void EnablePlug(Actor self, string type) { - string condition; - if (!Info.Conditions.TryGetValue(type, out condition)) + if (!Info.Conditions.TryGetValue(type, out var condition)) return; - if (conditionToken != ConditionManager.InvalidConditionToken) - conditionManager.RevokeCondition(self, conditionToken); + if (conditionToken != Actor.InvalidConditionToken) + self.RevokeCondition(conditionToken); - conditionToken = conditionManager.GrantCondition(self, condition); + conditionToken = self.GrantCondition(condition); active = type; } @@ -108,8 +135,8 @@ if (type != active) return; - if (conditionToken != ConditionManager.InvalidConditionToken) - conditionToken = conditionManager.RevokeCondition(self, conditionToken); + if (conditionToken != Actor.InvalidConditionToken) + conditionToken = self.RevokeCondition(conditionToken); active = null; } @@ -123,12 +150,9 @@ } } - public class PlugsInit : IActorInit> + public class PlugInit : ValueActorInit { - [DictionaryFromYamlKey] - readonly Dictionary value = new Dictionary(); - public PlugsInit() { } - public PlugsInit(Dictionary init) { value = init; } - public Dictionary Value(World world) { return value; } + public PlugInit(TraitInfo info, string value) + : base(info, value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Power/AffectedByPowerOutage.cs openra-20210321/OpenRA.Mods.Common/Traits/Power/AffectedByPowerOutage.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Power/AffectedByPowerOutage.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Power/AffectedByPowerOutage.cs 2021-03-21 11:10:05.000000000 +0000 @@ -27,8 +27,7 @@ public class AffectedByPowerOutage : ConditionalTrait, INotifyOwnerChanged, ISelectionBar, INotifyCreated, INotifyAddedToWorld { PowerManager playerPower; - ConditionManager conditionManager; - int token = ConditionManager.InvalidConditionToken; + int token = Actor.InvalidConditionToken; public AffectedByPowerOutage(Actor self, AffectedByPowerOutageInfo info) : base(info) @@ -40,13 +39,6 @@ protected override void TraitEnabled(Actor self) { UpdateStatus(self); } protected override void TraitDisabled(Actor self) { Revoke(self); } - protected override void Created(Actor self) - { - conditionManager = self.TraitOrDefault(); - - base.Created(self); - } - float ISelectionBar.GetValue() { if (IsTraitDisabled || playerPower.PowerOutageRemainingTicks <= 0) @@ -72,14 +64,14 @@ void Grant(Actor self) { - if (token == ConditionManager.InvalidConditionToken) - token = conditionManager.GrantCondition(self, Info.Condition); + if (token == Actor.InvalidConditionToken) + token = self.GrantCondition(Info.Condition); } void Revoke(Actor self) { - if (token != ConditionManager.InvalidConditionToken) - token = conditionManager.RevokeCondition(self, token); + if (token != Actor.InvalidConditionToken) + token = self.RevokeCondition(token); } void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs openra-20210321/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,14 +16,14 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Attach this to the player actor.")] - public class PowerManagerInfo : ITraitInfo, Requires + public class PowerManagerInfo : TraitInfo, Requires { public readonly int AdviceInterval = 250; [NotificationReference("Speech")] public readonly string SpeechNotification = null; - public object Create(ActorInitializer init) { return new PowerManager(init.Self, this); } + public override object Create(ActorInitializer init) { return new PowerManager(init.Self, this); } } public class PowerManager : INotifyCreated, ITick, ISync, IResolveOrder @@ -73,26 +73,39 @@ public void UpdateActor(Actor a) { - int old; - powerDrain.TryGetValue(a, out old); // old is 0 if a is not in powerDrain + // Do not add power from actors that are not in the world + if (!a.IsInWorld) + return; + + // Old is 0 if a is not in powerDrain + powerDrain.TryGetValue(a, out var old); + var amount = a.TraitsImplementing().Where(t => !t.IsTraitDisabled).Sum(p => p.GetEnabledPower()); powerDrain[a] = amount; + if (amount == old || devMode.UnlimitedPower) return; + if (old > 0) totalProvided -= old; else if (old < 0) totalDrained += old; + if (amount > 0) totalProvided += amount; else if (amount < 0) totalDrained -= amount; + + UpdatePowerState(); } public void RemoveActor(Actor a) { - int amount; - if (!powerDrain.TryGetValue(a, out amount)) + // Do not remove power from actors that are still in the world + if (a.IsInWorld) + return; + + if (!powerDrain.TryGetValue(a, out var amount)) return; powerDrain.Remove(a); @@ -103,6 +116,21 @@ totalProvided -= amount; else if (amount < 0) totalDrained += amount; + + UpdatePowerState(); + } + + void UpdatePowerState() + { + isLowPower = ExcessPower < 0; + + if (isLowPower != wasLowPower) + UpdatePowerRequiringActors(); + + if (isLowPower && !wasLowPower) + nextPowerAdviceTime = 0; + + wasLowPower = isLowPower; } void ITick.Tick(Actor self) @@ -113,30 +141,23 @@ totalDrained = 0; if (!devMode.UnlimitedPower) + { foreach (var kv in powerDrain) + { if (kv.Value > 0) totalProvided += kv.Value; else if (kv.Value < 0) totalDrained -= kv.Value; + } + } wasHackEnabled = devMode.UnlimitedPower; + UpdatePowerState(); } - isLowPower = ExcessPower < 0; - - if (isLowPower != wasLowPower) - UpdatePowerRequiringActors(); - - if (isLowPower && !wasLowPower) - nextPowerAdviceTime = 0; - - wasLowPower = isLowPower; - - if (--nextPowerAdviceTime <= 0) + if (isLowPower && --nextPowerAdviceTime <= 0) { - if (isLowPower) - Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.SpeechNotification, self.Owner.Faction.InternalName); - + Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.SpeechNotification, self.Owner.Faction.InternalName); nextPowerAdviceTime = info.AdviceInterval; } @@ -148,8 +169,12 @@ { get { - if (PowerProvided >= PowerDrained) return PowerState.Normal; - if (PowerProvided > PowerDrained / 2) return PowerState.Low; + if (PowerProvided >= PowerDrained) + return PowerState.Normal; + + if (PowerProvided > PowerDrained / 2) + return PowerState.Low; + return PowerState.Critical; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Power/ScalePowerWithHealth.cs openra-20210321/OpenRA.Mods.Common/Traits/Power/ScalePowerWithHealth.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Power/ScalePowerWithHealth.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Power/ScalePowerWithHealth.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,9 +14,9 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Scale power amount with the current health.")] - public class ScalePowerWithHealthInfo : ITraitInfo, Requires, Requires + public class ScalePowerWithHealthInfo : TraitInfo, Requires, Requires { - public object Create(ActorInitializer init) { return new ScalePowerWithHealth(init.Self); } + public override object Create(ActorInitializer init) { return new ScalePowerWithHealth(init.Self); } } public class ScalePowerWithHealth : IPowerModifier, INotifyDamage, INotifyOwnerChanged diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/PowerTooltip.cs openra-20210321/OpenRA.Mods.Common/Traits/PowerTooltip.cs --- openra-20200503/OpenRA.Mods.Common/Traits/PowerTooltip.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/PowerTooltip.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,9 +14,9 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Shown power info on the build palette widget.")] - public class PowerTooltipInfo : ITraitInfo + public class PowerTooltipInfo : TraitInfo { - public object Create(ActorInitializer init) { return new PowerTooltip(init.Self); } + public override object Create(ActorInitializer init) { return new PowerTooltip(init.Self); } } public class PowerTooltip : IProvideTooltipInfo, INotifyOwnerChanged diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ProducibleWithLevel.cs openra-20210321/OpenRA.Mods.Common/Traits/ProducibleWithLevel.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ProducibleWithLevel.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ProducibleWithLevel.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ [Desc("Actors possessing this trait should define the GainsExperience trait. When the prerequisites are fulfilled, ", "this trait grants a level-up to newly spawned actors. If additionally the actor's owning player defines the ProductionIconOverlay ", "trait, the production queue icon renders with an overlay defined in that trait.")] - public class ProducibleWithLevelInfo : ITraitInfo, Requires + public class ProducibleWithLevelInfo : TraitInfo, Requires { public readonly string[] Prerequisites = { }; @@ -26,7 +26,7 @@ [Desc("Should the level-up animation be suppressed when actor is created?")] public readonly bool SuppressLevelupAnimation = true; - public object Create(ActorInitializer init) { return new ProducibleWithLevel(init, this); } + public override object Create(ActorInitializer init) { return new ProducibleWithLevel(init, this); } } public class ProducibleWithLevel : INotifyCreated diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Production.cs openra-20210321/OpenRA.Mods.Common/Traits/Production.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Production.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Production.cs 2021-03-21 11:10:05.000000000 +0000 @@ -27,17 +27,22 @@ public override object Create(ActorInitializer init) { return new Production(init, this); } } - public class Production : PausableConditionalTrait, INotifyCreated + public class Production : PausableConditionalTrait { - readonly Lazy rp; + RallyPoint rp; public string Faction { get; private set; } public Production(ActorInitializer init, ProductionInfo info) : base(info) { - rp = Exts.Lazy(() => init.Self.IsDead ? null : init.Self.TraitOrDefault()); - Faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName; + Faction = init.GetValue(init.Self.Owner.Faction.InternalName); + } + + protected override void Created(Actor self) + { + rp = self.TraitOrDefault(); + base.Created(self); } public virtual void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo, string productionType, TypeDictionary inits) @@ -56,20 +61,22 @@ var spawn = self.CenterPosition + exitinfo.SpawnOffset; var to = self.World.Map.CenterOfCell(exit); - var initialFacing = exitinfo.Facing; - if (exitinfo.Facing < 0) + WAngle initialFacing; + if (!exitinfo.Facing.HasValue) { var delta = to - spawn; if (delta.HorizontalLengthSquared == 0) { var fi = producee.TraitInfoOrDefault(); - initialFacing = fi != null ? fi.GetInitialFacing() : 0; + initialFacing = fi != null ? fi.GetInitialFacing() : WAngle.Zero; } else - initialFacing = delta.Yaw.Facing; + initialFacing = delta.Yaw; } + else + initialFacing = exitinfo.Facing.Value; - exitLocations = rp.Value != null && rp.Value.Path.Count > 0 ? rp.Value.Path : new List { exit }; + exitLocations = rp != null && rp.Path.Count > 0 ? rp.Path : new List { exit }; td.Add(new LocationInit(exit)); td.Add(new CenterPositionInit(spawn)); @@ -99,7 +106,10 @@ protected virtual Exit SelectExit(Actor self, ActorInfo producee, string productionType, Func p) { - return self.RandomExitOrDefault(self.World, productionType, p); + if (rp == null || rp.Path.Count == 0) + return self.RandomExitOrDefault(self.World, productionType, p); + + return self.NearestExitOrDefault(self.World.Map.CenterOfCell(rp.Path[0]), productionType, p); } protected Exit SelectExit(Actor self, ActorInfo producee, string productionType) @@ -107,18 +117,16 @@ return SelectExit(self, producee, productionType, e => CanUseExit(self, producee, e.Info)); } - public virtual bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits) + public virtual bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits, int refundableValue) { if (IsTraitDisabled || IsTraitPaused || Reservable.IsReserved(self)) return false; // Pick a spawn/exit point pair var exit = SelectExit(self, producee, productionType); - if (exit != null || self.OccupiesSpace == null || !producee.HasTraitInfo()) { - DoProduction(self, producee, exit == null ? null : exit.Info, productionType, inits); - + DoProduction(self, producee, exit?.Info, productionType, inits); return true; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ProductionFromMapEdge.cs openra-20210321/OpenRA.Mods.Common/Traits/ProductionFromMapEdge.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ProductionFromMapEdge.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ProductionFromMapEdge.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,9 @@ #endregion using System.Collections.Generic; +using System.Linq; using OpenRA.Primitives; +using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { @@ -30,8 +32,10 @@ : base(init, info) { domainIndex = init.Self.World.WorldActor.Trait(); - if (init.Contains()) - spawnLocation = init.Get(); + + var spawnLocationInit = init.GetOrDefault(info); + if (spawnLocationInit != null) + spawnLocation = spawnLocationInit.Value; } protected override void Created(Actor self) @@ -41,7 +45,7 @@ rp = self.TraitOrDefault(); } - public override bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits) + public override bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits, int refundableValue) { if (IsTraitDisabled || IsTraitPaused) return false; @@ -59,9 +63,9 @@ if (mobileInfo != null) { - var locomotorInfo = mobileInfo.LocomotorInfo; + var locomotor = self.World.WorldActor.TraitsImplementing().First(l => l.Info.Name == mobileInfo.Locomotor); location = self.World.Map.ChooseClosestMatchingEdgeCell(self.Location, - c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destinations[0], locomotorInfo)); + c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destinations[0], locomotor)); } } @@ -75,7 +79,7 @@ if (aircraftInfo != null) pos += new WVec(0, 0, aircraftInfo.CruiseAltitude.Length); - var initialFacing = self.World.Map.FacingBetween(location.Value, destinations[0], 0); + var initialFacing = self.World.Map.FacingBetween(location.Value, destinations[0], WAngle.Zero); self.World.AddFrameEndTask(w => { @@ -107,13 +111,9 @@ } } - public class ProductionSpawnLocationInit : IActorInit + public class ProductionSpawnLocationInit : ValueActorInit { - [FieldFromYamlKey] - readonly CPos value = CPos.Zero; - - public ProductionSpawnLocationInit() { } - public ProductionSpawnLocationInit(CPos init) { value = init; } - public CPos Value(World world) { return value; } + public ProductionSpawnLocationInit(TraitInfo info, CPos value) + : base(info, value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ProductionParadrop.cs openra-20210321/OpenRA.Mods.Common/Traits/ProductionParadrop.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ProductionParadrop.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ProductionParadrop.cs 2021-03-21 11:10:05.000000000 +0000 @@ -45,7 +45,7 @@ rp = Exts.Lazy(() => init.Self.IsDead ? null : init.Self.TraitOrDefault()); } - public override bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits) + public override bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits, int refundableValue) { if (IsTraitDisabled || IsTraitPaused) return false; @@ -69,26 +69,32 @@ owner.World.AddFrameEndTask(w => { if (!self.IsInWorld || self.IsDead) + { + owner.PlayerActor.Trait().GiveCash(refundableValue); return; + } var altitude = self.World.Map.Rules.Actors[actorType].TraitInfo().CruiseAltitude; var actor = w.CreateActor(actorType, new TypeDictionary { new CenterPositionInit(w.Map.CenterOfCell(startPos) + new WVec(WDist.Zero, WDist.Zero, altitude)), new OwnerInit(owner), - new FacingInit(64) + new FacingInit(new WAngle(256)), }); actor.QueueActivity(new Fly(actor, Target.FromCell(w, dropPos))); actor.QueueActivity(new CallFunc(() => { if (!self.IsInWorld || self.IsDead) + { + owner.PlayerActor.Trait().GiveCash(refundableValue); return; + } foreach (var cargo in self.TraitsImplementing()) cargo.Delivered(self); - self.World.AddFrameEndTask(ww => DoProduction(self, producee, exit == null ? null : exit.Info, productionType, inits)); + self.World.AddFrameEndTask(ww => DoProduction(self, producee, exit?.Info, productionType, inits)); Game.Sound.Play(SoundType.World, info.ChuteSound, self.CenterPosition); Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.ReadyAudio, self.Owner.Faction.InternalName); })); @@ -124,7 +130,7 @@ var spawn = self.World.Map.CenterOfCell(exit) + new WVec(WDist.Zero, WDist.Zero, altitude); var to = self.World.Map.CenterOfCell(exit); - var initialFacing = exitinfo == null || exitinfo.Facing < 0 ? (to - spawn).Yaw.Facing : exitinfo.Facing; + var initialFacing = (exitinfo != null && exitinfo.Facing.HasValue) ? exitinfo.Facing.Value : (to - spawn).Yaw; exitLocations = rp.Value != null && rp.Value.Path.Count > 0 ? rp.Value.Path : new List { exit }; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ProductionQueueFromSelection.cs openra-20210321/OpenRA.Mods.Common/Traits/ProductionQueueFromSelection.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ProductionQueueFromSelection.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ProductionQueueFromSelection.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,12 +17,12 @@ namespace OpenRA.Mods.Common.Traits { - class ProductionQueueFromSelectionInfo : ITraitInfo + class ProductionQueueFromSelectionInfo : TraitInfo { public string ProductionTabsWidget = null; public string ProductionPaletteWidget = null; - public object Create(ActorInitializer init) { return new ProductionQueueFromSelection(init.World, this); } + public override object Create(ActorInitializer init) { return new ProductionQueueFromSelection(init.World, this); } } class ProductionQueueFromSelection : INotifySelection diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ProximityCapturable.cs openra-20210321/OpenRA.Mods.Common/Traits/ProximityCapturable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ProximityCapturable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ProximityCapturable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Actor can be captured by units in a specified proximity.")] - public class ProximityCapturableInfo : ITraitInfo, IRulesetLoaded + public class ProximityCapturableInfo : TraitInfo, IRulesetLoaded { [Desc("Maximum range at which a ProximityCaptor actor can initiate the capture.")] public readonly WDist Range = WDist.FromCells(5); @@ -43,7 +43,7 @@ throw new YamlException("ProximityCapturable requires the `Player` actor to have the ProximityCaptor trait."); } - public object Create(ActorInitializer init) { return new ProximityCapturable(init.Self, this); } + public override object Create(ActorInitializer init) { return new ProximityCapturable(init.Self, this); } } public class ProximityCapturable : ITick, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyOwnerChanged @@ -120,12 +120,6 @@ return pc != null && pc.Types.Overlaps(Info.CaptorTypes); } - bool IsClear(Actor self, Player captorOwner) - { - return actorsInRange - .All(a => a.Owner == captorOwner || WorldUtils.AreMutualAllies(a.Owner, captorOwner)); - } - void UpdateOwnership() { if (Captured && Info.Permanent) @@ -153,7 +147,7 @@ { if (Info.MustBeClear) { - var isClear = IsClear(Self, captor.Owner); + var isClear = actorsInRange.All(a => captor.Owner.RelationshipWith(a.Owner) == PlayerRelationship.Ally); // An enemy unit has wandered into the area, so we've lost control of it. if (Captured && !isClear) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Radar/AppearsOnRadar.cs openra-20210321/OpenRA.Mods.Common/Traits/Radar/AppearsOnRadar.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Radar/AppearsOnRadar.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Radar/AppearsOnRadar.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,8 +20,8 @@ { public readonly bool UseLocation = false; - [Desc("Player stances who can view this actor on radar.")] - public readonly Stance ValidStances = Stance.Ally | Stance.Neutral | Stance.Enemy; + [Desc("Player relationships who can view this actor on radar.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy; public override object Create(ActorInitializer init) { return new AppearsOnRadar(this); } } @@ -39,10 +39,10 @@ modifier = self.TraitsImplementing().FirstOrDefault(); } - public void PopulateRadarSignatureCells(Actor self, List> destinationBuffer) + public void PopulateRadarSignatureCells(Actor self, List<(CPos Cell, Color Color)> destinationBuffer) { var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer; - if (IsTraitDisabled || (viewer != null && !Info.ValidStances.HasStance(self.Owner.Stances[viewer]))) + if (IsTraitDisabled || (viewer != null && !Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(viewer)))) return; var color = Game.Settings.Game.UsePlayerStanceColors ? self.Owner.PlayerStanceColor(self) : self.Owner.Color; @@ -51,12 +51,12 @@ if (Info.UseLocation) { - destinationBuffer.Add(Pair.New(self.Location, color)); + destinationBuffer.Add((self.Location, color)); return; } foreach (var cell in self.OccupiesSpace.OccupiedCells()) - destinationBuffer.Add(Pair.New(cell.First, color)); + destinationBuffer.Add((cell.Cell, color)); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Radar/RadarColorFromTerrain.cs openra-20210321/OpenRA.Mods.Common/Traits/Radar/RadarColorFromTerrain.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Radar/RadarColorFromTerrain.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Radar/RadarColorFromTerrain.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,22 +14,27 @@ namespace OpenRA.Mods.Common.Traits.Radar { - public class RadarColorFromTerrainInfo : ITraitInfo + public class RadarColorFromTerrainInfo : TraitInfo { [FieldLoader.Require] public readonly string Terrain; - public object Create(ActorInitializer init) { return new RadarColorFromTerrain(init.Self, Terrain); } + public Color GetColorFromTerrain(World world) + { + var tileSet = world.Map.Rules.TileSet; + return tileSet[tileSet.GetTerrainIndex(Terrain)].Color; + } + + public override object Create(ActorInitializer init) { return new RadarColorFromTerrain(init.Self, this); } } public class RadarColorFromTerrain : IRadarColorModifier { - Color c; + readonly Color c; - public RadarColorFromTerrain(Actor self, string terrain) + public RadarColorFromTerrain(Actor self, RadarColorFromTerrainInfo info) { - var tileSet = self.World.Map.Rules.TileSet; - c = tileSet[tileSet.GetTerrainIndex(terrain)].Color; + c = info.GetColorFromTerrain(self.World); } public bool VisibleOnRadar(Actor self) { return true; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Rearmable.cs openra-20210321/OpenRA.Mods.Common/Traits/Rearmable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Rearmable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Rearmable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Common.Traits { - public class RearmableInfo : ITraitInfo + public class RearmableInfo : TraitInfo { [ActorReference] [FieldLoader.Require] @@ -25,7 +25,7 @@ [Desc("Name(s) of AmmoPool(s) that use this trait to rearm.")] public readonly HashSet AmmoPools = new HashSet { "primary" }; - public object Create(ActorInitializer init) { return new Rearmable(this); } + public override object Create(ActorInitializer init) { return new Rearmable(this); } } public class Rearmable : INotifyCreated, INotifyResupply diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ReloadAmmoPool.cs openra-20210321/OpenRA.Mods.Common/Traits/ReloadAmmoPool.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ReloadAmmoPool.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ReloadAmmoPool.cs 2021-03-21 11:10:05.000000000 +0000 @@ -66,13 +66,13 @@ }); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (Info.ResetOnFire) remainingTicks = Util.ApplyPercentageModifiers(Info.Delay, modifiers.Select(m => m.GetReloadAmmoModifier())); } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { } + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { } void ITick.Tick(Actor self) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/CashTricklerBar.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/CashTricklerBar.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/CashTricklerBar.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/CashTricklerBar.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,14 +17,14 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Display the time remaining until the next cash is given by actor's CashTrickler trait.")] - class CashTricklerBarInfo : ITraitInfo, Requires + class CashTricklerBarInfo : TraitInfo, Requires { [Desc("Defines to which players the bar is to be shown.")] - public readonly Stance DisplayStances = Stance.Ally; + public readonly PlayerRelationship DisplayRelationships = PlayerRelationship.Ally; public readonly Color Color = Color.Magenta; - public object Create(ActorInitializer init) { return new CashTricklerBar(init.Self, this); } + public override object Create(ActorInitializer init) { return new CashTricklerBar(init.Self, this); } } class CashTricklerBar : ISelectionBar @@ -43,7 +43,7 @@ float ISelectionBar.GetValue() { var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer; - if (viewer != null && !info.DisplayStances.HasStance(self.Owner.Stances[viewer])) + if (viewer != null && !info.DisplayRelationships.HasStance(self.Owner.RelationshipWith(viewer))) return 0; var complete = cashTricklers.Min(ct => (float)ct.Ticks / ct.Info.Interval); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/CustomTerrainDebugOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/CustomTerrainDebugOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/CustomTerrainDebugOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/CustomTerrainDebugOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,11 +18,11 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Displays custom terrain types.")] - class CustomTerrainDebugOverlayInfo : ITraitInfo + class CustomTerrainDebugOverlayInfo : TraitInfo { public readonly string Font = "TinyBold"; - public object Create(ActorInitializer init) { return new CustomTerrainDebugOverlay(init.Self, this); } + public override object Create(ActorInitializer init) { return new CustomTerrainDebugOverlay(init.Self, this); } } class CustomTerrainDebugOverlay : IWorldLoaded, IChatCommand, IRenderAnnotations diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/DrawLineToTarget.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/DrawLineToTarget.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/DrawLineToTarget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/DrawLineToTarget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,10 +18,10 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Renders target lines between order waypoints.")] - public class DrawLineToTargetInfo : ITraitInfo + public class DrawLineToTargetInfo : TraitInfo { - [Desc("Delay (in ticks) before the target lines disappear.")] - public readonly int Delay = 60; + [Desc("Delay (in milliseconds) before the target lines disappear.")] + public readonly int Delay = 2400; [Desc("Width (in pixels) of the target lines.")] public readonly int LineWidth = 1; @@ -35,14 +35,14 @@ [Desc("Width (in pixels) of the queued end node markers.")] public readonly int QueuedMarkerWidth = 2; - public virtual object Create(ActorInitializer init) { return new DrawLineToTarget(init.Self, this); } + public override object Create(ActorInitializer init) { return new DrawLineToTarget(init.Self, this); } } public class DrawLineToTarget : IRenderAboveShroud, IRenderAnnotationsWhenSelected, INotifySelected { readonly DrawLineToTargetInfo info; readonly List renderableCache = new List(); - int lifetime; + long lifetime; public DrawLineToTarget(Actor self, DrawLineToTargetInfo info) { @@ -55,7 +55,7 @@ return; // Reset the order line timeout. - lifetime = info.Delay; + lifetime = Game.RunTime + info.Delay; } void INotifySelected.Selected(Actor self) @@ -63,37 +63,41 @@ ShowTargetLines(self); } - IEnumerable IRenderAboveShroud.RenderAboveShroud(Actor self, WorldRenderer wr) + bool ShouldRender(Actor self) { if (!self.Owner.IsAlliedWith(self.World.LocalPlayer) || Game.Settings.Game.TargetLines == TargetLinesType.Disabled) - yield break; + return false; // Players want to see the lines when in waypoint mode. var force = Game.GetModifierKeys().HasModifier(Modifiers.Shift) || self.World.OrderGenerator is ForceModifiersOrderGenerator; - if (--lifetime <= 0 && !force) - yield break; + return force || Game.RunTime <= lifetime; + } + IEnumerable IRenderAboveShroud.RenderAboveShroud(Actor self, WorldRenderer wr) + { + if (!ShouldRender(self)) + return Enumerable.Empty(); + + return RenderAboveShroud(self, wr); + } + + IEnumerable RenderAboveShroud(Actor self, WorldRenderer wr) + { var pal = wr.Palette(TileSet.TerrainPaletteInternalName); var a = self.CurrentActivity; for (; a != null; a = a.NextActivity) if (!a.IsCanceling) foreach (var n in a.TargetLineNodes(self)) if (n.Tile != null && n.Target.Type != TargetType.Invalid) - yield return new SpriteRenderable(n.Tile, n.Target.CenterPosition, WVec.Zero, -511, pal, 1f, true); + yield return new SpriteRenderable(n.Tile, n.Target.CenterPosition, WVec.Zero, -511, pal, 1f, true, true); } bool IRenderAboveShroud.SpatiallyPartitionable { get { return false; } } IEnumerable IRenderAnnotationsWhenSelected.RenderAnnotations(Actor self, WorldRenderer wr) { - if (!self.Owner.IsAlliedWith(self.World.LocalPlayer) || Game.Settings.Game.TargetLines == TargetLinesType.Disabled) - return Enumerable.Empty(); - - // Players want to see the lines when in waypoint mode. - var force = Game.GetModifierKeys().HasModifier(Modifiers.Shift) || self.World.OrderGenerator is ForceModifiersOrderGenerator; - - if (--lifetime <= 0 && !force) + if (!ShouldRender(self)) return Enumerable.Empty(); renderableCache.Clear(); @@ -108,8 +112,8 @@ { if (n.Target.Type != TargetType.Invalid && n.Tile == null) { - var lineWidth = renderableCache.Any() ? info.QueuedLineWidth : info.LineWidth; - var markerWidth = renderableCache.Any() ? info.QueuedMarkerWidth : info.MarkerWidth; + var lineWidth = renderableCache.Count > 0 ? info.QueuedLineWidth : info.LineWidth; + var markerWidth = renderableCache.Count > 0 ? info.QueuedMarkerWidth : info.MarkerWidth; var pos = n.Target.CenterPosition; renderableCache.Add(new TargetLineRenderable(new[] { prev, pos }, n.Color, lineWidth, markerWidth)); @@ -118,9 +122,12 @@ } } + if (renderableCache.Count == 0) + return Enumerable.Empty(); + // Reverse draw order so target markers are drawn on top of the next line renderableCache.Reverse(); - return renderableCache; + return renderableCache.ToArray(); } bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return false; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/IsometricSelectionDecorations.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/IsometricSelectionDecorations.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/IsometricSelectionDecorations.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/IsometricSelectionDecorations.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,92 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + public class IsometricSelectionDecorationsInfo : SelectionDecorationsBaseInfo, Requires + { + public override object Create(ActorInitializer init) { return new IsometricSelectionDecorations(init.Self, this); } + } + + public class IsometricSelectionDecorations : SelectionDecorationsBase, IRender + { + readonly IsometricSelectable selectable; + + public IsometricSelectionDecorations(Actor self, IsometricSelectionDecorationsInfo info) + : base(info) + { + selectable = self.Trait(); + } + + int2 GetDecorationPosition(Actor self, WorldRenderer wr, string pos) + { + var bounds = selectable.DecorationBounds(self, wr); + switch (pos) + { + case "TopLeft": return bounds.Vertices[1]; + case "TopRight": return bounds.Vertices[5]; + case "BottomLeft": return bounds.Vertices[2]; + case "BottomRight": return bounds.Vertices[4]; + case "Top": return new int2((bounds.Vertices[1].X + bounds.Vertices[5].X) / 2, bounds.Vertices[1].Y); + default: return bounds.BoundingRect.TopLeft + new int2(bounds.BoundingRect.Size.Width / 2, bounds.BoundingRect.Size.Height / 2); + } + } + + static int2 GetDecorationMargin(string pos, int2 margin) + { + switch (pos) + { + case "TopLeft": return margin; + case "TopRight": return new int2(-margin.X, margin.Y); + case "BottomLeft": return new int2(margin.X, -margin.Y); + case "BottomRight": return -margin; + case "Top": return new int2(0, margin.Y); + default: return int2.Zero; + } + } + + protected override int2 GetDecorationOrigin(Actor self, WorldRenderer wr, string pos, int2 margin) + { + return wr.Viewport.WorldToViewPx(GetDecorationPosition(self, wr, pos)) + GetDecorationMargin(pos, margin); + } + + protected override IEnumerable RenderSelectionBox(Actor self, WorldRenderer wr, Color color) + { + var bounds = selectable.DecorationBounds(self, wr); + yield return new IsometricSelectionBoxAnnotationRenderable(self, bounds, color); + } + + protected override IEnumerable RenderSelectionBars(Actor self, WorldRenderer wr, bool displayHealth, bool displayExtra) + { + if (!displayHealth && !displayExtra) + yield break; + + var bounds = selectable.DecorationBounds(self, wr); + yield return new IsometricSelectionBarsAnnotationRenderable(self, bounds, displayHealth, displayExtra); + } + + IEnumerable IRender.Render(Actor self, WorldRenderer wr) + { + yield break; + } + + IEnumerable IRender.ScreenBounds(Actor self, WorldRenderer wr) + { + yield return selectable.DecorationBounds(self, wr).BoundingRect; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/LeavesTrails.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/LeavesTrails.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/LeavesTrails.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/LeavesTrails.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,9 +20,10 @@ [Desc("Renders a sprite effect when leaving a cell.")] public class LeavesTrailsInfo : ConditionalTraitInfo { + [FieldLoader.Require] public readonly string Image = null; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] public readonly string[] Sequences = { "idle" }; [PaletteReference] @@ -67,7 +68,7 @@ { BodyOrientation body; IFacing facing; - int cachedFacing; + WAngle cachedFacing; int cachedInterval; public LeavesTrails(Actor self, LeavesTrailsInfo info) @@ -81,7 +82,7 @@ { body = self.Trait(); facing = self.TraitOrDefault(); - cachedFacing = facing != null ? facing.Facing : 0; + cachedFacing = facing != null ? facing.Facing : WAngle.Zero; cachedPosition = self.CenterPosition; base.Created(self); @@ -111,6 +112,9 @@ if (++ticks >= cachedInterval) { var spawnCell = Info.SpawnAtLastPosition ? self.World.Map.CellContaining(cachedPosition) : self.World.Map.CellContaining(self.CenterPosition); + if (!self.World.Map.Contains(spawnCell)) + return; + var type = self.World.Map.GetTerrainInfo(spawnCell).Type; if (++offset >= Info.Offsets.Length) @@ -122,14 +126,14 @@ var pos = Info.Type == TrailType.CenterPosition ? spawnPosition + body.LocalToWorld(offsetRotation) : self.World.Map.CenterOfCell(spawnCell); - var spawnFacing = Info.SpawnAtLastPosition ? cachedFacing : (facing != null ? facing.Facing : 0); + var spawnFacing = Info.SpawnAtLastPosition ? cachedFacing : (facing != null ? facing.Facing : WAngle.Zero); if ((Info.TerrainTypes.Count == 0 || Info.TerrainTypes.Contains(type)) && !string.IsNullOrEmpty(Info.Image)) - self.World.AddFrameEndTask(w => w.Add(new SpriteEffect(pos, self.World, Info.Image, - Info.Sequences.Random(Game.CosmeticRandom), Info.Palette, Info.VisibleThroughFog, spawnFacing))); + self.World.AddFrameEndTask(w => w.Add(new SpriteEffect(pos, spawnFacing, self.World, Info.Image, + Info.Sequences.Random(Game.CosmeticRandom), Info.Palette, Info.VisibleThroughFog))); cachedPosition = self.CenterPosition; - cachedFacing = facing != null ? facing.Facing : 0; + cachedFacing = facing != null ? facing.Facing : WAngle.Zero; ticks = 0; cachedInterval = isMoving ? Info.MovingInterval : Info.StationaryInterval; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/ProductionBar.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/ProductionBar.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/ProductionBar.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/ProductionBar.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Visualizes the remaining build time of actor produced here.")] - class ProductionBarInfo : ConditionalTraitInfo, Requires + class ProductionBarInfo : ConditionalTraitInfo, Requires, IRulesetLoaded { [FieldLoader.Require] [Desc("Production queue type, for actors with multiple queues.")] @@ -24,6 +24,21 @@ public readonly Color Color = Color.SkyBlue; + public override void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + // Per-actor queue + var queue = ai.TraitInfos().FirstOrDefault(q => ProductionType == q.Type); + + // No queues available - check for classic production queues + if (queue == null) + queue = rules.Actors["player"].TraitInfos().FirstOrDefault(q => ProductionType == q.Type); + + if (queue == null) + throw new YamlException("Can't find a queue with ProductionType '{0}'".F(ProductionType)); + + base.RulesetLoaded(rules, ai); + } + public override object Create(ActorInitializer init) { return new ProductionBar(init.Self, this); } } @@ -65,7 +80,7 @@ if (IsTraitDisabled) return; - var current = queue.AllQueued().Where(i => i.Started).OrderBy(i => i.RemainingTime).FirstOrDefault(); + var current = queue.AllQueued().Where(i => i.Started).MinByOrDefault(i => i.RemainingTime); value = current != null ? 1 - (float)current.RemainingCost / current.TotalCost : 0; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/ReloadArmamentsBar.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/ReloadArmamentsBar.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/ReloadArmamentsBar.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/ReloadArmamentsBar.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,14 +17,14 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Visualizes the minimum remaining time for reloading the armaments.")] - class ReloadArmamentsBarInfo : ITraitInfo + class ReloadArmamentsBarInfo : TraitInfo { [Desc("Armament names")] public readonly string[] Armaments = { "primary", "secondary" }; public readonly Color Color = Color.Red; - public object Create(ActorInitializer init) { return new ReloadArmamentsBar(init.Self, this); } + public override object Create(ActorInitializer init) { return new ReloadArmamentsBar(init.Self, this); } } class ReloadArmamentsBar : ISelectionBar, INotifyCreated diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderDebugState.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderDebugState.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderDebugState.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderDebugState.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,11 +19,11 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Displays the actor's type and ID above the actor.")] - class RenderDebugStateInfo : ITraitInfo + class RenderDebugStateInfo : TraitInfo { public readonly string Font = "TinyBold"; - public object Create(ActorInitializer init) { return new RenderDebugState(init.Self, this); } + public override object Create(ActorInitializer init) { return new RenderDebugState(init.Self, this); } } class RenderDebugState : INotifyAddedToWorld, INotifyOwnerChanged, INotifyCreated, IRenderAnnotationsWhenSelected diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderDetectionCircle.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderDetectionCircle.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderDetectionCircle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderDetectionCircle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits.Render { - class RenderDetectionCircleInfo : ITraitInfo, Requires + class RenderDetectionCircleInfo : TraitInfo, Requires { [Desc("WAngle the Radar update line advances per tick.")] public readonly WAngle UpdateLineTick = new WAngle(-1); @@ -29,10 +29,16 @@ [Desc("Color of the circle and scanner update line.")] public readonly Color Color = Color.FromArgb(128, Color.LimeGreen); - [Desc("Contrast color of the circle and scanner update line.")] - public readonly Color ContrastColor = Color.FromArgb(96, Color.Black); + [Desc("Range circle line width.")] + public readonly float Width = 1; - public object Create(ActorInitializer init) { return new RenderDetectionCircle(init.Self, this); } + [Desc("Border color of the circle and scanner update line.")] + public readonly Color BorderColor = Color.FromArgb(96, Color.Black); + + [Desc("Range circle border width.")] + public readonly float BorderWidth = 3; + + public override object Create(ActorInitializer init) { return new RenderDetectionCircle(init.Self, this); } } class RenderDetectionCircle : ITick, IRenderAnnotationsWhenSelected @@ -65,7 +71,9 @@ info.UpdateLineTick, lineAngle, info.Color, - info.ContrastColor); + info.Width, + info.BorderColor, + info.BorderWidth); } bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return false; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderJammerCircle.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderJammerCircle.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderJammerCircle.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderJammerCircle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,89 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + // TODO: remove all the Render*Circle duplication + class RenderJammerCircleInfo : TraitInfo, IPlaceBuildingDecorationInfo + { + [Desc("Range circle color.")] + public readonly Color Color = Color.FromArgb(128, Color.Red); + + [Desc("Range circle line width.")] + public readonly float Width = 1; + + [Desc("Range circle border color.")] + public readonly Color BorderColor = Color.FromArgb(96, Color.Black); + + [Desc("Range circle border width.")] + public readonly float BorderWidth = 3; + + public IEnumerable RenderAnnotations(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) + { + var jamsMissiles = ai.TraitInfoOrDefault(); + if (jamsMissiles != null) + { + yield return new RangeCircleAnnotationRenderable( + centerPosition, + jamsMissiles.Range, + 0, + Color, + Width, + BorderColor, + BorderWidth); + } + + foreach (var a in w.ActorsWithTrait()) + if (a.Actor.Owner.IsAlliedWith(w.RenderPlayer)) + foreach (var r in a.Trait.RenderAnnotations(a.Actor, wr)) + yield return r; + } + + public override object Create(ActorInitializer init) { return new RenderJammerCircle(this); } + } + + class RenderJammerCircle : IRenderAnnotationsWhenSelected + { + readonly RenderJammerCircleInfo info; + + public RenderJammerCircle(RenderJammerCircleInfo info) + { + this.info = info; + } + + public IEnumerable RenderAnnotations(Actor self, WorldRenderer wr) + { + if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) + yield break; + + var jamsMissiles = self.Info.TraitInfoOrDefault(); + if (jamsMissiles != null) + { + yield return new RangeCircleAnnotationRenderable( + self.CenterPosition, + jamsMissiles.Range, + 0, + info.Color, + info.Width, + info.BorderColor, + info.BorderWidth); + } + } + + bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return false; } } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderNameTag.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderNameTag.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderNameTag.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderNameTag.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.Common.Graphics; -using OpenRA.Primitives; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits.Render -{ - [Desc("Displays the player name above the unit")] - class RenderNameTagInfo : ITraitInfo, Requires - { - public readonly int MaxLength = 10; - - public readonly string Font = "TinyBold"; - - public object Create(ActorInitializer init) { return new RenderNameTag(init.Self, this); } - } - - class RenderNameTag : IRenderAnnotations - { - readonly SpriteFont font; - readonly Color color; - readonly string name; - readonly IDecorationBounds[] decorationBounds; - - public RenderNameTag(Actor self, RenderNameTagInfo info) - { - font = Game.Renderer.Fonts[info.Font]; - color = self.Owner.Color; - - if (self.Owner.PlayerName.Length > info.MaxLength) - name = self.Owner.PlayerName.Substring(0, info.MaxLength); - else - name = self.Owner.PlayerName; - - decorationBounds = self.TraitsImplementing().ToArray(); - } - - IEnumerable IRenderAnnotations.RenderAnnotations(Actor self, WorldRenderer wr) - { - if (self.World.FogObscures(self)) - yield break; - - var bounds = decorationBounds.FirstNonEmptyBounds(self, wr); - var spaceBuffer = (int)(10 / wr.Viewport.Zoom); - var effectPos = wr.ProjectedPosition(new int2((bounds.Left + bounds.Right) / 2, bounds.Y - spaceBuffer)); - - yield return new TextAnnotationRenderable(font, effectPos, 0, color, name); - } - - bool IRenderAnnotations.SpatiallyPartitionable { get { return false; } } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderRangeCircle.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderRangeCircle.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderRangeCircle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderRangeCircle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,7 +22,7 @@ public enum RangeCircleMode { Maximum, Minimum } [Desc("Draw a circle indicating my weapon's range.")] - class RenderRangeCircleInfo : ITraitInfo, IPlaceBuildingDecorationInfo, IRulesetLoaded, Requires + class RenderRangeCircleInfo : TraitInfo, IPlaceBuildingDecorationInfo, IRulesetLoaded, Requires { public readonly string RangeCircleType = null; @@ -35,9 +35,15 @@ [Desc("Color of the circle.")] public readonly Color Color = Color.FromArgb(128, Color.Yellow); - [Desc("Color of the border of the circle.")] + [Desc("Range circle line width.")] + public readonly float Width = 1; + + [Desc("Color of the border.")] public readonly Color BorderColor = Color.FromArgb(96, Color.Black); + [Desc("Range circle border width.")] + public readonly float BorderWidth = 3; + // Computed range Lazy range; @@ -51,7 +57,9 @@ range.Value, 0, Color, - BorderColor); + Width, + BorderColor, + BorderWidth); var otherRanges = w.ActorsWithTrait() .Where(a => a.Trait.Info.RangeCircleType == RangeCircleType) @@ -60,7 +68,7 @@ return otherRanges.Append(localRange); } - public object Create(ActorInitializer init) { return new RenderRangeCircle(init.Self, this); } + public override object Create(ActorInitializer init) { return new RenderRangeCircle(init.Self, this); } public void RulesetLoaded(Ruleset rules, ActorInfo ai) { @@ -105,7 +113,9 @@ range, 0, Info.Color, - Info.BorderColor); + Info.Width, + Info.BorderColor, + Info.BorderWidth); } IEnumerable IRenderAnnotationsWhenSelected.RenderAnnotations(Actor self, WorldRenderer wr) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderShroudCircle.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderShroudCircle.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderShroudCircle.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderShroudCircle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,101 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + class RenderShroudCircleInfo : TraitInfo, IPlaceBuildingDecorationInfo + { + [Desc("Color of the circle.")] + public readonly Color Color = Color.FromArgb(128, Color.Cyan); + + [Desc("Range circle line width.")] + public readonly float Width = 1; + + [Desc("Border color of the circle.")] + public readonly Color BorderColor = Color.FromArgb(96, Color.Black); + + [Desc("Range circle border width.")] + public readonly float BorderWidth = 3; + + public IEnumerable RenderAnnotations(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition) + { + var localRange = ai.TraitInfos() + .Where(csi => csi.EnabledByDefault) + .Select(csi => csi.Range) + .DefaultIfEmpty(WDist.Zero) + .Max(); + + var localRangeRenderable = new RangeCircleAnnotationRenderable( + centerPosition, + localRange, + 0, + Color, + Width, + BorderColor, + BorderWidth); + + var otherRangeRenderables = w.ActorsWithTrait() + .SelectMany(a => a.Trait.RangeCircleRenderables(a.Actor, wr)); + + return otherRangeRenderables.Append(localRangeRenderable); + } + + public override object Create(ActorInitializer init) { return new RenderShroudCircle(init.Self, this); } + } + + class RenderShroudCircle : INotifyCreated, IRenderAnnotationsWhenSelected + { + readonly RenderShroudCircleInfo info; + WDist range; + + public RenderShroudCircle(Actor self, RenderShroudCircleInfo info) + { + this.info = info; + } + + void INotifyCreated.Created(Actor self) + { + range = self.TraitsImplementing() + .Select(cs => cs.Info.Range) + .DefaultIfEmpty(WDist.Zero) + .Max(); + } + + public IEnumerable RangeCircleRenderables(Actor self, WorldRenderer wr) + { + if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) + yield break; + + yield return new RangeCircleAnnotationRenderable( + self.CenterPosition, + range, + 0, + info.Color, + info.Width, + info.BorderColor, + info.BorderWidth); + } + + IEnumerable IRenderAnnotationsWhenSelected.RenderAnnotations(Actor self, WorldRenderer wr) + { + return RangeCircleRenderables(self, wr); + } + + bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return false; } } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,13 +19,13 @@ namespace OpenRA.Mods.Common.Traits.Render { - public interface IRenderActorPreviewSpritesInfo : ITraitInfo + public interface IRenderActorPreviewSpritesInfo : ITraitInfoInterface { IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p); } [Desc("Render trait fundament that won't work without additional With* render traits.")] - public class RenderSpritesInfo : IRenderActorPreviewInfo, ITraitInfo + public class RenderSpritesInfo : TraitInfo, IRenderActorPreviewInfo { [Desc("The sequence name that defines the actor sprites. Defaults to the actor name.")] public readonly string Image = null; @@ -44,13 +44,13 @@ [Desc("Change the sprite image size.")] public readonly float Scale = 1f; - public virtual object Create(ActorInitializer init) { return new RenderSprites(init, this); } + public override object Create(ActorInitializer init) { return new RenderSprites(init, this); } public IEnumerable RenderPreview(ActorPreviewInitializer init) { var sequenceProvider = init.World.Map.Rules.Sequences; - var faction = init.Get(); - var ownerName = init.Get().PlayerName; + var faction = init.GetValue(this); + var ownerName = init.Get().InternalName; var image = GetImage(init.Actor, sequenceProvider, faction); var palette = init.WorldRenderer.Palette(Palette ?? PlayerPalette + ownerName); @@ -74,12 +74,8 @@ public string GetImage(ActorInfo actor, SequenceProvider sequenceProvider, string faction) { - if (FactionImages != null && !string.IsNullOrEmpty(faction)) - { - string factionImage = null; - if (FactionImages.TryGetValue(faction, out factionImage) && sequenceProvider.HasSequence(factionImage)) - return factionImage; - } + if (FactionImages != null && !string.IsNullOrEmpty(faction) && FactionImages.TryGetValue(faction, out var factionImage)) + return factionImage.ToLowerInvariant(); return (Image ?? actor.Name).ToLowerInvariant(); } @@ -87,12 +83,12 @@ public class RenderSprites : IRender, ITick, INotifyOwnerChanged, INotifyEffectiveOwnerChanged, IActorPreviewInitModifier { - static readonly Pair[] DamagePrefixes = + static readonly (DamageState DamageState, string Prefix)[] DamagePrefixes = { - Pair.New(DamageState.Critical, "critical-"), - Pair.New(DamageState.Heavy, "damaged-"), - Pair.New(DamageState.Medium, "scratched-"), - Pair.New(DamageState.Light, "scuffed-") + (DamageState.Critical, "critical-"), + (DamageState.Heavy, "damaged-"), + (DamageState.Medium, "scratched-"), + (DamageState.Light, "scuffed-") }; class AnimationWrapper @@ -157,17 +153,19 @@ readonly List anims = new List(); string cachedImage; - public static Func MakeFacingFunc(Actor self) + public static Func MakeFacingFunc(Actor self) { var facing = self.TraitOrDefault(); - if (facing == null) return () => 0; + if (facing == null) + return () => WAngle.Zero; + return () => facing.Facing; } public RenderSprites(ActorInitializer init, RenderSpritesInfo info) { Info = info; - faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName; + faction = init.GetValue(init.Self.Owner.Faction.InternalName); } public string GetImage(Actor self) @@ -249,9 +247,9 @@ // Remove existing damage prefix foreach (var s in DamagePrefixes) { - if (sequence.StartsWith(s.Second, StringComparison.Ordinal)) + if (sequence.StartsWith(s.Prefix, StringComparison.Ordinal)) { - sequence = sequence.Substring(s.Second.Length); + sequence = sequence.Substring(s.Prefix.Length); break; } } @@ -265,8 +263,8 @@ sequence = UnnormalizeSequence(sequence); foreach (var s in DamagePrefixes) - if (state >= s.First && anim.HasSequence(s.Second + sequence)) - return s.Second + sequence; + if (state >= s.DamageState && anim.HasSequence(s.Prefix + sequence)) + return s.Prefix + sequence; return sequence; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,13 +19,13 @@ namespace OpenRA.Mods.Common.Traits.Render { - public interface IRenderActorPreviewVoxelsInfo : ITraitInfo + public interface IRenderActorPreviewVoxelsInfo : ITraitInfoInterface { IEnumerable RenderPreviewVoxels( ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func orientation, int facings, PaletteReference p); } - public class RenderVoxelsInfo : ITraitInfo, IRenderActorPreviewInfo, Requires + public class RenderVoxelsInfo : TraitInfo, IRenderActorPreviewInfo, Requires { [Desc("Defaults to the actor name.")] public readonly string Image = null; @@ -52,13 +52,13 @@ public readonly float[] LightAmbientColor = { 0.6f, 0.6f, 0.6f }; public readonly float[] LightDiffuseColor = { 0.4f, 0.4f, 0.4f }; - public virtual object Create(ActorInitializer init) { return new RenderVoxels(init.Self, this); } + public override object Create(ActorInitializer init) { return new RenderVoxels(init.Self, this); } public virtual IEnumerable RenderPreview(ActorPreviewInitializer init) { var body = init.Actor.TraitInfo(); - var faction = init.Get(); - var ownerName = init.Get().PlayerName; + var faction = init.GetValue(this); + var ownerName = init.Get().InternalName; var sequenceProvider = init.World.Map.Rules.Sequences; var image = Image ?? init.Actor.Name; var facings = body.QuantizedFacings == -1 ? diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/SelectionDecorationsBase.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/SelectionDecorationsBase.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/SelectionDecorationsBase.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/SelectionDecorationsBase.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,124 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + public abstract class SelectionDecorationsBaseInfo : TraitInfo + { + public readonly Color SelectionBoxColor = Color.White; + } + + public abstract class SelectionDecorationsBase : ISelectionDecorations, IRenderAnnotations, INotifyCreated + { + IDecoration[] decorations; + IDecoration[] selectedDecorations; + + protected readonly SelectionDecorationsBaseInfo info; + + public SelectionDecorationsBase(SelectionDecorationsBaseInfo info) + { + this.info = info; + } + + void INotifyCreated.Created(Actor self) + { + selectedDecorations = self.TraitsImplementing().ToArray(); + decorations = selectedDecorations.Where(d => !d.RequiresSelection).ToArray(); + } + + IEnumerable ActivityTargetPath(Actor self) + { + if (!self.IsInWorld || self.IsDead) + yield break; + + var activity = self.CurrentActivity; + if (activity != null) + { + var targets = activity.GetTargets(self); + yield return self.CenterPosition; + + foreach (var t in targets.Where(t => t.Type != TargetType.Invalid)) + yield return t.CenterPosition; + } + } + + IEnumerable IRenderAnnotations.RenderAnnotations(Actor self, WorldRenderer wr) + { + if (self.World.FogObscures(self)) + return Enumerable.Empty(); + + return DrawDecorations(self, wr); + } + + bool IRenderAnnotations.SpatiallyPartitionable { get { return true; } } + + IEnumerable DrawDecorations(Actor self, WorldRenderer wr) + { + var selected = self.World.Selection.Contains(self); + var rollover = self.World.Selection.RolloverContains(self); + var regularWorld = self.World.Type == WorldType.Regular; + var statusBars = Game.Settings.Game.StatusBars; + + // Health bars are shown when: + // * actor is selected / in active drag rectangle / under the mouse + // * status bar preference is set to "always show" + // * status bar preference is set to "when damaged" and actor is damaged + var displayHealth = selected || rollover || (regularWorld && statusBars == StatusBarsType.AlwaysShow) + || (regularWorld && statusBars == StatusBarsType.DamageShow && self.GetDamageState() != DamageState.Undamaged); + + // Extra bars are shown when: + // * actor is selected / in active drag rectangle / under the mouse + // * status bar preference is set to "always show" or "when damaged" + var displayExtra = selected || rollover || (regularWorld && statusBars != StatusBarsType.Standard); + + if (selected) + foreach (var r in RenderSelectionBox(self, wr, info.SelectionBoxColor)) + yield return r; + + if (displayHealth || displayExtra) + foreach (var r in RenderSelectionBars(self, wr, displayHealth, displayExtra)) + yield return r; + + if (selected && self.World.LocalPlayer != null && self.World.LocalPlayer.PlayerActor.Trait().PathDebug) + yield return new TargetLineRenderable(ActivityTargetPath(self), Color.Green); + + // Hide decorations for spectators that zoom out further than the normal minimum level + // This avoids graphical glitches with pip rows and icons overlapping the selection box + if (wr.Viewport.Zoom < wr.Viewport.MinZoom) + yield break; + + var renderDecorations = selected ? selectedDecorations : decorations; + foreach (var r in renderDecorations) + foreach (var rr in r.RenderDecoration(self, wr, this)) + yield return rr; + } + + IEnumerable ISelectionDecorations.RenderSelectionAnnotations(Actor self, WorldRenderer worldRenderer, Color color) + { + return RenderSelectionBox(self, worldRenderer, color); + } + + int2 ISelectionDecorations.GetDecorationOrigin(Actor self, WorldRenderer wr, string pos, int2 margin) + { + return GetDecorationOrigin(self, wr, pos, margin); + } + + protected abstract int2 GetDecorationOrigin(Actor self, WorldRenderer wr, string pos, int2 margin); + protected abstract IEnumerable RenderSelectionBox(Actor self, WorldRenderer wr, Color color); + protected abstract IEnumerable RenderSelectionBars(Actor self, WorldRenderer wr, bool displayHealth, bool displayExtra); + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/SelectionDecorations.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/SelectionDecorations.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/SelectionDecorations.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/SelectionDecorations.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Collections.Generic; -using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; using OpenRA.Primitives; @@ -18,160 +17,77 @@ namespace OpenRA.Mods.Common.Traits.Render { - public class SelectionDecorationsInfo : ITraitInfo, Requires + public class SelectionDecorationsInfo : SelectionDecorationsBaseInfo, Requires { - [PaletteReference] - public readonly string Palette = "chrome"; - - [Desc("Health bar, production progress bar etc.")] - public readonly bool RenderSelectionBars = true; - - public readonly bool RenderSelectionBox = true; - - public readonly Color SelectionBoxColor = Color.White; - - public readonly string Image = "pips"; - - public object Create(ActorInitializer init) { return new SelectionDecorations(init.Self, this); } + public override object Create(ActorInitializer init) { return new SelectionDecorations(init.Self, this); } } - public class SelectionDecorations : ISelectionDecorations, IRenderAnnotations, INotifyCreated, ITick + public class SelectionDecorations : SelectionDecorationsBase, IRender { - // depends on the order of pips in TraitsInterfaces.cs! - static readonly string[] PipStrings = { "pip-empty", "pip-green", "pip-yellow", "pip-red", "pip-gray", "pip-blue", "pip-ammo", "pip-ammoempty" }; - - public readonly SelectionDecorationsInfo Info; - - readonly IDecorationBounds[] decorationBounds; - readonly Animation pipImages; - IPips[] pipSources; + readonly Interactable interactable; public SelectionDecorations(Actor self, SelectionDecorationsInfo info) + : base(info) { - Info = info; - - decorationBounds = self.TraitsImplementing().ToArray(); - pipImages = new Animation(self.World, Info.Image); + interactable = self.Trait(); } - void INotifyCreated.Created(Actor self) + int2 GetDecorationPosition(Actor self, WorldRenderer wr, string pos) { - pipSources = self.TraitsImplementing().ToArray(); - } - - IEnumerable ActivityTargetPath(Actor self) - { - if (!self.IsInWorld || self.IsDead) - yield break; - - var activity = self.CurrentActivity; - if (activity != null) + var bounds = interactable.DecorationBounds(self, wr); + switch (pos) { - var targets = activity.GetTargets(self); - yield return self.CenterPosition; - - foreach (var t in targets.Where(t => t.Type != TargetType.Invalid)) - yield return t.CenterPosition; + case "TopLeft": return bounds.TopLeft; + case "TopRight": return bounds.TopRight; + case "BottomLeft": return bounds.BottomLeft; + case "BottomRight": return bounds.BottomRight; + case "Top": return new int2(bounds.Left + bounds.Size.Width / 2, bounds.Top); + default: return bounds.TopLeft + new int2(bounds.Size.Width / 2, bounds.Size.Height / 2); } } - IEnumerable IRenderAnnotations.RenderAnnotations(Actor self, WorldRenderer wr) + static int2 GetDecorationMargin(string pos, int2 margin) { - if (self.World.FogObscures(self)) - return Enumerable.Empty(); - - return DrawDecorations(self, wr); + switch (pos) + { + case "TopLeft": return margin; + case "TopRight": return new int2(-margin.X, margin.Y); + case "BottomLeft": return new int2(margin.X, -margin.Y); + case "BottomRight": return -margin; + case "Top": return new int2(0, margin.Y); + default: return int2.Zero; + } } - bool IRenderAnnotations.SpatiallyPartitionable { get { return true; } } - - IEnumerable DrawDecorations(Actor self, WorldRenderer wr) + protected override int2 GetDecorationOrigin(Actor self, WorldRenderer wr, string pos, int2 margin) { - var selected = self.World.Selection.Contains(self); - var regularWorld = self.World.Type == WorldType.Regular; - var statusBars = Game.Settings.Game.StatusBars; - var bounds = decorationBounds.FirstNonEmptyBounds(self, wr); - - // Health bars are shown when: - // * actor is selected - // * status bar preference is set to "always show" - // * status bar preference is set to "when damaged" and actor is damaged - var displayHealth = selected || (regularWorld && statusBars == StatusBarsType.AlwaysShow) - || (regularWorld && statusBars == StatusBarsType.DamageShow && self.GetDamageState() != DamageState.Undamaged); - - // Extra bars are shown when: - // * actor is selected - // * status bar preference is set to "always show" - // * status bar preference is set to "when damaged" - var displayExtra = selected || (regularWorld && statusBars != StatusBarsType.Standard); - - if (Info.RenderSelectionBox && selected) - yield return new SelectionBoxAnnotationRenderable(self, bounds, Info.SelectionBoxColor); - - if (Info.RenderSelectionBars && (displayHealth || displayExtra)) - yield return new SelectionBarsAnnotationRenderable(self, bounds, displayHealth, displayExtra); - - // Target lines and pips are always only displayed for selected allied actors - if (!selected || !self.Owner.IsAlliedWith(wr.World.RenderPlayer)) - yield break; - - if (self.World.LocalPlayer != null && self.World.LocalPlayer.PlayerActor.Trait().PathDebug) - yield return new TargetLineRenderable(ActivityTargetPath(self), Color.Green); - - foreach (var r in DrawPips(self, bounds, wr)) - yield return r; + return wr.Viewport.WorldToViewPx(GetDecorationPosition(self, wr, pos)) + GetDecorationMargin(pos, margin); } - public void DrawRollover(Actor self, WorldRenderer worldRenderer) + protected override IEnumerable RenderSelectionBox(Actor self, WorldRenderer wr, Color color) { - var bounds = decorationBounds.FirstNonEmptyBounds(self, worldRenderer); - new SelectionBarsAnnotationRenderable(self, bounds, true, true).Render(worldRenderer); + var bounds = interactable.DecorationBounds(self, wr); + yield return new SelectionBoxAnnotationRenderable(self, bounds, color); } - IEnumerable DrawPips(Actor self, Rectangle bounds, WorldRenderer wr) + protected override IEnumerable RenderSelectionBars(Actor self, WorldRenderer wr, bool displayHealth, bool displayExtra) { - if (pipSources.Length == 0) - return Enumerable.Empty(); + // Don't render the selection bars for non-selectable actors + if (!(interactable is Selectable) || (!displayHealth && !displayExtra)) + yield break; - return DrawPipsInner(self, bounds, wr); + var bounds = interactable.DecorationBounds(self, wr); + yield return new SelectionBarsAnnotationRenderable(self, bounds, displayHealth, displayExtra); } - IEnumerable DrawPipsInner(Actor self, Rectangle bounds, WorldRenderer wr) + IEnumerable IRender.Render(Actor self, WorldRenderer wr) { - pipImages.PlayRepeating(PipStrings[0]); - - var palette = wr.Palette(Info.Palette); - var basePosition = wr.Viewport.WorldToViewPx(new int2(bounds.Left, bounds.Bottom)); - var pipSize = pipImages.Image.Size.XY.ToInt2(); - var pipxyBase = basePosition + new int2(1 - pipSize.X / 2, -(3 + pipSize.Y / 2)); - var pipxyOffset = new int2(0, 0); - var width = bounds.Width; - - foreach (var pips in pipSources) - { - var thisRow = pips.GetPips(self); - if (thisRow == null) - continue; - - foreach (var pip in thisRow) - { - if (pipxyOffset.X + pipSize.X >= width) - pipxyOffset = new int2(0, pipxyOffset.Y - pipSize.Y); - - pipImages.PlayRepeating(PipStrings[(int)pip]); - pipxyOffset += new int2(pipSize.X, 0); - - yield return new UISpriteRenderable(pipImages.Image, self.CenterPosition, pipxyBase + pipxyOffset, 0, palette, 1f); - } - - // Increment row - pipxyOffset = new int2(0, pipxyOffset.Y - (pipSize.Y + 1)); - } + yield break; } - void ITick.Tick(Actor self) + IEnumerable IRender.ScreenBounds(Actor self, WorldRenderer wr) { - pipImages.Tick(); + yield return interactable.DecorationBounds(self, wr); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/SupportPowerChargeBar.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/SupportPowerChargeBar.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/SupportPowerChargeBar.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/SupportPowerChargeBar.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,7 +19,7 @@ class SupportPowerChargeBarInfo : ConditionalTraitInfo { [Desc("Defines to which players the bar is to be shown.")] - public readonly Stance DisplayStances = Stance.Ally; + public readonly PlayerRelationship DisplayRelationships = PlayerRelationship.Ally; public readonly Color Color = Color.Magenta; @@ -48,7 +48,7 @@ return 0; var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer; - if (viewer != null && !Info.DisplayStances.HasStance(self.Owner.Stances[viewer])) + if (viewer != null && !Info.DisplayRelationships.HasStance(self.Owner.RelationshipWith(viewer))) return 0; return 1 - (float)power.RemainingTicks / power.TotalTicks; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/TimedConditionBar.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/TimedConditionBar.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/TimedConditionBar.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/TimedConditionBar.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Visualizes the remaining time for a condition.")] - class TimedConditionBarInfo : ITraitInfo, Requires + class TimedConditionBarInfo : TraitInfo { [FieldLoader.Require] [Desc("Condition that this bar corresponds to")] @@ -23,7 +23,7 @@ public readonly Color Color = Color.Red; - public object Create(ActorInitializer init) { return new TimedConditionBar(init.Self, this); } + public override object Create(ActorInitializer init) { return new TimedConditionBar(init.Self, this); } } class TimedConditionBar : ISelectionBar, IConditionTimerWatcher diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/VeteranProductionIconOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/VeteranProductionIconOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/VeteranProductionIconOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/VeteranProductionIconOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,13 +18,13 @@ [Desc("Attach this to the player actor. When attached, enables all actors possessing the ProducibleWithLevel ", "trait to have their production queue icons render with an overlay defined in this trait. ", "The icon change occurs when ProducibleWithLevel.Prerequisites are met.")] - public class VeteranProductionIconOverlayInfo : ITraitInfo, Requires + public class VeteranProductionIconOverlayInfo : TraitInfo, Requires { [FieldLoader.Require] [Desc("Image used for the overlay.")] public readonly string Image = null; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] [Desc("Sequence used for the overlay (cannot be animated).")] public readonly string Sequence = null; @@ -32,11 +32,7 @@ [Desc("Palette to render the sprite in. Reference the world actor's PaletteFrom* traits.")] public readonly string Palette = "chrome"; - [Desc("Point on the production icon's used as reference for offsetting the overlay. ", - "Possible values are combinations of Center, Top, Bottom, Left, Right.")] - public readonly ReferencePoints ReferencePoint = ReferencePoints.Top | ReferencePoints.Left; - - public object Create(ActorInitializer init) { return new VeteranProductionIconOverlay(init, this); } + public override object Create(ActorInitializer init) { return new VeteranProductionIconOverlay(init, this); } } public class VeteranProductionIconOverlay : ITechTreeElement, IProductionIconOverlay @@ -77,25 +73,14 @@ string IProductionIconOverlay.Palette { get { return info.Palette; } } float2 IProductionIconOverlay.Offset(float2 iconSize) { - float x = 0; - float y = 0; - if (info.ReferencePoint.HasFlag(ReferencePoints.Top)) - y -= iconSize.Y / 2 - sprite.Size.Y / 2; - else if (info.ReferencePoint.HasFlag(ReferencePoints.Bottom)) - y += iconSize.Y / 2 - sprite.Size.Y / 2; - - if (info.ReferencePoint.HasFlag(ReferencePoints.Left)) - x -= iconSize.X / 2 - sprite.Size.X / 2; - else if (info.ReferencePoint.HasFlag(ReferencePoints.Right)) - x += iconSize.X / 2 - sprite.Size.X / 2; - + var x = (sprite.Size.X - iconSize.X) / 2; + var y = (sprite.Size.Y - iconSize.Y) / 2; return new float2(x, y); } bool IProductionIconOverlay.IsOverlayActive(ActorInfo ai) { - bool isActive; - if (!overlayActive.TryGetValue(ai, out isActive)) + if (!overlayActive.TryGetValue(ai, out var isActive)) return false; return isActive; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithAmmoPipsDecoration.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithAmmoPipsDecoration.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithAmmoPipsDecoration.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithAmmoPipsDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,92 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + public class WithAmmoPipsDecorationInfo : WithDecorationBaseInfo, Requires + { + [Desc("Number of pips to display. Defaults to the sum of the enabled AmmoPool.Ammo.")] + public readonly int PipCount = -1; + + [Desc("If non-zero, override the spacing between adjacent pips.")] + public readonly int2 PipStride = int2.Zero; + + [Desc("Image that defines the pip sequences.")] + public readonly string Image = "pips"; + + [SequenceReference(nameof(Image))] + [Desc("Sequence used for empty pips.")] + public readonly string EmptySequence = "pip-empty"; + + [SequenceReference(nameof(Image))] + [Desc("Sequence used for full pips.")] + public readonly string FullSequence = "pip-green"; + + [PaletteReference] + public readonly string Palette = "chrome"; + + [Desc("Name(s) of AmmoPool(s) that use this decoration. Leave empty to include all pools.")] + public readonly string[] AmmoPools = { }; + + public override object Create(ActorInitializer init) { return new WithAmmoPipsDecoration(init.Self, this); } + } + + public class WithAmmoPipsDecoration : WithDecorationBase + { + readonly AmmoPool[] ammo; + readonly Animation pips; + + public WithAmmoPipsDecoration(Actor self, WithAmmoPipsDecorationInfo info) + : base(self, info) + { + if (info.AmmoPools.Any()) + ammo = self.TraitsImplementing() + .Where(ap => info.AmmoPools.Contains(ap.Info.Name)) + .ToArray(); + else + ammo = self.TraitsImplementing().ToArray(); + + pips = new Animation(self.World, info.Image); + } + + protected override IEnumerable RenderDecoration(Actor self, WorldRenderer wr, int2 screenPos) + { + pips.PlayRepeating(Info.EmptySequence); + + var palette = wr.Palette(Info.Palette); + var pipSize = pips.Image.Size.XY.ToInt2(); + var pipStride = Info.PipStride != int2.Zero ? Info.PipStride : new int2(pipSize.X, 0); + screenPos -= pipSize / 2; + + var currentAmmo = 0; + var totalAmmo = 0; + foreach (var a in ammo) + { + currentAmmo += a.CurrentAmmoCount; + totalAmmo += a.Info.Ammo; + } + + var pipCount = Info.PipCount > 0 ? Info.PipCount : totalAmmo; + for (var i = 0; i < pipCount; i++) + { + pips.PlayRepeating(currentAmmo * pipCount > i * totalAmmo ? Info.FullSequence : Info.EmptySequence); + yield return new UISpriteRenderable(pips.Image, self.CenterPosition, screenPos, 0, palette, 1f); + + screenPos += pipStride; + } + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -65,7 +65,7 @@ wsb.PlayCustomAnimation(self, Info.Sequence); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (a == armament && Info.DelayRelativeTo == AttackDelayType.Attack) { @@ -76,7 +76,7 @@ } } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { if (a == armament && Info.DelayRelativeTo == AttackDelayType.Preparation) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithAttackOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithAttackOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithAttackOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithAttackOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,14 +15,14 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Rendered together with an attack.")] - public class WithAttackOverlayInfo : ITraitInfo, Requires + public class WithAttackOverlayInfo : TraitInfo, Requires { [SequenceReference] [FieldLoader.Require] [Desc("Sequence name to use")] public readonly string Sequence = null; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; @@ -35,7 +35,7 @@ [Desc("Should the overlay be delayed relative to preparation or actual attack?")] public readonly AttackDelayType DelayRelativeTo = AttackDelayType.Preparation; - public object Create(ActorInitializer init) { return new WithAttackOverlay(init, this); } + public override object Create(ActorInitializer init) { return new WithAttackOverlay(init, this); } } public class WithAttackOverlay : INotifyAttack, ITick @@ -65,7 +65,7 @@ overlay.PlayThen(info.Sequence, () => attacking = false); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (info.DelayRelativeTo == AttackDelayType.Attack) { @@ -76,7 +76,7 @@ } } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { if (info.DelayRelativeTo == AttackDelayType.Preparation) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithBridgeSpriteBody.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithBridgeSpriteBody.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithBridgeSpriteBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithBridgeSpriteBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -61,7 +61,7 @@ readonly Actor self; public WithBridgeSpriteBody(ActorInitializer init, WithBridgeSpriteBodyInfo info) - : base(init, info, () => 0) + : base(init, info) { self = init.Self; bridgeInfo = info; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithBuildingPlacedOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithBuildingPlacedOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithBuildingPlacedOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithBuildingPlacedOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,7 +24,7 @@ [Desc("Position relative to body")] public readonly WVec Offset = WVec.Zero; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithBuildingRepairDecoration.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithBuildingRepairDecoration.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithBuildingRepairDecoration.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithBuildingRepairDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -40,7 +40,7 @@ protected override bool ShouldRender(Actor self) { - if (!rb.Repairers.Any()) + if (rb.Repairers.Count == 0) return false; return base.ShouldRender(self); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithCargoPipsDecoration.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithCargoPipsDecoration.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithCargoPipsDecoration.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithCargoPipsDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,101 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + public class WithCargoPipsDecorationInfo : WithDecorationBaseInfo, Requires + { + [Desc("Number of pips to display. Defaults to Cargo.MaxWeight.")] + public readonly int PipCount = -1; + + [Desc("If non-zero, override the spacing between adjacent pips.")] + public readonly int2 PipStride = int2.Zero; + + [Desc("Image that defines the pip sequences.")] + public readonly string Image = "pips"; + + [SequenceReference(nameof(Image))] + [Desc("Sequence used for empty pips.")] + public readonly string EmptySequence = "pip-empty"; + + [SequenceReference(nameof(Image))] + [Desc("Sequence used for full pips that aren't defined in CustomPipSequences.")] + public readonly string FullSequence = "pip-green"; + + [SequenceReference(nameof(Image), dictionaryReference: LintDictionaryReference.Values)] + [Desc("Pip sequence to use for specific passenger actors.")] + public readonly Dictionary CustomPipSequences = new Dictionary(); + + [PaletteReference] + public readonly string Palette = "chrome"; + + public override object Create(ActorInitializer init) { return new WithCargoPipsDecoration(init.Self, this); } + } + + public class WithCargoPipsDecoration : WithDecorationBase + { + readonly Cargo cargo; + readonly Animation pips; + readonly int pipCount; + + public WithCargoPipsDecoration(Actor self, WithCargoPipsDecorationInfo info) + : base(self, info) + { + cargo = self.Trait(); + pipCount = info.PipCount > 0 ? info.PipCount : cargo.Info.MaxWeight; + pips = new Animation(self.World, info.Image); + } + + string GetPipSequence(int i) + { + var n = i * cargo.Info.MaxWeight / pipCount; + + foreach (var c in cargo.Passengers) + { + var pi = c.Info.TraitInfo(); + if (n < pi.Weight) + { + var sequence = Info.FullSequence; + if (pi.CustomPipType != null && !Info.CustomPipSequences.TryGetValue(pi.CustomPipType, out sequence)) + Log.Write("debug", "Actor type {0} defines a custom pip type {1} that is not defined for actor type {2}".F(c.Info.Name, pi.CustomPipType, self.Info.Name)); + + return sequence; + } + + n -= pi.Weight; + } + + return Info.EmptySequence; + } + + protected override IEnumerable RenderDecoration(Actor self, WorldRenderer wr, int2 screenPos) + { + pips.PlayRepeating(Info.EmptySequence); + + var palette = wr.Palette(Info.Palette); + var pipSize = pips.Image.Size.XY.ToInt2(); + var pipStride = Info.PipStride != int2.Zero ? Info.PipStride : new int2(pipSize.X, 0); + + screenPos -= pipSize / 2; + for (var i = 0; i < pipCount; i++) + { + pips.PlayRepeating(GetPipSequence(i)); + yield return new UISpriteRenderable(pips.Image, self.CenterPosition, screenPos, 0, palette, 1f); + + screenPos += pipStride; + } + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithChargeOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithChargeOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithChargeOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithChargeOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,7 +21,7 @@ [Desc("Sequence to use for the charge levels.")] public readonly string Sequence = "active"; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithChargeSpriteBody.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithChargeSpriteBody.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithChargeSpriteBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithChargeSpriteBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Collections.Generic; -using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; using OpenRA.Traits; @@ -39,7 +38,7 @@ readonly AttackCharges attackCharges; public WithChargeSpriteBody(ActorInitializer init, WithChargeSpriteBodyInfo info) - : base(init, info, () => 0) + : base(init, info) { attackCharges = init.Self.Trait(); ConfigureAnimation(init.Self); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Renders crates with both water and land variants.")] - class WithCrateBodyInfo : ITraitInfo, Requires, IRenderActorPreviewSpritesInfo + class WithCrateBodyInfo : TraitInfo, Requires, IRenderActorPreviewSpritesInfo { [Desc("Easteregg sequences to use in December.")] public readonly string[] XmasImages = { }; @@ -36,11 +36,11 @@ [SequenceReference] public readonly string LandSequence = null; - public object Create(ActorInitializer init) { return new WithCrateBody(init.Self, this); } + public override object Create(ActorInitializer init) { return new WithCrateBody(init.Self, this); } public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { - var anim = new Animation(init.World, rs.Image, () => 0); + var anim = new Animation(init.World, image); anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), IdleSequence)); yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDamageOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDamageOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDamageOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDamageOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,20 +16,20 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Renders an overlay when the actor is taking heavy damage.")] - public class WithDamageOverlayInfo : ITraitInfo, Requires + public class WithDamageOverlayInfo : TraitInfo, Requires { public readonly string Image = "smoke_m"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] public readonly string IdleSequence = "idle"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] public readonly string LoopSequence = "loop"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] public readonly string EndSequence = "end"; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name.")] public readonly string Palette = null; @@ -44,7 +44,7 @@ public readonly DamageState MinimumDamageState = DamageState.Heavy; public readonly DamageState MaximumDamageState = DamageState.Dead; - public object Create(ActorInitializer init) { return new WithDamageOverlay(init.Self, this); } + public override object Create(ActorInitializer init) { return new WithDamageOverlay(init.Self, this); } } public class WithDamageOverlay : INotifyDamage diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDeadBridgeSpriteBody.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDeadBridgeSpriteBody.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDeadBridgeSpriteBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDeadBridgeSpriteBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -66,7 +66,7 @@ readonly BridgeLayer bridgeLayer; public WithDeadBridgeSpriteBody(ActorInitializer init, WithDeadBridgeSpriteBodyInfo info) - : base(init, info, () => 0) + : base(init, info) { bridgeInfo = info; bridgeLayer = init.World.WorldActor.Trait(); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDeathAnimation.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDeathAnimation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDeathAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDeathAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,11 +20,11 @@ [Desc("This actor has a death animation.")] public class WithDeathAnimationInfo : ConditionalTraitInfo, Requires { - [SequenceReference(null, true)] + [SequenceReference(prefix: true)] [Desc("Sequence prefix to play when this actor is killed by a warhead.")] public readonly string DeathSequence = "die"; - [PaletteReference("DeathPaletteIsPlayerPalette")] + [PaletteReference(nameof(DeathPaletteIsPlayerPalette))] [Desc("The palette used for `DeathSequence`.")] public readonly string DeathSequencePalette = "player"; @@ -38,7 +38,7 @@ [Desc("Sequence to play when this actor is crushed.")] public readonly string CrushedSequence = null; - [PaletteReference("CrushedPaletteIsPlayerPalette")] + [PaletteReference(nameof(CrushedPaletteIsPlayerPalette))] [Desc("The palette used for `CrushedSequence`.")] public readonly string CrushedSequencePalette = "effect"; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDecorationBase.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDecorationBase.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDecorationBase.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDecorationBase.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,143 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Support; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + public enum BlinkState { Off, On } + + public abstract class WithDecorationBaseInfo : ConditionalTraitInfo + { + [Desc("Position in the actor's selection box to draw the decoration.")] + public readonly string Position = "TopLeft"; + + [Desc("Player relationships who can view the decoration.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally; + + [Desc("Should this be visible only when selected?")] + public readonly bool RequiresSelection = false; + + [Desc("Offset sprite center position from the selection box edge.")] + public readonly int2 Margin = int2.Zero; + + [Desc("Screen-space offsets to apply when defined conditions are enabled.", + "A dictionary of [condition string]: [x, y offset].")] + public readonly Dictionary Offsets = new Dictionary(); + + [Desc("The number of ticks that each step in the blink pattern in active.")] + public readonly int BlinkInterval = 5; + + [Desc("A pattern of ticks (BlinkInterval long) where the decoration is visible or hidden.")] + public readonly BlinkState[] BlinkPattern = { }; + + [Desc("Override blink conditions to use when defined conditions are enabled.", + "A dictionary of [condition string]: [pattern].")] + public readonly Dictionary BlinkPatterns = new Dictionary(); + + [ConsumedConditionReference] + public IEnumerable ConsumedConditions + { + get { return Offsets.Keys.Concat(BlinkPatterns.Keys).SelectMany(r => r.Variables).Distinct(); } + } + } + + public abstract class WithDecorationBase : ConditionalTrait, IDecoration where InfoType : WithDecorationBaseInfo + { + protected readonly Actor self; + int2 conditionalOffset; + BlinkState[] blinkPattern; + + public WithDecorationBase(Actor self, InfoType info) + : base(info) + { + this.self = self; + blinkPattern = info.BlinkPattern; + } + + protected virtual bool ShouldRender(Actor self) + { + if (self.World.FogObscures(self)) + return false; + + if (blinkPattern != null && blinkPattern.Any()) + { + var i = (self.World.WorldTick / Info.BlinkInterval) % blinkPattern.Length; + if (blinkPattern[i] != BlinkState.On) + return false; + } + + if (self.World.RenderPlayer != null) + { + var stance = self.Owner.RelationshipWith(self.World.RenderPlayer); + if (!Info.ValidRelationships.HasStance(stance)) + return false; + } + + return true; + } + + bool IDecoration.RequiresSelection { get { return Info.RequiresSelection; } } + + protected abstract IEnumerable RenderDecoration(Actor self, WorldRenderer wr, int2 pos); + + IEnumerable IDecoration.RenderDecoration(Actor self, WorldRenderer wr, ISelectionDecorations container) + { + if (IsTraitDisabled || self.IsDead || !self.IsInWorld || !ShouldRender(self)) + return Enumerable.Empty(); + + var screenPos = container.GetDecorationOrigin(self, wr, Info.Position, Info.Margin) + conditionalOffset; + return RenderDecoration(self, wr, screenPos); + } + + public override IEnumerable GetVariableObservers() + { + foreach (var observer in base.GetVariableObservers()) + yield return observer; + + foreach (var condition in Info.Offsets.Keys) + yield return new VariableObserver(OffsetConditionChanged, condition.Variables); + + foreach (var condition in Info.BlinkPatterns.Keys) + yield return new VariableObserver(BlinkConditionsChanged, condition.Variables); + } + + void OffsetConditionChanged(Actor self, IReadOnlyDictionary conditions) + { + conditionalOffset = int2.Zero; + foreach (var kv in Info.Offsets) + { + if (kv.Key.Evaluate(conditions)) + { + conditionalOffset = kv.Value; + break; + } + } + } + + void BlinkConditionsChanged(Actor self, IReadOnlyDictionary conditions) + { + blinkPattern = Info.BlinkPattern; + foreach (var kv in Info.BlinkPatterns) + { + if (kv.Key.Evaluate(conditions)) + { + blinkPattern = kv.Value; + return; + } + } + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,114 +9,45 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; -using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits.Render { - [Flags] - public enum ReferencePoints - { - Center = 0, - Top = 1, - Bottom = 2, - Left = 4, - Right = 8, - } - - public enum BlinkState { Off, On } - [Desc("Displays a custom UI overlay relative to the actor's mouseover bounds.")] - public class WithDecorationInfo : ConditionalTraitInfo, Requires + public class WithDecorationInfo : WithDecorationBaseInfo { [Desc("Image used for this decoration. Defaults to the actor's type.")] public readonly string Image = null; + [FieldLoader.Require] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Sequence used for this decoration (can be animated).")] public readonly string Sequence = null; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Palette to render the sprite in. Reference the world actor's PaletteFrom* traits.")] public readonly string Palette = "chrome"; [Desc("Custom palette is a player palette BaseName")] public readonly bool IsPlayerPalette = false; - [Desc("Point in the actor's selection box used as reference for offsetting the decoration image. " + - "Possible values are combinations of Center, Top, Bottom, Left, Right.")] - public readonly ReferencePoints ReferencePoint = ReferencePoints.Top | ReferencePoints.Left; - - [Desc("The Z offset to apply when rendering this decoration.")] - public readonly int ZOffset = 1; - - [Desc("Player stances who can view the decoration.")] - public readonly Stance ValidStances = Stance.Ally; - - [Desc("Should this be visible only when selected?")] - public readonly bool RequiresSelection = false; - - [Desc("Screen-space offsets to apply when defined conditions are enabled.", - "A dictionary of [condition string]: [x, y offset].")] - public readonly Dictionary Offsets = new Dictionary(); - - [Desc("The number of ticks that each step in the blink pattern in active.")] - public readonly int BlinkInterval = 5; - - [Desc("A pattern of ticks (BlinkInterval long) where the decoration is visible or hidden.")] - public readonly BlinkState[] BlinkPattern = { }; - - [Desc("Override blink conditions to use when defined conditions are enabled.", - "A dictionary of [condition string]: [pattern].")] - public readonly Dictionary BlinkPatterns = new Dictionary(); - - [ConsumedConditionReference] - public IEnumerable ConsumedConditions - { - get { return Offsets.Keys.Concat(BlinkPatterns.Keys).SelectMany(r => r.Variables).Distinct(); } - } - public override object Create(ActorInitializer init) { return new WithDecoration(init.Self, this); } } - public class WithDecoration : ConditionalTrait, ITick, IRenderAnnotations, IRenderAnnotationsWhenSelected + public class WithDecoration : WithDecorationBase, ITick { protected Animation anim; - readonly IDecorationBounds[] decorationBounds; readonly string image; - int2 conditionalOffset; - BlinkState[] blinkPattern; public WithDecoration(Actor self, WithDecorationInfo info) - : base(info) + : base(self, info) { image = info.Image ?? self.Info.Name; anim = new Animation(self.World, image, () => self.World.Paused); anim.PlayRepeating(info.Sequence); - decorationBounds = self.TraitsImplementing().ToArray(); - blinkPattern = info.BlinkPattern; - } - - protected virtual bool ShouldRender(Actor self) - { - if (blinkPattern != null && blinkPattern.Any()) - { - var i = (self.World.WorldTick / Info.BlinkInterval) % blinkPattern.Length; - if (blinkPattern[i] != BlinkState.On) - return false; - } - - if (self.World.RenderPlayer != null) - { - var stance = self.Owner.Stances[self.World.RenderPlayer]; - if (!Info.ValidStances.HasStance(stance)) - return false; - } - - return true; } protected virtual PaletteReference GetPalette(Actor self, WorldRenderer wr) @@ -124,99 +55,17 @@ return wr.Palette(Info.Palette + (Info.IsPlayerPalette ? self.Owner.InternalName : "")); } - IEnumerable IRenderAnnotations.RenderAnnotations(Actor self, WorldRenderer wr) - { - return !Info.RequiresSelection ? RenderInner(self, wr) : SpriteRenderable.None; - } - - IEnumerable IRenderAnnotationsWhenSelected.RenderAnnotations(Actor self, WorldRenderer wr) + protected override IEnumerable RenderDecoration(Actor self, WorldRenderer wr, int2 screenPos) { - return Info.RequiresSelection ? RenderInner(self, wr) : SpriteRenderable.None; - } - - bool IRenderAnnotations.SpatiallyPartitionable { get { return true; } } - bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return true; } } - - IEnumerable RenderInner(Actor self, WorldRenderer wr) - { - if (IsTraitDisabled || self.IsDead || !self.IsInWorld || anim == null) + if (anim == null) return Enumerable.Empty(); - if (!ShouldRender(self) || self.World.FogObscures(self)) - return Enumerable.Empty(); - - var bounds = decorationBounds.FirstNonEmptyBounds(self, wr); - var halfSize = (0.5f * anim.Image.Size.XY).ToInt2(); - - var boundsOffset = new int2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom) / 2; - var sizeOffset = -halfSize; - if (Info.ReferencePoint.HasFlag(ReferencePoints.Top)) - { - boundsOffset -= new int2(0, bounds.Height / 2); - sizeOffset += new int2(0, halfSize.Y); - } - else if (Info.ReferencePoint.HasFlag(ReferencePoints.Bottom)) - { - boundsOffset += new int2(0, bounds.Height / 2); - sizeOffset -= new int2(0, halfSize.Y); - } - - if (Info.ReferencePoint.HasFlag(ReferencePoints.Left)) - { - boundsOffset -= new int2(bounds.Width / 2, 0); - sizeOffset += new int2(halfSize.X, 0); - } - else if (Info.ReferencePoint.HasFlag(ReferencePoints.Right)) - { - boundsOffset += new int2(bounds.Width / 2, 0); - sizeOffset -= new int2(halfSize.X, 0); - } - - var pxPos = wr.Viewport.WorldToViewPx(boundsOffset) + sizeOffset + conditionalOffset; return new IRenderable[] { - new UISpriteRenderable(anim.Image, self.CenterPosition, pxPos, Info.ZOffset, GetPalette(self, wr), 1f) + new UISpriteRenderable(anim.Image, self.CenterPosition, screenPos - (0.5f * anim.Image.Size.XY).ToInt2(), 0, GetPalette(self, wr), 1f) }; } void ITick.Tick(Actor self) { anim.Tick(); } - - public override IEnumerable GetVariableObservers() - { - foreach (var observer in base.GetVariableObservers()) - yield return observer; - - foreach (var condition in Info.Offsets.Keys) - yield return new VariableObserver(OffsetConditionChanged, condition.Variables); - - foreach (var condition in Info.BlinkPatterns.Keys) - yield return new VariableObserver(BlinkConditionsChanged, condition.Variables); - } - - void OffsetConditionChanged(Actor self, IReadOnlyDictionary conditions) - { - conditionalOffset = int2.Zero; - foreach (var kv in Info.Offsets) - { - if (kv.Key.Evaluate(conditions)) - { - conditionalOffset = kv.Value; - break; - } - } - } - - void BlinkConditionsChanged(Actor self, IReadOnlyDictionary conditions) - { - blinkPattern = Info.BlinkPattern; - foreach (var kv in Info.BlinkPatterns) - { - if (kv.Key.Evaluate(conditions)) - { - blinkPattern = kv.Value; - return; - } - } - } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDeliveryAnimation.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDeliveryAnimation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDeliveryAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDeliveryAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Linq; -using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits.Render @@ -45,7 +44,9 @@ public void Delivered(Actor self) { - wsb.CancelCustomAnimation(self); + // Animation has already been cancelled by TraitDisabled below + if (!IsTraitDisabled) + wsb.CancelCustomAnimation(self); } protected override void TraitDisabled(Actor self) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDockedOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDockedOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithDockedOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithDockedOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,7 +24,7 @@ [Desc("Position relative to body")] public readonly WVec Offset = WVec.Zero; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithGateSpriteBody.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithGateSpriteBody.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithGateSpriteBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithGateSpriteBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -54,7 +54,7 @@ bool renderOpen; public WithGateSpriteBody(ActorInitializer init, WithGateSpriteBodyInfo info) - : base(init, info, () => 0) + : base(init, info) { gateBodyInfo = info; gate = init.Self.Trait(); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithHarvestAnimation.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithHarvestAnimation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithHarvestAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithHarvestAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,12 +10,11 @@ #endregion using System.Linq; -using OpenRA.Activities; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits.Render { - public class WithHarvestAnimationInfo : ITraitInfo, Requires, Requires + public class WithHarvestAnimationInfo : TraitInfo, Requires, Requires { [SequenceReference] [Desc("Displayed while harvesting.")] @@ -24,7 +23,7 @@ [Desc("Which sprite body to play the animation on.")] public readonly string Body = "body"; - public object Create(ActorInitializer init) { return new WithHarvestAnimation(init, this); } + public override object Create(ActorInitializer init) { return new WithHarvestAnimation(init, this); } } public class WithHarvestAnimation : INotifyHarvesterAction diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithHarvesterPipsDecoration.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithHarvesterPipsDecoration.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithHarvesterPipsDecoration.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithHarvesterPipsDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,98 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + public class WithHarvesterPipsDecorationInfo : WithDecorationBaseInfo, Requires + { + [FieldLoader.Require] + [Desc("Number of pips to display how filled unit is.")] + public readonly int PipCount = 0; + + [Desc("If non-zero, override the spacing between adjacent pips.")] + public readonly int2 PipStride = int2.Zero; + + [Desc("Image that defines the pip sequences.")] + public readonly string Image = "pips"; + + [SequenceReference(nameof(Image))] + [Desc("Sequence used for empty pips.")] + public readonly string EmptySequence = "pip-empty"; + + [SequenceReference(nameof(Image))] + [Desc("Sequence used for full pips that aren't defined in ResourceSequences.")] + public readonly string FullSequence = "pip-green"; + + [SequenceReference(nameof(Image), dictionaryReference: LintDictionaryReference.Values)] + [Desc("Pip sequence to use for specific resource types.")] + public readonly Dictionary ResourceSequences = new Dictionary(); + + [PaletteReference] + public readonly string Palette = "chrome"; + + public override object Create(ActorInitializer init) { return new WithHarvesterPipsDecoration(init.Self, this); } + } + + public class WithHarvesterPipsDecoration : WithDecorationBase + { + readonly Harvester harvester; + readonly Animation pips; + + public WithHarvesterPipsDecoration(Actor self, WithHarvesterPipsDecorationInfo info) + : base(self, info) + { + harvester = self.Trait(); + pips = new Animation(self.World, info.Image); + } + + string GetPipSequence(int i) + { + var n = i * harvester.Info.Capacity / Info.PipCount; + + foreach (var rt in harvester.Contents) + { + if (n < rt.Value) + { + if (!Info.ResourceSequences.TryGetValue(rt.Key.Type, out var sequence)) + sequence = Info.FullSequence; + + return sequence; + } + + n -= rt.Value; + } + + return Info.EmptySequence; + } + + protected override IEnumerable RenderDecoration(Actor self, WorldRenderer wr, int2 screenPos) + { + pips.PlayRepeating(Info.EmptySequence); + + var palette = wr.Palette(Info.Palette); + var pipSize = pips.Image.Size.XY.ToInt2(); + var pipStride = Info.PipStride != int2.Zero ? Info.PipStride : new int2(pipSize.X, 0); + + screenPos -= pipSize / 2; + for (var i = 0; i < Info.PipCount; i++) + { + pips.PlayRepeating(GetPipSequence(i)); + yield return new UISpriteRenderable(pips.Image, self.CenterPosition, screenPos, 0, palette, 1f); + + screenPos += pipStride; + } + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithHarvestOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithHarvestOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithHarvestOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithHarvestOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,14 +9,13 @@ */ #endregion -using OpenRA.Activities; using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits.Render { [Desc("Displays an overlay whenever resources are harvested by the actor.")] - class WithHarvestOverlayInfo : ITraitInfo, Requires, Requires + class WithHarvestOverlayInfo : TraitInfo, Requires, Requires { [SequenceReference] [Desc("Sequence name to use")] @@ -28,7 +27,7 @@ [PaletteReference] public readonly string Palette = "effect"; - public object Create(ActorInitializer init) { return new WithHarvestOverlay(init.Self, this); } + public override object Create(ActorInitializer init) { return new WithHarvestOverlay(init.Self, this); } } class WithHarvestOverlay : INotifyHarvesterAction diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithIdleAnimation.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithIdleAnimation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithIdleAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithIdleAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,7 +21,8 @@ [Desc("Sequence names to use.")] public readonly string[] Sequences = { "active" }; - public readonly int Interval = 750; + [Desc("The amount of time (in ticks) between animations. Two values indicate a range between which a random value is chosen.")] + public readonly int[] Interval = { 750 }; [Desc("Which sprite body to play the animation on.")] public readonly string Body = "body"; @@ -38,7 +39,7 @@ : base(info) { wsb = self.TraitsImplementing().Single(w => w.Info.Name == Info.Body); - ticks = info.Interval; + ticks = Util.RandomDelay(self.World, info.Interval); } void ITick.Tick(Actor self) @@ -49,7 +50,7 @@ if (--ticks <= 0) { wsb.PlayCustomAnimation(self, Info.Sequences.Random(Game.CosmeticRandom)); - ticks = Info.Interval; + ticks = Util.RandomDelay(self.World, Info.Interval); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,24 +20,29 @@ [Desc("Renders a decorative animation on units and buildings.")] public class WithIdleOverlayInfo : PausableConditionalTraitInfo, IRenderActorPreviewSpritesInfo, Requires, Requires { - [SequenceReference] + [Desc("Image used for this decoration. Defaults to the actor's type.")] + public readonly string Image = null; + + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Animation to play when the actor is created.")] public readonly string StartSequence = null; - [SequenceReference] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Sequence name to use")] public readonly string Sequence = "idle-overlay"; [Desc("Position relative to body")] public readonly WVec Offset = WVec.Zero; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; [Desc("Custom palette is a player palette BaseName")] public readonly bool IsPlayerPalette = false; + public readonly bool IsDecoration = false; + public override object Create(ActorInitializer init) { return new WithIdleOverlay(init.Self, this); } public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) @@ -48,20 +53,22 @@ if (Palette != null) p = init.WorldRenderer.Palette(Palette); - Func facing; - if (init.Contains()) - facing = init.Get>(); + Func facing; + var dynamicfacingInit = init.GetOrDefault(); + if (dynamicfacingInit != null) + facing = dynamicfacingInit.Value; else { - var f = init.Contains() ? init.Get() : 0; + var f = init.GetValue(WAngle.Zero); facing = () => f; } - var anim = new Animation(init.World, image, facing); + var anim = new Animation(init.World, Image ?? image, facing); + anim.IsDecoration = IsDecoration; anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence)); var body = init.Actor.TraitInfo(); - Func orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings); + Func orientation = () => body.QuantizeOrientation(WRot.FromYaw(facing()), facings); Func offset = () => body.LocalToWorld(Offset.Rotate(orientation())); Func zOffset = () => { @@ -83,7 +90,9 @@ var rs = self.Trait(); var body = self.Trait(); - overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused); + var image = info.Image ?? rs.GetImage(self); + overlay = new Animation(self.World, image, () => IsTraitPaused); + overlay.IsDecoration = info.IsDecoration; if (info.StartSequence != null) overlay.PlayThen(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.StartSequence), () => overlay.PlayRepeating(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.Sequence))); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,9 +28,11 @@ [SequenceReference] public readonly string DefaultAttackSequence = null; - // TODO: [SequenceReference] isn't smart enough to use Dictionaries. - [Desc("Attack sequence to use for each armament.")] - public readonly Dictionary AttackSequences = new Dictionary(); + [SequenceReference(dictionaryReference: LintDictionaryReference.Values)] + [Desc("Attack sequence to use for each armament.", + "A dictionary of [armament name]: [sequence name(s)].", + "Multiple sequence names can be defined to specify per-burst animations.")] + public readonly Dictionary AttackSequences = new Dictionary(); [SequenceReference] public readonly string[] IdleSequences = { }; @@ -38,6 +40,13 @@ [SequenceReference] public readonly string[] StandSequences = { "stand" }; + [PaletteReference(nameof(IsPlayerPalette))] + [Desc("Custom palette name")] + public readonly string Palette = null; + + [Desc("Palette is a player palette BaseName")] + public readonly bool IsPlayerPalette = false; + public override object Create(ActorInitializer init) { return new WithInfantryBody(init, this); } public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) @@ -47,6 +56,12 @@ var anim = new Animation(init.World, image, init.GetFacing()); anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), StandSequences.First())); + + if (IsPlayerPalette) + p = init.WorldRenderer.Palette(Palette + init.Get().InternalName); + else if (Palette != null) + p = init.WorldRenderer.Palette(Palette); + yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale); } } @@ -78,7 +93,7 @@ var rs = self.Trait(); DefaultAnimation = new Animation(init.World, rs.GetImage(self), RenderSprites.MakeFacingFunc(self)); - rs.Add(new AnimationWithOffset(DefaultAnimation, null, () => IsTraitDisabled)); + rs.Add(new AnimationWithOffset(DefaultAnimation, null, () => IsTraitDisabled), info.Palette, info.IsPlayerPalette); PlayStandAnimation(self); move = init.Self.Trait(); @@ -120,12 +135,21 @@ } } - public void Attacking(Actor self, Target target, Armament a) + void Attacking(Actor self, Armament a, Barrel barrel) { - string sequence; var info = GetDisplayInfo(); - if (!info.AttackSequences.TryGetValue(a.Info.Name, out sequence)) - sequence = info.DefaultAttackSequence; + var sequence = info.DefaultAttackSequence; + + if (info.AttackSequences.TryGetValue(a.Info.Name, out var sequences) && sequences.Length > 0) + { + sequence = sequences[0]; + + // Find the sequence corresponding to this barrel/burst. + if (barrel != null && sequences.Length > 1) + for (var i = 0; i < sequences.Length; i++) + if (a.Barrels[i] == barrel) + sequence = sequences[i]; + } if (!string.IsNullOrEmpty(sequence) && DefaultAnimation.HasSequence(NormalizeInfantrySequence(self, sequence))) { @@ -134,12 +158,14 @@ } } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { - Attacking(self, target, a); + // HACK: The FrameEndTask makes sure that this runs after Tick(), preventing that from + // overriding the animation when an infantry unit stops to attack + self.World.AddFrameEndTask(_ => Attacking(self, a, barrel)); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) { } + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { } void ITick.Tick(Actor self) { @@ -156,12 +182,12 @@ wasModifying = rsm.IsModifyingSequence; } - if ((state != AnimationState.Moving || dirty) && move.CurrentMovementTypes.HasFlag(MovementType.Horizontal)) + if ((state != AnimationState.Moving || dirty) && move.CurrentMovementTypes.HasMovementType(MovementType.Horizontal)) { state = AnimationState.Moving; DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, GetDisplayInfo().MoveSequence)); } - else if (((state == AnimationState.Moving || dirty) && !move.CurrentMovementTypes.HasFlag(MovementType.Horizontal)) + else if (((state == AnimationState.Moving || dirty) && !move.CurrentMovementTypes.HasMovementType(MovementType.Horizontal)) || ((state == AnimationState.Idle || state == AnimationState.IdleAnimating) && !self.IsIdle)) PlayStandAnimation(self); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Replaces the sprite during construction/deploy/undeploy.")] - public class WithMakeAnimationInfo : ITraitInfo, Requires + public class WithMakeAnimationInfo : TraitInfo, Requires { [SequenceReference] [Desc("Sequence name to use.")] @@ -30,7 +30,7 @@ [Desc("Apply to sprite bodies with these names.")] public readonly string[] BodyNames = { "body" }; - public object Create(ActorInitializer init) { return new WithMakeAnimation(init, this); } + public override object Create(ActorInitializer init) { return new WithMakeAnimation(init, this); } } public class WithMakeAnimation : INotifyCreated, INotifyDeployTriggered @@ -39,28 +39,26 @@ readonly WithSpriteBody[] wsbs; readonly bool skipMakeAnimation; - ConditionManager conditionManager; - int token = ConditionManager.InvalidConditionToken; + int token = Actor.InvalidConditionToken; public WithMakeAnimation(ActorInitializer init, WithMakeAnimationInfo info) { this.info = info; var self = init.Self; wsbs = self.TraitsImplementing().Where(w => info.BodyNames.Contains(w.Info.Name)).ToArray(); - skipMakeAnimation = init.Contains(); + skipMakeAnimation = init.Contains(info); } void INotifyCreated.Created(Actor self) { - conditionManager = self.TraitOrDefault(); if (!skipMakeAnimation) Forward(self, () => { }); } public void Forward(Actor self, Action onComplete) { - if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && token == ConditionManager.InvalidConditionToken) - token = conditionManager.GrantCondition(self, info.Condition); + if (token == Actor.InvalidConditionToken) + token = self.GrantCondition(info.Condition); var wsb = wsbs.FirstEnabledTraitOrDefault(); @@ -71,8 +69,8 @@ { self.World.AddFrameEndTask(w => { - if (token != ConditionManager.InvalidConditionToken) - token = conditionManager.RevokeCondition(self, token); + if (token != Actor.InvalidConditionToken) + token = self.RevokeCondition(token); // TODO: Rewrite this to use a trait notification for save game support onComplete(); @@ -82,8 +80,8 @@ public void Reverse(Actor self, Action onComplete) { - if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && token == ConditionManager.InvalidConditionToken) - token = conditionManager.GrantCondition(self, info.Condition); + if (token == Actor.InvalidConditionToken) + token = self.GrantCondition(info.Condition); var wsb = wsbs.FirstEnabledTraitOrDefault(); @@ -94,8 +92,8 @@ { self.World.AddFrameEndTask(w => { - if (token != ConditionManager.InvalidConditionToken) - token = conditionManager.RevokeCondition(self, token); + if (token != Actor.InvalidConditionToken) + token = self.RevokeCondition(token); // TODO: Rewrite this to use a trait notification for save game support onComplete(); @@ -107,17 +105,13 @@ { Reverse(self, () => { - var wsb = wsbs.FirstEnabledTraitOrDefault(); - // HACK: The actor remains alive and active for one tick before the followup activity // (sell/transform/etc) runs. This causes visual glitches that we attempt to minimize // by forcing the animation to frame 0 and regranting the make condition. // These workarounds will break the actor if the followup activity doesn't dispose it! - if (wsb != null) - wsb.DefaultAnimation.PlayFetchIndex(info.Sequence, () => 0); + wsbs.FirstEnabledTraitOrDefault()?.DefaultAnimation.PlayFetchIndex(info.Sequence, () => 0); - if (conditionManager != null && !string.IsNullOrEmpty(info.Condition)) - token = conditionManager.GrantCondition(self, info.Condition); + token = self.GrantCondition(info.Condition); self.QueueActivity(queued, activity); }); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithMuzzleOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithMuzzleOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithMuzzleOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithMuzzleOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,7 +31,7 @@ { readonly Dictionary visible = new Dictionary(); readonly Dictionary anims = new Dictionary(); - readonly Func getFacing; + readonly Func getFacing; readonly Armament[] armaments; public WithMuzzleOverlay(Actor self, WithMuzzleOverlayInfo info) @@ -52,14 +52,12 @@ var turreted = self.TraitsImplementing() .FirstOrDefault(t => t.Name == arm.Info.Turret); - // Workaround for broken ternary operators in certain versions of mono (3.10 and - // certain versions of the 3.8 series): https://bugzilla.xamarin.com/show_bug.cgi?id=23319 if (turreted != null) - getFacing = () => turreted.TurretFacing; + getFacing = () => turreted.WorldOrientation.Yaw; else if (facing != null) getFacing = () => facing.Facing; else - getFacing = () => 0; + getFacing = () => WAngle.Zero; var muzzleFlash = new Animation(self.World, render.GetImage(self), getFacing); visible.Add(barrel, false); @@ -72,20 +70,17 @@ } } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (a == null || barrel == null || !armaments.Contains(a)) return; var sequence = a.Info.MuzzleSequence; - if (a.Info.MuzzleSplitFacings > 0) - sequence += Util.QuantizeFacing(getFacing(), a.Info.MuzzleSplitFacings).ToString(); - visible[barrel] = true; anims[barrel].Animation.PlayThen(sequence, () => visible[barrel] = false); } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { } + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { } IEnumerable IRender.Render(Actor self, WorldRenderer wr) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,84 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + [Desc("Displays the player name above the unit")] + public class WithNameTagDecorationInfo : WithDecorationBaseInfo + { + public readonly int MaxLength = 10; + + public readonly string Font = "TinyBold"; + + [Desc("Display in this color when not using the player color.")] + public readonly Color Color = Color.White; + + [Desc("Use the player color of the current owner.")] + public readonly bool UsePlayerColor = false; + + public override object Create(ActorInitializer init) { return new WithNameTagDecoration(init.Self, this); } + + public override void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + if (!Game.ModData.Manifest.Get().FontList.ContainsKey(Font)) + throw new YamlException("Font '{0}' is not listed in the mod.yaml's Fonts section".F(Font)); + + base.RulesetLoaded(rules, ai); + } + } + + public class WithNameTagDecoration : WithDecorationBase, INotifyOwnerChanged + { + readonly SpriteFont font; + string name; + Color color; + + public WithNameTagDecoration(Actor self, WithNameTagDecorationInfo info) + : base(self, info) + { + font = Game.Renderer.Fonts[info.Font]; + color = info.UsePlayerColor ? self.Owner.Color : info.Color; + + name = self.Owner.PlayerName; + if (name.Length > info.MaxLength) + name = name.Substring(0, info.MaxLength); + } + + protected override IEnumerable RenderDecoration(Actor self, WorldRenderer wr, int2 screenPos) + { + if (IsTraitDisabled || self.IsDead || !self.IsInWorld || !ShouldRender(self)) + return Enumerable.Empty(); + + var size = font.Measure(name); + return new IRenderable[] + { + new UITextRenderable(font, self.CenterPosition, screenPos - size / 2, 0, color, name) + }; + } + + void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) + { + if (Info.UsePlayerColor) + color = newOwner.Color; + + name = self.Owner.PlayerName; + if (name.Length > Info.MaxLength) + name = name.Substring(0, Info.MaxLength); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchAnimation.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchAnimation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchAnimation.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits.Render -{ - [Desc("Replaces the building animation when `NukePower` is triggered.")] - public class WithNukeLaunchAnimationInfo : ConditionalTraitInfo, Requires - { - [SequenceReference] - [Desc("Sequence name to use")] - public readonly string Sequence = "active"; - - [Desc("Which sprite body to play the animation on.")] - public readonly string Body = "body"; - - public override object Create(ActorInitializer init) { return new WithNukeLaunchAnimation(init.Self, this); } - } - - public class WithNukeLaunchAnimation : ConditionalTrait, INotifyNuke - { - readonly WithSpriteBody wsb; - - public WithNukeLaunchAnimation(Actor self, WithNukeLaunchAnimationInfo info) - : base(info) - { - wsb = self.TraitsImplementing().Single(w => w.Info.Name == Info.Body); - } - - void INotifyNuke.Launching(Actor self) - { - if (!IsTraitDisabled) - wsb.PlayCustomAnimation(self, Info.Sequence, () => wsb.CancelCustomAnimation(self)); - } - - protected override void TraitDisabled(Actor self) - { - wsb.CancelCustomAnimation(self); - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchOverlay.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits.Render -{ - [Desc("Displays an overlay when `NukePower` is triggered.")] - public class WithNukeLaunchOverlayInfo : ConditionalTraitInfo, Requires, Requires - { - [SequenceReference] - [Desc("Sequence name to use")] - public readonly string Sequence = "active"; - - [Desc("Position relative to body")] - public readonly WVec Offset = WVec.Zero; - - [PaletteReference("IsPlayerPalette")] - [Desc("Custom palette name")] - public readonly string Palette = null; - - [Desc("Custom palette is a player palette BaseName")] - public readonly bool IsPlayerPalette = false; - - public override object Create(ActorInitializer init) { return new WithNukeLaunchOverlay(init.Self, this); } - } - - public class WithNukeLaunchOverlay : ConditionalTrait, INotifyNuke - { - readonly Animation overlay; - bool visible; - - public WithNukeLaunchOverlay(Actor self, WithNukeLaunchOverlayInfo info) - : base(info) - { - var rs = self.Trait(); - var body = self.Trait(); - - overlay = new Animation(self.World, rs.GetImage(self)); - overlay.PlayThen(info.Sequence, () => visible = false); - - var anim = new AnimationWithOffset(overlay, - () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), - () => IsTraitDisabled || !visible, - p => RenderUtils.ZOffsetFromCenter(self, p, 1)); - - rs.Add(anim, info.Palette, info.IsPlayerPalette); - } - - void INotifyNuke.Launching(Actor self) - { - visible = true; - overlay.PlayThen(overlay.CurrentSequence.Name, () => visible = false); - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithParachute.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithParachute.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithParachute.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithParachute.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,19 +25,19 @@ [Desc("The image that contains the parachute sequences.")] public readonly string Image = null; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Parachute opening sequence.")] public readonly string OpeningSequence = null; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Parachute idle sequence.")] public readonly string Sequence = null; - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("Parachute closing sequence. Defaults to opening sequence played backwards.")] public readonly string ClosingSequence = null; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Palette used to render the parachute.")] public readonly string Palette = "player"; @@ -49,7 +49,7 @@ [Desc("The image that contains the shadow sequence for the paradropped unit.")] public readonly string ShadowImage = null; - [SequenceReference("ShadowImage")] + [SequenceReference(nameof(ShadowImage), allowNullImage: true)] [Desc("Paradropped unit's shadow sequence.")] public readonly string ShadowSequence = null; @@ -77,12 +77,13 @@ if (Palette != null) p = init.WorldRenderer.Palette(Palette); - Func facing; - if (init.Contains()) - facing = init.Get>(); + Func facing; + var dynamicfacingInit = init.GetOrDefault(); + if (dynamicfacingInit != null) + facing = dynamicfacingInit.Value; else { - var f = init.Contains() ? init.Get() : 0; + var f = init.GetValue(WAngle.Zero); facing = () => f; } @@ -90,7 +91,7 @@ anim.PlayThen(OpeningSequence, () => anim.PlayRepeating(Sequence)); var body = init.Actor.TraitInfo(); - Func orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings); + Func orientation = () => body.QuantizeOrientation(WRot.FromYaw(facing()), facings); Func offset = () => body.LocalToWorld(Offset.Rotate(orientation())); Func zOffset = () => { @@ -158,8 +159,7 @@ void ITick.Tick(Actor self) { - if (shadow != null) - shadow.Tick(); + shadow?.Tick(); } IEnumerable IRender.Render(Actor self, WorldRenderer wr) @@ -176,7 +176,7 @@ var dat = self.World.Map.DistanceAboveTerrain(self.CenterPosition); var pos = self.CenterPosition - new WVec(0, 0, dat.Length); var palette = wr.Palette(info.ShadowPalette); - return new IRenderable[] { new SpriteRenderable(shadow.Image, pos, info.ShadowOffset, info.ShadowZOffset, palette, 1, true) }; + return new IRenderable[] { new SpriteRenderable(shadow.Image, pos, info.ShadowOffset, info.ShadowZOffset, palette, 1, true, shadow.CurrentSequence.IgnoreWorldTint) }; } IEnumerable IRender.ScreenBounds(Actor self, WorldRenderer wr) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Collections.Generic; -using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; using OpenRA.Traits; @@ -20,11 +19,12 @@ [Desc("Play an animation when a unit exits or blocks the exit after production finished.")] class WithProductionDoorOverlayInfo : ConditionalTraitInfo, IRenderActorPreviewSpritesInfo, Requires, Requires, Requires { + [SequenceReference] public readonly string Sequence = "build-door"; public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { - var anim = new Animation(init.World, image, () => 0); + var anim = new Animation(init.World, image); anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence), () => 0); var bi = init.Actor.TraitInfo(); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithProductionOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithProductionOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithProductionOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithProductionOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -30,7 +30,7 @@ [Desc("Position relative to body")] public readonly WVec Offset = WVec.Zero; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithRangeCircle.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithRangeCircle.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithRangeCircle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithRangeCircle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,12 +28,21 @@ [Desc("Color of the circle")] public readonly Color Color = Color.FromArgb(128, Color.White); + [Desc("Border width.")] + public readonly float Width = 1; + + [Desc("Color of the border.")] + public readonly Color BorderColor = Color.FromArgb(96, Color.Black); + + [Desc("Range circle border width.")] + public readonly float BorderWidth = 3; + [Desc("If set, the color of the owning player will be used instead of `Color`.")] public readonly bool UsePlayerColor = false; - [Desc("Stances of players which will be able to see the circle.", + [Desc("Player relationships which will be able to see the circle.", "Valid values are combinations of `None`, `Ally`, `Enemy` and `Neutral`.")] - public readonly Stance ValidStances = Stance.Ally; + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally; [Desc("When to show the range circle. Valid values are `Always`, and `WhenSelected`")] public readonly RangeCircleVisibility Visible = RangeCircleVisibility.WhenSelected; @@ -50,7 +59,9 @@ Range, 0, Color, - Color.FromArgb(96, Color.Black)); + Width, + BorderColor, + BorderWidth); foreach (var a in w.ActorsWithTrait()) if (a.Trait.Info.Type == Type) @@ -62,7 +73,7 @@ public override object Create(ActorInitializer init) { return new WithRangeCircle(init.Self, this); } } - class WithRangeCircle : ConditionalTrait, IRenderAnnotationsWhenSelected, IRenderAboveShroud + class WithRangeCircle : ConditionalTrait, IRenderAnnotationsWhenSelected, IRenderAnnotations { readonly Actor self; @@ -80,7 +91,7 @@ return false; var p = self.World.RenderPlayer; - return p == null || Info.ValidStances.HasStance(self.Owner.Stances[p]) || (p.Spectating && !p.NonCombatant); + return p == null || Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p)) || (p.Spectating && !p.NonCombatant); } } @@ -92,7 +103,9 @@ Info.Range, 0, Info.UsePlayerColor ? self.Owner.Color : Info.Color, - Color.FromArgb(96, Color.Black)); + Info.Width, + Info.BorderColor, + Info.BorderWidth); } IEnumerable IRenderAnnotationsWhenSelected.RenderAnnotations(Actor self, WorldRenderer wr) @@ -102,11 +115,11 @@ bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return false; } } - IEnumerable IRenderAboveShroud.RenderAboveShroud(Actor self, WorldRenderer wr) + IEnumerable IRenderAnnotations.RenderAnnotations(Actor self, WorldRenderer wr) { return RenderRangeCircle(self, wr, RangeCircleVisibility.Always); } - bool IRenderAboveShroud.SpatiallyPartitionable { get { return false; } } + bool IRenderAnnotations.SpatiallyPartitionable { get { return false; } } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithRepairOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithRepairOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithRepairOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithRepairOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ [Desc("Displays an overlay when the building is being repaired by the player.")] public class WithRepairOverlayInfo : PausableConditionalTraitInfo, Requires, Requires { - [SequenceReference("Image")] + [SequenceReference] [Desc("Sequence to use upon repair beginning.")] public readonly string StartSequence = null; @@ -26,14 +26,14 @@ [Desc("Sequence name to play once during repair intervals or repeatedly if a start sequence is set.")] public readonly string Sequence = "active"; - [SequenceReference("Image")] + [SequenceReference] [Desc("Sequence to use after repairing has finished.")] public readonly string EndSequence = null; [Desc("Position relative to body")] public readonly WVec Offset = WVec.Zero; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithResourceLevelOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithResourceLevelOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithResourceLevelOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithResourceLevelOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,7 +21,7 @@ [Desc("Sequence name to use")] public readonly string Sequence = "resources"; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name.")] public readonly string Palette = null; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithResourceLevelSpriteBody.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithResourceLevelSpriteBody.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithResourceLevelSpriteBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithResourceLevelSpriteBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Collections.Generic; -using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; using OpenRA.Traits; @@ -43,7 +42,7 @@ PlayerResources playerResources; public WithResourceLevelSpriteBody(ActorInitializer init, WithResourceLevelSpriteBodyInfo info) - : base(init, info, () => 0) + : base(init, info) { this.info = info; playerResources = init.Self.Owner.PlayerActor.Trait(); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithResourceStoragePipsDecoration.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithResourceStoragePipsDecoration.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithResourceStoragePipsDecoration.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithResourceStoragePipsDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,79 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + public class WithResourceStoragePipsDecorationInfo : WithDecorationBaseInfo + { + [FieldLoader.Require] + [Desc("Number of pips to display how filled unit is.")] + public readonly int PipCount = 0; + + [Desc("If non-zero, override the spacing between adjacing pips.")] + public readonly int2 PipStride = int2.Zero; + + [Desc("Image that defines the pip sequences.")] + public readonly string Image = "pips"; + + [SequenceReference(nameof(Image))] + [Desc("Sequence used for empty pips.")] + public readonly string EmptySequence = "pip-empty"; + + [SequenceReference(nameof(Image))] + [Desc("Sequence used for full pips.")] + public readonly string FullSequence = "pip-green"; + + [PaletteReference] + public readonly string Palette = "chrome"; + + public override object Create(ActorInitializer init) { return new WithResourceStoragePipsDecoration(init.Self, this); } + } + + public class WithResourceStoragePipsDecoration : WithDecorationBase, INotifyOwnerChanged + { + readonly Animation pips; + PlayerResources player; + + public WithResourceStoragePipsDecoration(Actor self, WithResourceStoragePipsDecorationInfo info) + : base(self, info) + { + player = self.Owner.PlayerActor.Trait(); + pips = new Animation(self.World, info.Image); + } + + protected override IEnumerable RenderDecoration(Actor self, WorldRenderer wr, int2 screenPos) + { + pips.PlayRepeating(Info.EmptySequence); + + var palette = wr.Palette(Info.Palette); + var pipSize = pips.Image.Size.XY.ToInt2(); + var pipStride = Info.PipStride != int2.Zero ? Info.PipStride : new int2(pipSize.X, 0); + + screenPos -= pipSize / 2; + for (var i = 0; i < Info.PipCount; i++) + { + pips.PlayRepeating(player.Resources * Info.PipCount > i * player.ResourceCapacity ? Info.FullSequence : Info.EmptySequence); + yield return new UISpriteRenderable(pips.Image, self.CenterPosition, screenPos, 0, palette, 1f); + + screenPos += pipStride; + } + } + + void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) + { + player = newOwner.PlayerActor.Trait(); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithResupplyAnimation.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithResupplyAnimation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithResupplyAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithResupplyAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System; using System.Linq; using OpenRA.Traits; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSpriteBarrel.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSpriteBarrel.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSpriteBarrel.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSpriteBarrel.cs 2021-03-21 11:10:05.000000000 +0000 @@ -45,12 +45,12 @@ var t = init.Actor.TraitInfos() .First(tt => tt.Turret == armament.Turret); - var turretFacing = Turreted.TurretFacingFromInit(init, t.InitialFacing, armament.Turret); + var turretFacing = t.WorldFacingFromInit(init); var anim = new Animation(init.World, image, turretFacing); anim.Play(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence)); - Func facing = init.GetFacing(); - Func orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings); + var facing = init.GetFacing(); + Func orientation = () => body.QuantizeOrientation(WRot.FromYaw(facing()), facings); Func turretOffset = () => body.LocalToWorld(t.Offset.Rotate(orientation())); Func zOffset = () => { @@ -82,7 +82,7 @@ .First(tt => tt.Name == armament.Info.Turret); rs = self.Trait(); - DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => turreted.TurretFacing); + DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => turreted.WorldOrientation.Yaw); DefaultAnimation.PlayRepeating(NormalizeSequence(self, Info.Sequence)); rs.Add(new AnimationWithOffset( DefaultAnimation, () => BarrelOffset(), () => IsTraitDisabled, p => RenderUtils.ZOffsetFromCenter(self, p, 0))); @@ -98,21 +98,10 @@ WVec BarrelOffset() { + var orientation = turreted != null ? turreted.WorldOrientation : self.Orientation; var localOffset = Info.LocalOffset + new WVec(-armament.Recoil, WDist.Zero, WDist.Zero); - var turretOffset = turreted != null ? turreted.Position(self) : WVec.Zero; - var quantizedBody = body.QuantizeOrientation(self, self.Orientation); - var turretOrientation = turreted != null ? turreted.WorldOrientation(self) - quantizedBody : WRot.Zero; - - var quantizedTurret = body.QuantizeOrientation(self, turretOrientation); - return turretOffset + body.LocalToWorld(localOffset.Rotate(quantizedTurret).Rotate(quantizedBody)); - } - - IEnumerable BarrelRotation() - { - var b = self.Orientation; - var qb = body.QuantizeOrientation(self, b); - yield return turreted.WorldOrientation(self) - qb + WRot.FromYaw(b.Yaw - qb.Yaw); - yield return qb; + var turretLocalOffset = turreted != null ? turreted.Offset : WVec.Zero; + return body.LocalToWorld(turretLocalOffset + localOffset.Rotate(orientation)); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -56,9 +56,9 @@ readonly Animation boundsAnimation; public WithSpriteBody(ActorInitializer init, WithSpriteBodyInfo info) - : this(init, info, () => 0) { } + : this(init, info, () => WAngle.Zero) { } - protected WithSpriteBody(ActorInitializer init, WithSpriteBodyInfo info, Func baseFacing) + protected WithSpriteBody(ActorInitializer init, WithSpriteBodyInfo info, Func baseFacing) : base(info) { rs = init.Self.Trait(); @@ -97,8 +97,7 @@ DefaultAnimation.PlayThen(NormalizeSequence(self, name), () => { CancelCustomAnimation(self); - if (after != null) - after(); + after?.Invoke(); }); } @@ -112,8 +111,7 @@ DefaultAnimation.PlayBackwardsThen(NormalizeSequence(self, name), () => { CancelCustomAnimation(self); - if (after != null) - after(); + after?.Invoke(); }); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSpriteControlGroupDecoration.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSpriteControlGroupDecoration.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSpriteControlGroupDecoration.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSpriteControlGroupDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,77 +17,56 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Renders Ctrl groups using pixel art.")] - public class WithSpriteControlGroupDecorationInfo : ITraitInfo, Requires + public class WithSpriteControlGroupDecorationInfo : TraitInfo { [PaletteReference] public readonly string Palette = "chrome"; public readonly string Image = "pips"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] [Desc("Sprite sequence used to render the control group 0-9 numbers.")] public readonly string GroupSequence = "groups"; - [Desc("Point in the actor's selection box used as reference for offsetting the decoration image. " + - "Possible values are combinations of Center, Top, Bottom, Left, Right.")] - public readonly ReferencePoints ReferencePoint = ReferencePoints.Top | ReferencePoints.Left; + [Desc("Position in the actor's selection box to draw the decoration.")] + public readonly string Position = "TopLeft"; - public object Create(ActorInitializer init) { return new WithSpriteControlGroupDecoration(init.Self, this); } + [Desc("Offset sprite center position from the selection box edge.")] + public readonly int2 Margin = int2.Zero; + + public override object Create(ActorInitializer init) { return new WithSpriteControlGroupDecoration(init.Self, this); } } - public class WithSpriteControlGroupDecoration : IRenderAnnotationsWhenSelected + public class WithSpriteControlGroupDecoration : IDecoration { public readonly WithSpriteControlGroupDecorationInfo Info; - readonly IDecorationBounds[] decorationBounds; - readonly Animation pipImages; + readonly Actor self; + readonly Animation anim; public WithSpriteControlGroupDecoration(Actor self, WithSpriteControlGroupDecorationInfo info) { Info = info; + this.self = self; - decorationBounds = self.TraitsImplementing().ToArray(); - pipImages = new Animation(self.World, Info.Image); - } - - IEnumerable IRenderAnnotationsWhenSelected.RenderAnnotations(Actor self, WorldRenderer wr) - { - if (self.Owner != wr.World.LocalPlayer) - yield break; - - if (self.World.FogObscures(self)) - yield break; - - var pal = wr.Palette(Info.Palette); - foreach (var r in DrawControlGroup(self, wr, pal)) - yield return r; + anim = new Animation(self.World, Info.Image); } - bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return true; } } + bool IDecoration.RequiresSelection { get { return true; } } - IEnumerable DrawControlGroup(Actor self, WorldRenderer wr, PaletteReference palette) + IEnumerable IDecoration.RenderDecoration(Actor self, WorldRenderer wr, ISelectionDecorations container) { var group = self.World.Selection.GetControlGroupForActor(self); if (group == null) - yield break; - - pipImages.PlayFetchIndex(Info.GroupSequence, () => (int)group); - - var bounds = decorationBounds.FirstNonEmptyBounds(self, wr); - var boundsOffset = 0.5f * new float2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom); - if (Info.ReferencePoint.HasFlag(ReferencePoints.Top)) - boundsOffset -= new float2(0, 0.5f * bounds.Height); - - if (Info.ReferencePoint.HasFlag(ReferencePoints.Bottom)) - boundsOffset += new float2(0, 0.5f * bounds.Height); - - if (Info.ReferencePoint.HasFlag(ReferencePoints.Left)) - boundsOffset -= new float2(0.5f * bounds.Width, 0); + return Enumerable.Empty(); - if (Info.ReferencePoint.HasFlag(ReferencePoints.Right)) - boundsOffset += new float2(0.5f * bounds.Width, 0); + anim.PlayFetchIndex(Info.GroupSequence, () => (int)group); - var pxPos = wr.Viewport.WorldToViewPx(boundsOffset.ToInt2()) - (0.5f * pipImages.Image.Size.XY).ToInt2(); - yield return new UISpriteRenderable(pipImages.Image, self.CenterPosition, pxPos, 0, palette, 1f); + var screenPos = container.GetDecorationOrigin(self, wr, Info.Position, Info.Margin) - (0.5f * anim.Image.Size.XY).ToInt2(); + var palette = wr.Palette(Info.Palette); + return new IRenderable[] + { + new UISpriteRenderable(anim.Image, self.CenterPosition, screenPos, 0, palette, 1f) + }; } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,7 +26,7 @@ [Desc("Sequence name to use")] public readonly string Sequence = "turret"; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; @@ -50,12 +50,12 @@ var t = init.Actor.TraitInfos() .First(tt => tt.Turret == Turret); - var turretFacing = Turreted.TurretFacingFromInit(init, t.InitialFacing, Turret); + var turretFacing = t.WorldFacingFromInit(init); var anim = new Animation(init.World, image, turretFacing); anim.Play(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence)); - Func facing = init.GetFacing(); - Func orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings); + var facing = init.GetFacing(); + Func orientation = () => body.QuantizeOrientation(WRot.FromYaw(facing()), facings); Func offset = () => body.LocalToWorld(t.Offset.Rotate(orientation())); Func zOffset = () => { @@ -64,7 +64,7 @@ }; if (IsPlayerPalette) - p = init.WorldRenderer.Palette(Palette + init.Get().PlayerName); + p = init.WorldRenderer.Palette(Palette + init.Get().InternalName); else if (Palette != null) p = init.WorldRenderer.Palette(Palette); @@ -90,7 +90,7 @@ arms = self.TraitsImplementing() .Where(w => w.Info.Turret == info.Turret).ToArray(); - DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => t.TurretFacing); + DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => t.WorldOrientation.Yaw); DefaultAnimation.PlayRepeating(NormalizeSequence(self, info.Sequence)); rs.Add(new AnimationWithOffset(DefaultAnimation, () => TurretOffset(self), @@ -106,10 +106,11 @@ if (!Info.Recoils) return t.Position(self); - var recoil = arms.Aggregate(WDist.Zero, (a, b) => a + b.Recoil); - var localOffset = new WVec(-recoil, WDist.Zero, WDist.Zero); - var quantizedWorldTurret = t.WorldOrientation(self); - return t.Position(self) + body.LocalToWorld(localOffset.Rotate(quantizedWorldTurret)); + var recoilDist = 0; + foreach (var arm in arms) + recoilDist += arm.Recoil.Length; + var recoil = new WVec(new WDist(-recoilDist), WDist.Zero, WDist.Zero); + return t.Position(self) + body.LocalToWorld(recoil.Rotate(t.WorldOrientation)); } public string NormalizeSequence(Actor self, string sequence) @@ -133,8 +134,7 @@ DefaultAnimation.PlayThen(NormalizeSequence(self, name), () => { CancelCustomAnimation(self); - if (after != null) - after(); + after?.Invoke(); }); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSupportPowerActivationAnimation.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSupportPowerActivationAnimation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSupportPowerActivationAnimation.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSupportPowerActivationAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,53 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + [Desc("Replaces the building animation when a support power is triggered.")] + public class WithSupportPowerActivationAnimationInfo : ConditionalTraitInfo, Requires + { + [SequenceReference] + [Desc("Sequence name to use")] + public readonly string Sequence = "active"; + + [Desc("Which sprite body to play the animation on.")] + public readonly string Body = "body"; + + public override object Create(ActorInitializer init) { return new WithSupportPowerActivationAnimation(init.Self, this); } + } + + public class WithSupportPowerActivationAnimation : ConditionalTrait, INotifySupportPower + { + readonly WithSpriteBody wsb; + + public WithSupportPowerActivationAnimation(Actor self, WithSupportPowerActivationAnimationInfo info) + : base(info) + { + wsb = self.TraitsImplementing().Single(w => w.Info.Name == Info.Body); + } + + void INotifySupportPower.Charged(Actor self) { } + + void INotifySupportPower.Activated(Actor self) + { + if (!IsTraitDisabled) + wsb.PlayCustomAnimation(self, Info.Sequence, () => wsb.CancelCustomAnimation(self)); + } + + protected override void TraitDisabled(Actor self) + { + wsb.CancelCustomAnimation(self); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSupportPowerActivationOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSupportPowerActivationOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithSupportPowerActivationOverlay.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithSupportPowerActivationOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,67 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + [Desc("Displays an overlay when a support power is triggered.")] + public class WithSupportPowerActivationOverlayInfo : ConditionalTraitInfo, Requires, Requires + { + [SequenceReference] + [Desc("Sequence name to use")] + public readonly string Sequence = "active"; + + [Desc("Position relative to body")] + public readonly WVec Offset = WVec.Zero; + + [PaletteReference(nameof(IsPlayerPalette))] + [Desc("Custom palette name")] + public readonly string Palette = null; + + [Desc("Custom palette is a player palette BaseName")] + public readonly bool IsPlayerPalette = false; + + public override object Create(ActorInitializer init) { return new WithSupportPowerActivationOverlay(init.Self, this); } + } + + public class WithSupportPowerActivationOverlay : ConditionalTrait, INotifySupportPower + { + readonly Animation overlay; + bool visible; + + public WithSupportPowerActivationOverlay(Actor self, WithSupportPowerActivationOverlayInfo info) + : base(info) + { + var rs = self.Trait(); + var body = self.Trait(); + + overlay = new Animation(self.World, rs.GetImage(self)); + overlay.PlayThen(info.Sequence, () => visible = false); + + var anim = new AnimationWithOffset(overlay, + () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), + () => IsTraitDisabled || !visible, + p => RenderUtils.ZOffsetFromCenter(self, p, 1)); + + rs.Add(anim, info.Palette, info.IsPlayerPalette); + } + + void INotifySupportPower.Charged(Actor self) { } + + void INotifySupportPower.Activated(Actor self) + { + visible = true; + overlay.PlayThen(overlay.CurrentSequence.Name, () => visible = false); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,13 +13,14 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; +using OpenRA.Mods.Common.Widgets; using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits.Render { [Desc("Renders Ctrl groups using typeface.")] - public class WithTextControlGroupDecorationInfo : ITraitInfo, IRulesetLoaded, Requires + public class WithTextControlGroupDecorationInfo : TraitInfo, IRulesetLoaded { public readonly string Font = "TinyBold"; @@ -29,15 +30,11 @@ [Desc("Use the player color of the current owner.")] public readonly bool UsePlayerColor = false; - [Desc("The Z offset to apply when rendering this decoration.")] - public readonly int ZOffset = 1; + [Desc("Position in the actor's selection box to draw the decoration.")] + public readonly string Position = "TopLeft"; - [Desc("Point in the actor's selection box used as reference for offsetting the decoration image. " + - "Possible values are combinations of Center, Top, Bottom, Left, Right.")] - public readonly ReferencePoints ReferencePoint = ReferencePoints.Bottom | ReferencePoints.Left; - - [Desc("Manual offset in screen pixel.")] - public readonly int2 ScreenOffset = new int2(2, -2); + [Desc("Offset text center position from the selection box edge.")] + public readonly int2 Margin = int2.Zero; void IRulesetLoaded.RulesetLoaded(Ruleset rules, ActorInfo info) { @@ -45,79 +42,41 @@ throw new YamlException("Font '{0}' is not listed in the mod.yaml's Fonts section".F(Font)); } - public object Create(ActorInitializer init) { return new WithTextControlGroupDecoration(init.Self, this); } + public override object Create(ActorInitializer init) { return new WithTextControlGroupDecoration(init.Self, this); } } - public class WithTextControlGroupDecoration : IRenderAnnotationsWhenSelected, INotifyOwnerChanged + public class WithTextControlGroupDecoration : IDecoration, INotifyOwnerChanged { readonly WithTextControlGroupDecorationInfo info; - readonly IDecorationBounds[] decorationBounds; readonly SpriteFont font; + readonly Actor self; + readonly CachedTransform label; Color color; public WithTextControlGroupDecoration(Actor self, WithTextControlGroupDecorationInfo info) { this.info = info; - - if (!Game.Renderer.Fonts.TryGetValue(info.Font, out font)) - throw new YamlException("Font '{0}' is not listed in the mod.yaml's Fonts section".F(info.Font)); - - decorationBounds = self.TraitsImplementing().ToArray(); + this.self = self; + font = Game.Renderer.Fonts[info.Font]; color = info.UsePlayerColor ? self.Owner.Color : info.Color; + label = new CachedTransform(g => g.ToString()); } - IEnumerable IRenderAnnotationsWhenSelected.RenderAnnotations(Actor self, WorldRenderer wr) - { - if (self.Owner != wr.World.LocalPlayer) - yield break; - - if (self.World.FogObscures(self)) - yield break; - - foreach (var r in DrawControlGroup(self, wr)) - yield return r; - } - - bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return true; } } + bool IDecoration.RequiresSelection { get { return true; } } - IEnumerable DrawControlGroup(Actor self, WorldRenderer wr) + IEnumerable IDecoration.RenderDecoration(Actor self, WorldRenderer wr, ISelectionDecorations container) { var group = self.World.Selection.GetControlGroupForActor(self); if (group == null) - yield break; - - var bounds = decorationBounds.FirstNonEmptyBounds(self, wr); - var number = group.Value.ToString(); - var halfSize = font.Measure(number) / 2; - - var boundsOffset = new int2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom) / 2; - var sizeOffset = int2.Zero; - if (info.ReferencePoint.HasFlag(ReferencePoints.Top)) - { - boundsOffset -= new int2(0, bounds.Height / 2); - sizeOffset += new int2(0, halfSize.Y); - } - else if (info.ReferencePoint.HasFlag(ReferencePoints.Bottom)) - { - boundsOffset += new int2(0, bounds.Height / 2); - sizeOffset -= new int2(0, halfSize.Y); - } + return Enumerable.Empty(); - if (info.ReferencePoint.HasFlag(ReferencePoints.Left)) + var text = label.Update(group.Value); + var screenPos = container.GetDecorationOrigin(self, wr, info.Position, info.Margin); + return new IRenderable[] { - boundsOffset -= new int2(bounds.Width / 2, 0); - sizeOffset += new int2(halfSize.X, 0); - } - else if (info.ReferencePoint.HasFlag(ReferencePoints.Right)) - { - boundsOffset += new int2(bounds.Width / 2, 0); - sizeOffset -= new int2(halfSize.X, 0); - } - - var screenPos = boundsOffset + sizeOffset + info.ScreenOffset; - - yield return new TextAnnotationRenderable(font, wr.ProjectedPosition(screenPos), info.ZOffset, color, number); + new UITextRenderable(font, self.CenterPosition, screenPos, 0, color, text) + }; } void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits.Render { [Desc("Displays a text overlay relative to the selection box.")] - public class WithTextDecorationInfo : ConditionalTraitInfo, Requires + public class WithTextDecorationInfo : WithDecorationBaseInfo { [Translate] [FieldLoader.Require] @@ -33,19 +33,6 @@ [Desc("Use the player color of the current owner.")] public readonly bool UsePlayerColor = false; - [Desc("Point in the actor's selection box used as reference for offsetting the decoration image. " + - "Possible values are combinations of Center, Top, Bottom, Left, Right.")] - public readonly ReferencePoints ReferencePoint = ReferencePoints.Top | ReferencePoints.Left; - - [Desc("The Z offset to apply when rendering this decoration.")] - public readonly int ZOffset = 1; - - [Desc("Player stances who can view the decoration.")] - public readonly Stance ValidStances = Stance.Ally; - - [Desc("Should this be visible only when selected?")] - public readonly bool RequiresSelection = false; - public override object Create(ActorInitializer init) { return new WithTextDecoration(init.Self, this); } public override void RulesetLoaded(Ruleset rules, ActorInfo ai) @@ -57,79 +44,28 @@ } } - public class WithTextDecoration : ConditionalTrait, IRenderAnnotations, IRenderAnnotationsWhenSelected, INotifyOwnerChanged + public class WithTextDecoration : WithDecorationBase, INotifyOwnerChanged { readonly SpriteFont font; - readonly IDecorationBounds[] decorationBounds; Color color; public WithTextDecoration(Actor self, WithTextDecorationInfo info) - : base(info) + : base(self, info) { font = Game.Renderer.Fonts[info.Font]; - decorationBounds = self.TraitsImplementing().ToArray(); - color = Info.UsePlayerColor ? self.Owner.Color : Info.Color; - } - - public virtual bool ShouldRender(Actor self) { return true; } - - IEnumerable IRenderAnnotations.RenderAnnotations(Actor self, WorldRenderer wr) - { - return !Info.RequiresSelection ? RenderInner(self, wr) : SpriteRenderable.None; + color = info.UsePlayerColor ? self.Owner.Color : info.Color; } - public bool SpatiallyPartitionable { get { return true; } } - - IEnumerable IRenderAnnotationsWhenSelected.RenderAnnotations(Actor self, WorldRenderer wr) + protected override IEnumerable RenderDecoration(Actor self, WorldRenderer wr, int2 screenPos) { - return Info.RequiresSelection ? RenderInner(self, wr) : SpriteRenderable.None; - } - - bool IRenderAnnotationsWhenSelected.SpatiallyPartitionable { get { return true; } } - - IEnumerable RenderInner(Actor self, WorldRenderer wr) - { - if (IsTraitDisabled || self.IsDead || !self.IsInWorld) - return Enumerable.Empty(); - - if (self.World.RenderPlayer != null) - { - var stance = self.Owner.Stances[self.World.RenderPlayer]; - if (!Info.ValidStances.HasStance(stance)) - return Enumerable.Empty(); - } - - if (!ShouldRender(self) || self.World.FogObscures(self)) + if (IsTraitDisabled || self.IsDead || !self.IsInWorld || !ShouldRender(self)) return Enumerable.Empty(); - var bounds = decorationBounds.FirstNonEmptyBounds(self, wr); - var halfSize = font.Measure(Info.Text) / 2; - - var boundsOffset = new int2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom) / 2; - var sizeOffset = int2.Zero; - if (Info.ReferencePoint.HasFlag(ReferencePoints.Top)) + var size = font.Measure(Info.Text); + return new IRenderable[] { - boundsOffset -= new int2(0, bounds.Height / 2); - sizeOffset += new int2(0, halfSize.Y); - } - else if (Info.ReferencePoint.HasFlag(ReferencePoints.Bottom)) - { - boundsOffset += new int2(0, bounds.Height / 2); - sizeOffset -= new int2(0, halfSize.Y); - } - - if (Info.ReferencePoint.HasFlag(ReferencePoints.Left)) - { - boundsOffset -= new int2(bounds.Width / 2, 0); - sizeOffset += new int2(halfSize.X, 0); - } - else if (Info.ReferencePoint.HasFlag(ReferencePoints.Right)) - { - boundsOffset += new int2(bounds.Width / 2, 0); - sizeOffset -= new int2(halfSize.X, 0); - } - - return new IRenderable[] { new TextAnnotationRenderable(font, wr.ProjectedPosition(boundsOffset + sizeOffset), Info.ZOffset, color, Info.Text) }; + new UITextRenderable(font, self.CenterPosition, screenPos - size / 2, 0, color, Info.Text) + }; } void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithTurretAttackAnimation.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithTurretAttackAnimation.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithTurretAttackAnimation.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithTurretAttackAnimation.cs 2021-03-21 11:10:05.000000000 +0000 @@ -64,13 +64,13 @@ PlayAttackAnimation(self); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (!IsTraitDisabled && a == armament && Info.DelayRelativeTo == AttackDelayType.Attack) NotifyAttack(self); } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { if (!IsTraitDisabled && a == armament && Info.DelayRelativeTo == AttackDelayType.Preparation) NotifyAttack(self); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithVoxelBarrel.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithVoxelBarrel.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithVoxelBarrel.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithVoxelBarrel.cs 2021-03-21 11:10:05.000000000 +0000 @@ -30,7 +30,7 @@ public readonly WVec LocalOffset = WVec.Zero; [Desc("Rotate the barrel relative to the body")] - public readonly WRot LocalOrientation = WRot.Zero; + public readonly WRot LocalOrientation = WRot.None; [Desc("Defines if the Voxel should have a shadow.")] public readonly bool ShowShadow = true; @@ -51,15 +51,11 @@ var model = init.World.ModelCache.GetModelSequence(image, Sequence); - var turretFacing = Turreted.TurretFacingFromInit(init, t.InitialFacing, t.Turret); - Func turretOrientation = () => body.QuantizeOrientation(WRot.FromYaw(WAngle.FromFacing(turretFacing()) - orientation().Yaw), facings); + var turretOrientation = t.PreviewOrientation(init, orientation, facings); + Func barrelOffset = () => body.LocalToWorld(t.Offset + LocalOffset.Rotate(turretOrientation())); + Func barrelOrientation = () => LocalOrientation.Rotate(turretOrientation()); - Func quantizedTurret = () => body.QuantizeOrientation(turretOrientation(), facings); - Func quantizedBody = () => body.QuantizeOrientation(orientation(), facings); - Func barrelOffset = () => body.LocalToWorld((t.Offset + LocalOffset.Rotate(quantizedTurret())).Rotate(quantizedBody())); - - yield return new ModelAnimation(model, barrelOffset, () => new[] { turretOrientation(), orientation() }, - () => false, () => 0, ShowShadow); + yield return new ModelAnimation(model, barrelOffset, barrelOrientation, () => false, () => 0, ShowShadow); } } @@ -88,22 +84,20 @@ WVec BarrelOffset() { - var b = self.Orientation; - var qb = body.QuantizeOrientation(self, b); + // Barrel offset in turret coordinates var localOffset = Info.LocalOffset + new WVec(-armament.Recoil, WDist.Zero, WDist.Zero); - var turretLocalOffset = turreted != null ? turreted.Offset : WVec.Zero; - var turretOrientation = turreted != null ? turreted.WorldOrientation(self) - b + WRot.FromYaw(b.Yaw - qb.Yaw) : WRot.Zero; - return body.LocalToWorld((turretLocalOffset + localOffset.Rotate(turretOrientation)).Rotate(qb)); + // Turret coordinates to body coordinates + var bodyOrientation = body.QuantizeOrientation(self, self.Orientation); + localOffset = localOffset.Rotate(turreted.WorldOrientation) + turreted.Offset.Rotate(bodyOrientation); + + // Body coordinates to world coordinates + return body.LocalToWorld(localOffset); } - IEnumerable BarrelRotation() + WRot BarrelRotation() { - var b = self.Orientation; - var qb = body.QuantizeOrientation(self, b); - yield return Info.LocalOrientation; - yield return turreted.WorldOrientation(self) - b + WRot.FromYaw(b.Yaw - qb.Yaw); - yield return qb; + return Info.LocalOrientation.Rotate(turreted.WorldOrientation); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -34,7 +34,7 @@ var body = init.Actor.TraitInfo(); var model = init.World.ModelCache.GetModelSequence(image, Sequence); yield return new ModelAnimation(model, () => WVec.Zero, - () => new[] { body.QuantizeOrientation(orientation(), facings) }, + () => body.QuantizeOrientation(orientation(), facings), () => false, () => 0, ShowShadow); } } @@ -52,7 +52,7 @@ var model = self.World.ModelCache.GetModelSequence(rv.Image, info.Sequence); modelAnimation = new ModelAnimation(model, () => WVec.Zero, - () => new[] { body.QuantizeOrientation(self, self.Orientation) }, + () => body.QuantizeOrientation(self, self.Orientation), () => IsTraitDisabled, () => 0, info.ShowShadow); rv.Add(modelAnimation); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithVoxelTurret.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithVoxelTurret.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithVoxelTurret.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithVoxelTurret.cs 2021-03-21 11:10:05.000000000 +0000 @@ -37,17 +37,13 @@ if (!EnabledByDefault) yield break; - var body = init.Actor.TraitInfo(); var t = init.Actor.TraitInfos() .First(tt => tt.Turret == Turret); var model = init.World.ModelCache.GetModelSequence(image, Sequence); - Func turretOffset = () => body.LocalToWorld(t.Offset.Rotate(orientation())); - - var turretFacing = Turreted.TurretFacingFromInit(init, t.InitialFacing, Turret); - Func turretBodyOrientation = () => WRot.FromYaw(WAngle.FromFacing(turretFacing()) - orientation().Yaw); - yield return new ModelAnimation(model, turretOffset, - () => new[] { turretBodyOrientation(), body.QuantizeOrientation(orientation(), facings) }, () => false, () => 0, ShowShadow); + var turretOffset = t.PreviewPosition(init, orientation); + var turretOrientation = t.PreviewOrientation(init, orientation, facings); + yield return new ModelAnimation(model, turretOffset, turretOrientation, () => false, () => 0, ShowShadow); } } @@ -67,16 +63,8 @@ var rv = self.Trait(); rv.Add(new ModelAnimation(self.World.ModelCache.GetModelSequence(rv.Image, Info.Sequence), - () => turreted.Position(self), TurretRotation, + () => turreted.Position(self), () => turreted.WorldOrientation, () => IsTraitDisabled, () => 0, info.ShowShadow)); } - - IEnumerable TurretRotation() - { - var b = self.Orientation; - var qb = body.QuantizeOrientation(self, b); - yield return turreted.WorldOrientation(self) - b + WRot.FromYaw(b.Yaw - qb.Yaw); - yield return qb; - } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Render/WithWallSpriteBody.cs openra-20210321/OpenRA.Mods.Common/Traits/Render/WithWallSpriteBody.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Render/WithWallSpriteBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Render/WithWallSpriteBody.cs 2021-03-21 11:10:05.000000000 +0000 @@ -37,15 +37,13 @@ yield break; var adjacent = 0; + var locationInit = init.GetOrDefault(); + var neighbourInit = init.GetOrDefault(); - if (init.Contains()) + if (locationInit != null && neighbourInit != null) { - var location = CPos.Zero; - if (init.Contains()) - location = init.Get(); - - var neighbours = init.Get>(); - foreach (var kv in neighbours) + var location = locationInit.Value; + foreach (var kv in neighbourInit.Value) { var haveNeighbour = false; foreach (var n in kv.Value) @@ -72,7 +70,7 @@ } } - var anim = new Animation(init.World, image, () => 0); + var anim = new Animation(init.World, image); anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence), () => adjacent); yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale); @@ -99,13 +97,16 @@ void IWallConnector.SetDirty() { dirty = true; } public WithWallSpriteBody(ActorInitializer init, WithWallSpriteBodyInfo info) - : base(init, info, () => 0) + : base(init, info) { wallInfo = info; } protected override void DamageStateChanged(Actor self) { + if (IsTraitDisabled) + return; + DefaultAnimation.PlayFetchIndex(NormalizeSequence(self, Info.Sequence), () => adjacent); } @@ -121,9 +122,8 @@ adjacent = 0; foreach (var a in adjacentActors) { - CVec facing; var wc = a.TraitsImplementing().FirstEnabledTraitOrDefault(); - if (wc == null || !wc.AdjacentWallCanConnect(a, self.Location, wallInfo.Type, out facing)) + if (wc == null || !wc.AdjacentWallCanConnect(a, self.Location, wallInfo.Type, out var facing)) continue; if (facing.Y > 0) @@ -167,13 +167,9 @@ } } - public class RuntimeNeighbourInit : IActorInit>, ISuppressInitExport + public class RuntimeNeighbourInit : ValueActorInit>, ISuppressInitExport, ISingleInstanceInit { - [FieldFromYamlKey] - readonly Dictionary value = null; - - public RuntimeNeighbourInit() { } - public RuntimeNeighbourInit(Dictionary init) { value = init; } - public Dictionary Value(World world) { return value; } + public RuntimeNeighbourInit(Dictionary value) + : base(value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Repairable.cs openra-20210321/OpenRA.Mods.Common/Traits/Repairable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Repairable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Repairable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,17 +11,15 @@ using System.Collections.Generic; using System.Linq; -using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; -using OpenRA.Primitives; using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("This actor can be sent to a structure for repairs.")] - public class RepairableInfo : ITraitInfo, Requires, Requires, IObservesVariablesInfo + public class RepairableInfo : TraitInfo, Requires, Requires, IObservesVariablesInfo { [ActorReference] [FieldLoader.Require] @@ -37,7 +35,13 @@ [Desc("Boolean expression defining the condition under which the regular (non-force) enter cursor is disabled.")] public readonly BooleanExpression RequireForceMoveCondition = null; - public virtual object Create(ActorInitializer init) { return new Repairable(init.Self, this); } + [Desc("Cursor to display when able to be repaired at target actor.")] + public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to be repaired at target actor.")] + public readonly string EnterBlockedCursor = "enter-blocked"; + + public override object Create(ActorInitializer init) { return new Repairable(init.Self, this); } } public class Repairable : IIssueOrder, IResolveOrder, IOrderVoice, INotifyCreated, IObservesVariables @@ -65,11 +69,17 @@ get { if (!isAircraft) - yield return new EnterAlliedActorTargeter("Repair", 5, CanRepairAt, _ => CanRepair() || CanRearm()); + yield return new EnterAlliedActorTargeter( + "Repair", + 5, + Info.EnterCursor, + Info.EnterBlockedCursor, + CanRepairAt, + _ => CanRepair() || CanRearm()); } } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "Repair") return new Order(order.OrderID, self, target, queued); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/RepairableNear.cs openra-20210321/OpenRA.Mods.Common/Traits/RepairableNear.cs --- openra-20200503/OpenRA.Mods.Common/Traits/RepairableNear.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/RepairableNear.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,13 +13,12 @@ using System.Linq; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; -using OpenRA.Primitives; using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - class RepairableNearInfo : ITraitInfo, Requires, Requires, IObservesVariablesInfo + public class RepairableNearInfo : TraitInfo, Requires, Requires, IObservesVariablesInfo { [ActorReference] [FieldLoader.Require] @@ -34,10 +33,16 @@ [Desc("Boolean expression defining the condition under which the regular (non-force) enter cursor is disabled.")] public readonly BooleanExpression RequireForceMoveCondition = null; - public object Create(ActorInitializer init) { return new RepairableNear(init.Self, this); } + [Desc("Cursor to display when able to be repaired near target actor.")] + public readonly string EnterCursor = "enter"; + + [Desc("Cursor to display when unable to be repaired near target actor.")] + public readonly string EnterBlockedCursor = "enter-blocked"; + + public override object Create(ActorInitializer init) { return new RepairableNear(init.Self, this); } } - class RepairableNear : IIssueOrder, IResolveOrder, IOrderVoice, IObservesVariables + public class RepairableNear : IIssueOrder, IResolveOrder, IOrderVoice, IObservesVariables { public readonly RepairableNearInfo Info; readonly Actor self; @@ -53,12 +58,17 @@ { get { - yield return new EnterAlliedActorTargeter("RepairNear", 5, - CanRepairAt, _ => ShouldRepair()); + yield return new EnterAlliedActorTargeter( + "RepairNear", + 5, + Info.EnterCursor, + Info.EnterBlockedCursor, + CanRepairAt, + _ => ShouldRepair()); } } - Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "RepairNear") return new Order(order.OrderID, self, target, queued); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/RepairsBridges.cs openra-20210321/OpenRA.Mods.Common/Traits/RepairsBridges.cs --- openra-20200503/OpenRA.Mods.Common/Traits/RepairsBridges.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/RepairsBridges.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,26 +18,29 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Can enter a BridgeHut or LegacyBridgeHut to trigger a repair.")] - class RepairsBridgesInfo : ITraitInfo + class RepairsBridgesInfo : TraitInfo { [VoiceReference] public readonly string Voice = "Action"; + [Desc("Color to use for the target line.")] + public readonly Color TargetLineColor = Color.Yellow; + [Desc("Behaviour when entering the structure.", "Possible values are Exit, Suicide, Dispose.")] public readonly EnterBehaviour EnterBehaviour = EnterBehaviour.Dispose; - [Desc("Cursor to use when targeting an unrepaired bridge.")] + [Desc("Cursor to display when targeting an unrepaired bridge.")] public readonly string TargetCursor = "goldwrench"; - [Desc("Cursor to use when repairing is denied.")] + [Desc("Cursor to display when repairing is denied.")] public readonly string TargetBlockedCursor = "goldwrench-blocked"; [NotificationReference("Speech")] [Desc("Speech notification to play when a bridge is repaired.")] public readonly string RepairNotification = null; - public object Create(ActorInitializer init) { return new RepairsBridges(this); } + public override object Create(ActorInitializer init) { return new RepairsBridges(this); } } class RepairsBridges : IIssueOrder, IResolveOrder, IOrderVoice @@ -54,7 +57,7 @@ get { yield return new RepairBridgeOrderTargeter(info); } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "RepairBridge") return new Order(order.OrderID, self, target, queued); @@ -102,7 +105,7 @@ else return; - self.QueueActivity(order.Queued, new RepairBridge(self, order.Target, info.EnterBehaviour, info.RepairNotification)); + self.QueueActivity(order.Queued, new RepairBridge(self, order.Target, info.EnterBehaviour, info.RepairNotification, info.TargetLineColor)); self.ShowTargetLines(); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/RepairsUnits.cs openra-20210321/OpenRA.Mods.Common/Traits/RepairsUnits.cs --- openra-20200503/OpenRA.Mods.Common/Traits/RepairsUnits.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/RepairsUnits.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,6 +9,7 @@ */ #endregion +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -23,6 +24,9 @@ [Desc("Time (in ticks) between two repair steps.")] public readonly int Interval = 24; + [Desc("Damage types used for the repair.")] + public readonly BitSet RepairDamageTypes = default(BitSet); + [NotificationReference("Speech")] [Desc("The sound played when starting to repair a unit.")] public readonly string StartRepairingNotification = null; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Replaceable.cs openra-20210321/OpenRA.Mods.Common/Traits/Replaceable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Replaceable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Replaceable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,22 +10,21 @@ #endregion using System.Collections.Generic; -using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class ReplaceableInfo : ConditionalTraitInfo, ITraitInfo + public class ReplaceableInfo : ConditionalTraitInfo { [FieldLoader.Require] - [Desc("Replacement types this Relpaceable actor accepts.")] + [Desc("Replacement types this Replaceable actor accepts.")] public readonly HashSet Types = new HashSet(); - public override object Create(ActorInitializer init) { return new Replaceable(init, this); } + public override object Create(ActorInitializer init) { return new Replaceable(this); } } public class Replaceable : ConditionalTrait { - public Replaceable(ActorInitializer init, ReplaceableInfo info) + public Replaceable(ReplaceableInfo info) : base(info) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Replacement.cs openra-20210321/OpenRA.Mods.Common/Traits/Replacement.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Replacement.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Replacement.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ public class ReplacementInfo : TraitInfo { [FieldLoader.Require] - [Desc("Replacement type (matched against Conditions in Replaceable).")] + [Desc("Replacement type (matched against Types in Replaceable).")] public readonly HashSet ReplaceableTypes = new HashSet(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/RevealOnDeath.cs openra-20210321/OpenRA.Mods.Common/Traits/RevealOnDeath.cs --- openra-20200503/OpenRA.Mods.Common/Traits/RevealOnDeath.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/RevealOnDeath.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,8 +18,8 @@ [Desc("Reveal this actor's last position when killed.")] public class RevealOnDeathInfo : ConditionalTraitInfo { - [Desc("Stances relative to the actors' owner that shroud will be revealed for.")] - public readonly Stance RevealForStances = Stance.Ally; + [Desc("Relationships relative to the actors' owner that shroud will be revealed for.")] + public readonly PlayerRelationship RevealForRelationships = PlayerRelationship.Ally; [Desc("Duration of the reveal.")] public readonly int Duration = 25; @@ -66,7 +66,7 @@ w.Add(new RevealShroudEffect(self.CenterPosition, info.Radius, info.RevealGeneratedShroud ? Shroud.SourceType.Visibility : Shroud.SourceType.PassiveVisibility, - owner, info.RevealForStances, duration: info.Duration)); + owner, info.RevealForRelationships, duration: info.Duration)); }); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/RevealOnFire.cs openra-20210321/OpenRA.Mods.Common/Traits/RevealOnFire.cs --- openra-20200503/OpenRA.Mods.Common/Traits/RevealOnFire.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/RevealOnFire.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,8 +21,8 @@ [Desc("The armament types which trigger revealing.")] public readonly string[] ArmamentNames = { "primary", "secondary" }; - [Desc("Stances relative to the target player this actor will be revealed to during firing.")] - public readonly Stance RevealForStancesRelativeToTarget = Stance.Ally; + [Desc("Player relationships relative to the target player this actor will be revealed to during firing.")] + public readonly PlayerRelationship RevealForRelationships = PlayerRelationship.Ally; [Desc("Duration of the reveal.")] public readonly int Duration = 25; @@ -46,7 +46,7 @@ this.info = info; } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (IsTraitDisabled) return; @@ -60,11 +60,11 @@ { self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(self.CenterPosition, info.Radius, info.RevealGeneratedShroud ? Shroud.SourceType.Visibility : Shroud.SourceType.PassiveVisibility, - targetPlayer, info.RevealForStancesRelativeToTarget, duration: info.Duration))); + targetPlayer, info.RevealForRelationships, duration: info.Duration))); } } - Player GetTargetPlayer(Target target) + Player GetTargetPlayer(in Target target) { if (target.Type == TargetType.Actor) return target.Actor.Owner; @@ -74,6 +74,6 @@ return null; } - void INotifyAttack.PreparingAttack(Actor self, OpenRA.Traits.Target target, Armament a, Barrel barrel) { } + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/RevealsMap.cs openra-20210321/OpenRA.Mods.Common/Traits/RevealsMap.cs --- openra-20200503/OpenRA.Mods.Common/Traits/RevealsMap.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/RevealsMap.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,75 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Reveals shroud and fog across the whole map while active.")] + public class RevealsMapInfo : ConditionalTraitInfo + { + [Desc("Relationships the watching player needs to see the shroud removed.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally; + + [Desc("Can this actor reveal shroud generated by the `GeneratesShroud` trait?")] + public readonly bool RevealGeneratedShroud = true; + + public override object Create(ActorInitializer init) { return new RevealsMap(this); } + } + + public class RevealsMap : ConditionalTrait, INotifyKilled, INotifyActorDisposing + { + readonly Shroud.SourceType type; + + public RevealsMap(RevealsMapInfo info) + : base(info) + { + type = info.RevealGeneratedShroud ? Shroud.SourceType.Visibility + : Shroud.SourceType.PassiveVisibility; + } + + protected void AddCellsToPlayerShroud(Actor self, Player p, PPos[] uv) + { + if (!Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p))) + return; + + p.Shroud.AddSource(this, type, uv); + } + + protected void RemoveCellsFromPlayerShroud(Actor self, Player p) { p.Shroud.RemoveSource(this); } + + protected PPos[] ProjectedCells(Actor self) + { + return self.World.Map.ProjectedCells; + } + + void INotifyActorDisposing.Disposing(Actor self) + { + RemoveCellsFromPlayerShroud(self, self.Owner); + } + + void INotifyKilled.Killed(Actor self, AttackInfo e) + { + RemoveCellsFromPlayerShroud(self, self.Owner); + } + + protected override void TraitEnabled(Actor self) + { + foreach (var player in self.World.Players) + AddCellsToPlayerShroud(self, player, ProjectedCells(self)); + } + + protected override void TraitDisabled(Actor self) + { + RemoveCellsFromPlayerShroud(self, self.Owner); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/RevealsShroud.cs openra-20210321/OpenRA.Mods.Common/Traits/RevealsShroud.cs --- openra-20200503/OpenRA.Mods.Common/Traits/RevealsShroud.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/RevealsShroud.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,6 +9,7 @@ */ #endregion +using System.Collections.Generic; using System.Linq; using OpenRA.Traits; @@ -16,8 +17,8 @@ { public class RevealsShroudInfo : AffectsShroudInfo { - [Desc("Stance the watching player needs to see the shroud removed.")] - public readonly Stance ValidStances = Stance.Ally; + [Desc("Relationships the watching player needs to see the shroud removed.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally; [Desc("Can this actor reveal shroud generated by the GeneratesShroud trait?")] public readonly bool RevealGeneratedShroud = true; @@ -29,7 +30,7 @@ { readonly RevealsShroudInfo info; readonly Shroud.SourceType type; - IRevealsShroudModifier[] rangeModifiers; + IEnumerable rangeModifiers; public RevealsShroud(Actor self, RevealsShroudInfo info) : base(self, info) @@ -43,12 +44,12 @@ { base.Created(self); - rangeModifiers = self.TraitsImplementing().ToArray(); + rangeModifiers = self.TraitsImplementing().ToArray().Select(x => x.GetRevealsShroudModifier()); } protected override void AddCellsToPlayerShroud(Actor self, Player p, PPos[] uv) { - if (!info.ValidStances.HasStance(p.Stances[self.Owner])) + if (!info.ValidRelationships.HasStance(self.Owner.RelationshipWith(p))) return; p.Shroud.AddSource(this, type, uv); @@ -63,8 +64,7 @@ if (CachedTraitDisabled) return WDist.Zero; - var revealsShroudModifier = rangeModifiers.Select(x => x.GetRevealsShroudModifier()); - var range = Util.ApplyPercentageModifiers(Info.Range.Length, revealsShroudModifier); + var range = Util.ApplyPercentageModifiers(Info.Range.Length, rangeModifiers); return new WDist(range); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ScriptTags.cs openra-20210321/OpenRA.Mods.Common/Traits/ScriptTags.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ScriptTags.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ScriptTags.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,9 +15,9 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Allows this actor to be 'tagged' with arbitrary strings. Tags must be unique or they will be rejected.")] - public class ScriptTagsInfo : ITraitInfo + public class ScriptTagsInfo : TraitInfo { - object ITraitInfo.Create(ActorInitializer init) { return new ScriptTags(init, this); } + public override object Create(ActorInitializer init) { return new ScriptTags(init, this); } } public class ScriptTags @@ -26,8 +26,9 @@ public ScriptTags(ActorInitializer init, ScriptTagsInfo info) { - if (init.Contains()) - foreach (var tag in init.Get()) + var scriptTagsInit = init.GetOrDefault(info); + if (scriptTagsInit != null) + foreach (var tag in scriptTagsInit.Value) tags.Add(tag); } @@ -48,13 +49,9 @@ } /// Allows mappers to 'tag' actors with arbitrary strings that may have meaning in their scripts. - public class ScriptTagsInit : IActorInit + public class ScriptTagsInit : ValueActorInit { - [FieldFromYamlKey] - readonly string[] value = new string[0]; - - public ScriptTagsInit() { } - public ScriptTagsInit(string[] init) { value = init; } - public string[] Value(World world) { return value; } + public ScriptTagsInit(string[] value) + : base(value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Selectable.cs openra-20210321/OpenRA.Mods.Common/Traits/Selectable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Selectable.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Selectable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,55 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("This actor is selectable. Defines bounds of selectable area, selection class, selection priority and selection priority modifiers.")] + public class SelectableInfo : InteractableInfo, ISelectableInfo + { + public readonly int Priority = 10; + + [Desc("Allow selection priority to be modified using a hotkey.", + "Valid values are None (priority is not affected by modifiers)", + "Ctrl (priority is raised when Ctrl pressed) and", + "Alt (priority is raised when Alt pressed).")] + public readonly SelectionPriorityModifiers PriorityModifiers = SelectionPriorityModifiers.None; + + [Desc("All units having the same selection class specified will be selected with select-by-type commands (e.g. double-click). " + + "Defaults to the actor name when not defined or inherited.")] + public readonly string Class = null; + + [VoiceReference] + public readonly string Voice = "Select"; + + public override object Create(ActorInitializer init) { return new Selectable(init.Self, this); } + + int ISelectableInfo.Priority { get { return Priority; } } + SelectionPriorityModifiers ISelectableInfo.PriorityModifiers { get { return PriorityModifiers; } } + string ISelectableInfo.Voice { get { return Voice; } } + } + + public class Selectable : Interactable, ISelectable + { + readonly string selectionClass = null; + public readonly SelectableInfo Info; + + public Selectable(Actor self, SelectableInfo info) + : base(info) + { + selectionClass = string.IsNullOrEmpty(info.Class) ? self.Info.Name : info.Class; + Info = info; + } + + string ISelectable.Class { get { return selectionClass; } } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SelfHealing.cs openra-20210321/OpenRA.Mods.Common/Traits/SelfHealing.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SelfHealing.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SelfHealing.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using OpenRA.Primitives; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - [Desc("Attach this to actors which should be able to regenerate their health points.")] - class SelfHealingInfo : ConditionalTraitInfo, Requires - { - [Desc("Absolute amount of health points added in each step.")] - public readonly int Step = 5; - - [Desc("Relative percentages of health added in each step.", - "When both values are defined, their summary will be applied.")] - public readonly int PercentageStep = 0; - - public readonly int Delay = 5; - - [Desc("Heal if current health is below this percentage of full health.")] - public readonly int HealIfBelow = 50; - - public readonly int DamageCooldown = 0; - - [Desc("Apply the selfhealing using these damagetypes.")] - public readonly BitSet DamageTypes = default(BitSet); - - public override object Create(ActorInitializer init) { return new SelfHealing(init.Self, this); } - } - - class SelfHealing : ConditionalTrait, ITick, INotifyDamage - { - readonly IHealth health; - - [Sync] - int ticks; - - [Sync] - int damageTicks; - - public SelfHealing(Actor self, SelfHealingInfo info) - : base(info) - { - health = self.Trait(); - } - - void ITick.Tick(Actor self) - { - if (self.IsDead || IsTraitDisabled) - return; - - // Cast to long to avoid overflow when multiplying by the health - if (health.HP >= Info.HealIfBelow * (long)health.MaxHP / 100) - return; - - if (damageTicks > 0) - { - --damageTicks; - return; - } - - if (--ticks <= 0) - { - ticks = Info.Delay; - - // Cast to long to avoid overflow when multiplying by the health - self.InflictDamage(self, new Damage((int)(-(Info.Step + Info.PercentageStep * (long)health.MaxHP / 100)), Info.DamageTypes)); - } - } - - void INotifyDamage.Damaged(Actor self, AttackInfo e) - { - if (e.Damage.Value > 0) - damageTicks = Info.DamageCooldown; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Sellable.cs openra-20210321/OpenRA.Mods.Common/Traits/Sellable.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Sellable.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Sellable.cs 2021-03-21 11:10:05.000000000 +0000 @@ -35,7 +35,7 @@ [Desc("Skip playing (reversed) make animation.")] public readonly bool SkipMakeAnimation = false; - [Desc("Cursor type to use when the sell order generator hovers over this actor.")] + [Desc("Cursor to display when the sell order generator hovers over this actor.")] public readonly string Cursor = "sell"; public override object Create(ActorInitializer init) { return new Sellable(init.Self, this); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ShakeOnDeath.cs openra-20210321/OpenRA.Mods.Common/Traits/ShakeOnDeath.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ShakeOnDeath.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ShakeOnDeath.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,15 +9,19 @@ */ #endregion +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class ShakeOnDeathInfo : ITraitInfo + public class ShakeOnDeathInfo : TraitInfo { + [Desc("DeathType(s) that trigger the shake. Leave empty to always trigger a shake.")] + public readonly BitSet DeathTypes = default(BitSet); + public readonly int Duration = 10; public readonly int Intensity = 1; - public object Create(ActorInitializer init) { return new ShakeOnDeath(this); } + public override object Create(ActorInitializer init) { return new ShakeOnDeath(this); } } public class ShakeOnDeath : INotifyKilled @@ -31,6 +35,9 @@ void INotifyKilled.Killed(Actor self, AttackInfo e) { + if (!info.DeathTypes.IsEmpty && !e.Damage.DamageTypes.Overlaps(info.DeathTypes)) + return; + self.World.WorldActor.Trait().AddEffect(info.Duration, self.CenterPosition, info.Intensity); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SmokeTrailWhenDamaged.cs openra-20210321/OpenRA.Mods.Common/Traits/SmokeTrailWhenDamaged.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SmokeTrailWhenDamaged.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SmokeTrailWhenDamaged.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,12 +9,14 @@ */ #endregion +using System; using OpenRA.Mods.Common.Effects; +using OpenRA.Mods.Common.Traits.Render; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - class SmokeTrailWhenDamagedInfo : ITraitInfo, Requires + class SmokeTrailWhenDamagedInfo : TraitInfo, Requires { [Desc("Position relative to body")] public readonly WVec Offset = WVec.Zero; @@ -23,33 +25,28 @@ public readonly string Sprite = "smokey"; - [SequenceReference("Sprite")] + [SequenceReference(nameof(Sprite))] public readonly string Sequence = "idle"; public readonly string Palette = "effect"; public readonly DamageState MinDamage = DamageState.Heavy; - public object Create(ActorInitializer init) { return new SmokeTrailWhenDamaged(init.Self, this); } + public override object Create(ActorInitializer init) { return new SmokeTrailWhenDamaged(init.Self, this); } } class SmokeTrailWhenDamaged : ITick { readonly SmokeTrailWhenDamagedInfo info; readonly BodyOrientation body; - readonly int getFacing; + readonly Func getFacing; int ticks; public SmokeTrailWhenDamaged(Actor self, SmokeTrailWhenDamagedInfo info) { this.info = info; body = self.Trait(); - var facing = self.TraitOrDefault(); - - if (facing != null) - getFacing = facing.Facing; - else - getFacing = 0; + getFacing = RenderSprites.MakeFacingFunc(self); } void ITick.Tick(Actor self) @@ -61,7 +58,7 @@ { var offset = info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation)); var pos = position + body.LocalToWorld(offset); - self.World.AddFrameEndTask(w => w.Add(new SpriteEffect(pos, w, info.Sprite, info.Sequence, info.Palette, facing: getFacing))); + self.World.AddFrameEndTask(w => w.Add(new SpriteEffect(pos, getFacing(), w, info.Sprite, info.Sequence, info.Palette))); } ticks = info.Interval; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Sound/ActorLostNotification.cs openra-20210321/OpenRA.Mods.Common/Traits/Sound/ActorLostNotification.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Sound/ActorLostNotification.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Sound/ActorLostNotification.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,14 +13,14 @@ namespace OpenRA.Mods.Common.Traits.Sound { - class ActorLostNotificationInfo : ITraitInfo + class ActorLostNotificationInfo : TraitInfo { [NotificationReference("Speech")] public readonly string Notification = "UnitLost"; public readonly bool NotifyAll = false; - public object Create(ActorInitializer init) { return new ActorLostNotification(this); } + public override object Create(ActorInitializer init) { return new ActorLostNotification(this); } } class ActorLostNotification : INotifyKilled diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs openra-20210321/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,13 +52,16 @@ currentSounds.RemoveWhere(s => s == null || s.Complete); - var pos = self.CenterPosition; - if (pos != cachedPosition) + if (self.OccupiesSpace != null) { - foreach (var s in currentSounds) - s.SetPosition(pos); + var pos = self.CenterPosition; + if (pos != cachedPosition) + { + foreach (var s in currentSounds) + s.SetPosition(pos); - cachedPosition = pos; + cachedPosition = pos; + } } if (delay < 0) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs openra-20210321/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits.Sound { [Desc("Play the Kill voice of this actor when eliminating enemies.")] - public class AnnounceOnKillInfo : ITraitInfo + public class AnnounceOnKillInfo : TraitInfo { [Desc("Minimum duration (in seconds) between sound events.")] public readonly int Interval = 5; @@ -23,7 +23,7 @@ [Desc("Voice to use when killing something.")] public readonly string Voice = "Kill"; - public object Create(ActorInitializer init) { return new AnnounceOnKill(init.Self, this); } + public override object Create(ActorInitializer init) { return new AnnounceOnKill(init.Self, this); } } public class AnnounceOnKill : INotifyAppliedDamage diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Sound/AnnounceOnSeen.cs openra-20210321/OpenRA.Mods.Common/Traits/Sound/AnnounceOnSeen.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Sound/AnnounceOnSeen.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Sound/AnnounceOnSeen.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ { [Desc("Players will be notified when this actor becomes visible to them.", "Requires the 'EnemyWatcher' trait on the player actor.")] - public class AnnounceOnSeenInfo : ITraitInfo + public class AnnounceOnSeenInfo : TraitInfo { [Desc("Should there be a radar ping on enemies' radar at the actor's location when they see him")] public readonly bool PingRadar = false; @@ -27,7 +27,7 @@ public readonly bool AnnounceNeutrals = false; - public object Create(ActorInitializer init) { return new AnnounceOnSeen(init.Self, this); } + public override object Create(ActorInitializer init) { return new AnnounceOnSeen(init.Self, this); } } public class AnnounceOnSeen : INotifyDiscovered @@ -57,8 +57,8 @@ Game.Sound.PlayNotification(self.World.Map.Rules, discoverer, "Speech", Info.Notification, discoverer.Faction.InternalName); // Radar notification - if (Info.PingRadar && radarPings.Value != null) - radarPings.Value.Add(() => true, self.CenterPosition, Color.Red, 50); + if (Info.PingRadar) + radarPings.Value?.Add(() => true, self.CenterPosition, Color.Red, 50); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Sound/AttackSounds.cs openra-20210321/OpenRA.Mods.Common/Traits/Sound/AttackSounds.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Sound/AttackSounds.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Sound/AttackSounds.cs 2021-03-21 11:10:05.000000000 +0000 @@ -46,7 +46,7 @@ Game.Sound.Play(SoundType.World, info.Sounds, self.World, self.CenterPosition); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.Attacking(Actor self, in Target target, Armament a, Barrel barrel) { if (info.DelayRelativeTo == AttackDelayType.Attack) { @@ -57,7 +57,7 @@ } } - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) + void INotifyAttack.PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel) { if (info.DelayRelativeTo == AttackDelayType.Preparation) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Sound/CaptureNotification.cs openra-20210321/OpenRA.Mods.Common/Traits/Sound/CaptureNotification.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Sound/CaptureNotification.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Sound/CaptureNotification.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits.Sound { - public class CaptureNotificationInfo : ITraitInfo + public class CaptureNotificationInfo : TraitInfo { [NotificationReference("Speech")] [Desc("The speech notification to play to the new owner.")] @@ -30,7 +30,7 @@ [Desc("Specifies if LoseNotification is played with the voice of the new owners faction.")] public readonly bool LoseNewOwnerVoice = false; - public object Create(ActorInitializer init) { return new CaptureNotification(this); } + public override object Create(ActorInitializer init) { return new CaptureNotification(this); } } public class CaptureNotification : INotifyCapture diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Sound/SoundOnDamageTransition.cs openra-20210321/OpenRA.Mods.Common/Traits/Sound/SoundOnDamageTransition.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Sound/SoundOnDamageTransition.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Sound/SoundOnDamageTransition.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,11 +9,12 @@ */ #endregion +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits.Sound { - public class SoundOnDamageTransitionInfo : ITraitInfo + public class SoundOnDamageTransitionInfo : TraitInfo { [Desc("Play a random sound from this list when damaged.")] public readonly string[] DamagedSounds = { }; @@ -21,7 +22,10 @@ [Desc("Play a random sound from this list when destroyed.")] public readonly string[] DestroyedSounds = { }; - public object Create(ActorInitializer init) { return new SoundOnDamageTransition(this); } + [Desc("DamageType(s) that trigger the sounds. Leave empty to always trigger a sound.")] + public readonly BitSet DamageTypes = default(BitSet); + + public override object Create(ActorInitializer init) { return new SoundOnDamageTransition(this); } } public class SoundOnDamageTransition : INotifyDamageStateChanged @@ -35,6 +39,9 @@ void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) { + if (!info.DamageTypes.IsEmpty && !e.Damage.DamageTypes.Overlaps(info.DamageTypes)) + return; + var rand = Game.CosmeticRandom; if (e.DamageState == DamageState.Dead) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Sound/VoiceAnnouncement.cs openra-20210321/OpenRA.Mods.Common/Traits/Sound/VoiceAnnouncement.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Sound/VoiceAnnouncement.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Sound/VoiceAnnouncement.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,8 +21,8 @@ [Desc("Voice to play.")] public readonly string Voice = null; - [Desc("Player stances who can hear this voice.")] - public readonly Stance ValidStances = Stance.Ally | Stance.Neutral | Stance.Enemy; + [Desc("Player relationships who can hear this voice.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy; [Desc("Play the voice to the owning player even if Stance.Ally is not included in ValidStances.")] public readonly bool PlayToOwner = true; @@ -53,7 +53,7 @@ if (player == null) return; - if (Info.ValidStances.HasStance(self.Owner.Stances[player])) + if (Info.ValidRelationships.HasStance(self.Owner.RelationshipWith(player))) self.PlayVoice(Info.Voice); else if (Info.PlayToOwner && self.Owner == player) self.PlayVoice(Info.Voice); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SpawnActorOnDeath.cs openra-20210321/OpenRA.Mods.Common/Traits/SpawnActorOnDeath.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SpawnActorOnDeath.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SpawnActorOnDeath.cs 2021-03-21 11:10:05.000000000 +0000 @@ -72,15 +72,12 @@ : base(info) { enabled = !info.RequiresLobbyCreeps || init.Self.World.WorldActor.Trait().Enabled; - faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName; + faction = init.GetValue(init.Self.Owner.Faction.InternalName); } void INotifyKilled.Killed(Actor self, AttackInfo e) { - if (!enabled || IsTraitDisabled) - return; - - if (!self.IsInWorld) + if (!enabled || IsTraitDisabled || !self.IsInWorld) return; if (self.World.SharedRandom.Next(100) > Info.Probability) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/StoresResources.cs openra-20210321/OpenRA.Mods.Common/Traits/StoresResources.cs --- openra-20200503/OpenRA.Mods.Common/Traits/StoresResources.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/StoresResources.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,29 +9,21 @@ */ #endregion -using System.Collections.Generic; -using System.Linq; using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Adds capacity to a player's harvested resource limit.")] - public class StoresResourcesInfo : ITraitInfo + public class StoresResourcesInfo : TraitInfo { [FieldLoader.Require] public readonly int Capacity = 0; - [FieldLoader.Require] - [Desc("Number of little squares used to display how filled unit is.")] - public readonly int PipCount = 0; - - public readonly PipType PipColor = PipType.Yellow; - - public object Create(ActorInitializer init) { return new StoresResources(init.Self, this); } + public override object Create(ActorInitializer init) { return new StoresResources(init.Self, this); } } - public class StoresResources : IPips, INotifyOwnerChanged, INotifyCapture, IStoreResources, ISync, INotifyKilled, INotifyAddedToWorld, INotifyRemovedFromWorld + public class StoresResources : INotifyOwnerChanged, INotifyCapture, IStoreResources, ISync, INotifyKilled, INotifyAddedToWorld, INotifyRemovedFromWorld { readonly StoresResourcesInfo info; PlayerResources player; @@ -65,13 +57,6 @@ player.TakeResources(Stored); } - IEnumerable IPips.GetPips(Actor self) - { - return Enumerable.Range(0, info.PipCount).Select(i => - player.Resources * info.PipCount > i * player.ResourceCapacity - ? info.PipColor : PipType.Transparent); - } - void INotifyAddedToWorld.AddedToWorld(Actor self) { player.AddStorage(info.Capacity); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -64,13 +64,7 @@ public override void SelectTarget(Actor self, string order, SupportPowerManager manager) { if (info.UseDirectionalTarget) - { - Game.Sound.PlayToPlayer(SoundType.UI, manager.Self.Owner, Info.SelectTargetSound); - Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", - Info.SelectTargetSpeechNotification, self.Owner.Faction.InternalName); - self.World.OrderGenerator = new SelectDirectionalTarget(self.World, order, manager, Info.Cursor, info.DirectionArrowAnimation, info.DirectionArrowPalette); - } else base.SelectTarget(self, order, manager); } @@ -78,16 +72,19 @@ public override void Activate(Actor self, Order order, SupportPowerManager manager) { base.Activate(self, order, manager); - SendAirstrike(self, order.Target.CenterPosition, !info.UseDirectionalTarget || order.ExtraData == uint.MaxValue, (int)order.ExtraData); + + var facing = info.UseDirectionalTarget && order.ExtraData != uint.MaxValue ? (WAngle?)WAngle.FromFacing((int)order.ExtraData) : null; + SendAirstrike(self, order.Target.CenterPosition, facing); } - public void SendAirstrike(Actor self, WPos target, bool randomize = true, int attackFacing = 0) + public Actor[] SendAirstrike(Actor self, WPos target, WAngle? facing = null) { - if (randomize) - attackFacing = 256 * self.World.SharedRandom.Next(info.QuantizedFacings) / info.QuantizedFacings; + var aircraft = new List(); + if (!facing.HasValue) + facing = new WAngle(1024 * self.World.SharedRandom.Next(info.QuantizedFacings) / info.QuantizedFacings); var altitude = self.World.Map.Rules.Actors[info.UnitType].TraitInfo().CruiseAltitude.Length; - var attackRotation = WRot.FromFacing(attackFacing); + var attackRotation = WRot.FromYaw(facing.Value); var delta = new WVec(0, -1024, 0).Rotate(attackRotation); target = target + new WVec(0, 0, altitude); var startEdge = target - (self.World.Map.DistanceToEdge(target, -delta) + info.Cordon).Length * delta / 1024; @@ -131,19 +128,48 @@ aircraftInRange[a] = false; // Checking for attack range is not relevant here because - // aircraft may be shot down before entering. Thus we remove - // the camera and beacon only if the whole squad is dead. - if (aircraftInRange.All(kv => kv.Key.IsDead)) + // aircraft may be shot down before entering the range. + // If at the map's edge, they may be removed from world before leaving. + if (aircraftInRange.All(kv => !kv.Key.IsInWorld)) { RemoveCamera(camera); RemoveBeacon(beacon); } }; + // Create the actors immediately so they can be returned + for (var i = -info.SquadSize / 2; i <= info.SquadSize / 2; i++) + { + // Even-sized squads skip the lead plane + if (i == 0 && (info.SquadSize & 1) == 0) + continue; + + // Includes the 90 degree rotation between body and world coordinates + var so = info.SquadOffset; + var spawnOffset = new WVec(i * so.Y, -Math.Abs(i) * so.X, 0).Rotate(attackRotation); + var targetOffset = new WVec(i * so.Y, 0, 0).Rotate(attackRotation); + var a = self.World.CreateActor(false, info.UnitType, new TypeDictionary + { + new CenterPositionInit(startEdge + spawnOffset), + new OwnerInit(self.Owner), + new FacingInit(facing.Value), + }); + + aircraft.Add(a); + aircraftInRange.Add(a, false); + + var attack = a.Trait(); + attack.SetTarget(self.World, target + targetOffset); + attack.OnEnteredAttackRange += onEnterRange; + attack.OnExitedAttackRange += onExitRange; + attack.OnRemovedFromWorld += onRemovedFromWorld; + } + self.World.AddFrameEndTask(w => { PlayLaunchSounds(); + var j = 0; Actor distanceTestActor = null; for (var i = -info.SquadSize / 2; i <= info.SquadSize / 2; i++) { @@ -154,25 +180,13 @@ // Includes the 90 degree rotation between body and world coordinates var so = info.SquadOffset; var spawnOffset = new WVec(i * so.Y, -Math.Abs(i) * so.X, 0).Rotate(attackRotation); - var targetOffset = new WVec(i * so.Y, 0, 0).Rotate(attackRotation); - - var a = w.CreateActor(info.UnitType, new TypeDictionary - { - new CenterPositionInit(startEdge + spawnOffset), - new OwnerInit(self.Owner), - new FacingInit(attackFacing), - }); - var attack = a.Trait(); - attack.SetTarget(w, target + targetOffset); - attack.OnEnteredAttackRange += onEnterRange; - attack.OnExitedAttackRange += onExitRange; - attack.OnRemovedFromWorld += onRemovedFromWorld; + var a = aircraft[j++]; + w.Add(a); a.QueueActivity(new Fly(a, Target.FromPos(target + spawnOffset))); a.QueueActivity(new Fly(a, Target.FromPos(finishEdge + spawnOffset))); a.QueueActivity(new RemoveSelf()); - aircraftInRange.Add(a, false); distanceTestActor = a; } @@ -198,6 +212,8 @@ w.Add(beacon); } }); + + return aircraft.ToArray(); } void RemoveCamera(Actor camera) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/GrantExternalConditionPower.cs openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/GrantExternalConditionPower.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/GrantExternalConditionPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/GrantExternalConditionPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; -using OpenRA.Mods.Common.Graphics; using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Traits.Render; using OpenRA.Primitives; @@ -29,14 +28,19 @@ [Desc("Duration of the condition (in ticks). Set to 0 for a permanent condition.")] public readonly int Duration = 0; - [Desc("Cells - affects whole cells only")] - public readonly int Range = 1; + [FieldLoader.Require] + [Desc("Size of the footprint of the affected area.")] + public readonly CVec Dimensions = CVec.Zero; + + [FieldLoader.Require] + [Desc("Actual footprint. Cells marked as x will be affected.")] + public readonly string Footprint = string.Empty; [Desc("Sound to instantly play at the targeted area.")] public readonly string OnFireSound = null; - [Desc("Player stances which condition can be applied to.")] - public readonly Stance ValidStances = Stance.Ally; + [Desc("Player relationships which condition can be applied to.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally; [SequenceReference] [Desc("Sequence to play for granting actor when activated.", @@ -52,16 +56,17 @@ class GrantExternalConditionPower : SupportPower { readonly GrantExternalConditionPowerInfo info; + readonly char[] footprint; public GrantExternalConditionPower(Actor self, GrantExternalConditionPowerInfo info) : base(self, info) { this.info = info; + footprint = info.Footprint.Where(c => !char.IsWhiteSpace(c)).ToArray(); } public override void SelectTarget(Actor self, string order, SupportPowerManager manager) { - Game.Sound.PlayToPlayer(SoundType.World, manager.Self.Owner, Info.SelectTargetSound); self.World.OrderGenerator = new SelectConditionTarget(Self.World, order, manager, this); } @@ -77,26 +82,21 @@ Game.Sound.Play(SoundType.World, info.OnFireSound, order.Target.CenterPosition); foreach (var a in UnitsInRange(self.World.Map.CellContaining(order.Target.CenterPosition))) - { - var external = a.TraitsImplementing() - .FirstOrDefault(t => t.Info.Condition == info.Condition && t.CanGrantCondition(a, self)); - - if (external != null) - external.GrantCondition(a, self, info.Duration); - } + a.TraitsImplementing() + .FirstOrDefault(t => t.Info.Condition == info.Condition && t.CanGrantCondition(a, self)) + ?.GrantCondition(a, self, info.Duration); } public IEnumerable UnitsInRange(CPos xy) { - var range = info.Range; - var tiles = Self.World.Map.FindTilesInCircle(xy, range); + var tiles = CellsMatching(xy, footprint, info.Dimensions); var units = new List(); foreach (var t in tiles) units.AddRange(Self.World.ActorMap.GetActorsAt(t)); return units.Distinct().Where(a => { - if (!info.ValidStances.HasStance(a.Owner.Stances[Self.Owner])) + if (!info.ValidRelationships.HasStance(Self.Owner.RelationshipWith(a.Owner))) return false; return a.TraitsImplementing() @@ -107,7 +107,8 @@ class SelectConditionTarget : OrderGenerator { readonly GrantExternalConditionPower power; - readonly int range; + readonly char[] footprint; + readonly CVec dimensions; readonly Sprite tile; readonly SupportPowerManager manager; readonly string order; @@ -121,7 +122,8 @@ this.manager = manager; this.order = order; this.power = power; - range = power.info.Range; + footprint = power.info.Footprint.Where(c => !char.IsWhiteSpace(c)).ToArray(); + dimensions = power.info.Dimensions; tile = world.Map.Rules.Sequences.GetSequence("overlay", "target-select").GetSprite(0); } @@ -135,7 +137,7 @@ protected override void Tick(World world) { // Cancel the OG if we can't use the power - if (!manager.Powers.ContainsKey(order)) + if (!manager.Powers.TryGetValue(order, out var p) || !p.Active || !p.Ready) world.CancelInputMode(); } @@ -146,8 +148,10 @@ var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos); foreach (var unit in power.UnitsInRange(xy)) { - var bounds = unit.TraitsImplementing().FirstNonEmptyBounds(unit, wr); - yield return new SelectionBoxAnnotationRenderable(unit, bounds, Color.Red); + var decorations = unit.TraitsImplementing().FirstEnabledTraitOrDefault(); + if (decorations != null) + foreach (var d in decorations.RenderSelectionAnnotations(unit, wr, Color.Red)) + yield return d; } } @@ -156,8 +160,8 @@ var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos); var pal = wr.Palette(TileSet.TerrainPaletteInternalName); - foreach (var t in world.Map.FindTilesInCircle(xy, range)) - yield return new SpriteRenderable(tile, wr.World.Map.CenterOfCell(t), WVec.Zero, -511, pal, 1f, true); + foreach (var t in power.CellsMatching(xy, footprint, dimensions)) + yield return new SpriteRenderable(tile, wr.World.Map.CenterOfCell(t), WVec.Zero, -511, pal, 1f, true, true); } protected override string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,14 +9,18 @@ */ #endregion +using System.Collections.Generic; using System.Linq; using OpenRA.GameRules; +using OpenRA.Graphics; using OpenRA.Mods.Common.Effects; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - class NukePowerInfo : SupportPowerInfo + public class NukePowerInfo : SupportPowerInfo { [WeaponReference] [FieldLoader.Require] @@ -27,11 +31,11 @@ [Desc("Delay (in ticks) after launch until the missile is spawned.")] public readonly int MissileDelay = 0; - [SequenceReference("MissileWeapon")] + [SequenceReference(nameof(MissileWeapon))] [Desc("Sprite sequence for the ascending missile.")] public readonly string MissileUp = "up"; - [SequenceReference("MissileWeapon")] + [SequenceReference(nameof(MissileWeapon))] [Desc("Sprite sequence for the descending missile.")] public readonly string MissileDown = "down"; @@ -45,7 +49,7 @@ "'False' will make the missile continue until it hits the ground and disappears (without triggering another explosion).")] public readonly bool RemoveMissileOnDetonation = true; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Palette to use for the missile weapon image.")] public readonly string MissilePalette = "effect"; @@ -55,7 +59,7 @@ [Desc("Trail animation.")] public readonly string TrailImage = null; - [SequenceReference("TrailImage")] + [SequenceReference(nameof(TrailImage), allowNullImage: true)] [Desc("Loop a randomly chosen sequence of TrailImage from this list while this projectile is moving.")] public readonly string[] TrailSequences = { }; @@ -65,7 +69,7 @@ [Desc("Delay in ticks until trail animation is spawned.")] public readonly int TrailDelay = 1; - [PaletteReference("TrailUsePlayerPalette")] + [PaletteReference(nameof(TrailUsePlayerPalette))] [Desc("Palette used to render the trail sequence.")] public readonly string TrailPalette = "effect"; @@ -90,8 +94,8 @@ [Desc("Can the camera reveal shroud generated by the GeneratesShroud trait?")] public readonly bool RevealGeneratedShroud = true; - [Desc("Reveal cells to players with these stances only.")] - public readonly Stance CameraStances = Stance.Ally; + [Desc("Reveal cells to players with these relationships only.")] + public readonly PlayerRelationship CameraRelationships = PlayerRelationship.Ally; [Desc("Amount of time before detonation to spawn the camera.")] public readonly int CameraSpawnAdvance = 25; @@ -99,8 +103,20 @@ [Desc("Amount of time after detonation to remove the camera.")] public readonly int CameraRemoveDelay = 25; - [Desc("Corresponds to `Type` from `FlashPaletteEffect` on the world actor.")] - public readonly string FlashType = null; + [Desc("Range circle color.")] + public readonly Color CircleColor = Color.FromArgb(128, Color.Red); + + [Desc("Range circle width in pixel.")] + public readonly float CircleWidth = 1; + + [Desc("Range circle border color.")] + public readonly Color CircleBorderColor = Color.FromArgb(64, Color.Red); + + [Desc("Range circle border width in pixel.")] + public readonly float CircleBorderWidth = 3; + + [Desc("Render circles based on these distance ranges while targeting.")] + public readonly WDist[] CircleRanges = null; public WeaponInfo WeaponInfo { get; private set; } @@ -110,9 +126,8 @@ if (!string.IsNullOrEmpty(TrailImage) && !TrailSequences.Any()) throw new YamlException("At least one entry in TrailSequences must be defined when TrailImage is defined."); - WeaponInfo weapon; var weaponToLower = (MissileWeapon ?? string.Empty).ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(weaponToLower, out weapon)) + if (!rules.Weapons.TryGetValue(weaponToLower, out var weapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); WeaponInfo = weapon; @@ -148,9 +163,6 @@ public void Activate(Actor self, WPos targetPosition) { - foreach (var launchpad in self.TraitsImplementing()) - launchpad.Launching(self); - var palette = info.IsPlayerPalette ? info.MissilePalette + self.Owner.InternalName : info.MissilePalette; var skipAscent = info.SkipAscent || body == null; var launchPos = skipAscent ? WPos.Zero : self.CenterPosition + body.LocalToWorld(info.SpawnOffset); @@ -159,7 +171,6 @@ launchPos, targetPosition, info.DetonationAltitude, info.RemoveMissileOnDetonation, info.FlightVelocity, info.MissileDelay, info.FlightDelay, skipAscent, - info.FlashType, info.TrailImage, info.TrailSequences, info.TrailPalette, info.TrailUsePlayerPalette, info.TrailDelay, info.TrailInterval); self.World.AddFrameEndTask(w => w.Add(missile)); @@ -169,7 +180,7 @@ var type = info.RevealGeneratedShroud ? Shroud.SourceType.Visibility : Shroud.SourceType.PassiveVisibility; - self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(targetPosition, info.CameraRange, type, self.Owner, info.CameraStances, + self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(targetPosition, info.CameraRange, type, self.Owner, info.CameraRelationships, info.FlightDelay - info.CameraSpawnAdvance, info.CameraSpawnAdvance + info.CameraRemoveDelay))); } @@ -197,5 +208,38 @@ }); } } + + public override void SelectTarget(Actor self, string order, SupportPowerManager manager) + { + self.World.OrderGenerator = new SelectNukePowerTarget(order, manager, info, MouseButton.Left); + } + } + + public class SelectNukePowerTarget : SelectGenericPowerTarget + { + readonly NukePowerInfo info; + + public SelectNukePowerTarget(string order, SupportPowerManager manager, NukePowerInfo info, MouseButton button) + : base(order, manager, info.Cursor, button) + { + this.info = info; + } + + protected override IEnumerable RenderAnnotations(WorldRenderer wr, World world) + { + if (info.CircleRanges == null) + yield break; + + var centerPosition = wr.World.Map.CenterOfCell(wr.Viewport.ViewToWorld(Viewport.LastMousePos)); + foreach (var range in info.CircleRanges) + yield return new RangeCircleAnnotationRenderable( + centerPosition, + range, + 0, + info.CircleColor, + info.CircleWidth, + info.CircleBorderColor, + info.CircleBorderWidth); + } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/ParatroopersPower.cs openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/ParatroopersPower.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/ParatroopersPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/ParatroopersPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -78,13 +78,7 @@ public override void SelectTarget(Actor self, string order, SupportPowerManager manager) { if (info.UseDirectionalTarget) - { - Game.Sound.PlayToPlayer(SoundType.UI, manager.Self.Owner, Info.SelectTargetSound); - Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", - Info.SelectTargetSpeechNotification, self.Owner.Faction.InternalName); - self.World.OrderGenerator = new SelectDirectionalTarget(self.World, order, manager, Info.Cursor, info.DirectionArrowAnimation, info.DirectionArrowPalette); - } else base.SelectTarget(self, order, manager); } @@ -93,27 +87,26 @@ { base.Activate(self, order, manager); - var facing = info.UseDirectionalTarget && order.ExtraData != uint.MaxValue ? (int)order.ExtraData : -1; + var facing = info.UseDirectionalTarget && order.ExtraData != uint.MaxValue ? (WAngle?)WAngle.FromFacing((int)order.ExtraData) : null; SendParatroopers(self, order.Target.CenterPosition, facing); } - public Pair SendParatroopers(Actor self, WPos target, int facing = -1) + public (Actor[] Aircraft, Actor[] Units) SendParatroopers(Actor self, WPos target, WAngle? facing = null) { var aircraft = new List(); var units = new List(); var info = Info as ParatroopersPowerInfo; - if (facing < 0) - facing = 256 * self.World.SharedRandom.Next(info.QuantizedFacings) / info.QuantizedFacings; + if (!facing.HasValue) + facing = new WAngle(1024 * self.World.SharedRandom.Next(info.QuantizedFacings) / info.QuantizedFacings); var utLower = info.UnitType.ToLowerInvariant(); - ActorInfo unitType; - if (!self.World.Map.Rules.Actors.TryGetValue(utLower, out unitType)) + if (!self.World.Map.Rules.Actors.TryGetValue(utLower, out var unitType)) throw new YamlException("Actors ruleset does not include the entry '{0}'".F(utLower)); var altitude = unitType.TraitInfo().CruiseAltitude.Length; - var dropRotation = WRot.FromFacing(facing); + var dropRotation = WRot.FromYaw(facing.Value); var delta = new WVec(0, -1024, 0).Rotate(dropRotation); target = target + new WVec(0, 0, altitude); var startEdge = target - (self.World.Map.DistanceToEdge(target, -delta) + info.Cordon).Length * delta / 1024; @@ -161,9 +154,9 @@ aircraftInRange[a] = false; // Checking for attack range is not relevant here because - // aircraft may be shot down before entering. Thus we remove - // the camera and beacon only if the whole squad is dead. - if (aircraftInRange.All(kv => kv.Key.IsDead)) + // aircraft may be shot down before entering the range. + // If at the map's edge, they may be removed from world before leaving. + if (aircraftInRange.All(kv => !kv.Key.IsInWorld)) { RemoveCamera(camera); RemoveBeacon(beacon); @@ -185,7 +178,7 @@ { new CenterPositionInit(startEdge + spawnOffset), new OwnerInit(self.Owner), - new FacingInit(facing), + new FacingInit(facing.Value), })); } @@ -266,7 +259,7 @@ } }); - return Pair.New(aircraft.ToArray(), units.ToArray()); + return (aircraft.ToArray(), units.ToArray()); } void RemoveCamera(Actor camera) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/ProduceActorPower.cs openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/ProduceActorPower.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/ProduceActorPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/ProduceActorPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -47,7 +47,7 @@ public ProduceActorPower(ActorInitializer init, ProduceActorPowerInfo info) : base(init.Self, info) { - faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName; + faction = init.GetValue(init.Self.Owner.Faction.InternalName); } public override void SelectTarget(Actor self, string order, SupportPowerManager manager) @@ -83,7 +83,7 @@ new FactionInit(BuildableInfo.GetInitialFaction(ai, faction)) }; - activated |= p.Trait.Produce(p.Actor, ai, info.Type, inits); + activated |= p.Trait.Produce(p.Actor, ai, info.Type, inits, 0); } if (activated) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/SelectDirectionalTarget.cs openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/SelectDirectionalTarget.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/SelectDirectionalTarget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/SelectDirectionalTarget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -106,10 +106,12 @@ void IOrderGenerator.Tick(World world) { // Cancel the OG if we can't use the power - if (!manager.Powers.ContainsKey(order)) + if (!manager.Powers.TryGetValue(order, out var p) || !p.Active || !p.Ready) world.CancelInputMode(); } + void IOrderGenerator.SelectionChanged(World world, IEnumerable selected) { } + bool IsOutsideDragZone { get { return dragStarted && dragDirection.Length > MinDragThreshold; } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/SpawnActorPower.cs openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/SpawnActorPower.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/SpawnActorPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/SpawnActorPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,8 +31,8 @@ public readonly string EffectImage = null; - [SequenceReference("EffectImage")] - public readonly string EffectSequence = "idle"; + [SequenceReference(nameof(EffectImage))] + public readonly string EffectSequence = null; [PaletteReference] public readonly string EffectPalette = null; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,6 +9,7 @@ */ #endregion +using System.Collections.Generic; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -17,10 +18,24 @@ { [Desc("Measured in ticks.")] public readonly int ChargeInterval = 0; + + public readonly string IconImage = "icon"; + + [SequenceReference(nameof(IconImage))] + [Desc("Icon sprite displayed in the support power palette.")] public readonly string Icon = null; + + [PaletteReference] + [Desc("Palette used for the icon.")] + public readonly string IconPalette = "chrome"; + public readonly string Description = ""; public readonly string LongDesc = ""; + + [Desc("Allow multiple instances of the same support power.")] public readonly bool AllowMultiple = false; + + [Desc("Allow this to be used only once.")] public readonly bool OneShot = false; [Desc("Cursor to display for using this support power.")] @@ -62,38 +77,34 @@ public readonly string IncomingSpeechNotification = null; [Desc("Defines to which players the timer is shown.")] - public readonly Stance DisplayTimerStances = Stance.None; - - [PaletteReference] - [Desc("Palette used for the icon.")] - public readonly string IconPalette = "chrome"; + public readonly PlayerRelationship DisplayTimerRelationships = PlayerRelationship.None; [Desc("Beacons are only supported on the Airstrike, Paratroopers, and Nuke powers")] public readonly bool DisplayBeacon = false; public readonly bool BeaconPaletteIsPlayerPalette = true; - [PaletteReference("BeaconPaletteIsPlayerPalette")] + [PaletteReference(nameof(BeaconPaletteIsPlayerPalette))] public readonly string BeaconPalette = "player"; public readonly string BeaconImage = "beacon"; - [SequenceReference("BeaconImage")] + [SequenceReference(nameof(BeaconImage))] public readonly string BeaconPoster = null; [PaletteReference] public readonly string BeaconPosterPalette = "chrome"; - [SequenceReference("BeaconImage")] + [SequenceReference(nameof(BeaconImage))] public readonly string ClockSequence = null; - [SequenceReference("BeaconImage")] + [SequenceReference(nameof(BeaconImage))] public readonly string BeaconSequence = null; - [SequenceReference("BeaconImage")] + [SequenceReference(nameof(BeaconImage))] public readonly string ArrowSequence = null; - [SequenceReference("BeaconImage")] + [SequenceReference(nameof(BeaconImage))] public readonly string CircleSequence = null; [Desc("Delay after launch, measured in ticks.")] @@ -142,13 +153,13 @@ Game.Sound.PlayToPlayer(SoundType.UI, self.Owner, Info.EndChargeSound); Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", Info.EndChargeSpeechNotification, self.Owner.Faction.InternalName); + + foreach (var notify in self.TraitsImplementing()) + notify.Charged(self); } public virtual void SelectTarget(Actor self, string order, SupportPowerManager manager) { - Game.Sound.PlayToPlayer(SoundType.UI, manager.Self.Owner, Info.SelectTargetSound); - Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", - Info.SelectTargetSpeechNotification, self.Owner.Faction.InternalName); self.World.OrderGenerator = new SelectGenericPowerTarget(order, manager, info.Cursor, MouseButton.Left); } @@ -162,6 +173,9 @@ order.Player.Color, Info.RadarPingDuration); } + + foreach (var notify in self.TraitsImplementing()) + notify.Activated(self); } public virtual void PlayLaunchSounds() @@ -175,5 +189,16 @@ var speech = isAllied ? Info.LaunchSpeechNotification : Info.IncomingSpeechNotification; Game.Sound.PlayNotification(Self.World.Map.Rules, toPlayer, "Speech", speech, toPlayer.Faction.InternalName); } + + public IEnumerable CellsMatching(CPos location, char[] footprint, CVec dimensions) + { + var index = 0; + var x = location.X - (dimensions.X - 1) / 2; + var y = location.Y - (dimensions.Y - 1) / 2; + for (var j = 0; j < dimensions.Y; j++) + for (var i = 0; i < dimensions.X; i++) + if (footprint[index++] == 'x') + yield return new CPos(x + i, y + j); + } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,9 +19,9 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Attach this to the player actor.")] - public class SupportPowerManagerInfo : ITraitInfo, Requires, Requires + public class SupportPowerManagerInfo : TraitInfo, Requires, Requires { - public object Create(ActorInitializer init) { return new SupportPowerManager(init); } + public override object Create(ActorInitializer init) { return new SupportPowerManager(init); } } public class SupportPowerManager : ITick, IResolveOrder, ITechTreeElement @@ -119,8 +119,7 @@ public void PrerequisitesAvailable(string key) { - SupportPowerInstance sp; - if (!Powers.TryGetValue(key, out sp)) + if (!Powers.TryGetValue(key, out var sp)) return; sp.PrerequisitesAvailable(true); @@ -128,8 +127,7 @@ public void PrerequisitesUnavailable(string key) { - SupportPowerInstance sp; - if (!Powers.TryGetValue(key, out sp)) + if (!Powers.TryGetValue(key, out var sp)) return; sp.PrerequisitesAvailable(false); @@ -171,6 +169,11 @@ protected bool notifiedCharging; bool notifiedReady; + public void ResetTimer() + { + remainingSubTicks = TotalTicks * 100; + } + public SupportPowerInstance(string key, SupportPowerInfo info, SupportPowerManager manager) { Key = key; @@ -198,27 +201,23 @@ if (!Active) return; - if (Active) - { - var power = Instances.First(); - if (Manager.DevMode.FastCharge && remainingSubTicks > 2500) - remainingSubTicks = 2500; + var power = Instances.First(); + if (Manager.DevMode.FastCharge && remainingSubTicks > 2500) + remainingSubTicks = 2500; - if (remainingSubTicks > 0) - remainingSubTicks = (remainingSubTicks - 100).Clamp(0, TotalTicks * 100); + if (remainingSubTicks > 0) + remainingSubTicks = (remainingSubTicks - 100).Clamp(0, TotalTicks * 100); - if (!notifiedCharging) - { - power.Charging(power.Self, Key); - notifiedCharging = true; - } + if (!notifiedCharging) + { + power.Charging(power.Self, Key); + notifiedCharging = true; + } - if (RemainingTicks == 0 - && !notifiedReady) - { - power.Charged(power.Self, Key); - notifiedReady = true; - } + if (RemainingTicks == 0 && !notifiedReady) + { + power.Charged(power.Self, Key); + notifiedReady = true; } } @@ -228,9 +227,14 @@ return; var power = Instances.FirstOrDefault(i => !i.IsTraitPaused); + if (power == null) return; + Game.Sound.PlayToPlayer(SoundType.UI, Manager.Self.Owner, Info.SelectTargetSound); + Game.Sound.PlayNotification(power.Self.World.Map.Rules, power.Self.Owner, "Speech", + Info.SelectTargetSpeechNotification, power.Self.Owner.Faction.InternalName); + power.SelectTarget(power.Self, Key, Manager); } @@ -305,7 +309,7 @@ protected override void Tick(World world) { // Cancel the OG if we can't use the power - if (!manager.Powers.ContainsKey(order)) + if (!manager.Powers.TryGetValue(order, out var p) || !p.Active || !p.Ready) world.CancelInputMode(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/TemporaryOwnerManager.cs openra-20210321/OpenRA.Mods.Common/Traits/TemporaryOwnerManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/TemporaryOwnerManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/TemporaryOwnerManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,11 +16,11 @@ { [Desc("Interacts with the ChangeOwner warhead.", "Displays a bar how long this actor is affected and reverts back to the old owner on temporary changes.")] - public class TemporaryOwnerManagerInfo : ITraitInfo + public class TemporaryOwnerManagerInfo : TraitInfo { public readonly Color BarColor = Color.Orange; - public object Create(ActorInitializer init) { return new TemporaryOwnerManager(init.Self, this); } + public override object Create(ActorInitializer init) { return new TemporaryOwnerManager(init.Self, this); } } public class TemporaryOwnerManager : ISelectionBar, ITick, ISync, INotifyOwnerChanged diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/TerrainLighting.cs openra-20210321/OpenRA.Mods.Common/Traits/TerrainLighting.cs --- openra-20200503/OpenRA.Mods.Common/Traits/TerrainLighting.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/TerrainLighting.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,140 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Primitives; +using OpenRA.Support; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Add to the world actor to apply a global lighting tint and allow actors using the TerrainLightSource to add localised lighting.")] + public class TerrainLightingInfo : TraitInfo, ILobbyCustomRulesIgnore + { + public readonly float Intensity = 1; + public readonly float HeightStep = 0; + public readonly float RedTint = 1; + public readonly float GreenTint = 1; + public readonly float BlueTint = 1; + + [Desc("Size of light source partition bins (cells)")] + public readonly int BinSize = 10; + + public override object Create(ActorInitializer init) { return new TerrainLighting(init.World, this); } + } + + public sealed class TerrainLighting : ITerrainLighting + { + class LightSource + { + public readonly WPos Pos; + public readonly CPos Cell; + public readonly WDist Range; + public readonly float Intensity; + public readonly float3 Tint; + + public LightSource(WPos pos, CPos cell, WDist range, float intensity, in float3 tint) + { + Pos = pos; + Cell = cell; + Range = range; + Intensity = intensity; + Tint = tint; + } + } + + readonly TerrainLightingInfo info; + readonly Map map; + readonly Dictionary lightSources = new Dictionary(); + readonly SpatiallyPartitioned partitionedLightSources; + readonly float3 globalTint; + int nextLightSourceToken = 1; + + public event Action CellChanged = null; + + public TerrainLighting(World world, TerrainLightingInfo info) + { + this.info = info; + map = world.Map; + globalTint = new float3(info.RedTint, info.GreenTint, info.BlueTint); + + var cellSize = map.Grid.Type == MapGridType.RectangularIsometric ? 1448 : 1024; + partitionedLightSources = new SpatiallyPartitioned( + (map.MapSize.X + 1) * cellSize, + (map.MapSize.Y + 1) * cellSize, + info.BinSize * cellSize); + } + + Rectangle Bounds(LightSource source) + { + var c = source.Pos; + var r = source.Range.Length; + return new Rectangle(c.X - r, c.Y - r, 2 * r, 2 * r); + } + + public int AddLightSource(WPos pos, WDist range, float intensity, in float3 tint) + { + var token = nextLightSourceToken++; + var source = new LightSource(pos, map.CellContaining(pos), range, intensity, tint); + var bounds = Bounds(source); + lightSources.Add(token, source); + partitionedLightSources.Add(source, bounds); + + if (CellChanged != null) + foreach (var c in map.FindTilesInCircle(source.Cell, (source.Range.Length + 1023) / 1024)) + CellChanged(c.ToMPos(map)); + + return token; + } + + public void RemoveLightSource(int token) + { + if (!lightSources.TryGetValue(token, out var source)) + return; + + lightSources.Remove(token); + partitionedLightSources.Remove(source); + if (CellChanged != null) + foreach (var c in map.FindTilesInCircle(source.Cell, (source.Range.Length + 1023) / 1024)) + CellChanged(c.ToMPos(map)); + } + + float3 ITerrainLighting.TintAt(WPos pos) + { + using (new PerfSample("terrain_lighting")) + { + var uv = map.CellContaining(pos).ToMPos(map); + var tint = globalTint; + if (!map.Height.Contains(uv)) + return tint; + + var intensity = info.Intensity + info.HeightStep * map.Height[uv]; + if (lightSources.Count > 0) + { + foreach (var source in partitionedLightSources.At(new int2(pos.X, pos.Y))) + { + var range = source.Range.Length; + var distance = (source.Pos - pos).Length; + if (distance > range) + continue; + + var falloff = (range - distance) * 1f / range; + intensity += falloff * source.Intensity; + tint += falloff * source.Tint; + } + } + + return intensity * tint; + } + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/TerrainLightSource.cs openra-20210321/OpenRA.Mods.Common/Traits/TerrainLightSource.cs --- openra-20200503/OpenRA.Mods.Common/Traits/TerrainLightSource.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/TerrainLightSource.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,67 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Adds a localized circular light centered on the actor to the world's TerrainLightSource trait.")] + public class TerrainLightSourceInfo : TraitInfo, INotifyEditorPlacementInfo, IRulesetLoaded, ILobbyCustomRulesIgnore + { + public readonly WDist Range = WDist.FromCells(10); + public readonly float Intensity = 0; + public readonly float RedTint = 0; + public readonly float GreenTint = 0; + public readonly float BlueTint = 0; + + object INotifyEditorPlacementInfo.AddedToEditor(EditorActorPreview preview, World editorWorld) + { + var tint = new float3(RedTint, GreenTint, BlueTint); + return editorWorld.WorldActor.Trait().AddLightSource(preview.CenterPosition, Range, Intensity, tint); + } + + void INotifyEditorPlacementInfo.RemovedFromEditor(EditorActorPreview preview, World editorWorld, object data) + { + editorWorld.WorldActor.Trait().RemoveLightSource((int)data); + } + + public void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + if (!rules.Actors["world"].HasTraitInfo()) + throw new YamlException("TerrainLightSource can only be used with the world TerrainLighting trait."); + } + + public override object Create(ActorInitializer init) { return new TerrainLightSource(init.Self, this); } + } + + public sealed class TerrainLightSource : INotifyAddedToWorld, INotifyRemovedFromWorld + { + readonly TerrainLightSourceInfo info; + readonly TerrainLighting terrainLighting; + int lightingToken = -1; + + public TerrainLightSource(Actor self, TerrainLightSourceInfo info) + { + this.info = info; + terrainLighting = self.World.WorldActor.Trait(); + } + + void INotifyAddedToWorld.AddedToWorld(Actor self) + { + lightingToken = terrainLighting.AddLightSource(self.CenterPosition, info.Range, info.Intensity, new float3(info.RedTint, info.GreenTint, info.BlueTint)); + } + + void INotifyRemovedFromWorld.RemovedFromWorld(Actor self) + { + terrainLighting.RemoveLightSource(lightingToken); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ThrowsParticle.cs openra-20210321/OpenRA.Mods.Common/Traits/ThrowsParticle.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ThrowsParticle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ThrowsParticle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { - class ThrowsParticleInfo : ITraitInfo, Requires, Requires + class ThrowsParticleInfo : TraitInfo, Requires, Requires { [FieldLoader.Require] public readonly string Anim = null; @@ -40,9 +40,9 @@ public readonly int Velocity = 75; [Desc("Speed at which the particle turns.")] - public readonly int TurnSpeed = 15; + public readonly WAngle TurnSpeed = new WAngle(60); - public object Create(ActorInitializer init) { return new ThrowsParticle(init, this); } + public override object Create(ActorInitializer init) { return new ThrowsParticle(init, this); } } class ThrowsParticle : ITick @@ -57,6 +57,7 @@ WAngle facing; WAngle rotation; + int direction; public ThrowsParticle(ActorInitializer init, ThrowsParticleInfo info) { @@ -65,23 +66,25 @@ var body = self.Trait(); // TODO: Carry orientation over from the parent instead of just facing - var bodyFacing = init.Contains() ? init.Get>()() - : init.Contains() ? init.Get() : 0; - facing = WAngle.FromFacing(Turreted.TurretFacingFromInit(init, 0)()); + var dynamicFacingInit = init.GetOrDefault(); + var bodyFacing = dynamicFacingInit != null ? dynamicFacingInit.Value() : init.GetValue(WAngle.Zero); + facing = TurretedInfo.WorldFacingFromInit(init, info, WAngle.Zero)(); // Calculate final position - var throwRotation = WRot.FromFacing(Game.CosmeticRandom.Next(1024)); + var throwRotation = WRot.FromYaw(new WAngle(Game.CosmeticRandom.Next(1024))); var throwDistance = Game.CosmeticRandom.Next(info.MinThrowRange.Length, info.MaxThrowRange.Length); - initialPos = pos = info.Offset.Rotate(body.QuantizeOrientation(self, WRot.FromFacing(bodyFacing))); + initialPos = pos = info.Offset.Rotate(body.QuantizeOrientation(self, WRot.FromYaw(bodyFacing))); finalPos = initialPos + new WVec(throwDistance, 0, 0).Rotate(throwRotation); angle = new WAngle(Game.CosmeticRandom.Next(info.MinThrowAngle.Angle, info.MaxThrowAngle.Angle)); length = (finalPos - initialPos).Length / info.Velocity; - // Facing rotation - rotation = WAngle.FromFacing(WDist.FromPDF(Game.CosmeticRandom, 2).Length * info.TurnSpeed / 1024); + // WAngle requires positive inputs, so track the speed and direction separately + var rotationSpeed = WDist.FromPDF(Game.CosmeticRandom, 2).Length * info.TurnSpeed.Angle / 1024; + direction = rotationSpeed < 0 ? -1 : 1; + rotation = new WAngle(Math.Abs(rotationSpeed)); - var anim = new Animation(init.World, rs.GetImage(self), () => facing.Angle / 4); + var anim = new Animation(init.World, rs.GetImage(self), () => facing); anim.PlayRepeating(info.Anim); rs.Add(new AnimationWithOffset(anim, () => pos, null)); } @@ -94,7 +97,7 @@ pos = WVec.LerpQuadratic(initialPos, finalPos, angle, tick++, length); // Spin the particle - facing += rotation; + facing += new WAngle(direction * rotation.Angle); rotation = new WAngle(rotation.Angle * 90 / 100); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/ThrowsShrapnel.cs openra-20210321/OpenRA.Mods.Common/Traits/ThrowsShrapnel.cs --- openra-20200503/OpenRA.Mods.Common/Traits/ThrowsShrapnel.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/ThrowsShrapnel.cs 2021-03-21 11:10:05.000000000 +0000 @@ -38,9 +38,8 @@ WeaponInfos = Weapons.Select(w => { - WeaponInfo weapon; var weaponToLower = w.ToLowerInvariant(); - if (!rules.Weapons.TryGetValue(weaponToLower, out weapon)) + if (!rules.Weapons.TryGetValue(weaponToLower, out var weapon)) throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); return weapon; }).ToArray(); @@ -64,12 +63,12 @@ for (var i = 0; pieces > i; i++) { - var rotation = WRot.FromFacing(self.World.SharedRandom.Next(1024)); + var rotation = WRot.FromYaw(new WAngle(self.World.SharedRandom.Next(1024))); var args = new ProjectileArgs { Weapon = wep, - Facing = self.World.SharedRandom.Next(-1, 255), - CurrentMuzzleFacing = () => 0, + Facing = new WAngle(self.World.SharedRandom.Next(1024)), + CurrentMuzzleFacing = () => WAngle.Zero, DamageModifiers = self.TraitsImplementing() .Select(a => a.GetFirepowerModifier()).ToArray(), diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Tooltip.cs openra-20210321/OpenRA.Mods.Common/Traits/Tooltip.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Tooltip.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Tooltip.cs 2021-03-21 11:10:05.000000000 +0000 @@ -49,25 +49,25 @@ public readonly string EnemyPrefix = "Enemy"; [Desc("Player stances that the generic name should be shown to.")] - public readonly Stance GenericVisibility = Stance.None; + public readonly PlayerRelationship GenericVisibility = PlayerRelationship.None; [Desc("Show the actor's owner and their faction flag")] public readonly bool ShowOwnerRow = true; public override object Create(ActorInitializer init) { return new Tooltip(init.Self, this); } - public string TooltipForPlayerStance(Stance stance) + public string TooltipForPlayerStance(PlayerRelationship stance) { - if (stance == Stance.None || !GenericVisibility.HasStance(stance)) + if (stance == PlayerRelationship.None || !GenericVisibility.HasStance(stance)) return Name; - if (GenericStancePrefix && !string.IsNullOrEmpty(AllyPrefix) && stance == Stance.Ally) + if (GenericStancePrefix && !string.IsNullOrEmpty(AllyPrefix) && stance == PlayerRelationship.Ally) return AllyPrefix + " " + GenericName; - if (GenericStancePrefix && !string.IsNullOrEmpty(NeutralPrefix) && stance == Stance.Neutral) + if (GenericStancePrefix && !string.IsNullOrEmpty(NeutralPrefix) && stance == PlayerRelationship.Neutral) return NeutralPrefix + " " + GenericName; - if (GenericStancePrefix && !string.IsNullOrEmpty(EnemyPrefix) && stance == Stance.Enemy) + if (GenericStancePrefix && !string.IsNullOrEmpty(EnemyPrefix) && stance == PlayerRelationship.Enemy) return EnemyPrefix + " " + GenericName; return GenericName; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/TooltipDescription.cs openra-20210321/OpenRA.Mods.Common/Traits/TooltipDescription.cs --- openra-20200503/OpenRA.Mods.Common/Traits/TooltipDescription.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/TooltipDescription.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,8 +20,8 @@ [Translate] public readonly string Description = ""; - [Desc("Player stances who can view the description.")] - public readonly Stance ValidStances = Stance.Ally | Stance.Neutral | Stance.Enemy; + [Desc("Player relationships who can view the description.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy; public override object Create(ActorInitializer init) { return new TooltipDescription(init.Self, this); } } @@ -53,10 +53,7 @@ if (Owner == null || forPlayer == null) return false; - if (!Info.ValidStances.HasStance(Owner.Stances[forPlayer])) - return false; - - return true; + return Info.ValidRelationships.HasStance(Owner.RelationshipWith(forPlayer)); } public string TooltipText diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/TransformCrusherOnCrush.cs openra-20210321/OpenRA.Mods.Common/Traits/TransformCrusherOnCrush.cs --- openra-20200503/OpenRA.Mods.Common/Traits/TransformCrusherOnCrush.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/TransformCrusherOnCrush.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Put this on the actor that gets crushed to replace the crusher with a new actor.")] - public class TransformCrusherOnCrushInfo : ITraitInfo + public class TransformCrusherOnCrushInfo : TraitInfo { [ActorReference] [FieldLoader.Require] @@ -26,7 +26,7 @@ public readonly BitSet CrushClasses = default(BitSet); - public virtual object Create(ActorInitializer init) { return new TransformCrusherOnCrush(init, this); } + public override object Create(ActorInitializer init) { return new TransformCrusherOnCrush(init, this); } } public class TransformCrusherOnCrush : INotifyCrushed @@ -37,7 +37,7 @@ public TransformCrusherOnCrush(ActorInitializer init, TransformCrusherOnCrushInfo info) { this.info = info; - faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName; + faction = init.GetValue(init.Self.Owner.Faction.InternalName); } void INotifyCrushed.WarnCrush(Actor self, Actor crusher, BitSet crushClasses) { } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/TransformOnCapture.cs openra-20210321/OpenRA.Mods.Common/Traits/TransformOnCapture.cs --- openra-20200503/OpenRA.Mods.Common/Traits/TransformOnCapture.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/TransformOnCapture.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Replaces the captured actor with a new one.")] - public class TransformOnCaptureInfo : ITraitInfo + public class TransformOnCaptureInfo : TraitInfo { [ActorReference] [FieldLoader.Require] @@ -29,7 +29,7 @@ [Desc("Transform only if the capturer's CaptureTypes overlap with these types. Leave empty to allow all types.")] public readonly BitSet CaptureTypes = default(BitSet); - public virtual object Create(ActorInitializer init) { return new TransformOnCapture(init, this); } + public override object Create(ActorInitializer init) { return new TransformOnCapture(init, this); } } public class TransformOnCapture : INotifyCapture @@ -40,7 +40,7 @@ public TransformOnCapture(ActorInitializer init, TransformOnCaptureInfo info) { this.info = info; - faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName; + faction = init.GetValue(init.Self.Owner.Faction.InternalName); } void INotifyCapture.OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner, BitSet captureTypes) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Transforms.cs openra-20210321/OpenRA.Mods.Common/Traits/Transforms.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Transforms.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Transforms.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,7 +29,7 @@ public readonly CVec Offset = CVec.Zero; [Desc("Facing that the actor must face before transforming.")] - public readonly int Facing = 96; + public readonly WAngle Facing = new WAngle(384); [Desc("Sounds to play when transforming.")] public readonly string[] TransformSounds = { }; @@ -70,7 +70,7 @@ self = init.Self; actorInfo = self.World.Map.Rules.Actors[info.IntoActor]; buildingInfo = actorInfo.TraitInfoOrDefault(); - faction = init.Contains() ? init.Get() : self.Owner.Faction.InternalName; + faction = init.GetValue(self.Owner.Faction.InternalName); } public string VoicePhraseForOrder(Actor self, Order order) @@ -108,7 +108,7 @@ } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) { if (order.OrderID == "DeployTransform") return new Order(order.OrderID, self, queued); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/TunnelEntrance.cs openra-20210321/OpenRA.Mods.Common/Traits/TunnelEntrance.cs --- openra-20200503/OpenRA.Mods.Common/Traits/TunnelEntrance.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/TunnelEntrance.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ { [Desc("Provides a target for players to issue orders for units to move through a TerrainTunnel.", "The host actor should be placed so that the Sensor position overlaps one of the TerrainTunnel portal cells.")] - public class TunnelEntranceInfo : ITraitInfo + public class TunnelEntranceInfo : TraitInfo { [FieldLoader.Require] [Desc("Offset to use as a staging point for actors entering or exiting the tunnel.", @@ -29,7 +29,7 @@ [Desc("Offset to check for the corresponding TerrainTunnel portal cell(s).")] public readonly CVec Sensor = CVec.Zero; - public object Create(ActorInitializer init) { return new TunnelEntrance(init.Self, this); } + public override object Create(ActorInitializer init) { return new TunnelEntrance(init.Self, this); } } public class TunnelEntrance : INotifyCreated diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/TurnOnIdle.cs openra-20210321/OpenRA.Mods.Common/Traits/TurnOnIdle.cs --- openra-20200503/OpenRA.Mods.Common/Traits/TurnOnIdle.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/TurnOnIdle.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,62 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Turns actor randomly when idle.")] + class TurnOnIdleInfo : ConditionalTraitInfo, Requires + { + [Desc("Minimum amount of ticks the actor will wait before the turn.")] + public readonly int MinDelay = 400; + + [Desc("Maximum amount of ticks the actor will wait before the turn.")] + public readonly int MaxDelay = 800; + + public override object Create(ActorInitializer init) { return new TurnOnIdle(init, this); } + } + + class TurnOnIdle : ConditionalTrait, INotifyIdle + { + int currentDelay; + WAngle targetFacing; + readonly Mobile mobile; + + public TurnOnIdle(ActorInitializer init, TurnOnIdleInfo info) + : base(info) + { + currentDelay = init.World.SharedRandom.Next(Info.MinDelay, Info.MaxDelay); + mobile = init.Self.Trait(); + targetFacing = mobile.Facing; + } + + void INotifyIdle.TickIdle(Actor self) + { + if (IsTraitDisabled) + return; + + if (mobile.IsTraitDisabled || mobile.IsTraitPaused) + return; + + if (--currentDelay > 0) + return; + + if (targetFacing == mobile.Facing) + { + targetFacing = new WAngle(self.World.SharedRandom.Next(1024)); + currentDelay = self.World.SharedRandom.Next(Info.MinDelay, Info.MaxDelay); + } + + mobile.Facing = Util.TickFacing(mobile.Facing, targetFacing, mobile.TurnSpeed); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Turreted.cs openra-20210321/OpenRA.Mods.Common/Traits/Turreted.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Turreted.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Turreted.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; +using OpenRA.Mods.Common.Graphics; using OpenRA.Primitives; using OpenRA.Traits; @@ -20,9 +21,11 @@ public class TurretedInfo : PausableConditionalTraitInfo, Requires, IActorPreviewInitInfo, IEditorActorOptions { public readonly string Turret = "primary"; + [Desc("Speed at which the turret turns.")] - public readonly int TurnSpeed = 255; - public readonly int InitialFacing = 0; + public readonly WAngle TurnSpeed = new WAngle(512); + + public readonly WAngle InitialFacing = WAngle.Zero; [Desc("Number of ticks before turret is realigned. (-1 turns off realignment)")] public readonly int RealignDelay = 40; @@ -30,44 +33,95 @@ [Desc("Muzzle position relative to turret or body. (forward, right, up) triples")] public readonly WVec Offset = WVec.Zero; - [Desc("Facing to use for actor previews (map editor, color picker, etc)")] - public readonly int PreviewFacing = 96; - [Desc("Display order for the turret facing slider in the map editor")] public readonly int EditorTurretFacingDisplayOrder = 4; - IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) + IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) { - // HACK: The ActorInit system does not support multiple instances of the same type - // Make sure that we only return one TurretFacingInit, even for actors with multiple turrets - if (ai.TraitInfos().FirstOrDefault() == this) - yield return new TurretFacingInit(PreviewFacing); + yield return new TurretFacingInit(this, InitialFacing); } IEnumerable IEditorActorOptions.ActorOptions(ActorInfo ai, World world) { - // TODO: Handle multiple turrets properly (will probably require a rewrite of the Init system) - if (ai.TraitInfos().FirstOrDefault() != this) - yield break; - - yield return new EditorActorSlider("Turret", EditorTurretFacingDisplayOrder, 0, 255, 8, + yield return new EditorActorSlider("Turret", EditorTurretFacingDisplayOrder, 0, 1023, 8, actor => { - var init = actor.Init(); + var init = actor.GetInitOrDefault(this); if (init != null) - return init.Value(world); + return init.Value.Angle; - var facingInit = actor.Init(); - if (facingInit != null) - return facingInit.Value(world); - - return InitialFacing; + return InitialFacing.Angle; }, - (actor, value) => - { - actor.RemoveInit(); - actor.ReplaceInit(new TurretFacingInit((int)value)); - }); + (actor, value) => actor.ReplaceInit(new TurretFacingInit(this, new WAngle((int)value)), this)); + } + + public static Func WorldFacingFromInit(IActorInitializer init, TraitInfo info, WAngle defaultFacing) + { + // (Dynamic)TurretFacingInit is specified relative to the actor body. + // We need to add the body facing to return an absolute world angle. + Func bodyFacing = null; + var facingInit = init.GetOrDefault(); + if (facingInit != null) + { + var facing = facingInit.Value; + bodyFacing = () => facing; + } + + var turretFacingInit = init.GetOrDefault(info); + if (turretFacingInit != null) + { + var facing = turretFacingInit.Value; + return bodyFacing != null ? (Func)(() => bodyFacing() + facing) : () => facing; + } + + var dynamicFacingInit = init.GetOrDefault(info); + if (dynamicFacingInit != null) + return bodyFacing != null ? () => bodyFacing() + dynamicFacingInit.Value() : dynamicFacingInit.Value; + + return bodyFacing ?? (() => defaultFacing); + } + + public Func WorldFacingFromInit(IActorInitializer init) + { + return WorldFacingFromInit(init, this, InitialFacing); + } + + public Func LocalFacingFromInit(IActorInitializer init) + { + var turretFacingInit = init.GetOrDefault(this); + if (turretFacingInit != null) + { + var facing = turretFacingInit.Value; + return () => facing; + } + + var dynamicFacingInit = init.GetOrDefault(this); + if (dynamicFacingInit != null) + return dynamicFacingInit.Value; + + return () => InitialFacing; + } + + // Turret offset in world-space + public Func PreviewPosition(ActorPreviewInitializer init, Func orientation) + { + var body = init.Actor.TraitInfo(); + return () => body.LocalToWorld(Offset.Rotate(orientation())); + } + + // Orientation in world-space + public Func PreviewOrientation(ActorPreviewInitializer init, Func orientation, int facings) + { + var body = init.Actor.TraitInfo(); + var turretFacing = LocalFacingFromInit(init); + + Func world = () => WRot.FromYaw(turretFacing()).Rotate(orientation()); + if (facings == 0) + return world; + + // Quantize orientation to match a rendered sprite + // Implies no pitch or roll + return () => WRot.FromYaw(body.QuantizeFacing(world().Yaw, facings)); } public override object Create(ActorInitializer init) { return new Turreted(init, this); } @@ -82,56 +136,36 @@ [Sync] public int QuantizedFacings = 0; - [Sync] - public int TurretFacing = 0; - - public int? DesiredFacing; + WVec desiredDirection; int realignTick = 0; + bool realignDesired; - // For subclasses that want to move the turret relative to the body - protected WVec localOffset = WVec.Zero; - - public WVec Offset { get { return Info.Offset + localOffset; } } - public string Name { get { return Info.Turret; } } - - public static Func TurretFacingFromInit(IActorInitializer init, int def, string turret = null) + public WRot WorldOrientation { - if (turret != null && init.Contains()) - { - Func facing; - if (init.Get>>().TryGetValue(turret, out facing)) - return facing; - } - - if (turret != null && init.Contains()) + get { - int facing; - if (init.Get>().TryGetValue(turret, out facing)) - return () => facing; - } - - if (init.Contains()) - { - var facing = init.Get(); - return () => facing; + var world = facing != null ? LocalOrientation.Rotate(facing.Orientation) : LocalOrientation; + if (QuantizedFacings == 0) + return world; + + // Quantize orientation to match a rendered sprite + // Implies no pitch or roll + return WRot.FromYaw(body.QuantizeFacing(world.Yaw, QuantizedFacings)); } + } - if (init.Contains()) - return init.Get>(); + public WRot LocalOrientation { get; private set; } - if (init.Contains()) - { - var facing = init.Get(); - return () => facing; - } + // For subclasses that want to move the turret relative to the body + protected WVec localOffset = WVec.Zero; - return () => def; - } + public WVec Offset { get { return Info.Offset + localOffset; } } + public string Name { get { return Info.Turret; } } public Turreted(ActorInitializer init, TurretedInfo info) : base(info) { - TurretFacing = TurretFacingFromInit(init, Info.InitialFacing, Info.Turret)(); + LocalOrientation = WRot.FromYaw(info.LocalFacingFromInit(init)()); } protected override void Created(Actor self) @@ -157,12 +191,18 @@ { // Only realign while not attacking anything if (attack.IsAiming) + { + realignTick = 0; return; + } if (realignTick < Info.RealignDelay) realignTick++; else if (Info.RealignDelay > -1) - DesiredFacing = null; + { + realignDesired = true; + desiredDirection = WVec.Zero; + } MoveTurret(); } @@ -173,28 +213,70 @@ } } + WAngle DesiredLocalFacing + { + get + { + // A zero value means that we have a target, but it is on top of us + if (desiredDirection == WVec.Zero) + return LocalOrientation.Yaw; + + if (facing == null) + return desiredDirection.Yaw; + + // PERF: If the turret rotation axis is vertical we can directly take the difference in facing/yaw + var orientation = facing.Orientation; + if (orientation.Pitch == WAngle.Zero && orientation.Roll == WAngle.Zero) + return desiredDirection.Yaw - orientation.Yaw; + + // If the turret rotation axis is not vertical we must transform the + // target direction into the turrets local coordinate system + return desiredDirection.Rotate(-orientation).Yaw; + } + } + void MoveTurret() { - var df = DesiredFacing ?? (facing != null ? facing.Facing : TurretFacing); - TurretFacing = Util.TickFacing(TurretFacing, df, Info.TurnSpeed); + var desired = realignDesired ? Info.InitialFacing : DesiredLocalFacing; + if (desired == LocalOrientation.Yaw) + return; + + LocalOrientation = LocalOrientation.WithYaw(Util.TickFacing(LocalOrientation.Yaw, desired, Info.TurnSpeed)); + + if (desired == LocalOrientation.Yaw) + { + realignDesired = false; + desiredDirection = WVec.Zero; + } } - public bool FaceTarget(Actor self, Target target) + public bool FaceTarget(Actor self, in Target target) { if (IsTraitDisabled || IsTraitPaused || attack == null || attack.IsTraitDisabled || attack.IsTraitPaused) return false; - var pos = self.CenterPosition; - var targetPos = attack.GetTargetPosition(pos, target); - var delta = targetPos - pos; - DesiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : TurretFacing; + if (target.Type == TargetType.Invalid) + { + desiredDirection = WVec.Zero; + return false; + } + + var turretPos = self.CenterPosition + Position(self); + var targetPos = attack.GetTargetPosition(turretPos, target); + desiredDirection = targetPos - turretPos; + realignDesired = false; + MoveTurret(); return HasAchievedDesiredFacing; } public virtual bool HasAchievedDesiredFacing { - get { return DesiredFacing == null || TurretFacing == DesiredFacing.Value; } + get + { + var desired = realignDesired ? Info.InitialFacing : DesiredLocalFacing; + return desired == LocalOrientation.Yaw; + } } // Turret offset in world-space @@ -204,54 +286,14 @@ return body.LocalToWorld(Offset.Rotate(bodyOrientation)); } - // Orientation in world-space - public WRot WorldOrientation(Actor self) - { - // Hack: turretFacing is relative to the world, so subtract the body yaw - var world = WRot.FromYaw(WAngle.FromFacing(TurretFacing)); - - if (QuantizedFacings == 0) - return world; - - // Quantize orientation to match a rendered sprite - // Implies no pitch or yaw - var facing = body.QuantizeFacing(world.Yaw.Angle / 4, QuantizedFacings); - return new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing)); - } - public void ModifyDeathActorInit(Actor self, TypeDictionary init) { - var facings = init.GetOrDefault(); - if (facings == null) - { - facings = new TurretFacingsInit(); - init.Add(facings); - } - - if (!facings.Value(self.World).ContainsKey(Name)) - facings.Value(self.World).Add(Name, TurretFacing); + init.Add(new TurretFacingInit(Info, LocalOrientation.Yaw)); } void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits) { - var facings = inits.GetOrDefault(); - if (facings == null) - { - facings = new DynamicTurretFacingsInit(); - inits.Add(facings); - } - - Func bodyFacing = () => facing.Facing; - var dynamicFacing = inits.GetOrDefault(); - var staticFacing = inits.GetOrDefault(); - if (dynamicFacing != null) - bodyFacing = dynamicFacing.Value(self.World); - else if (staticFacing != null) - bodyFacing = () => staticFacing.Value(self.World); - - // Freeze the relative turret facing to its current value - var facingOffset = TurretFacing - bodyFacing(); - facings.Value(self.World).Add(Name, () => bodyFacing() + facingOffset); + inits.Add(new DynamicTurretFacingInit(Info, () => LocalOrientation.Yaw)); } protected override void TraitDisabled(Actor self) @@ -261,31 +303,21 @@ } } - public class TurretFacingInit : IActorInit + public class TurretFacingInit : ValueActorInit { - [FieldFromYamlKey] - readonly int value = 128; + public TurretFacingInit(TraitInfo info, WAngle value) + : base(info, value) { } - public TurretFacingInit() { } - public TurretFacingInit(int init) { value = init; } - public int Value(World world) { return value; } - } - - public class TurretFacingsInit : IActorInit> - { - [DictionaryFromYamlKey] - readonly Dictionary value = new Dictionary(); + public TurretFacingInit(string instanceName, WAngle value) + : base(instanceName, value) { } - public TurretFacingsInit() { } - public TurretFacingsInit(Dictionary init) { value = init; } - public Dictionary Value(World world) { return value; } + public TurretFacingInit(WAngle value) + : base(value) { } } - public class DynamicTurretFacingsInit : IActorInit>> + public class DynamicTurretFacingInit : ValueActorInit> { - readonly Dictionary> value = new Dictionary>(); - public DynamicTurretFacingsInit() { } - public DynamicTurretFacingsInit(Dictionary> init) { value = init; } - public Dictionary> Value(World world) { return value; } + public DynamicTurretFacingInit(TraitInfo info, Func value) + : base(info, value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Voiced.cs openra-20210321/OpenRA.Mods.Common/Traits/Voiced.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Voiced.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Voiced.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("This actor has a voice.")] - public class VoicedInfo : ITraitInfo + public class VoicedInfo : TraitInfo { [VoiceSetReference] [FieldLoader.Require] @@ -24,7 +24,7 @@ [Desc("Multiply volume with this factor.")] public readonly float Volume = 1f; - public object Create(ActorInitializer init) { return new Voiced(init.Self, this); } + public override object Create(ActorInitializer init) { return new Voiced(init.Self, this); } } public class Voiced : IVoiced diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/Wanders.cs openra-20210321/OpenRA.Mods.Common/Traits/Wanders.cs --- openra-20200503/OpenRA.Mods.Common/Traits/Wanders.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/Wanders.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,6 +9,8 @@ */ #endregion +using System.Collections.Generic; +using System.Linq; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -27,6 +29,9 @@ [Desc("Maximum amount of ticks the actor will sit idly before starting to wander.")] public readonly int MaxMoveDelay = 0; + [Desc("The terrain types that this actor should avoid wandering on to.")] + public readonly HashSet AvoidTerrainTypes = new HashSet(); + public override object Create(ActorInitializer init) { return new Wanders(init.Self, this); } } @@ -75,8 +80,8 @@ return; var targetCell = PickTargetLocation(); - if (targetCell != CPos.Zero) - DoAction(self, targetCell); + if (targetCell.HasValue) + DoAction(self, targetCell.Value); } void INotifyIdle.TickIdle(Actor self) @@ -84,7 +89,7 @@ TickIdle(self); } - CPos PickTargetLocation() + CPos? PickTargetLocation() { var target = self.CenterPosition + new WVec(0, -1024 * effectiveMoveRadius, 0).Rotate(WRot.FromFacing(self.World.SharedRandom.Next(255))); var targetCell = self.World.Map.CellContaining(target); @@ -95,7 +100,15 @@ if (++ticksIdle % info.ReduceMoveRadiusDelay == 0) effectiveMoveRadius--; - return CPos.Zero; // We'll be back the next tick; better to sit idle for a few seconds than prolong this tick indefinitely with a loop + // We'll be back the next tick; better to sit idle for a few seconds than prolong this tick indefinitely with a loop + return null; + } + + if (info.AvoidTerrainTypes.Count > 0) + { + var terrainType = self.World.Map.GetTerrainInfo(targetCell).Type; + if (Info.AvoidTerrainTypes.Contains(terrainType)) + return null; } ticksIdle = 0; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/ActorMap.cs openra-20210321/OpenRA.Mods.Common/Traits/World/ActorMap.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/ActorMap.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/ActorMap.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,12 +18,12 @@ namespace OpenRA.Mods.Common.Traits { - public class ActorMapInfo : ITraitInfo + public class ActorMapInfo : TraitInfo { [Desc("Size of partition bins (cells)")] public readonly int BinSize = 10; - public object Create(ActorInitializer init) { return new ActorMap(init.World, this); } + public override object Create(ActorInitializer init) { return new ActorMap(init.World, this); } } public class ActorMap : IActorMap, ITick, INotifyCreated @@ -216,21 +216,32 @@ } } - sealed class ActorsAtEnumerator : IEnumerator + struct ActorsAtEnumerator : IEnumerator { InfluenceNode node; - public ActorsAtEnumerator(InfluenceNode node) { this.node = node; } + Actor current; + + public ActorsAtEnumerator(InfluenceNode node) + { + this.node = node; + current = null; + } + public void Reset() { throw new NotSupportedException(); } - public Actor Current { get; private set; } - object IEnumerator.Current { get { return Current; } } + public Actor Current + { + get { return current; } + } + + object IEnumerator.Current { get { return current; } } public void Dispose() { } public bool MoveNext() { while (node != null) { - Current = node.Actor; + current = node.Actor; node = node.Next; - if (!Current.Disposed) + if (!current.Disposed) return true; } @@ -238,7 +249,7 @@ } } - sealed class ActorsAtEnumerable : IEnumerable + struct ActorsAtEnumerable : IEnumerable { readonly InfluenceNode node; public ActorsAtEnumerable(InfluenceNode node) { this.node = node; } @@ -359,20 +370,18 @@ { foreach (var c in ios.OccupiedCells()) { - var uv = c.First.ToMPos(map); + var uv = c.Cell.ToMPos(map); if (!influence.Contains(uv)) continue; - var layer = c.First.Layer == 0 ? influence : customInfluence[c.First.Layer]; - layer[uv] = new InfluenceNode { Next = layer[uv], SubCell = c.Second, Actor = self }; + var layer = c.Cell.Layer == 0 ? influence : customInfluence[c.Cell.Layer]; + layer[uv] = new InfluenceNode { Next = layer[uv], SubCell = c.SubCell, Actor = self }; - List triggers; - if (cellTriggerInfluence.TryGetValue(c.First, out triggers)) + if (cellTriggerInfluence.TryGetValue(c.Cell, out var triggers)) foreach (var t in triggers) t.Dirty = true; - if (CellUpdated != null) - CellUpdated(c.First); + CellUpdated?.Invoke(c.Cell); } } @@ -380,22 +389,20 @@ { foreach (var c in ios.OccupiedCells()) { - var uv = c.First.ToMPos(map); + var uv = c.Cell.ToMPos(map); if (!influence.Contains(uv)) continue; - var layer = c.First.Layer == 0 ? influence : customInfluence[c.First.Layer]; + var layer = c.Cell.Layer == 0 ? influence : customInfluence[c.Cell.Layer]; var temp = layer[uv]; RemoveInfluenceInner(ref temp, self); layer[uv] = temp; - List triggers; - if (cellTriggerInfluence.TryGetValue(c.First, out triggers)) + if (cellTriggerInfluence.TryGetValue(c.Cell, out var triggers)) foreach (var t in triggers) t.Dirty = true; - if (CellUpdated != null) - CellUpdated(c.First); + CellUpdated?.Invoke(c.Cell); } } @@ -416,7 +423,7 @@ return; foreach (var c in ios.OccupiedCells()) - CellUpdated(c.First); + CellUpdated(c.Cell); } void ITick.Tick(Actor self) @@ -476,8 +483,7 @@ public void RemoveCellTrigger(int id) { - CellTrigger trigger; - if (!cellTriggers.TryGetValue(id, out trigger)) + if (!cellTriggers.TryGetValue(id, out var trigger)) return; foreach (var c in trigger.Footprint) @@ -503,8 +509,7 @@ public void RemoveProximityTrigger(int id) { - ProximityTrigger t; - if (!proximityTriggers.TryGetValue(id, out t)) + if (!proximityTriggers.TryGetValue(id, out var t)) return; foreach (var bin in BinsInBox(t.TopLeft, t.BottomRight)) @@ -515,8 +520,7 @@ public void UpdateProximityTrigger(int id, WPos newPos, WDist newRange, WDist newVRange) { - ProximityTrigger t; - if (!proximityTriggers.TryGetValue(id, out t)) + if (!proximityTriggers.TryGetValue(id, out var t)) return; foreach (var bin in BinsInBox(t.TopLeft, t.BottomRight)) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/BridgeLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/BridgeLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/BridgeLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/BridgeLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,6 +9,7 @@ */ #endregion +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -16,7 +17,7 @@ interface IBridgeSegment { void Repair(Actor repairer); - void Demolish(Actor saboteur); + void Demolish(Actor saboteur, BitSet damageTypes); string Type { get; } DamageState DamageState { get; } @@ -25,9 +26,9 @@ CPos Location { get; } } - class BridgeLayerInfo : ITraitInfo + class BridgeLayerInfo : TraitInfo { - public object Create(ActorInitializer init) { return new BridgeLayer(init.World); } + public override object Create(ActorInitializer init) { return new BridgeLayer(init.World); } } class BridgeLayer diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/CliffBackImpassabilityLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/CliffBackImpassabilityLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/CliffBackImpassabilityLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/CliffBackImpassabilityLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,11 +17,11 @@ { [Desc("Sets a custom terrain type for cells that are obscured by back-facing cliffs.", "This trait replicates the default CliffBackImpassability=2 behaviour from the TS/RA2 rules.ini.")] - class CliffBackImpassabilityLayerInfo : ITraitInfo + class CliffBackImpassabilityLayerInfo : TraitInfo { public readonly string TerrainType = "Impassable"; - public object Create(ActorInitializer init) { return new CliffBackImpassabilityLayer(this); } + public override object Create(ActorInitializer init) { return new CliffBackImpassabilityLayer(this); } } class CliffBackImpassabilityLayer : IWorldLoaded diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/CrateSpawner.cs openra-20210321/OpenRA.Mods.Common/Traits/World/CrateSpawner.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/CrateSpawner.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/CrateSpawner.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { - public class CrateSpawnerInfo : ITraitInfo, ILobbyOptions + public class CrateSpawnerInfo : TraitInfo, ILobbyOptions { [Translate] [Desc("Descriptive label for the crates checkbox in the lobby.")] @@ -83,7 +83,7 @@ yield return new LobbyBooleanOption("crates", CheckboxLabel, CheckboxDescription, CheckboxVisible, CheckboxDisplayOrder, CheckboxEnabled, CheckboxLocked); } - public object Create(ActorInitializer init) { return new CrateSpawner(init.Self, this); } + public override object Create(ActorInitializer init) { return new CrateSpawner(init.Self, this); } } public class CrateSpawner : ITick, INotifyCreated @@ -141,8 +141,8 @@ if (info.DeliveryAircraft != null) { var crate = w.CreateActor(false, crateActor, new TypeDictionary { new OwnerInit(w.WorldActor.Owner) }); - var dropFacing = 256 * self.World.SharedRandom.Next(info.QuantizedFacings) / info.QuantizedFacings; - var delta = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(dropFacing)); + var dropFacing = new WAngle(1024 * self.World.SharedRandom.Next(info.QuantizedFacings) / info.QuantizedFacings); + var delta = new WVec(0, -1024, 0).Rotate(WRot.FromYaw(dropFacing)); var altitude = self.World.Map.Rules.Actors[info.DeliveryAircraft].TraitInfo().CruiseAltitude.Length; var target = self.World.Map.CenterOfCell(p) + new WVec(0, 0, altitude); @@ -180,8 +180,7 @@ continue; // Don't drop on any actors - if (self.World.WorldActor.Trait().GetBuildingAt(p) != null - || self.World.ActorMap.GetActorsAt(p).Any()) + if (self.World.ActorMap.GetActorsAt(p).Any()) continue; return p; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/CreateMPPlayers.cs openra-20210321/OpenRA.Mods.Common/Traits/World/CreateMPPlayers.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/CreateMPPlayers.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/CreateMPPlayers.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,16 +13,77 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Network; +using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Attach this to the world actor.")] - public class CreateMPPlayersInfo : TraitInfo { } + public class CreateMPPlayersInfo : TraitInfo, ICreatePlayersInfo + { + /// + /// Returns a list of GameInformation.Players that matches the indexing of ICreatePlayers.CreatePlayers. + /// Non-playable players appear as null in the list. + /// + void ICreatePlayersInfo.CreateServerPlayers(MapPreview map, Session lobbyInfo, List players, MersenneTwister playerRandom) + { + var worldInfo = map.Rules.Actors["world"]; + var factions = worldInfo.TraitInfos().ToArray(); + var assignSpawnLocations = worldInfo.TraitInfoOrDefault(); + var spawnState = assignSpawnLocations?.InitializeState(map, lobbyInfo); + + // Create the unplayable map players -- neutral, shellmap, scripted, etc. + foreach (var p in map.Players.Players.Where(p => !p.Value.Playable)) + { + // We need to resolve the faction, even though we don't use it, to match the RNG state with clients + Player.ResolveFaction(p.Value.Faction, factions, playerRandom, false); + players.Add(null); + } + + // Create the regular playable players. + var bots = map.Rules.Actors["player"].TraitInfos().ToArray(); + + foreach (var kv in lobbyInfo.Slots) + { + var client = lobbyInfo.ClientInSlot(kv.Key); + if (client == null) + continue; + + var clientFaction = factions.First(f => client.Faction == f.InternalName); + var resolvedFaction = Player.ResolveFaction(client.Faction, factions, playerRandom, !kv.Value.LockFaction); + var resolvedSpawnPoint = assignSpawnLocations?.AssignSpawnPoint(spawnState, lobbyInfo, client, playerRandom) ?? 0; + var player = new GameInformation.Player + { + ClientIndex = client.Index, + Name = Player.ResolvePlayerName(client, lobbyInfo.Clients, bots), + IsHuman = client.Bot == null, + IsBot = client.Bot != null, + FactionName = resolvedFaction.Name, + FactionId = resolvedFaction.InternalName, + DisplayFactionName = clientFaction.Name, + DisplayFactionId = clientFaction.InternalName, + Color = client.Color, + Team = client.Team, + Handicap = client.Handicap, + SpawnPoint = resolvedSpawnPoint, + IsRandomFaction = clientFaction.RandomFactionMembers.Any(), + IsRandomSpawnPoint = client.SpawnPoint == 0, + Fingerprint = client.Fingerprint, + }; + + players.Add(player); + } + + // Create a player that is allied with everyone for shared observer shroud. + // We need to resolve the faction, even though we don't use it, to match the RNG state with clients + Player.ResolveFaction("Random", factions, playerRandom, false); + players.Add(null); + } + } public class CreateMPPlayers : ICreatePlayers { - void ICreatePlayers.CreatePlayers(World w) + void ICreatePlayers.CreatePlayers(World w, MersenneTwister playerRandom) { var players = new MapPlayers(w.Map.PlayerDefinitions).Players; var worldPlayers = new List(); @@ -31,7 +92,7 @@ // Create the unplayable map players -- neutral, shellmap, scripted, etc. foreach (var kv in players.Where(p => !p.Value.Playable)) { - var player = new Player(w, null, kv.Value); + var player = new Player(w, null, kv.Value, playerRandom); worldPlayers.Add(player); if (kv.Value.OwnsWorld) @@ -53,7 +114,7 @@ if (client == null) continue; - var player = new Player(w, client, players[kv.Value.PlayerReference]); + var player = new Player(w, client, players[kv.Value.PlayerReference], playerRandom); worldPlayers.Add(player); if (client.Index == Game.LocalClientId) @@ -68,29 +129,31 @@ Spectating = true, Faction = "Random", Allies = worldPlayers.Where(p => !p.NonCombatant && p.Playable).Select(p => p.InternalName).ToArray() - })); + }, playerRandom)); w.SetPlayers(worldPlayers, localPlayer); foreach (var p in w.Players) foreach (var q in w.Players) - if (!p.Stances.ContainsKey(q)) - p.Stances[q] = ChooseInitialStance(p, q); + SetupPlayerMasks(p, q); } - static Stance ChooseInitialStance(Player p, Player q) + static void SetupPlayerMasks(Player p, Player q) { - if (p == q) - return Stance.Ally; + if (!p.Spectating) + p.World.AllPlayersMask = p.World.AllPlayersMask.Union(p.PlayerMask); - if (q.Spectating && !p.NonCombatant && p.Playable) - return Stance.Ally; + if (p == q || p.PlayerReference.Allies.Contains(q.InternalName)) + { + p.AlliedPlayersMask = p.AlliedPlayersMask.Union(q.PlayerMask); + return; + } - // Stances set via PlayerReference - if (p.PlayerReference.Allies.Contains(q.InternalName)) - return Stance.Ally; if (p.PlayerReference.Enemies.Contains(q.InternalName)) - return Stance.Enemy; + { + p.EnemyPlayersMask = p.EnemyPlayersMask.Union(q.PlayerMask); + return; + } // HACK: Map players share a ClientID with the host, so would // otherwise take the host's team stance instead of being neutral @@ -100,12 +163,13 @@ var pc = GetClientForPlayer(p); var qc = GetClientForPlayer(q); if (pc != null && qc != null) - return pc.Team != 0 && pc.Team == qc.Team - ? Stance.Ally : Stance.Enemy; + { + if (pc.Team != 0 && pc.Team == qc.Team) + p.AlliedPlayersMask = p.AlliedPlayersMask.Union(q.PlayerMask); + else + p.EnemyPlayersMask = p.EnemyPlayersMask.Union(q.PlayerMask); + } } - - // Otherwise, default to neutral - return Stance.Neutral; } static Session.Client GetClientForPlayer(Player p) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/DomainIndex.cs openra-20210321/OpenRA.Mods.Common/Traits/World/DomainIndex.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/DomainIndex.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/DomainIndex.cs 2021-03-21 11:10:05.000000000 +0000 @@ -31,24 +31,23 @@ domainIndexes = new Dictionary(); tileSet = world.Map.Rules.TileSet; var locomotors = world.WorldActor.TraitsImplementing().Where(l => !string.IsNullOrEmpty(l.Info.Name)); - var movementClasses = locomotors.Select(t => (uint)t.Info.GetMovementClass(tileSet)).Distinct(); + var movementClasses = locomotors.Select(t => t.MovementClass).Distinct(); foreach (var mc in movementClasses) domainIndexes[mc] = new MovementClassDomainIndex(world, mc); } - public bool IsPassable(CPos p1, CPos p2, LocomotorInfo li) + public bool IsPassable(CPos p1, CPos p2, Locomotor locomotor) { // HACK: Work around units in other movement layers from being blocked // when the point in the main layer is not pathable if (p1.Layer != 0 || p2.Layer != 0) return true; - if (li.DisableDomainPassabilityCheck) + if (locomotor.Info.DisableDomainPassabilityCheck) return true; - var movementClass = li.GetMovementClass(tileSet); - return domainIndexes[movementClass].IsPassable(p1, p2); + return domainIndexes[locomotor.MovementClass].IsPassable(p1, p2); } /// Regenerate the domain index for a group of cells. diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/EditorActionManager.cs openra-20210321/OpenRA.Mods.Common/Traits/World/EditorActionManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/EditorActionManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/EditorActionManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -49,8 +49,7 @@ ClearRedo(); undoStack.Push(actionContainer); - if (ItemAdded != null) - ItemAdded(actionContainer); + ItemAdded?.Invoke(actionContainer); } public void Undo() @@ -66,8 +65,7 @@ editorAction.Status = EditorActionStatus.Future; redoStack.Push(editorAction); - if (OnChange != null) - OnChange(); + OnChange?.Invoke(); } void ClearRedo() @@ -76,8 +74,7 @@ { var item = redoStack.Pop(); - if (ItemRemoved != null) - ItemRemoved(item); + ItemRemoved?.Invoke(item); } } @@ -95,8 +92,7 @@ undoStack.Peek().Status = EditorActionStatus.History; undoStack.Push(editorAction); - if (OnChange != null) - OnChange(); + OnChange?.Invoke(); } public bool HasUndos() diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,18 +14,25 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits.Render; +using OpenRA.Network; using OpenRA.Primitives; +using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Required for the map editor to work. Attach this to the world actor.")] - public class EditorActorLayerInfo : ITraitInfo + public class EditorActorLayerInfo : TraitInfo, ICreatePlayersInfo { [Desc("Size of partition bins (world pixels)")] public readonly int BinSize = 250; - public object Create(ActorInitializer init) { return new EditorActorLayer(init.Self, this); } + void ICreatePlayersInfo.CreateServerPlayers(MapPreview map, Session lobbyInfo, List players, MersenneTwister playerRandom) + { + throw new NotImplementedException("EditorActorLayer must not be defined on the world actor"); + } + + public override object Create(ActorInitializer init) { return new EditorActorLayer(init.Self, this); } } public class EditorActorLayer : IWorldLoaded, ITickRender, IRender, IRadarSignature, ICreatePlayers, IRenderAnnotations @@ -44,7 +51,7 @@ this.info = info; } - void ICreatePlayers.CreatePlayers(World w) + void ICreatePlayers.CreatePlayers(World w, MersenneTwister playerRandom) { if (w.Type != WorldType.Editor) return; @@ -52,7 +59,7 @@ Players = new MapPlayers(w.Map.PlayerDefinitions); var worldOwner = Players.Players.Select(kvp => kvp.Value).First(p => !p.Playable && p.OwnsWorld); - w.SetWorldOwner(new Player(w, null, worldOwner)); + w.SetWorldOwner(new Player(w, null, worldOwner, playerRandom)); } public void WorldLoaded(World world, WorldRenderer wr) @@ -118,8 +125,7 @@ public EditorActorPreview Add(string id, ActorReference reference, bool initialSetup = false) { - var owner = Players.Players[reference.InitDict.Get().PlayerName]; - + var owner = Players.Players[reference.Get().InternalName]; var preview = new EditorActorPreview(worldRenderer, id, reference, owner); Add(preview, initialSetup); @@ -141,11 +147,13 @@ foreach (var cell in footprint) AddPreviewLocation(preview, cell); + preview.AddedToEditor(); + if (!initialSetup) { UpdateNeighbours(preview.Footprint); - if (preview.Actor.Type == "mpspawn") + if (preview.Type == "mpspawn") SyncMultiplayerCount(); } } @@ -162,8 +170,7 @@ foreach (var cell in footprint) { - List list; - if (!cellMap.TryGetValue(cell, out list)) + if (!cellMap.TryGetValue(cell, out var list)) continue; list.Remove(preview); @@ -172,6 +179,7 @@ cellMap.Remove(cell); } + preview.RemovedFromEditor(); UpdateNeighbours(preview.Footprint); if (preview.Info.Name == "mpspawn") @@ -226,8 +234,7 @@ void AddPreviewLocation(EditorActorPreview preview, CPos location) { - List list; - if (!cellMap.TryGetValue(location, out list)) + if (!cellMap.TryGetValue(location, out var list)) { list = new List(); cellMap.Add(location, list); @@ -254,8 +261,7 @@ public IEnumerable PreviewsAt(CPos cell) { - List list; - if (cellMap.TryGetValue(cell, out list)) + if (cellMap.TryGetValue(cell, out var list)) return list; return Enumerable.Empty(); @@ -272,8 +278,7 @@ { var blocked = previews.Any(p => { - SubCell s; - return p.Footprint.TryGetValue(cell, out s) && s == (SubCell)i; + return p.Footprint.TryGetValue(cell, out var s) && s == (SubCell)i; }); if (!blocked) @@ -313,11 +318,11 @@ return nodes; } - public void PopulateRadarSignatureCells(Actor self, List> destinationBuffer) + public void PopulateRadarSignatureCells(Actor self, List<(CPos Cell, Color Color)> destinationBuffer) { foreach (var previewsForCell in cellMap) foreach (var preview in previewsForCell.Value) - destinationBuffer.Add(Pair.New(previewsForCell.Key, preview.Owner.Color)); + destinationBuffer.Add((previewsForCell.Key, preview.RadarColor)); } public EditorActorPreview this[string id] diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs openra-20210321/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,6 +15,7 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; +using OpenRA.Mods.Common.Traits.Radar; using OpenRA.Primitives; using OpenRA.Traits; @@ -28,7 +29,6 @@ public readonly IReadOnlyDictionary Footprint; public readonly Rectangle Bounds; public readonly SelectionBoxAnnotationRenderable SelectionBox; - public readonly ActorReference Actor; public string Tooltip { @@ -39,39 +39,47 @@ } } + public string Type { get { return reference.Type; } } + public string ID { get; set; } public PlayerReference Owner { get; set; } public SubCell SubCell { get; private set; } public bool Selected { get; set; } + public readonly Color RadarColor; readonly WorldRenderer worldRenderer; readonly TooltipInfoBase tooltip; IActorPreview[] previews; + readonly ActorReference reference; + readonly Dictionary editorData = new Dictionary(); - public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference actor, PlayerReference owner) + public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference reference, PlayerReference owner) { ID = id; - Actor = actor; + this.reference = reference; Owner = owner; this.worldRenderer = worldRenderer; - if (!actor.InitDict.Contains()) - actor.InitDict.Add(new FactionInit(owner.Faction)); + if (!reference.Contains()) + reference.Add(new FactionInit(owner.Faction)); - if (!actor.InitDict.Contains()) - actor.InitDict.Add(new OwnerInit(owner.Name)); + if (!reference.Contains()) + reference.Add(new OwnerInit(owner.Name)); var world = worldRenderer.World; - if (!world.Map.Rules.Actors.TryGetValue(actor.Type.ToLowerInvariant(), out Info)) - throw new InvalidDataException("Actor {0} of unknown type {1}".F(id, actor.Type.ToLowerInvariant())); + if (!world.Map.Rules.Actors.TryGetValue(reference.Type.ToLowerInvariant(), out Info)) + throw new InvalidDataException("Actor {0} of unknown type {1}".F(id, reference.Type.ToLowerInvariant())); - CenterPosition = PreviewPosition(world, actor.InitDict); + CenterPosition = PreviewPosition(world, reference); - var location = actor.InitDict.Get().Value(worldRenderer.World); + var location = reference.Get().Value; var ios = Info.TraitInfoOrDefault(); - var subCellInit = actor.InitDict.GetOrDefault(); - var subCell = subCellInit != null ? subCellInit.Value(worldRenderer.World) : SubCell.Any; + var subCellInit = reference.GetOrDefault(); + var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any; + + var radarColorInfo = Info.TraitInfoOrDefault(); + RadarColor = radarColorInfo == null ? owner.Color : radarColorInfo.GetColorFromTerrain(world); if (ios != null) Footprint = ios.OccupiedCells(Info, location, subCell); @@ -124,27 +132,78 @@ yield return SelectionBox; } - public void ReplaceInit(T init) + public void AddedToEditor() + { + foreach (var notify in Info.TraitInfos()) + editorData[notify] = notify.AddedToEditor(this, worldRenderer.World); + } + + public void RemovedFromEditor() + { + foreach (var kv in editorData) + kv.Key.RemovedFromEditor(this, worldRenderer.World, kv.Value); + } + + public void AddInit(T init) where T : ActorInit + { + reference.Add(init); + GeneratePreviews(); + } + + public void ReplaceInit(T init, TraitInfo info) where T : ActorInit { - var original = Actor.InitDict.GetOrDefault(); + var original = GetInitOrDefault(info); if (original != null) - Actor.InitDict.Remove(original); + reference.Remove(original); - Actor.InitDict.Add(init); + reference.Add(init); GeneratePreviews(); } - public void RemoveInit() + public void RemoveInit(TraitInfo info) where T : ActorInit { - var original = Actor.InitDict.GetOrDefault(); + var original = GetInitOrDefault(info); if (original != null) - Actor.InitDict.Remove(original); + reference.Remove(original); GeneratePreviews(); } - public T Init() + public int RemoveInits() where T : ActorInit { - return Actor.InitDict.GetOrDefault(); + var removed = reference.RemoveAll(); + GeneratePreviews(); + return removed; + } + + public T GetInitOrDefault(TraitInfo info) where T : ActorInit + { + return reference.GetOrDefault(info); + } + + public IEnumerable GetInits() where T : ActorInit + { + return reference.GetAll(); + } + + public T GetInitOrDefault() where T : ActorInit, ISingleInstanceInit + { + return reference.GetOrDefault(); + } + + public void ReplaceInit(T init) where T : ActorInit, ISingleInstanceInit + { + var original = reference.GetOrDefault(); + if (original != null) + reference.Remove(original); + + reference.Add(init); + GeneratePreviews(); + } + + public void RemoveInit() where T : ActorInit, ISingleInstanceInit + { + reference.RemoveAll(); + GeneratePreviews(); } public MiniYaml Save() @@ -152,7 +211,11 @@ Func saveInit = init => { var factionInit = init as FactionInit; - if (factionInit != null && factionInit.Faction == Owner.Faction) + if (factionInit != null && factionInit.Value == Owner.Faction) + return false; + + var healthInit = init as HealthInit; + if (healthInit != null && healthInit.Value == 100) return false; // TODO: Other default values will need to be filtered @@ -160,21 +223,24 @@ return true; }; - return Actor.Save(saveInit); + return reference.Save(saveInit); } - WPos PreviewPosition(World world, TypeDictionary init) + WPos PreviewPosition(World world, ActorReference actor) { - if (init.Contains()) - return init.Get().Value(world); + var centerPositionInit = actor.GetOrDefault(); + if (centerPositionInit != null) + return centerPositionInit.Value; + + var locationInit = actor.GetOrDefault(); - if (init.Contains()) + if (locationInit != null) { - var cell = init.Get().Value(world); + var cell = locationInit.Value; var offset = WVec.Zero; - var subCellInit = Actor.InitDict.GetOrDefault(); - var subCell = subCellInit != null ? subCellInit.Value(worldRenderer.World) : SubCell.Any; + var subCellInit = reference.GetOrDefault(); + var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any; var buildingInfo = Info.TraitInfoOrDefault(); if (buildingInfo != null) @@ -188,7 +254,7 @@ void GeneratePreviews() { - var init = new ActorPreviewInitializer(Info, worldRenderer, Actor.InitDict); + var init = new ActorPreviewInitializer(reference, worldRenderer); previews = Info.TraitInfos() .SelectMany(rpi => rpi.RenderPreview(init)) .ToArray(); @@ -196,7 +262,7 @@ public ActorReference Export() { - return new ActorReference(Actor.Type, Actor.Save().ToDictionary()); + return reference.Clone(); } public override string ToString() diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,11 +19,11 @@ public enum EditorCursorType { None, Actor, TerrainTemplate, Resource } [Desc("Required for the map editor to work. Attach this to the world actor.")] - public class EditorCursorLayerInfo : ITraitInfo, Requires + public class EditorCursorLayerInfo : TraitInfo, Requires { - public readonly int PreviewFacing = 96; + public readonly WAngle PreviewFacing = new WAngle(384); - public object Create(ActorInitializer init) { return new EditorCursorLayer(init.Self, this); } + public override object Create(ActorInitializer init) { return new EditorCursorLayer(init.Self, this); } } public class EditorCursorLayer : ITickRender, IRenderAboveShroud, IRenderAnnotations @@ -88,7 +88,7 @@ var offset = world.Map.Offset(new CVec(x, y), tileInfo.Height); var palette = wr.Palette(TerrainTemplate.Palette ?? TileSet.TerrainPaletteInternalName); - terrainOrResourcePreview.Add(new SpriteRenderable(sprite, pos, offset, 0, palette, 1, false)); + terrainOrResourcePreview.Add(new SpriteRenderable(sprite, pos, offset, 0, palette, 1, false, false)); } } } @@ -99,7 +99,7 @@ var sprite = sequence.GetSprite(Resource.MaxDensity - 1); var palette = wr.Palette(Resource.Palette); - terrainOrResourcePreview.Add(new SpriteRenderable(sprite, pos, WVec.Zero, 0, palette, 1, false)); + terrainOrResourcePreview.Add(new SpriteRenderable(sprite, pos, WVec.Zero, 0, palette, 1, false, sequence.IgnoreWorldTint)); } } } @@ -113,8 +113,7 @@ if (actorLocation != cell) { actorLocation = cell; - Actor.Actor.InitDict.Remove(Actor.Actor.InitDict.Get()); - Actor.Actor.InitDict.Add(new LocationInit(cell)); + Actor.ReplaceInit(new LocationInit(cell)); updated = true; } @@ -122,23 +121,19 @@ { actorSubCell = subCell; - var subcellInit = Actor.Actor.InitDict.GetOrDefault(); - if (subcellInit != null) - { - Actor.Actor.InitDict.Remove(subcellInit); + if (Actor.RemoveInits() > 0) updated = true; - } var subcell = world.Map.Tiles.Contains(cell) ? editorLayer.FreeSubCellAt(cell) : SubCell.Invalid; if (subcell != SubCell.Invalid) { - Actor.Actor.InitDict.Add(new SubCellInit(subcell)); + Actor.AddInit(new SubCellInit(subcell)); updated = true; } } if (updated) - Actor = new EditorActorPreview(wr, null, Actor.Actor, Actor.Owner); + Actor = new EditorActorPreview(wr, null, Actor.Export(), Actor.Owner); } } @@ -152,7 +147,7 @@ return terrainOrResourcePreview; if (Type == EditorCursorType.Actor) - return Actor.Render().OrderBy(WorldRenderer.RenderableScreenZPositionComparisonKey); + return Actor.Render().OrderBy(WorldRenderer.RenderableZPositionComparisonKey); return NoRenderables; } @@ -184,25 +179,22 @@ ownerName = specificOwnerInfo.ValidOwnerNames.First(); var reference = new ActorReference(actor.Name); - reference.InitDict.Add(new OwnerInit(ownerName)); - reference.InitDict.Add(new FactionInit(owner.Faction)); + reference.Add(new OwnerInit(ownerName)); + reference.Add(new FactionInit(owner.Faction)); var worldPx = wr.Viewport.ViewToWorldPx(Viewport.LastMousePos) - wr.ScreenPxOffset(actorCenterOffset); var cell = wr.Viewport.ViewToWorld(wr.Viewport.WorldToViewPx(worldPx)); - reference.InitDict.Add(new LocationInit(cell)); + reference.Add(new LocationInit(cell)); if (ios != null && ios.SharesCell) { actorSubCell = editorLayer.FreeSubCellAt(cell); if (actorSubCell != SubCell.Invalid) - reference.InitDict.Add(new SubCellInit(actorSubCell)); + reference.Add(new SubCellInit(actorSubCell)); } if (actor.HasTraitInfo()) - reference.InitDict.Add(new FacingInit(info.PreviewFacing)); - - if (actor.HasTraitInfo()) - reference.InitDict.Add(new TurretFacingInit(info.PreviewFacing)); + reference.Add(new FacingInit(info.PreviewFacing)); Type = EditorCursorType.Actor; Actor = new EditorActorPreview(wr, null, reference, owner); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,35 +11,34 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - using CellContents = ResourceLayer.CellContents; - [Desc("Required for the map editor to work. Attach this to the world actor.")] - public class EditorResourceLayerInfo : ITraitInfo, Requires + public class EditorResourceLayerInfo : TraitInfo, IResourceLayerInfo, Requires { - public virtual object Create(ActorInitializer init) { return new EditorResourceLayer(init.Self); } + public override object Create(ActorInitializer init) { return new EditorResourceLayer(init.Self); } } - public class EditorResourceLayer : IWorldLoaded, IRenderOverlay, INotifyActorDisposing + public class EditorResourceLayer : IResourceLayer, IWorldLoaded, INotifyActorDisposing { protected readonly Map Map; protected readonly TileSet Tileset; protected readonly Dictionary Resources; - protected readonly CellLayer Tiles; - protected readonly HashSet Dirty = new HashSet(); - - readonly Dictionary spriteLayers = new Dictionary(); + protected readonly CellLayer Tiles; public int NetWorth { get; protected set; } bool disposed; + public event Action CellChanged; + + ResourceLayerContents IResourceLayer.GetResource(CPos cell) { return Tiles[cell]; } + bool IResourceLayer.IsVisible(CPos cell) { return Map.Contains(cell); } + public EditorResourceLayer(Actor self) { if (self.World.Type != WorldType.Editor) @@ -48,7 +47,7 @@ Map = self.World.Map; Tileset = self.World.Map.Rules.TileSet; - Tiles = new CellLayer(Map); + Tiles = new CellLayer(Map); Resources = self.TraitsImplementing() .ToDictionary(r => r.Info.ResourceType, r => r); @@ -62,74 +61,77 @@ foreach (var cell in Map.AllCells) UpdateCell(cell); - - // Build the sprite layer dictionary for rendering resources - // All resources that have the same palette must also share a sheet and blend mode - foreach (var r in Resources) - { - var res = r; - var layer = spriteLayers.GetOrAdd(r.Value.Palette, pal => - { - var first = res.Value.Variants.First().Value.First(); - return new TerrainSpriteLayer(w, wr, first.Sheet, first.BlendMode, pal, false); - }); - - // Validate that sprites are compatible with this layer - var sheet = layer.Sheet; - if (res.Value.Variants.Any(kv => kv.Value.Any(s => s.Sheet != sheet))) - throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); - - var blendMode = layer.BlendMode; - if (res.Value.Variants.Any(kv => kv.Value.Any(s => s.BlendMode != blendMode))) - throw new InvalidDataException("Resource sprites specify different blend modes. " - + "Try using different palettes for resource types that use different blend modes."); - } } public void UpdateCell(CPos cell) { var uv = cell.ToMPos(Map); - var tile = Map.Resources[uv]; + if (!Map.Resources.Contains(uv)) + return; - var t = Tiles[cell]; - if (t.Density > 0) - NetWorth -= (t.Density + 1) * t.Type.Info.ValuePerUnit; + var tile = Map.Resources[uv]; + var t = Tiles[uv]; - ResourceType type; - if (Resources.TryGetValue(tile.Type, out type)) + var newTile = ResourceLayerContents.Empty; + var newTerrain = byte.MaxValue; + if (Resources.TryGetValue(tile.Type, out var type)) { - Tiles[uv] = new EditorCellContents + newTile = new ResourceLayerContents { Type = type, - Variant = ChooseRandomVariant(type), + Density = CalculateCellDensity(type, cell) }; - Map.CustomTerrain[uv] = Tileset.GetTerrainIndex(type.Info.TerrainType); - } - else - { - Tiles[uv] = EditorCellContents.Empty; - Map.CustomTerrain[uv] = byte.MaxValue; + newTerrain = Tileset.GetTerrainIndex(type.Info.TerrainType); } - // Ingame resource rendering is a giant hack (#6395), - // so we must also touch all the neighbouring tiles - Dirty.Add(cell); + // Nothing has changed + if (newTile.Type == t.Type && newTile.Density == t.Density) + return; + + UpdateNetWorth(t.Type, t.Density, newTile.Type, newTile.Density); + Tiles[uv] = newTile; + Map.CustomTerrain[uv] = newTerrain; + CellChanged?.Invoke(cell, type); + + // Neighbouring cell density depends on this cell foreach (var d in CVec.Directions) - Dirty.Add(cell + d); + { + var neighbouringCell = cell + d; + if (!Tiles.Contains(neighbouringCell)) + continue; + + var neighbouringTile = Tiles[neighbouringCell]; + var density = CalculateCellDensity(neighbouringTile.Type, neighbouringCell); + if (neighbouringTile.Density == density) + continue; + + UpdateNetWorth(neighbouringTile.Type, neighbouringTile.Density, neighbouringTile.Type, density); + neighbouringTile.Density = density; + Tiles[neighbouringCell] = neighbouringTile; + + CellChanged?.Invoke(neighbouringCell, type); + } } - protected virtual string ChooseRandomVariant(ResourceType t) + void UpdateNetWorth(ResourceType oldType, int oldDensity, ResourceType newType, int newDensity) { - return t.Variants.Keys.Random(Game.CosmeticRandom); + // Density + 1 as workaround for fixing ResourceLayer.Harvest as it would be very disruptive to balancing + if (oldType != null && oldDensity > 0) + NetWorth -= (oldDensity + 1) * oldType.Info.ValuePerUnit; + + if (newType != null && newDensity > 0) + NetWorth += (newDensity + 1) * newType.Info.ValuePerUnit; } - public int ResourceDensityAt(CPos c) + public int CalculateCellDensity(ResourceType type, CPos c) { + var resources = Map.Resources; + if (type == null || resources[c].Type != type.Info.ResourceType) + return 0; + // Set density based on the number of neighboring resources var adjacent = 0; - var type = Tiles[c].Type; - var resources = Map.Resources; for (var u = -1; u < 2; u++) { for (var v = -1; v < 2; v++) @@ -143,83 +145,14 @@ return Math.Max(int2.Lerp(0, type.Info.MaxDensity, adjacent, 9), 1); } - public virtual EditorCellContents UpdateDirtyTile(CPos c) - { - var t = Tiles[c]; - var type = t.Type; - - // Empty tile - if (type == null) - { - t.Sprite = null; - return t; - } - - // Density + 1 as workaround for fixing ResourceLayer.Harvest as it would be very disruptive to balancing - if (t.Density > 0) - NetWorth -= (t.Density + 1) * type.Info.ValuePerUnit; - - // Set density based on the number of neighboring resources - t.Density = ResourceDensityAt(c); - - NetWorth += (t.Density + 1) * type.Info.ValuePerUnit; - - var sprites = type.Variants[t.Variant]; - var frame = int2.Lerp(0, sprites.Length - 1, t.Density, type.Info.MaxDensity); - t.Sprite = sprites[frame]; - - return t; - } - - void IRenderOverlay.Render(WorldRenderer wr) - { - if (wr.World.Type != WorldType.Editor) - return; - - foreach (var c in Dirty) - { - if (Tiles.Contains(c)) - { - var resource = UpdateDirtyTile(c); - Tiles[c] = resource; - - foreach (var kv in spriteLayers) - { - // resource.Type is meaningless (and may be null) if resource.Sprite is null - if (resource.Sprite != null && resource.Type.Palette == kv.Key) - kv.Value.Update(c, resource.Sprite); - else - kv.Value.Update(c, null); - } - } - } - - Dirty.Clear(); - - foreach (var l in spriteLayers.Values) - l.Draw(wr.Viewport); - } - void INotifyActorDisposing.Disposing(Actor self) { if (disposed) return; - foreach (var kv in spriteLayers.Values) - kv.Dispose(); - Map.Resources.CellEntryChanged -= UpdateCell; disposed = true; } } - - public struct EditorCellContents - { - public static readonly EditorCellContents Empty = default(EditorCellContents); - public ResourceType Type; - public int Density; - public string Variant; - public Sprite Sprite; - } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/EditorSelectionLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/EditorSelectionLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/EditorSelectionLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/EditorSelectionLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Required for the map editor to work. Attach this to the world actor.")] - public class EditorSelectionLayerInfo : ITraitInfo + public class EditorSelectionLayerInfo : TraitInfo { [PaletteReference] [Desc("Palette to use for rendering the placement sprite.")] @@ -25,15 +25,15 @@ [Desc("Sequence image where the selection overlay types are defined.")] public readonly string Image = "editor-overlay"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] [Desc("Sequence to use for the copy overlay.")] public readonly string CopySequence = "copy"; - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] [Desc("Sequence to use for the paste overlay.")] public readonly string PasteSequence = "paste"; - public virtual object Create(ActorInitializer init) { return new EditorSelectionLayer(init.Self, this); } + public override object Create(ActorInitializer init) { return new EditorSelectionLayer(init.Self, this); } } public class EditorSelectionLayer : IWorldLoaded, IRenderAboveShroud @@ -89,12 +89,12 @@ if (CopyRegion != null) foreach (var c in CopyRegion) yield return new SpriteRenderable(copySprite, wr.World.Map.CenterOfCell(c), - WVec.Zero, -511, palette, 1f, true); + WVec.Zero, -511, palette, 1f, true, true); if (PasteRegion != null) foreach (var c in PasteRegion) yield return new SpriteRenderable(pasteSprite, wr.World.Map.CenterOfCell(c), - WVec.Zero, -511, palette, 1f, true); + WVec.Zero, -511, palette, 1f, true, true); } bool IRenderAboveShroud.SpatiallyPartitionable { get { return false; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/ElevatedBridgeLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/ElevatedBridgeLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/ElevatedBridgeLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/ElevatedBridgeLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,12 +15,12 @@ namespace OpenRA.Mods.Common.Traits { - public class ElevatedBridgeLayerInfo : ITraitInfo, Requires, ILobbyCustomRulesIgnore + public class ElevatedBridgeLayerInfo : TraitInfo, Requires, ILobbyCustomRulesIgnore { [Desc("Terrain type used by cells outside any elevated bridge footprint.")] public readonly string ImpassableTerrainType = "Impassable"; - public object Create(ActorInitializer init) { return new ElevatedBridgeLayer(init.Self, this); } + public override object Create(ActorInitializer init) { return new ElevatedBridgeLayer(init.Self, this); } } // For now this is mostly copies TerrainTunnelLayer. This will change once bridge destruction is implemented diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/ExitsDebugOverlayManager.cs openra-20210321/OpenRA.Mods.Common/Traits/World/ExitsDebugOverlayManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/ExitsDebugOverlayManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/ExitsDebugOverlayManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,12 +15,12 @@ namespace OpenRA.Mods.Common.Traits { - public class ExitsDebugOverlayManagerInfo : ITraitInfo + public class ExitsDebugOverlayManagerInfo : TraitInfo { [Desc("The font used to draw cell vectors. Should match the value as-is in the Fonts section of the mod manifest (do not convert to lowercase).")] public readonly string Font = "TinyBold"; - object ITraitInfo.Create(ActorInitializer init) { return new ExitsDebugOverlayManager(init.Self, this); } + public override object Create(ActorInitializer init) { return new ExitsDebugOverlayManager(init.Self, this); } } public class ExitsDebugOverlayManager : IWorldLoaded, IChatCommand diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/GameSaveViewportManager.cs openra-20210321/OpenRA.Mods.Common/Traits/World/GameSaveViewportManager.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/GameSaveViewportManager.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/GameSaveViewportManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,9 +16,9 @@ namespace OpenRA.Mods.Common.Traits { - public class GameSaveViewportManagerInfo : ITraitInfo + public class GameSaveViewportManagerInfo : TraitInfo { - public object Create(ActorInitializer init) { return new GameSaveViewportManager(); } + public override object Create(ActorInitializer init) { return new GameSaveViewportManager(); } } public class GameSaveViewportManager : IWorldLoaded, IGameSaveTraitData diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/IndexedPalette.cs openra-20210321/OpenRA.Mods.Common/Traits/World/IndexedPalette.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/IndexedPalette.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/IndexedPalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,90 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.IO; +using OpenRA.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common +{ + [Desc("Define a palette by swapping palette indices.")] + public class IndexedPaletteInfo : TraitInfo, IRulesetLoaded + { + [PaletteDefinition] + [FieldLoader.Require] + [Desc("Internal palette name")] + public readonly string Name = null; + + [PaletteReference] + [Desc("The name of the palette to base off.")] + public readonly string BasePalette = null; + + [FieldLoader.Require] + [Desc("Indices from BasePalette to be swapped with ReplaceIndex.")] + public readonly int[] Index = { }; + + [FieldLoader.Require] + [Desc("Indices from BasePalette to replace from Index.")] + public readonly int[] ReplaceIndex = { }; + + [Desc("Allow palette modifiers to change the palette.")] + public readonly bool AllowModifiers = true; + + public override object Create(ActorInitializer init) { return new IndexedPalette(this); } + + public void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + if (Index.Length != ReplaceIndex.Length) + throw new YamlException("ReplaceIndex length does not match Index length for palette {0}".F(Name)); + } + } + + public class IndexedPalette : ILoadsPalettes + { + readonly IndexedPaletteInfo info; + + public IndexedPalette(IndexedPaletteInfo info) + { + this.info = info; + } + + public void LoadPalettes(WorldRenderer wr) + { + var basePalette = wr.Palette(info.BasePalette).Palette; + var pal = new ImmutablePalette(basePalette, new IndexedColorRemap(basePalette, info.Index, info.ReplaceIndex)); + wr.AddPalette(info.Name, pal, info.AllowModifiers); + } + } + + public class IndexedColorRemap : IPaletteRemap + { + Dictionary replacements = new Dictionary(); + IPalette basePalette; + + public IndexedColorRemap(IPalette basePalette, int[] ramp, int[] remap) + { + this.basePalette = basePalette; + if (ramp.Length != remap.Length) + throw new InvalidDataException("ramp and remap lengths do no match."); + + for (var i = 0; i < ramp.Length; i++) + replacements[ramp[i]] = remap[i]; + } + + public Color GetRemappedColor(Color original, int index) + { + return replacements.TryGetValue(index, out var c) + ? basePalette.GetColor(c) : original; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/IndexedPlayerPalette.cs openra-20210321/OpenRA.Mods.Common/Traits/World/IndexedPlayerPalette.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/IndexedPlayerPalette.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/IndexedPlayerPalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,70 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common +{ + [Desc("Define a player palette by swapping palette indices.")] + public class IndexedPlayerPaletteInfo : TraitInfo, IRulesetLoaded + { + [PaletteReference] + [Desc("The name of the palette to base off.")] + public readonly string BasePalette = null; + + [PaletteDefinition(true)] + [Desc("The prefix for the resulting player palettes")] + public readonly string BaseName = "player"; + + [Desc("Remap these indices to player colors.")] + public readonly int[] RemapIndex = { }; + + [Desc("Allow palette modifiers to change the palette.")] + public readonly bool AllowModifiers = true; + + public readonly Dictionary PlayerIndex; + + public override object Create(ActorInitializer init) { return new IndexedPlayerPalette(this); } + + public void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + foreach (var p in PlayerIndex) + if (p.Value.Length != RemapIndex.Length) + throw new YamlException("PlayerIndex for player `{0}` length does not match RemapIndex!".F(p.Key)); + } + } + + public class IndexedPlayerPalette : ILoadsPlayerPalettes + { + readonly IndexedPlayerPaletteInfo info; + + public IndexedPlayerPalette(IndexedPlayerPaletteInfo info) + { + this.info = info; + } + + public void LoadPlayerPalettes(WorldRenderer wr, string playerName, Color color, bool replaceExisting) + { + var basePalette = wr.Palette(info.BasePalette).Palette; + ImmutablePalette pal; + + if (info.PlayerIndex.TryGetValue(playerName, out var remap)) + pal = new ImmutablePalette(basePalette, new IndexedColorRemap(basePalette, info.RemapIndex, remap)); + else + pal = new ImmutablePalette(basePalette); + + wr.AddPalette(info.BaseName + playerName, pal, info.AllowModifiers, replaceExisting); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/JumpjetActorLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/JumpjetActorLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/JumpjetActorLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/JumpjetActorLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits { - public class JumpjetActorLayerInfo : ITraitInfo + public class JumpjetActorLayerInfo : TraitInfo { [Desc("Terrain type of the airborne layer.")] public readonly string TerrainType = "Jumpjet"; @@ -25,7 +25,7 @@ [Desc("Cell radius for smoothing adjacent cell heights.")] public readonly int SmoothingRadius = 2; - public object Create(ActorInitializer init) { return new JumpjetActorLayer(init.Self, this); } + public override object Create(ActorInitializer init) { return new JumpjetActorLayer(init.Self, this); } } public class JumpjetActorLayer : ICustomMovementLayer @@ -83,9 +83,7 @@ if (jli.JumpjetTransitionOnRamps) return true; - var tile = map.Tiles[cell]; - var ti = map.Rules.TileSet.GetTileInfo(tile); - return ti == null || ti.RampType == 0; + return map.Ramp[cell] == 0; } int ICustomMovementLayer.EntryMovementCost(ActorInfo a, LocomotorInfo li, CPos cell) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/LegacyBridgeLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/LegacyBridgeLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/LegacyBridgeLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/LegacyBridgeLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,18 +17,18 @@ namespace OpenRA.Mods.Common.Traits { - class LegacyBridgeLayerInfo : ITraitInfo + class LegacyBridgeLayerInfo : TraitInfo { [ActorReference] public readonly string[] Bridges = { "bridge1", "bridge2" }; - public object Create(ActorInitializer init) { return new LegacyBridgeLayer(init.Self, this); } + public override object Create(ActorInitializer init) { return new LegacyBridgeLayer(init.Self, this); } } class LegacyBridgeLayer : IWorldLoaded { readonly LegacyBridgeLayerInfo info; - readonly Dictionary> bridgeTypes = new Dictionary>(); + readonly Dictionary bridgeTypes = new Dictionary(); CellLayer bridges; @@ -46,7 +46,7 @@ { var bi = w.Map.Rules.Actors[bridge].TraitInfo(); foreach (var template in bi.Templates) - bridgeTypes.Add(template.First, Pair.New(bridge, template.Second)); + bridgeTypes.Add(template.Template, (bridge, template.Health)); } // Take all templates to overlay from the map @@ -65,18 +65,19 @@ return; // Correlate the tile "image" aka subtile with its position to find the template origin - var tile = w.Map.Tiles[cell].Type; - var index = w.Map.Tiles[cell].Index; + var ti = w.Map.Tiles[cell]; + var tile = ti.Type; + var index = ti.Index; var template = w.Map.Rules.TileSet.Templates[tile]; var ni = cell.X - index % template.Size.X; var nj = cell.Y - index / template.Size.X; // Create a new actor for this bridge and keep track of which subtiles this bridge includes - var bridge = w.CreateActor(bridgeTypes[tile].First, new TypeDictionary + var bridge = w.CreateActor(bridgeTypes[tile].Template, new TypeDictionary { new LocationInit(new CPos(ni, nj)), new OwnerInit(w.WorldActor.Owner), - new HealthInit(bridgeTypes[tile].Second, true), + new HealthInit(bridgeTypes[tile].Health, true), }).Trait(); var subTiles = new Dictionary(); @@ -88,8 +89,12 @@ // Where do we expect to find the subtile var subtile = new CPos(ni + ind % template.Size.X, nj + ind / template.Size.X); + if (!mapTiles.Contains(subtile)) + continue; + // This isn't the bridge you're looking for - if (!mapTiles.Contains(subtile) || mapTiles[subtile].Type != tile || mapTiles[subtile].Index != ind) + var subti = mapTiles[subtile]; + if (subti.Type != tile || subti.Index != ind) continue; subTiles.Add(subtile, ind); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/LoadWidgetAtGameStart.cs openra-20210321/OpenRA.Mods.Common/Traits/World/LoadWidgetAtGameStart.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/LoadWidgetAtGameStart.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/LoadWidgetAtGameStart.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { - public class LoadWidgetAtGameStartInfo : ITraitInfo + public class LoadWidgetAtGameStartInfo : TraitInfo { [Desc("The widget tree to open when a shellmap is loaded (i.e. the main menu).")] public readonly string ShellmapRoot = "MAINMENU"; @@ -33,7 +33,7 @@ [Desc("Remove any existing UI when a map is loaded.")] public readonly bool ClearRoot = true; - public object Create(ActorInitializer init) { return new LoadWidgetAtGameStart(this); } + public override object Create(ActorInitializer init) { return new LoadWidgetAtGameStart(this); } } public class LoadWidgetAtGameStart : IWorldLoaded, INotifyGameLoading, INotifyGameLoaded diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/LobbyPrerequisiteCheckbox.cs openra-20210321/OpenRA.Mods.Common/Traits/World/LobbyPrerequisiteCheckbox.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/LobbyPrerequisiteCheckbox.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/LobbyPrerequisiteCheckbox.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Enables defined prerequisites at game start for all players if the checkbox is enabled.")] - public class LobbyPrerequisiteCheckboxInfo : ITraitInfo, ILobbyOptions, ITechTreePrerequisiteInfo + public class LobbyPrerequisiteCheckboxInfo : TraitInfo, ILobbyOptions, ITechTreePrerequisiteInfo { [FieldLoader.Require] [Desc("Internal id for this checkbox.")] @@ -52,7 +52,7 @@ Visible, DisplayOrder, Enabled, Locked); } - public object Create(ActorInitializer init) { return new LobbyPrerequisiteCheckbox(this); } + public override object Create(ActorInitializer init) { return new LobbyPrerequisiteCheckbox(this); } } public class LobbyPrerequisiteCheckbox : INotifyCreated, ITechTreePrerequisite diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/Locomotor.cs openra-20210321/OpenRA.Mods.Common/Traits/World/Locomotor.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/Locomotor.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/Locomotor.cs 2021-03-21 11:10:05.000000000 +0000 @@ -55,7 +55,7 @@ } [Desc("Used by Mobile. Attach these to the world actor. You can have multiple variants by adding @suffixes.")] - public class LocomotorInfo : ITraitInfo + public class LocomotorInfo : TraitInfo { [Desc("Locomotor ID.")] public readonly string Name = "default"; @@ -99,22 +99,6 @@ return ret; } - TerrainInfo[] LoadTilesetSpeeds(TileSet tileSet) - { - var info = new TerrainInfo[tileSet.TerrainInfo.Length]; - for (var i = 0; i < info.Length; i++) - info[i] = TerrainInfo.Impassable; - - foreach (var kvp in TerrainSpeeds) - { - byte index; - if (tileSet.TryGetTerrainIndex(kvp.Key, out index)) - info[index] = kvp.Value; - } - - return info; - } - public class TerrainInfo { public static readonly TerrainInfo Impassable = new TerrainInfo(); @@ -135,56 +119,9 @@ } } - public struct WorldMovementInfo - { - internal readonly World World; - internal readonly TerrainInfo[] TerrainInfos; - internal WorldMovementInfo(World world, LocomotorInfo info) - { - // PERF: This struct allows us to cache the terrain info for the tileset used by the world. - // This allows us to speed up some performance-sensitive pathfinding calculations. - World = world; - TerrainInfos = info.TilesetTerrainInfo[world.Map.Rules.TileSet]; - } - } - - public readonly Cache TilesetTerrainInfo; - public readonly Cache TilesetMovementClass; - - public LocomotorInfo() - { - TilesetTerrainInfo = new Cache(LoadTilesetSpeeds); - TilesetMovementClass = new Cache(CalculateTilesetMovementClass); - } - - public int CalculateTilesetMovementClass(TileSet tileset) - { - // collect our ability to cross *all* terraintypes, in a bitvector - return TilesetTerrainInfo[tileset].Select(ti => ti.Cost < short.MaxValue).ToBits(); - } - - public uint GetMovementClass(TileSet tileset) - { - return (uint)TilesetMovementClass[tileset]; - } - - public int TileSetMovementHash(TileSet tileSet) - { - var terrainInfos = TilesetTerrainInfo[tileSet]; - - // Compute and return the hash using aggregate - return terrainInfos.Aggregate(terrainInfos.Length, - (current, terrainInfo) => unchecked(current * 31 + terrainInfo.Cost)); - } - - public WorldMovementInfo GetWorldMovementInfo(World world) - { - return new WorldMovementInfo(world, this); - } - public virtual bool DisableDomainPassabilityCheck { get { return false; } } - public virtual object Create(ActorInitializer init) { return new Locomotor(init.Self, this); } + public override object Create(ActorInitializer init) { return new Locomotor(init.Self, this); } } public class Locomotor : IWorldLoaded @@ -204,14 +141,15 @@ } public readonly LocomotorInfo Info; + public readonly uint MovementClass; CellLayer cellsCost; CellLayer blockingCache; readonly Dictionary> customLayerCellsCost = new Dictionary>(); readonly Dictionary> customLayerBlockingCache = new Dictionary>(); - LocomotorInfo.TerrainInfo[] terrainInfos; - World world; + readonly LocomotorInfo.TerrainInfo[] terrainInfos; + readonly World world; readonly HashSet dirtyCells = new HashSet(); IActorMap actorMap; @@ -221,6 +159,15 @@ { Info = info; sharesCell = info.SharesCell; + world = self.World; + + var tileSet = world.Map.Rules.TileSet; + terrainInfos = new LocomotorInfo.TerrainInfo[tileSet.TerrainInfo.Length]; + for (var i = 0; i < terrainInfos.Length; i++) + if (!info.TerrainSpeeds.TryGetValue(tileSet.TerrainInfo[i].Type, out terrainInfos[i])) + terrainInfos[i] = LocomotorInfo.TerrainInfo.Impassable; + + MovementClass = (uint)terrainInfos.Select(ti => ti.Cost < short.MaxValue).ToBits(); } public short MovementCostForCell(CPos cell) @@ -231,6 +178,14 @@ return cell.Layer == 0 ? cellsCost[cell] : customLayerCellsCost[cell.Layer][cell]; } + public int MovementSpeedForCell(CPos cell) + { + var index = cell.Layer == 0 ? world.Map.GetTerrainIndex(cell) : + world.GetCustomMovementLayers()[cell.Layer].GetTerrainIndex(cell); + + return terrainInfos[index].Speed; + } + public short MovementCostToEnterCell(Actor actor, CPos destNode, BlockedByActor check, Actor ignoreActor) { if (!world.Map.Contains(destNode)) @@ -312,6 +267,9 @@ public bool CanStayInCell(CPos cell) { + if (!world.Map.Contains(cell)) + return false; + return !GetCache(cell).CellFlag.HasCellFlag(CellFlag.HasTransitOnlyActor); } @@ -343,9 +301,9 @@ // If the check allows: We are not blocked by units that we can force to move out of the way. if (check <= BlockedByActor.Immovable && cellFlag.HasCellFlag(CellFlag.HasMovableActor) && - actor.Owner.Stances[otherActor.Owner] == Stance.Ally) + actor.Owner.RelationshipWith(otherActor.Owner) == PlayerRelationship.Ally) { - var mobile = otherActor.TraitOrDefault(); + var mobile = otherActor.OccupiesSpace as Mobile; if (mobile != null && !mobile.IsTraitDisabled && !mobile.IsTraitPaused && !mobile.IsImmovable) return false; } @@ -366,7 +324,7 @@ if (cellFlag.HasCellFlag(CellFlag.HasTransitOnlyActor)) { // Transit only tiles should not block movement - var building = otherActor.TraitOrDefault(); + var building = otherActor.OccupiesSpace as Building; if (building != null && building.TransitOnlyCells().Contains(cell)) return false; } @@ -402,11 +360,9 @@ public void WorldLoaded(World w, WorldRenderer wr) { - world = w; var map = w.Map; actorMap = w.ActorMap; actorMap.CellUpdated += CellUpdated; - terrainInfos = Info.TilesetTerrainInfo[map.Rules.TileSet]; blockingCache = new CellLayer(map); cellsCost = new CellLayer(map); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/MapBuildRadius.cs openra-20210321/OpenRA.Mods.Common/Traits/World/MapBuildRadius.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/MapBuildRadius.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/MapBuildRadius.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Controls the build radius checkboxes in the lobby options.")] - public class MapBuildRadiusInfo : ITraitInfo, ILobbyOptions + public class MapBuildRadiusInfo : TraitInfo, ILobbyOptions { [Translate] [Desc("Descriptive label for the ally build radius checkbox in the lobby.")] @@ -66,7 +66,7 @@ BuildRadiusCheckboxVisible, BuildRadiusCheckboxDisplayOrder, BuildRadiusCheckboxEnabled, BuildRadiusCheckboxLocked); } - public object Create(ActorInitializer init) { return new MapBuildRadius(this); } + public override object Create(ActorInitializer init) { return new MapBuildRadius(this); } } public class MapBuildRadius : INotifyCreated diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/MapCreeps.cs openra-20210321/OpenRA.Mods.Common/Traits/World/MapCreeps.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/MapCreeps.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/MapCreeps.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Controls the 'Creeps' checkbox in the lobby options.")] - public class MapCreepsInfo : ITraitInfo, ILobbyOptions + public class MapCreepsInfo : TraitInfo, ILobbyOptions { [Translate] [Desc("Descriptive label for the creeps checkbox in the lobby.")] @@ -42,7 +42,7 @@ yield return new LobbyBooleanOption("creeps", CheckboxLabel, CheckboxDescription, CheckboxVisible, CheckboxDisplayOrder, CheckboxEnabled, CheckboxLocked); } - public object Create(ActorInitializer init) { return new MapCreeps(this); } + public override object Create(ActorInitializer init) { return new MapCreeps(this); } } public class MapCreeps : INotifyCreated diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/MapOptions.cs openra-20210321/OpenRA.Mods.Common/Traits/World/MapOptions.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/MapOptions.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/MapOptions.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Controls the game speed, tech level, and short game lobby options.")] - public class MapOptionsInfo : ITraitInfo, ILobbyOptions, IRulesetLoaded + public class MapOptionsInfo : TraitInfo, ILobbyOptions, IRulesetLoaded { [Translate] [Desc("Descriptive label for the short game checkbox in the lobby.")] @@ -105,7 +105,7 @@ throw new YamlException("Invalid default game speed '{0}'.".F(GameSpeed)); } - public object Create(ActorInitializer init) { return new MapOptions(this); } + public override object Create(ActorInitializer init) { return new MapOptions(this); } } public class MapOptions : INotifyCreated diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs openra-20210321/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,17 +9,18 @@ */ #endregion -using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; -using OpenRA.Primitives; +using OpenRA.Mods.Common.Widgets.Logic; +using OpenRA.Network; +using OpenRA.Support; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Allows the map to have working spawnpoints. Also controls the 'Separate Team Spawns' checkbox in the lobby options.")] - public class MPStartLocationsInfo : ITraitInfo, ILobbyOptions + public class MPStartLocationsInfo : TraitInfo, ILobbyOptions, IAssignSpawnPointsInfo { public readonly WDist InitialExploreRange = WDist.FromCells(5); @@ -43,7 +44,7 @@ [Desc("Display order for the spawn positions checkbox in the lobby.")] public readonly int SeparateTeamSpawnsCheckboxDisplayOrder = 0; - public virtual object Create(ActorInitializer init) { return new MPStartLocations(this); } + public override object Create(ActorInitializer init) { return new MPStartLocations(this); } IEnumerable ILobbyOptions.LobbyOptions(Ruleset rules) { @@ -56,15 +57,61 @@ SeparateTeamSpawnsCheckboxEnabled, SeparateTeamSpawnsCheckboxLocked); } + + class AssignSpawnLocationsState + { + public CPos[] SpawnLocations; + public List AvailableSpawnPoints; + public readonly Dictionary OccupiedSpawnPoints = new Dictionary(); + } + + object IAssignSpawnPointsInfo.InitializeState(MapPreview map, Session lobbyInfo) + { + var state = new AssignSpawnLocationsState(); + + // Initialize the list of unoccupied spawn points for AssignSpawnLocations to pick from + state.SpawnLocations = map.SpawnPoints; + state.AvailableSpawnPoints = LobbyUtils.AvailableSpawnPoints(map.SpawnPoints.Length, lobbyInfo); + foreach (var kv in lobbyInfo.Slots) + { + var client = lobbyInfo.ClientInSlot(kv.Key); + if (client == null || client.SpawnPoint == 0) + continue; + + state.AvailableSpawnPoints.Remove(client.SpawnPoint); + state.OccupiedSpawnPoints.Add(client.SpawnPoint, client); + } + + return state; + } + + int IAssignSpawnPointsInfo.AssignSpawnPoint(object stateObject, Session lobbyInfo, Session.Client client, MersenneTwister playerRandom) + { + var state = (AssignSpawnLocationsState)stateObject; + var separateTeamSpawns = lobbyInfo.GlobalSettings.OptionOrDefault("separateteamspawns", SeparateTeamSpawnsCheckboxEnabled); + + if (client.SpawnPoint > 0 && client.SpawnPoint <= state.SpawnLocations.Length) + return client.SpawnPoint; + + var spawnPoint = state.OccupiedSpawnPoints.Count == 0 || !separateTeamSpawns + ? state.AvailableSpawnPoints.Random(playerRandom) + : state.AvailableSpawnPoints // pick the most distant spawnpoint from everyone else + .Select(s => (Cell: state.SpawnLocations[s - 1], Index: s)) + .MaxBy(s => state.OccupiedSpawnPoints.Sum(kv => (state.SpawnLocations[kv.Key - 1] - s.Cell).LengthSquared)).Index; + + state.AvailableSpawnPoints.Remove(spawnPoint); + state.OccupiedSpawnPoints.Add(spawnPoint, client); + return spawnPoint; + } } - public class MPStartLocations : IWorldLoaded, INotifyCreated + public class MPStartLocations : IWorldLoaded, INotifyCreated, IAssignSpawnPoints { readonly MPStartLocationsInfo info; - - public readonly Dictionary Start = new Dictionary(); - + readonly Dictionary occupiedSpawnPoints = new Dictionary(); bool separateTeamSpawns; + CPos[] spawnLocations; + List availableSpawnPoints; public MPStartLocations(MPStartLocationsInfo info) { @@ -75,71 +122,69 @@ { separateTeamSpawns = self.World.LobbyInfo.GlobalSettings .OptionOrDefault("separateteamspawns", info.SeparateTeamSpawnsCheckboxEnabled); - } - - public void WorldLoaded(World world, WorldRenderer wr) - { - var spawns = world.Actors.Where(a => a.Info.Name == "mpspawn") - .Select(a => a.Location) - .ToArray(); - - var taken = world.LobbyInfo.Clients.Where(c => c.SpawnPoint != 0 && c.Slot != null) - .Select(c => spawns[c.SpawnPoint - 1]).ToList(); - var available = spawns.Except(taken).ToList(); - // Set spawn - foreach (var kv in world.LobbyInfo.Slots) + var spawns = new List(); + foreach (var n in self.World.Map.ActorDefinitions) + if (n.Value.Value == "mpspawn") + spawns.Add(new ActorReference(n.Key, n.Value.ToDictionary()).GetValue()); + + spawnLocations = spawns.ToArray(); + + // Initialize the list of unoccupied spawn points for AssignSpawnLocations to pick from + availableSpawnPoints = LobbyUtils.AvailableSpawnPoints(spawnLocations.Length, self.World.LobbyInfo); + foreach (var kv in self.World.LobbyInfo.Slots) { - var player = FindPlayerInSlot(world, kv.Key); - if (player == null) continue; + var client = self.World.LobbyInfo.ClientInSlot(kv.Key); + if (client == null || client.SpawnPoint == 0) + continue; - var client = world.LobbyInfo.ClientInSlot(kv.Key); - var spid = (client == null || client.SpawnPoint == 0) - ? ChooseSpawnPoint(world, available, taken) - : spawns[client.SpawnPoint - 1]; - - Start.Add(player, spid); - - player.SpawnPoint = (client == null || client.SpawnPoint == 0) - ? spawns.IndexOf(spid) + 1 - : client.SpawnPoint; + availableSpawnPoints.Remove(client.SpawnPoint); + occupiedSpawnPoints.Add(client.SpawnPoint, client); } + } - // Explore allied shroud - var map = world.Map; - foreach (var p in Start.Keys) - { - var cells = Shroud.ProjectedCellsInRange(map, Start[p], info.InitialExploreRange); - foreach (var q in world.Players) - if (p.IsAlliedWith(q)) - q.Shroud.ExploreProjectedCells(world, cells); - } + CPos IAssignSpawnPoints.AssignHomeLocation(World world, Session.Client client, MersenneTwister playerRandom) + { + if (client.SpawnPoint > 0 && client.SpawnPoint <= spawnLocations.Length) + return spawnLocations[client.SpawnPoint - 1]; + + var spawnPoint = occupiedSpawnPoints.Count == 0 || !separateTeamSpawns + ? availableSpawnPoints.Random(playerRandom) + : availableSpawnPoints // pick the most distant spawnpoint from everyone else + .Select(s => (Cell: spawnLocations[s - 1], Index: s)) + .MaxBy(s => occupiedSpawnPoints.Sum(kv => (spawnLocations[kv.Key - 1] - s.Cell).LengthSquared)).Index; - // Set viewport - if (world.LocalPlayer != null && Start.ContainsKey(world.LocalPlayer)) - wr.Viewport.Center(map.CenterOfCell(Start[world.LocalPlayer])); + availableSpawnPoints.Remove(spawnPoint); + occupiedSpawnPoints.Add(spawnPoint, client); + return spawnLocations[spawnPoint - 1]; } - static Player FindPlayerInSlot(World world, string pr) + int IAssignSpawnPoints.SpawnPointForPlayer(Player player) { - return world.Players.FirstOrDefault(p => p.PlayerReference.Name == pr); + foreach (var kv in occupiedSpawnPoints) + if (kv.Value.Index == player.ClientIndex) + return kv.Key; + + return 0; } - CPos ChooseSpawnPoint(World world, List available, List taken) + void IWorldLoaded.WorldLoaded(World world, WorldRenderer wr) { - if (available.Count == 0) - throw new InvalidOperationException("No free spawnpoint."); + foreach (var p in world.Players) + { + if (!p.Playable) + continue; + + if (p == world.LocalPlayer) + wr.Viewport.Center(world.Map.CenterOfCell(p.HomeLocation)); - var n = taken.Count == 0 || !separateTeamSpawns - ? world.SharedRandom.Next(available.Count) - : available // pick the most distant spawnpoint from everyone else - .Select((k, i) => Pair.New(k, i)) - .MaxBy(a => taken.Sum(t => (t - a.First).LengthSquared)).Second; + var cells = Shroud.ProjectedCellsInRange(world.Map, p.HomeLocation, info.InitialExploreRange) + .ToList(); - var sp = available[n]; - available.RemoveAt(n); - taken.Add(sp); - return sp; + foreach (var q in world.Players) + if (p.IsAlliedWith(q)) + q.Shroud.ExploreProjectedCells(world, cells); + } } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/MPStartUnits.cs openra-20210321/OpenRA.Mods.Common/Traits/World/MPStartUnits.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/MPStartUnits.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/MPStartUnits.cs 2021-03-21 11:10:05.000000000 +0000 @@ -27,12 +27,14 @@ public readonly HashSet Factions = new HashSet(); [Desc("The actor at the center, usually the mobile construction vehicle.")] + [ActorReference] public readonly string BaseActor = null; [Desc("Offset from the spawn point, BaseActor will spawn at.")] public readonly CVec BaseActorOffset = CVec.Zero; [Desc("A group of units ready to defend or scout.")] + [ActorReference] public readonly string[] SupportActors = { }; [Desc("Inner radius for spawning support actors")] @@ -41,11 +43,11 @@ [Desc("Outer radius for spawning support actors")] public readonly int OuterSupportRadius = 4; - [Desc("Initial facing of BaseActor. -1 means random.")] - public readonly int BaseActorFacing = 128; + [Desc("Initial facing of BaseActor. Leave undefined for random facings.")] + public readonly WAngle? BaseActorFacing = new WAngle(512); - [Desc("Initial facing of SupportActors. -1 means random.")] - public readonly int SupportActorsFacing = -1; + [Desc("Initial facing of SupportActors. Leave undefined for random facings.")] + public readonly WAngle? SupportActorsFacing = null; } public class MPStartUnits { } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/MusicPlaylist.cs openra-20210321/OpenRA.Mods.Common/Traits/World/MusicPlaylist.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/MusicPlaylist.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/MusicPlaylist.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Trait for music handling. Attach this to the world actor.")] - public class MusicPlaylistInfo : ITraitInfo + public class MusicPlaylistInfo : TraitInfo { [Desc("Music to play when the map starts.", "Plays the first song on the playlist when undefined.")] public readonly string StartingMusic = null; @@ -39,7 +39,7 @@ [Desc("Disable all world sounds (combat etc).")] public readonly bool DisableWorldSounds = false; - public object Create(ActorInitializer init) { return new MusicPlaylist(init.World, this); } + public override object Create(ActorInitializer init) { return new MusicPlaylist(init.World, this); } } public class MusicPlaylist : INotifyActorDisposing, IGameOver, IWorldLoaded, INotifyGameLoaded @@ -69,9 +69,6 @@ this.info = info; this.world = world; - if (info.DisableWorldSounds) - Game.Sound.DisableWorldSounds = true; - IsMusicInstalled = world.Map.Rules.InstalledMusic.Any(); if (!IsMusicInstalled) return; @@ -105,6 +102,9 @@ void IWorldLoaded.WorldLoaded(World world, WorldRenderer wr) { + // Reset any bogus pre-existing state + Game.Sound.DisableWorldSounds = info.DisableWorldSounds; + if (!world.IsLoadingGameSave) Play(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromEmbeddedSpritePalette.cs openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromEmbeddedSpritePalette.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromEmbeddedSpritePalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromEmbeddedSpritePalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { - public class PaletteFromEmbeddedSpritePaletteInfo : ITraitInfo, IProvidesCursorPaletteInfo + public class PaletteFromEmbeddedSpritePaletteInfo : TraitInfo, IProvidesCursorPaletteInfo { [PaletteDefinition] [FieldLoader.Require] @@ -39,7 +39,7 @@ [Desc("Whether this palette is available for cursors.")] public readonly bool CursorPalette = false; - public object Create(ActorInitializer init) { return new PaletteFromEmbeddedSpritePalette(this); } + public override object Create(ActorInitializer init) { return new PaletteFromEmbeddedSpritePalette(this); } string IProvidesCursorPaletteInfo.Palette { get { return CursorPalette ? Name : null; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromFile.cs openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromFile.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromFile.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromFile.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Load VGA palette (.pal) registers.")] - class PaletteFromFileInfo : ITraitInfo, IProvidesCursorPaletteInfo + class PaletteFromFileInfo : TraitInfo, IProvidesCursorPaletteInfo { [PaletteDefinition] [FieldLoader.Require] @@ -39,7 +39,7 @@ [Desc("Whether this palette is available for cursors.")] public readonly bool CursorPalette = false; - public object Create(ActorInitializer init) { return new PaletteFromFile(init.World, this); } + public override object Create(ActorInitializer init) { return new PaletteFromFile(init.World, this); } string IProvidesCursorPaletteInfo.Palette { get { return CursorPalette ? Name : null; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromGimpOrJascFile.cs openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromGimpOrJascFile.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromGimpOrJascFile.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromGimpOrJascFile.cs 2021-03-21 11:10:05.000000000 +0000 @@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Load a GIMP .gpl or JASC .pal palette file. Supports per-color alpha.")] - class PaletteFromGimpOrJascFileInfo : ITraitInfo, IProvidesCursorPaletteInfo + class PaletteFromGimpOrJascFileInfo : TraitInfo, IProvidesCursorPaletteInfo { [PaletteDefinition] [FieldLoader.Require] @@ -49,7 +49,7 @@ [Desc("Whether this palette is available for cursors.")] public readonly bool CursorPalette = false; - public object Create(ActorInitializer init) { return new PaletteFromGimpOrJascFile(init.World, this); } + public override object Create(ActorInitializer init) { return new PaletteFromGimpOrJascFile(init.World, this); } string IProvidesCursorPaletteInfo.Palette { get { return CursorPalette ? Name : null; } } @@ -63,7 +63,7 @@ if (!lines.MoveNext() || (lines.Current != "GIMP Palette" && lines.Current != "JASC-PAL")) throw new InvalidDataException("File `{0}` is not a valid GIMP or JASC palette.".F(Filename)); - byte r, g, b, a; + byte a; a = 255; var i = 0; @@ -77,13 +77,13 @@ if (rgba.Length < 3) throw new InvalidDataException("Invalid RGB(A) triplet/quartet: ({0})".F(string.Join(" ", rgba))); - if (!byte.TryParse(rgba[0], out r)) + if (!byte.TryParse(rgba[0], out var r)) throw new InvalidDataException("Invalid R value: {0}".F(rgba[0])); - if (!byte.TryParse(rgba[1], out g)) + if (!byte.TryParse(rgba[1], out var g)) throw new InvalidDataException("Invalid G value: {0}".F(rgba[1])); - if (!byte.TryParse(rgba[2], out b)) + if (!byte.TryParse(rgba[2], out var b)) throw new InvalidDataException("Invalid B value: {0}".F(rgba[2])); // Check if color has a (valid) alpha value. diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromPaletteWithAlpha.cs openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromPaletteWithAlpha.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromPaletteWithAlpha.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromPaletteWithAlpha.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Create a palette by applying alpha transparency to another palette.")] - class PaletteFromPaletteWithAlphaInfo : ITraitInfo + class PaletteFromPaletteWithAlphaInfo : TraitInfo { [PaletteDefinition] [FieldLoader.Require] @@ -38,7 +38,7 @@ [Desc("Premultiply color by the alpha component.")] public readonly bool Premultiply = true; - public object Create(ActorInitializer init) { return new PaletteFromPaletteWithAlpha(this); } + public override object Create(ActorInitializer init) { return new PaletteFromPaletteWithAlpha(this); } } class PaletteFromPaletteWithAlpha : ILoadsPalettes, IProvidesAssetBrowserPalettes diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromPlayerPaletteWithAlpha.cs openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromPlayerPaletteWithAlpha.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromPlayerPaletteWithAlpha.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromPlayerPaletteWithAlpha.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Create player palettes by applying alpha transparency to another player palette.")] - class PaletteFromPlayerPaletteWithAlphaInfo : ITraitInfo + class PaletteFromPlayerPaletteWithAlphaInfo : TraitInfo { [FieldLoader.Require] [PaletteDefinition(true)] @@ -37,7 +37,7 @@ [Desc("Premultiply color by the alpha component.")] public readonly bool Premultiply = true; - public object Create(ActorInitializer init) { return new PaletteFromPlayerPaletteWithAlpha(this); } + public override object Create(ActorInitializer init) { return new PaletteFromPlayerPaletteWithAlpha(this); } } class PaletteFromPlayerPaletteWithAlpha : ILoadsPlayerPalettes diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromPng.cs openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromPng.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromPng.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromPng.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Load a PNG and use its embedded palette.")] - class PaletteFromPngInfo : ITraitInfo, IProvidesCursorPaletteInfo + class PaletteFromPngInfo : TraitInfo, IProvidesCursorPaletteInfo { [PaletteDefinition] [FieldLoader.Require] @@ -41,7 +41,7 @@ [Desc("Whether this palette is available for cursors.")] public readonly bool CursorPalette = false; - public object Create(ActorInitializer init) { return new PaletteFromPng(init.World, this); } + public override object Create(ActorInitializer init) { return new PaletteFromPng(init.World, this); } string IProvidesCursorPaletteInfo.Palette { get { return CursorPalette ? Name : null; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromRGBA.cs openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromRGBA.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/PaletteFromRGBA.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/PaletteFromRGBA.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Creates a single color palette without any base palette file.")] - class PaletteFromRGBAInfo : ITraitInfo + class PaletteFromRGBAInfo : TraitInfo { [PaletteDefinition] [FieldLoader.Require] @@ -44,7 +44,7 @@ [Desc("Index set to be fully transparent/invisible.")] public readonly int TransparentIndex = 0; - public object Create(ActorInitializer init) { return new PaletteFromRGBA(init.World, this); } + public override object Create(ActorInitializer init) { return new PaletteFromRGBA(init.World, this); } } class PaletteFromRGBA : ILoadsPalettes diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/PathFinder.cs openra-20210321/OpenRA.Mods.Common/Traits/World/PathFinder.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/PathFinder.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/PathFinder.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,9 +9,7 @@ */ #endregion -using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using OpenRA.Mods.Common.Pathfinder; using OpenRA.Traits; @@ -19,9 +17,9 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Calculates routes for mobile units based on the A* search algorithm.", " Attach this to the world actor.")] - public class PathFinderInfo : ITraitInfo, Requires + public class PathFinderInfo : TraitInfo, Requires { - public object Create(ActorInitializer init) + public override object Create(ActorInitializer init) { return new PathFinderUnitPathCacheDecorator(new PathFinder(init.World), new PathCacheStorage(init.World)); } @@ -64,8 +62,8 @@ public List FindUnitPath(CPos source, CPos target, Actor self, Actor ignoreActor, BlockedByActor check) { - var mobile = self.Trait(); - var locomotor = mobile.Locomotor; + // PERF: Because we can be sure that OccupiesSpace is Mobile here, we can save some performance by avoiding querying for the trait. + var locomotor = ((Mobile)self.OccupiesSpace).Locomotor; if (!cached) { @@ -74,7 +72,7 @@ } // If a water-land transition is required, bail early - if (domainIndex != null && !domainIndex.IsPassable(source, target, locomotor.Info)) + if (domainIndex != null && !domainIndex.IsPassable(source, target, locomotor)) return EmptyPath; var distance = source - target; @@ -102,9 +100,10 @@ cached = true; } - var mobile = self.Trait(); - var mi = mobile.Info; - var li = mi.LocomotorInfo; + // PERF: Because we can be sure that OccupiesSpace is Mobile here, we can save some performance by avoiding querying for the trait. + var mobile = (Mobile)self.OccupiesSpace; + var locomotor = mobile.Locomotor; + var targetCell = world.Map.CellContaining(target); // Correct for SubCell offset @@ -114,19 +113,17 @@ // This assumes that the SubCell does not change during the path traversal var tilesInRange = world.Map.FindTilesInCircle(targetCell, range.Length / 1024 + 1) .Where(t => (world.Map.CenterOfCell(t) - target).LengthSquared <= range.LengthSquared - && mi.CanEnterCell(self.World, self, t)); + && mobile.Info.CanEnterCell(self.World, self, t)); // See if there is any cell within range that does not involve a cross-domain request // Really, we only need to check the circle perimeter, but it's not clear that would be a performance win if (domainIndex != null) { - tilesInRange = new List(tilesInRange.Where(t => domainIndex.IsPassable(source, t, li))); + tilesInRange = new List(tilesInRange.Where(t => domainIndex.IsPassable(source, t, locomotor))); if (!tilesInRange.Any()) return EmptyPath; } - var locomotor = mobile.Locomotor; - using (var fromSrc = PathSearch.FromPoints(world, locomotor, self, tilesInRange, source, check)) using (var fromDest = PathSearch.FromPoint(world, locomotor, self, source, targetCell, check).Reverse()) return FindBidiPath(fromSrc, fromDest); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/RadarPings.cs openra-20210321/OpenRA.Mods.Common/Traits/World/RadarPings.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/RadarPings.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/RadarPings.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,14 +16,14 @@ namespace OpenRA.Mods.Common.Traits { - public class RadarPingsInfo : ITraitInfo + public class RadarPingsInfo : TraitInfo { public readonly int FromRadius = 200; public readonly int ToRadius = 15; public readonly int ShrinkSpeed = 4; public readonly float RotationSpeed = 0.12f; - public object Create(ActorInitializer init) { return new RadarPings(this); } + public override object Create(ActorInitializer init) { return new RadarPings(this); } } public class RadarPings : ITick diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/ResourceClaimLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/ResourceClaimLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/ResourceClaimLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/ResourceClaimLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -38,8 +38,7 @@ return false; // Remove the actor's last claim, if it has one - CPos lastClaim; - if (claimByActor.TryGetValue(claimer, out lastClaim)) + if (claimByActor.TryGetValue(claimer, out var lastClaim)) claimByCell.GetOrAdd(lastClaim).Remove(claimer); claimers.Add(claimer); @@ -61,8 +60,7 @@ /// public void RemoveClaim(Actor claimer) { - CPos lastClaim; - if (claimByActor.TryGetValue(claimer, out lastClaim)) + if (claimByActor.TryGetValue(claimer, out var lastClaim)) claimByCell.GetOrAdd(lastClaim).Remove(claimer); claimByActor.Remove(claimer); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,28 +10,42 @@ #endregion using System; -using System.Collections.Generic; -using System.IO; using System.Linq; using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - [Desc("Attach this to the world actor.", "Order of the layers defines the Z sorting.")] - public class ResourceLayerInfo : ITraitInfo, Requires, Requires + public struct ResourceLayerContents { - public virtual object Create(ActorInitializer init) { return new ResourceLayer(init.Self); } + public static readonly ResourceLayerContents Empty = default(ResourceLayerContents); + public ResourceType Type; + public int Density; } - public class ResourceLayer : IWorldLoaded + public interface IResourceLayerInfo : ITraitInfoInterface { } + + [RequireExplicitImplementation] + public interface IResourceLayer { - static readonly CellContents EmptyCell = default(CellContents); + event Action CellChanged; + ResourceLayerContents GetResource(CPos cell); + bool IsVisible(CPos cell); + } + + [Desc("Attach this to the world actor.", "Order of the layers defines the Z sorting.")] + public class ResourceLayerInfo : TraitInfo, IResourceLayerInfo, Requires, Requires + { + public override object Create(ActorInitializer init) { return new ResourceLayer(init.Self); } + } + + public class ResourceLayer : IResourceLayer, IWorldLoaded + { readonly World world; readonly BuildingInfluence buildingInfluence; - protected readonly CellLayer Content; + protected readonly CellLayer Content; public bool IsResourceLayerEmpty { get { return resCells < 1; } } @@ -44,7 +58,7 @@ world = self.World; buildingInfluence = self.Trait(); - Content = new CellLayer(world.Map); + Content = new CellLayer(world.Map); } int GetAdjacentCellsWith(ResourceType t, CPos cell) @@ -68,8 +82,7 @@ foreach (var cell in w.Map.AllCells) { - ResourceType t; - if (!resources.TryGetValue(w.Map.Resources[cell].Type, out t)) + if (!resources.TryGetValue(w.Map.Resources[cell].Type, out var t)) continue; if (!AllowResourceAt(t, cell)) @@ -87,7 +100,7 @@ // Adjacent includes the current cell, so is always >= 1 var adjacent = GetAdjacentCellsWith(type, cell); var density = int2.Lerp(0, type.Info.MaxDensity, adjacent, 9); - var temp = GetResource(cell); + var temp = Content[cell]; temp.Density = Math.Max(density, 1); Content[cell] = temp; @@ -109,15 +122,7 @@ if (!rt.Info.AllowUnderBuildings && buildingInfluence.GetBuildingAt(cell) != null) return false; - if (!rt.Info.AllowOnRamps) - { - var tile = world.Map.Tiles[cell]; - var tileInfo = world.Map.Rules.TileSet.GetTileInfo(tile); - if (tileInfo != null && tileInfo.RampType > 0) - return false; - } - - return true; + return rt.Info.AllowOnRamps || world.Map.Ramp[cell] == 0; } public bool CanSpawnResourceAt(ResourceType newResourceType, CPos cell) @@ -130,12 +135,12 @@ || (currentResourceType == null && AllowResourceAt(newResourceType, cell)); } - CellContents CreateResourceCell(ResourceType t, CPos cell) + ResourceLayerContents CreateResourceCell(ResourceType t, CPos cell) { world.Map.CustomTerrain[cell] = world.Map.Rules.TileSet.GetTerrainIndex(t.Info.TerrainType); ++resCells; - return new CellContents + return new ResourceLayerContents { Type = t }; @@ -153,8 +158,7 @@ cell.Density = Math.Min(cell.Type.Info.MaxDensity, cell.Density + n); Content[p] = cell; - if (CellChanged != null) - CellChanged(p, cell.Type); + CellChanged?.Invoke(p, cell.Type); } public bool IsFull(CPos cell) @@ -171,15 +175,14 @@ if (--c.Density < 0) { - Content[cell] = EmptyCell; + Content[cell] = ResourceLayerContents.Empty; world.Map.CustomTerrain[cell] = byte.MaxValue; --resCells; } else Content[cell] = c; - if (CellChanged != null) - CellChanged(cell, c.Type); + CellChanged?.Invoke(cell, c.Type); return c.Type; } @@ -194,30 +197,17 @@ --resCells; // Clear cell - Content[cell] = EmptyCell; + Content[cell] = ResourceLayerContents.Empty; world.Map.CustomTerrain[cell] = byte.MaxValue; - if (CellChanged != null) - CellChanged(cell, c.Type); + CellChanged?.Invoke(cell, c.Type); } - public CellContents GetResource(CPos cell) { return Content[cell]; } public ResourceType GetResourceType(CPos cell) { return Content[cell].Type; } public int GetResourceDensity(CPos cell) { return Content[cell].Density; } - public int GetMaxResourceDensity(CPos cell) - { - if (Content[cell].Type == null) - return 0; - return Content[cell].Type.Info.MaxDensity; - } - - public struct CellContents - { - public static readonly CellContents Empty = default(CellContents); - public ResourceType Type; - public int Density; - } + ResourceLayerContents IResourceLayer.GetResource(CPos cell) { return Content[cell]; } + bool IResourceLayer.IsVisible(CPos cell) { return !world.FogObscures(cell); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,18 +18,18 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Visualizes the state of the `ResourceLayer`.", " Attach this to the world actor.")] - public class ResourceRendererInfo : ITraitInfo, Requires + public class ResourceRendererInfo : TraitInfo, Requires { [FieldLoader.Require] [Desc("Only render these ResourceType names.")] public readonly string[] RenderTypes = null; - public virtual object Create(ActorInitializer init) { return new ResourceRenderer(init.Self, this); } + public override object Create(ActorInitializer init) { return new ResourceRenderer(init.Self, this); } } public class ResourceRenderer : IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing { - protected readonly ResourceLayer ResourceLayer; + protected readonly IResourceLayer ResourceLayer; protected readonly CellLayer RenderContent; protected readonly ResourceRendererInfo Info; @@ -41,7 +41,7 @@ { Info = info; - ResourceLayer = self.Trait(); + ResourceLayer = self.Trait(); ResourceLayer.CellChanged += AddDirtyCell; RenderContent = new CellLayer(self.World.Map); @@ -64,17 +64,18 @@ { var layer = spriteLayers.GetOrAdd(r.Value.Palette, pal => { - var first = r.Value.Variants.First().Value.First(); + var first = r.Value.Variants.First().Value.GetSprite(0); return new TerrainSpriteLayer(w, wr, first.Sheet, first.BlendMode, pal, wr.World.Type != WorldType.Editor); }); // Validate that sprites are compatible with this layer var sheet = layer.Sheet; - if (r.Value.Variants.Any(kv => kv.Value.Any(s => s.Sheet != sheet))) + var sprites = r.Value.Variants.Values.SelectMany(v => Exts.MakeArray(v.Length, x => v.GetSprite(x))); + if (sprites.Any(s => s.Sheet != sheet)) throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); var blendMode = layer.BlendMode; - if (r.Value.Variants.Any(kv => kv.Value.Any(s => s.BlendMode != blendMode))) + if (sprites.Any(s => s.BlendMode != blendMode)) throw new InvalidDataException("Resource sprites specify different blend modes. " + "Try using different palettes for resource types that use different blend modes."); } @@ -83,7 +84,7 @@ // because the shroud may not be enabled. foreach (var cell in w.Map.AllCells) { - var type = ResourceLayer.GetResourceType(cell); + var type = ResourceLayer.GetResource(cell).Type; if (type != null && Info.RenderTypes.Contains(type.Info.Type)) { var resourceContent = ResourceLayer.GetResource(cell); @@ -94,15 +95,15 @@ } } - protected void UpdateSpriteLayers(CPos cell, Sprite sprite, PaletteReference palette) + protected void UpdateSpriteLayers(CPos cell, ISpriteSequence sequence, int frame, PaletteReference palette) { foreach (var kv in spriteLayers) { - // resource.Type is meaningless (and may be null) if resource.Sprite is null - if (sprite != null && palette == kv.Key) - kv.Value.Update(cell, sprite); + // resource.Type is meaningless (and may be null) if resource.Sequence is null + if (sequence != null && palette == kv.Key) + kv.Value.Update(cell, sequence, frame); else - kv.Value.Update(cell, null); + kv.Value.Clear(cell); } } @@ -116,7 +117,7 @@ { foreach (var cell in dirty) { - if (self.World.FogObscures(cell)) + if (!ResourceLayer.IsVisible(cell)) continue; var resourceContent = ResourceLayer.GetResource(cell); @@ -162,10 +163,10 @@ var maxDensity = type.Info.MaxDensity; var frame = int2.Lerp(0, sprites.Length - 1, density, maxDensity); - UpdateSpriteLayers(cell, sprites[frame], type.Palette); + UpdateSpriteLayers(cell, sprites, frame, type.Palette); } else - UpdateSpriteLayers(cell, null, null); + UpdateSpriteLayers(cell, null, 0, null); } bool disposed; diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/ResourceType.cs openra-20210321/OpenRA.Mods.Common/Traits/World/ResourceType.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/ResourceType.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/ResourceType.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,13 +16,13 @@ namespace OpenRA.Mods.Common.Traits { - public class ResourceTypeInfo : ITraitInfo, IMapPreviewSignatureInfo + public class ResourceTypeInfo : TraitInfo, IMapPreviewSignatureInfo { [Desc("Sequence image that holds the different variants.")] public readonly string Image = "resources"; [FieldLoader.Require] - [SequenceReference("Image")] + [SequenceReference(nameof(Image))] [Desc("Randomly chosen image sequences.")] public readonly string[] Sequences = { }; @@ -63,10 +63,7 @@ [Desc("Allow resource to spawn on ramp tiles.")] public readonly bool AllowOnRamps = false; - [Desc("Harvester content pip color.")] - public PipType PipColor = PipType.Yellow; - - void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List> destinationBuffer) + void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer) { var tileSet = map.Rules.TileSet; var color = tileSet[tileSet.GetTerrainIndex(TerrainType)].Color; @@ -77,29 +74,28 @@ { var cell = new MPos(i, j); if (map.Resources[cell].Type == ResourceType) - destinationBuffer.Add(new Pair(cell, color)); + destinationBuffer.Add((cell, color)); } } } - public object Create(ActorInitializer init) { return new ResourceType(this, init.World); } + public override object Create(ActorInitializer init) { return new ResourceType(this, init.World); } } public class ResourceType : IWorldLoaded { public readonly ResourceTypeInfo Info; public PaletteReference Palette { get; private set; } - public readonly Dictionary Variants; + public readonly Dictionary Variants; public ResourceType(ResourceTypeInfo info, World world) { Info = info; - Variants = new Dictionary(); + Variants = new Dictionary(); foreach (var v in info.Sequences) { var seq = world.Map.Rules.Sequences.GetSequence(Info.Image, v); - var sprites = Exts.MakeArray(seq.Length, x => seq.GetSprite(x)); - Variants.Add(v, sprites); + Variants.Add(v, seq); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/ScriptLobbyDropdown.cs openra-20210321/OpenRA.Mods.Common/Traits/World/ScriptLobbyDropdown.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/ScriptLobbyDropdown.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/ScriptLobbyDropdown.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,7 +15,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Controls the map difficulty, tech level, and short game lobby options.")] - public class ScriptLobbyDropdownInfo : ITraitInfo, ILobbyOptions + public class ScriptLobbyDropdownInfo : TraitInfo, ILobbyOptions { [FieldLoader.Require] [Desc("Internal id for this option.")] @@ -53,7 +53,7 @@ new ReadOnlyDictionary(Values), Default, Locked); } - public object Create(ActorInitializer init) { return new ScriptLobbyDropdown(this); } + public override object Create(ActorInitializer init) { return new ScriptLobbyDropdown(this); } } public class ScriptLobbyDropdown : INotifyCreated diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/Selection.cs openra-20210321/OpenRA.Mods.Common/Traits/World/Selection.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/Selection.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/Selection.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,9 +17,9 @@ namespace OpenRA.Mods.Common.Traits { - public class SelectionInfo : ITraitInfo + public class SelectionInfo : TraitInfo { - public object Create(ActorInitializer init) { return new Selection(this); } + public override object Create(ActorInitializer init) { return new Selection(this); } } public class Selection : ISelection, INotifyCreated, INotifyOwnerChanged, ITick, IGameSaveTraitData @@ -28,6 +28,9 @@ public IEnumerable Actors { get { return actors; } } readonly HashSet actors = new HashSet(); + World world; + IEnumerable rolloverActors; + INotifySelection[] worldNotifySelection; public Selection(SelectionInfo info) { } @@ -35,6 +38,7 @@ void INotifyCreated.Created(Actor self) { worldNotifySelection = self.TraitsImplementing().ToArray(); + world = self.World; } void UpdateHash() @@ -53,6 +57,7 @@ foreach (var sel in a.TraitsImplementing()) sel.Selected(a); + Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, world, () => world.OrderGenerator.SelectionChanged(world, actors)); foreach (var ns in worldNotifySelection) ns.SelectionChanged(); } @@ -62,6 +67,7 @@ if (actors.Remove(a)) { UpdateHash(); + Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, world, () => world.OrderGenerator.SelectionChanged(world, actors)); foreach (var ns in worldNotifySelection) ns.SelectionChanged(); } @@ -74,7 +80,7 @@ // Remove the actor from the original owners selection // Call UpdateHash directly for everyone else so watchers can account for the owner change if needed - if (oldOwner == a.World.LocalPlayer) + if (oldOwner == world.LocalPlayer) Remove(a); else UpdateHash(); @@ -89,7 +95,8 @@ { if (isClick) { - var adjNewSelection = newSelection.Take(1); // TODO: select BEST, not FIRST + // TODO: select BEST, not FIRST + var adjNewSelection = newSelection.Take(1); if (isCombine) actors.SymmetricExceptWith(adjNewSelection); else @@ -115,6 +122,7 @@ foreach (var sel in a.TraitsImplementing()) sel.Selected(a); + Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, world, () => world.OrderGenerator.SelectionChanged(world, actors)); foreach (var ns in worldNotifySelection) ns.SelectionChanged(); @@ -123,13 +131,12 @@ // Play the selection voice from one of the selected actors // TODO: This probably should only be considering the newly selected actors - // TODO: Ship this into an INotifySelection trait to remove the engine dependency on Selectable foreach (var actor in actors) { if (actor.Owner != world.LocalPlayer || !actor.IsInWorld) continue; - var selectable = actor.Info.TraitInfoOrDefault(); + var selectable = actor.Info.TraitInfoOrDefault(); if (selectable == null || !actor.HasVoice(selectable.Voice)) continue; @@ -142,22 +149,40 @@ { actors.Clear(); UpdateHash(); + Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, world, () => world.OrderGenerator.SelectionChanged(world, actors)); + foreach (var ns in worldNotifySelection) + ns.SelectionChanged(); + } + + public void SetRollover(IEnumerable rollover) + { + rolloverActors = rollover; + } + + public bool RolloverContains(Actor a) + { + return rolloverActors != null && rolloverActors.Contains(a); } void ITick.Tick(Actor self) { - var removed = actors.RemoveWhere(a => !a.IsInWorld || (!a.Owner.IsAlliedWith(self.World.RenderPlayer) && self.World.FogObscures(a))); + var removed = actors.RemoveWhere(a => !a.IsInWorld || (!a.Owner.IsAlliedWith(world.RenderPlayer) && world.FogObscures(a))); if (removed > 0) + { UpdateHash(); + Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, world, () => world.OrderGenerator.SelectionChanged(world, actors)); + foreach (var ns in worldNotifySelection) + ns.SelectionChanged(); + } foreach (var cg in controlGroups.Values) { // note: NOT `!a.IsInWorld`, since that would remove things that are in transports. - cg.RemoveAll(a => a.Disposed || a.Owner != self.World.LocalPlayer); + cg.RemoveAll(a => a.Disposed || a.Owner != world.LocalPlayer); } } - Cache> controlGroups = new Cache>(_ => new List()); + readonly Cache> controlGroups = new Cache>(_ => new List()); public void DoControlGroup(World world, WorldRenderer worldRenderer, int group, Modifiers mods, int multiTapCount) { @@ -177,7 +202,7 @@ return; } - var groupActors = controlGroups[group].Where(a => !a.IsDead); + var groupActors = controlGroups[group].Where(a => a.IsInWorld); if (mods.HasModifier(Modifiers.Alt) || multiTapCount >= 2) { diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,18 +14,17 @@ using System.IO; using System.Linq; using OpenRA.Graphics; -using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class ShroudRendererInfo : ITraitInfo + public class ShroudRendererInfo : TraitInfo { public readonly string Sequence = "shroud"; - [SequenceReference("Sequence")] + [SequenceReference(nameof(Sequence))] public readonly string[] ShroudVariants = { "shroud" }; - [SequenceReference("Sequence")] + [SequenceReference(nameof(Sequence))] public readonly string[] FogVariants = { "fog" }; [PaletteReference] @@ -41,20 +40,20 @@ [Desc("Use the upper four bits when calculating frame")] public readonly bool UseExtendedIndex = false; - [SequenceReference("Sequence")] + [SequenceReference(nameof(Sequence))] [Desc("Override for source art that doesn't define a fully shrouded tile")] public readonly string OverrideFullShroud = null; public readonly int OverrideShroudIndex = 15; - [SequenceReference("Sequence")] + [SequenceReference(nameof(Sequence))] [Desc("Override for source art that doesn't define a fully fogged tile")] public readonly string OverrideFullFog = null; public readonly int OverrideFogIndex = 15; public readonly BlendMode ShroudBlend = BlendMode.Alpha; - public object Create(ActorInitializer init) { return new ShroudRenderer(init.World, this); } + public override object Create(ActorInitializer init) { return new ShroudRenderer(init.World, this); } } public sealed class ShroudRenderer : IRenderShroud, IWorldLoaded, INotifyActorDisposing @@ -85,7 +84,7 @@ public readonly float3 ScreenPosition; public readonly byte Variant; - public TileInfo(float3 screenPosition, byte variant) + public TileInfo(in float3 screenPosition, byte variant) { ScreenPosition = screenPosition; Variant = variant; @@ -101,6 +100,7 @@ readonly CellLayer tileInfos; readonly CellLayer cellsDirty; + bool anyCellDirty; readonly Sprite[] fogSprites, shroudSprites; Shroud shroud; @@ -129,6 +129,7 @@ tileInfos = new CellLayer(map); cellsDirty = new CellLayer(map); + anyCellDirty = true; // Load sprite variants var variantCount = info.ShroudVariants.Length; @@ -266,13 +267,17 @@ // Dirty the full projected space so the cells outside // the map bounds can be initialized as fully shrouded. cellsDirty.Clear(true); + anyCellDirty = true; var tl = new PPos(0, 0); var br = new PPos(map.MapSize.X - 1, map.MapSize.Y - 1); UpdateShroud(new ProjectedCellRegion(map, tl, br)); } - void UpdateShroud(ProjectedCellRegion region) + void UpdateShroud(IEnumerable region) { + if (!anyCellDirty) + return; + foreach (var puv in region) { var uv = (MPos)puv; @@ -292,14 +297,16 @@ if (fogSprite != null) fogPos += fogSprite.Offset - 0.5f * fogSprite.Size; - shroudLayer.Update(uv, shroudSprite, shroudPos); - fogLayer.Update(uv, fogSprite, fogPos); + shroudLayer.Update(uv, shroudSprite, shroudPos, true); + fogLayer.Update(uv, fogSprite, fogPos, true); } + + anyCellDirty = false; } void IRenderShroud.RenderShroud(WorldRenderer wr) { - UpdateShroud(map.ProjectedCellBounds); + UpdateShroud(map.ProjectedCells); fogLayer.Draw(wr.Viewport); shroudLayer.Draw(wr.Viewport); } @@ -308,6 +315,7 @@ { var uv = (MPos)puv; cellsDirty[uv] = true; + anyCellDirty = true; var cell = uv.ToCPos(map); foreach (var direction in CVec.Directions) if (map.Contains((PPos)(cell + direction).ToMPos(map))) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,20 +25,22 @@ } [Desc("Attach this to the world actor.", "Order of the layers defines the Z sorting.")] - public class SmudgeLayerInfo : ITraitInfo + public class SmudgeLayerInfo : TraitInfo { public readonly string Type = "Scorch"; [Desc("Sprite sequence name")] public readonly string Sequence = "scorch"; - public readonly int SmokePercentage = 25; + [Desc("Chance of smoke rising from the ground")] + public readonly int SmokeChance = 0; - [Desc("Sprite sequence name")] - public readonly string SmokeType = "smoke_m"; + [Desc("Smoke sprite image name")] + public readonly string SmokeImage = null; - [SequenceReference("SmokeType")] - public readonly string SmokeSequence = "idle"; + [SequenceReference(nameof(SmokeImage))] + [Desc("Smoke sprite sequences randomly chosen from")] + public readonly string[] SmokeSequences = { }; [PaletteReference] public readonly string SmokePalette = "effect"; @@ -51,10 +53,9 @@ public static object LoadInitialSmudges(MiniYaml yaml) { - MiniYaml smudgeYaml; var nd = yaml.ToDictionary(); var smudges = new Dictionary(); - if (nd.TryGetValue("InitialSmudges", out smudgeYaml)) + if (nd.TryGetValue("InitialSmudges", out var smudgeYaml)) { foreach (var node in smudgeYaml.Nodes) { @@ -73,7 +74,7 @@ return smudges; } - public object Create(ActorInitializer init) { return new SmudgeLayer(init.Self, this); } + public override object Create(ActorInitializer init) { return new SmudgeLayer(init.Self, this); } } public class SmudgeLayer : IRenderOverlay, IWorldLoaded, ITickRender, INotifyActorDisposing @@ -82,14 +83,15 @@ { public string Type; public int Depth; - public Sprite Sprite; + public ISpriteSequence Sequence; } public readonly SmudgeLayerInfo Info; readonly Dictionary tiles = new Dictionary(); readonly Dictionary dirty = new Dictionary(); - readonly Dictionary smudges = new Dictionary(); + readonly Dictionary smudges = new Dictionary(); readonly World world; + readonly bool hasSmoke; TerrainSpriteLayer render; bool disposed; @@ -98,30 +100,28 @@ { Info = info; world = self.World; + hasSmoke = !string.IsNullOrEmpty(info.SmokeImage) && info.SmokeSequences.Any(); var sequenceProvider = world.Map.Rules.Sequences; var types = sequenceProvider.Sequences(Info.Sequence); foreach (var t in types) - { - var seq = sequenceProvider.GetSequence(Info.Sequence, t); - var sprites = Exts.MakeArray(seq.Length, x => seq.GetSprite(x)); - smudges.Add(t, sprites); - } + smudges.Add(t, sequenceProvider.GetSequence(Info.Sequence, t)); } public void WorldLoaded(World w, WorldRenderer wr) { - var first = smudges.First().Value.First(); - var sheet = first.Sheet; - if (smudges.Values.Any(sprites => sprites.Any(s => s.Sheet != sheet))) + var sprites = smudges.Values.SelectMany(v => Exts.MakeArray(v.Length, x => v.GetSprite(x))).ToList(); + var sheet = sprites[0].Sheet; + var blendMode = sprites[0].BlendMode; + + if (sprites.Any(s => s.Sheet != sheet)) throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); - var blendMode = first.BlendMode; - if (smudges.Values.Any(sprites => sprites.Any(s => s.BlendMode != blendMode))) + if (sprites.Any(s => s.BlendMode != blendMode)) throw new InvalidDataException("Smudges specify different blend modes. " + "Try using different smudge types for smudges that use different blend modes."); - render = new TerrainSpriteLayer(w, wr, sheet, blendMode, wr.Palette(Info.Palette), wr.World.Type != WorldType.Editor); + render = new TerrainSpriteLayer(w, wr, sheet, blendMode, wr.Palette(Info.Palette), w.Type != WorldType.Editor); // Add map smudges foreach (var kv in Info.InitialSmudges) @@ -130,15 +130,16 @@ if (!smudges.ContainsKey(s.Type)) continue; + var seq = smudges[s.Type]; var smudge = new Smudge { Type = s.Type, Depth = s.Depth, - Sprite = smudges[s.Type][s.Depth] + Sequence = seq }; tiles.Add(kv.Key, smudge); - render.Update(kv.Key, smudge.Sprite); + render.Update(kv.Key, seq, s.Depth); } } @@ -147,27 +148,25 @@ if (!world.Map.Contains(loc)) return; - if (Game.CosmeticRandom.Next(0, 100) <= Info.SmokePercentage) - world.AddFrameEndTask(w => w.Add(new SpriteEffect(world.Map.CenterOfCell(loc), w, Info.SmokeType, Info.SmokeSequence, Info.SmokePalette))); + if (hasSmoke && Game.CosmeticRandom.Next(0, 100) <= Info.SmokeChance) + world.AddFrameEndTask(w => w.Add(new SpriteEffect( + w.Map.CenterOfCell(loc), w, Info.SmokeImage, Info.SmokeSequences.Random(w.SharedRandom), Info.SmokePalette))); - // A null Sprite indicates a deleted smudge. - if ((!dirty.ContainsKey(loc) || dirty[loc].Sprite == null) && !tiles.ContainsKey(loc)) + // A null Sequence indicates a deleted smudge. + if ((!dirty.ContainsKey(loc) || dirty[loc].Sequence == null) && !tiles.ContainsKey(loc)) { // No smudge; create a new one var st = smudges.Keys.Random(Game.CosmeticRandom); - dirty[loc] = new Smudge { Type = st, Depth = 0, Sprite = smudges[st][0] }; + dirty[loc] = new Smudge { Type = st, Depth = 0, Sequence = smudges[st] }; } else { // Existing smudge; make it deeper - // A null Sprite indicates a deleted smudge. - var tile = dirty.ContainsKey(loc) && dirty[loc].Sprite != null ? dirty[loc] : tiles[loc]; + // A null Sequence indicates a deleted smudge. + var tile = dirty.ContainsKey(loc) && dirty[loc].Sequence != null ? dirty[loc] : tiles[loc]; var maxDepth = smudges[tile.Type].Length; if (tile.Depth < maxDepth - 1) - { tile.Depth++; - tile.Sprite = smudges[tile.Type][tile.Depth]; - } dirty[loc] = tile; } @@ -180,8 +179,8 @@ var tile = dirty.ContainsKey(loc) ? dirty[loc] : default(Smudge); - // Setting Sprite to null to indicate a deleted smudge. - tile.Sprite = null; + // Setting Sequence to null to indicate a deleted smudge. + tile.Sequence = null; dirty[loc] = tile; } @@ -190,14 +189,20 @@ var remove = new List(); foreach (var kv in dirty) { - if (!self.World.FogObscures(kv.Key)) + if (!world.FogObscures(kv.Key)) { - // A null Sprite indicates a deleted smudge. - if (kv.Value.Sprite == null) + // A null Sequence + if (kv.Value.Sequence == null) + { tiles.Remove(kv.Key); + render.Clear(kv.Key); + } else - tiles[kv.Key] = kv.Value; - render.Update(kv.Key, kv.Value.Sprite); + { + var smudge = kv.Value; + tiles[kv.Key] = smudge; + render.Update(kv.Key, smudge.Sequence, smudge.Depth); + } remove.Add(kv.Key); } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs openra-20210321/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs 2021-03-21 11:10:05.000000000 +0000 @@ -35,18 +35,17 @@ var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); // If there is no real player associated, don't spawn it. - var ownerName = actorReference.InitDict.Get().PlayerName; + var ownerName = actorReference.Get().InternalName; if (!world.Players.Any(p => p.InternalName == ownerName)) continue; - var initDict = actorReference.InitDict; - initDict.Add(new SkipMakeAnimsInit()); - initDict.Add(new SpawnedByMapInit(kv.Key)); + actorReference.Add(new SkipMakeAnimsInit()); + actorReference.Add(new SpawnedByMapInit(kv.Key)); if (PreventMapSpawn(world, actorReference, preventMapSpawns)) continue; - var actor = world.CreateActor(actorReference.Type, initDict); + var actor = world.CreateActor(true, actorReference); Actors[kv.Key] = actor; LastMapActorID = actor.ActorID; } @@ -62,15 +61,10 @@ } } - public class SkipMakeAnimsInit : IActorInit, ISuppressInitExport { } - public class SpawnedByMapInit : IActorInit, ISuppressInitExport + public class SkipMakeAnimsInit : RuntimeFlagInit { } + public class SpawnedByMapInit : ValueActorInit, ISuppressInitExport, ISingleInstanceInit { - public readonly string Name; - public SpawnedByMapInit(string name) { Name = name; } - - public string Value(World world) - { - return Name; - } + public SpawnedByMapInit(string value) + : base(value) { } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/SpawnMPUnits.cs openra-20210321/OpenRA.Mods.Common/Traits/World/SpawnMPUnits.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/SpawnMPUnits.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/SpawnMPUnits.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Spawn base actor at the spawnpoint and support units in an annulus around the base actor. Both are defined at MPStartUnits. Attach this to the world actor.")] - public class SpawnMPUnitsInfo : ITraitInfo, Requires, Requires, ILobbyOptions + public class SpawnMPUnitsInfo : TraitInfo, Requires, ILobbyOptions { public readonly string StartingUnitsClass = "none"; @@ -53,7 +53,7 @@ new ReadOnlyDictionary(startingUnits), StartingUnitsClass, DropdownLocked); } - public object Create(ActorInitializer init) { return new SpawnMPUnits(this); } + public override object Create(ActorInitializer init) { return new SpawnMPUnits(this); } } public class SpawnMPUnits : IWorldLoaded @@ -67,11 +67,12 @@ public void WorldLoaded(World world, WorldRenderer wr) { - foreach (var s in world.WorldActor.Trait().Start) - SpawnUnitsForPlayer(world, s.Key, s.Value); + foreach (var p in world.Players) + if (p.Playable) + SpawnUnitsForPlayer(world, p); } - void SpawnUnitsForPlayer(World w, Player p, CPos sp) + void SpawnUnitsForPlayer(World w, Player p) { var spawnClass = p.PlayerReference.StartingUnitsClass ?? w.LobbyInfo.GlobalSettings .OptionOrDefault("startingunits", info.StartingUnitsClass); @@ -85,19 +86,20 @@ if (unitGroup.BaseActor != null) { + var facing = unitGroup.BaseActorFacing.HasValue ? unitGroup.BaseActorFacing.Value : new WAngle(w.SharedRandom.Next(1024)); w.CreateActor(unitGroup.BaseActor.ToLowerInvariant(), new TypeDictionary { - new LocationInit(sp + unitGroup.BaseActorOffset), + new LocationInit(p.HomeLocation + unitGroup.BaseActorOffset), new OwnerInit(p), new SkipMakeAnimsInit(), - new FacingInit(unitGroup.BaseActorFacing < 0 ? w.SharedRandom.Next(256) : unitGroup.BaseActorFacing), + new FacingInit(facing), }); } if (!unitGroup.SupportActors.Any()) return; - var supportSpawnCells = w.Map.FindTilesInAnnulus(sp, unitGroup.InnerSupportRadius + 1, unitGroup.OuterSupportRadius); + var supportSpawnCells = w.Map.FindTilesInAnnulus(p.HomeLocation, unitGroup.InnerSupportRadius + 1, unitGroup.OuterSupportRadius); foreach (var s in unitGroup.SupportActors) { @@ -112,13 +114,14 @@ } var subCell = ip.SharesCell ? w.ActorMap.FreeSubCell(validCell) : 0; + var facing = unitGroup.SupportActorsFacing.HasValue ? unitGroup.SupportActorsFacing.Value : new WAngle(w.SharedRandom.Next(1024)); w.CreateActor(s.ToLowerInvariant(), new TypeDictionary { new OwnerInit(p), new LocationInit(validCell), new SubCellInit(subCell), - new FacingInit(unitGroup.SupportActorsFacing < 0 ? w.SharedRandom.Next(256) : unitGroup.SupportActorsFacing) + new FacingInit(facing), }); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/StartGameNotification.cs openra-20210321/OpenRA.Mods.Common/Traits/World/StartGameNotification.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/StartGameNotification.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/StartGameNotification.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits { - class StartGameNotificationInfo : ITraitInfo + class StartGameNotificationInfo : TraitInfo { [NotificationReference("Speech")] public readonly string Notification = "StartGame"; @@ -25,7 +25,7 @@ [NotificationReference("Speech")] public readonly string SavedNotification = "GameSaved"; - public object Create(ActorInitializer init) { return new StartGameNotification(this); } + public override object Create(ActorInitializer init) { return new StartGameNotification(this); } } class StartGameNotification : IWorldLoaded, INotifyGameLoaded, INotifyGameSaved diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -14,7 +14,7 @@ namespace OpenRA.Mods.Common.Traits { - public class SubterraneanActorLayerInfo : ITraitInfo + public class SubterraneanActorLayerInfo : TraitInfo { [Desc("Terrain type of the underground layer.")] public readonly string TerrainType = "Subterranean"; @@ -25,7 +25,7 @@ [Desc("Cell radius for smoothing adjacent cell heights.")] public readonly int SmoothingRadius = 2; - public object Create(ActorInitializer init) { return new SubterraneanActorLayer(init.Self, this); } + public override object Create(ActorInitializer init) { return new SubterraneanActorLayer(init.Self, this); } } public class SubterraneanActorLayer : ICustomMovementLayer @@ -82,9 +82,7 @@ if (sli.SubterraneanTransitionOnRamps) return true; - var tile = map.Tiles[cell]; - var ti = map.Rules.TileSet.GetTileInfo(tile); - return ti == null || ti.RampType == 0; + return map.Ramp[cell] == 0; } int ICustomMovementLayer.EntryMovementCost(ActorInfo a, LocomotorInfo li, CPos cell) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Collections.Generic; -using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Commands; using OpenRA.Mods.Common.Graphics; @@ -63,28 +62,27 @@ continue; var height = (int)map.Height[uv]; - var tile = map.Tiles[uv]; - var ti = tileSet.GetTileInfo(tile); - var ramp = ti != null ? ti.RampType : 0; - - var corners = map.Grid.CellCorners[ramp]; - var pos = map.CenterOfCell(uv.ToCPos(map)); + var r = map.Grid.Ramps[map.Ramp[uv]]; + var pos = map.CenterOfCell(uv.ToCPos(map)) - new WVec(0, 0, r.CenterHeightOffset); var width = uv == mouseCell ? 3 : 1; // Colors change between points, so render separately - for (var i = 0; i < 4; i++) + foreach (var p in r.Polygons) { - var j = (i + 1) % 4; - var start = pos + corners[i]; - var end = pos + corners[j]; - var startColor = colors[height + corners[i].Z / 512]; - var endColor = colors[height + corners[j].Z / 512]; - yield return new LineAnnotationRenderable(start, end, width, startColor, endColor); + for (var i = 0; i < p.Length; i++) + { + var j = (i + 1) % p.Length; + var start = pos + p[i]; + var end = pos + p[j]; + var startColor = colors[height + p[i].Z / 512]; + var endColor = colors[height + p[j].Z / 512]; + yield return new LineAnnotationRenderable(start, end, width, startColor, endColor); + } } } // Projected cell coordinates for the current cell - var projectedCorners = map.Grid.CellCorners[0]; + var projectedCorners = map.Grid.Ramps[0].Corners; foreach (var puv in map.ProjectedCellsCovering(mouseCell)) { var pos = map.CenterOfCell(((MPos)puv).ToCPos(map)); diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,9 +15,9 @@ namespace OpenRA.Mods.Common.Traits { - public class TerrainRendererInfo : ITraitInfo + public class TerrainRendererInfo : TraitInfo { - public object Create(ActorInitializer init) { return new TerrainRenderer(init.World); } + public override object Create(ActorInitializer init) { return new TerrainRenderer(init.World); } } public sealed class TerrainRenderer : IRenderTerrain, IWorldLoaded, INotifyActorDisposing @@ -59,7 +59,7 @@ var sprite = theater.TileSprite(tile); foreach (var kv in spriteLayers) - kv.Value.Update(cell, palette == kv.Key ? sprite : null); + kv.Value.Update(cell, palette == kv.Key ? sprite : null, false); } void IRenderTerrain.RenderTerrain(WorldRenderer wr, Viewport viewport) diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/TerrainTunnelLayer.cs openra-20210321/OpenRA.Mods.Common/Traits/World/TerrainTunnelLayer.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/TerrainTunnelLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/TerrainTunnelLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,12 +15,12 @@ namespace OpenRA.Mods.Common.Traits { - public class TerrainTunnelLayerInfo : ITraitInfo, Requires, ILobbyCustomRulesIgnore + public class TerrainTunnelLayerInfo : TraitInfo, Requires, ILobbyCustomRulesIgnore { [Desc("Terrain type used by cells outside any tunnel footprint.")] public readonly string ImpassableTerrainType = "Impassable"; - public object Create(ActorInitializer init) { return new TerrainTunnelLayer(init.Self, this); } + public override object Create(ActorInitializer init) { return new TerrainTunnelLayer(init.Self, this); } } public class TerrainTunnelLayer : ICustomMovementLayer, IWorldLoaded diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/WarheadDebugOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/World/WarheadDebugOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/WarheadDebugOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/WarheadDebugOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,11 +18,11 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Part of the combat overlay from DeveloperMode. Attach this to the world actor.")] - public class WarheadDebugOverlayInfo : ITraitInfo + public class WarheadDebugOverlayInfo : TraitInfo { public readonly int DisplayDuration = 25; - public object Create(ActorInitializer init) { return new WarheadDebugOverlay(this); } + public override object Create(ActorInitializer init) { return new WarheadDebugOverlay(this); } } public class WarheadDebugOverlay : IRenderAnnotations diff -Nru openra-20200503/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs openra-20210321/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs --- openra-20200503/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Adds a particle-based overlay.")] - public class WeatherOverlayInfo : ITraitInfo, ILobbyCustomRulesIgnore + public class WeatherOverlayInfo : TraitInfo, ILobbyCustomRulesIgnore { [Desc("Average number of particles per 100x100 px square.")] public readonly int ParticleDensityFactor = 8; @@ -68,7 +68,7 @@ [Desc("Works only with line enabled and can be used to fade out the tail of the line like a contrail.")] public readonly byte LineTailAlphaValue = 200; - public object Create(ActorInitializer init) { return new WeatherOverlay(init.World, this); } + public override object Create(ActorInitializer init) { return new WeatherOverlay(init.World, this); } } public class WeatherOverlay : ITick, IRenderAboveWorld, INotifyViewportZoomExtentsChanged diff -Nru openra-20200503/OpenRA.Mods.Common/TraitsInterfaces.cs openra-20210321/OpenRA.Mods.Common/TraitsInterfaces.cs --- openra-20200503/OpenRA.Mods.Common/TraitsInterfaces.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/TraitsInterfaces.cs 2021-03-21 11:10:05.000000000 +0000 @@ -32,12 +32,12 @@ Repair = 2 } - public interface IQuantizeBodyOrientationInfo : ITraitInfo + public interface IQuantizeBodyOrientationInfo : ITraitInfoInterface { int QuantizedBodyFacings(ActorInfo ai, SequenceProvider sequenceProvider, string race); } - public interface IPlaceBuildingDecorationInfo : ITraitInfo + public interface IPlaceBuildingDecorationInfo : ITraitInfoInterface { IEnumerable RenderAnnotations(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition); } @@ -80,7 +80,7 @@ public interface IDemolishable { bool IsValidTarget(Actor self, Actor saboteur); - void Demolish(Actor self, Actor saboteur, int delay); + void Demolish(Actor self, Actor saboteur, int delay, BitSet damageTypes); } // Type tag for crush class bits @@ -110,8 +110,8 @@ [RequireExplicitImplementation] public interface INotifyAttack { - void Attacking(Actor self, Target target, Armament a, Barrel barrel); - void PreparingAttack(Actor self, Target target, Armament a, Barrel barrel); + void Attacking(Actor self, in Target target, Armament a, Barrel barrel); + void PreparingAttack(Actor self, in Target target, Armament a, Barrel barrel); } [RequireExplicitImplementation] @@ -132,11 +132,18 @@ } [RequireExplicitImplementation] + public interface INotifyBeingResupplied + { + void StartingResupply(Actor self, Actor host); + void StoppingResupply(Actor self, Actor host); + } + + [RequireExplicitImplementation] public interface INotifyPowerLevelChanged { void PowerLevelChanged(Actor self); } + public interface INotifySupportPower { void Charged(Actor self); void Activated(Actor self); } public interface INotifyBuildingPlaced { void BuildingPlaced(Actor self); } - public interface INotifyNuke { void Launching(Actor self); } - public interface INotifyBurstComplete { void FiredBurst(Actor self, Target target, Armament a); } + public interface INotifyBurstComplete { void FiredBurst(Actor self, in Target target, Armament a); } public interface INotifyChat { bool OnChat(string from, string message); } public interface INotifyProduction { void UnitProduced(Actor self, Actor other, CPos exit); } public interface INotifyOtherProduction { void UnitProducedByOther(Actor self, Actor producer, Actor produced, string productionType, TypeDictionary init); } @@ -150,8 +157,8 @@ [RequireExplicitImplementation] public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner, BitSet captureTypes); } public interface INotifyDiscovered { void OnDiscovered(Actor self, Player discoverer, bool playNotification); } - public interface IRenderActorPreviewInfo : ITraitInfo { IEnumerable RenderPreview(ActorPreviewInitializer init); } - public interface ICruiseAltitudeInfo : ITraitInfo { WDist GetCruiseAltitude(); } + public interface IRenderActorPreviewInfo : ITraitInfoInterface { IEnumerable RenderPreview(ActorPreviewInitializer init); } + public interface ICruiseAltitudeInfo : ITraitInfoInterface { WDist GetCruiseAltitude(); } public interface IHuskModifier { string HuskActor(Actor self); } @@ -175,26 +182,6 @@ [RequireExplicitImplementation] public interface INotifyExitedCargo { void OnExitedCargo(Actor self, Actor cargo); } - [RequireExplicitImplementation] - public interface IObservesVariablesInfo : ITraitInfo { } - - public delegate void VariableObserverNotifier(Actor self, IReadOnlyDictionary variables); - public struct VariableObserver - { - public VariableObserverNotifier Notifier; - public IEnumerable Variables; - public VariableObserver(VariableObserverNotifier notifier, IEnumerable variables) - { - Notifier = notifier; - Variables = variables; - } - } - - public interface IObservesVariables - { - IEnumerable GetVariableObservers(); - } - public interface INotifyHarvesterAction { void MovingToResources(Actor self, CPos targetCell); @@ -223,7 +210,7 @@ void Infiltrating(Actor self); } - public interface ITechTreePrerequisiteInfo : ITraitInfo + public interface ITechTreePrerequisiteInfo : ITraitInfoInterface { IEnumerable Prerequisites(ActorInfo info); } @@ -268,7 +255,7 @@ void Undeploy(Actor self, bool skipMakeAnim); } - public interface IAcceptResourcesInfo : ITraitInfo { } + public interface IAcceptResourcesInfo : ITraitInfoInterface { } public interface IAcceptResources { void OnDock(Actor harv, DeliverResources dockOrder); @@ -314,7 +301,7 @@ } [RequireExplicitImplementation] - interface IWallConnector + public interface IWallConnector { bool AdjacentWallCanConnect(Actor self, CPos wallLocation, string wallType, out CVec facing); void SetDirty(); @@ -342,10 +329,10 @@ } [RequireExplicitImplementation] - public interface IProductionCostModifierInfo : ITraitInfo { int GetProductionCostModifier(TechTree techTree, string queue); } + public interface IProductionCostModifierInfo : ITraitInfoInterface { int GetProductionCostModifier(TechTree techTree, string queue); } [RequireExplicitImplementation] - public interface IProductionTimeModifierInfo : ITraitInfo { int GetProductionTimeModifier(TechTree techTree, string queue); } + public interface IProductionTimeModifierInfo : ITraitInfoInterface { int GetProductionTimeModifier(TechTree techTree, string queue); } [RequireExplicitImplementation] public interface ICashTricklerModifier { int GetCashTricklerModifier(); } @@ -418,30 +405,30 @@ public enum ActorPreviewType { PlaceBuilding, ColorPicker, MapEditorSidebar } [RequireExplicitImplementation] - public interface IActorPreviewInitInfo : ITraitInfo + public interface IActorPreviewInitInfo : ITraitInfoInterface { - IEnumerable ActorPreviewInits(ActorInfo ai, ActorPreviewType type); + IEnumerable ActorPreviewInits(ActorInfo ai, ActorPreviewType type); } public interface IMove { Activity MoveTo(CPos cell, int nearEnough = 0, Actor ignoreActor = null, bool evaluateNearestMovableCell = false, Color? targetLineColor = null); - Activity MoveWithinRange(Target target, WDist range, + Activity MoveWithinRange(in Target target, WDist range, WPos? initialTargetPosition = null, Color? targetLineColor = null); - Activity MoveWithinRange(Target target, WDist minRange, WDist maxRange, + Activity MoveWithinRange(in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null); - Activity MoveFollow(Actor self, Target target, WDist minRange, WDist maxRange, + Activity MoveFollow(Actor self, in Target target, WDist minRange, WDist maxRange, WPos? initialTargetPosition = null, Color? targetLineColor = null); - Activity MoveToTarget(Actor self, Target target, + Activity MoveToTarget(Actor self, in Target target, WPos? initialTargetPosition = null, Color? targetLineColor = null); Activity ReturnToCell(Actor self); - Activity MoveIntoTarget(Actor self, Target target); + Activity MoveIntoTarget(Actor self, in Target target); Activity VisualMove(Actor self, WPos fromPos, WPos toPos); int EstimatedMoveDuration(Actor self, WPos fromPos, WPos toPos); CPos NearestMoveableCell(CPos target); MovementType CurrentMovementTypes { get; set; } - bool CanEnterTargetNow(Actor self, Target target); + bool CanEnterTargetNow(Actor self, in Target target); } public interface IWrapMove @@ -461,7 +448,7 @@ public interface IRadarSignature { - void PopulateRadarSignatureCells(Actor self, List> destinationBuffer); + void PopulateRadarSignatureCells(Actor self, List<(CPos Cell, Color Color)> destinationBuffer); } public interface IRadarColorModifier { Color RadarColorOverride(Actor self, Color color); } @@ -496,7 +483,7 @@ [RequireExplicitImplementation] public interface ITargetableCells { - Pair[] TargetableCells(); + (CPos Cell, SubCell SubCell)[] TargetableCells(); } [RequireExplicitImplementation] @@ -611,6 +598,13 @@ } [RequireExplicitImplementation] + public interface INotifyEditorPlacementInfo : ITraitInfoInterface + { + object AddedToEditor(EditorActorPreview preview, World editorWorld); + void RemovedFromEditor(EditorActorPreview preview, World editorWorld, object data); + } + + [RequireExplicitImplementation] public interface IPreventMapSpawn { bool PreventMapSpawn(World world, ActorReference actorReference); @@ -636,4 +630,17 @@ { void NotifyTimerExpired(Actor self); } + + [RequireExplicitImplementation] + public interface ISelectable + { + string Class { get; } + } + + public interface IDecoration + { + bool RequiresSelection { get; } + + IEnumerable RenderDecoration(Actor self, WorldRenderer wr, ISelectionDecorations container); + } } diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddAirAttackTypes.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddAirAttackTypes.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddAirAttackTypes.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddAirAttackTypes.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class AddAirAttackTypes : UpdateRule - { - public override string Name { get { return "Add AttackType field to AttackAircraft"; } } - public override string Description - { - get - { - return "Aircraft attack behavior now depends on AttackAircraft.AttackType\n" - + "instead of Aircraft.CanHover."; - } - } - - readonly List> hoveringActors = new List>(); - - public override IEnumerable AfterUpdate(ModData modData) - { - var message = "Aircraft attack behavior (Hover or Strafe) is now controlled via AttackAircraft.AttackType.\n" - + "Aircraft with CanHover: true will now also need AttackType: Hover on AttackAircraft\n" - + "to maintain position while attacking as before.\n" - + "The following places might need manual changes:\n" - + UpdateUtils.FormatMessageList(hoveringActors.Select(n => n.Item1 + " (" + n.Item2 + ")")); - - if (hoveringActors.Any()) - yield return message; - - hoveringActors.Clear(); - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - var aircraftTraits = actorNode.ChildrenMatching("Aircraft"); - var attackAircraftTraits = actorNode.ChildrenMatching("AttackAircraft"); - foreach (var attackAircraft in attackAircraftTraits) - { - var isHover = false; - foreach (var aircraft in aircraftTraits) - { - var canHoverNode = aircraft.LastChildMatching("CanHover"); - if (canHoverNode != null) - isHover = canHoverNode.NodeValue(); - - if (isHover) - break; - } - - // It's still possible that CanHover: true is inherited, so let modders check manually if 'false', - // otherwise add AttackType: Hover. - if (!isHover) - hoveringActors.Add(Tuple.Create(actorNode.Key, actorNode.Location.Filename)); - else - attackAircraft.AddNode("AttackType", "Hover"); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddAircraftIdleBehavior.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddAircraftIdleBehavior.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddAircraftIdleBehavior.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddAircraftIdleBehavior.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class AddAircraftIdleBehavior : UpdateRule - { - public override string Name { get { return "Several aircraft traits and fields were replaced by Aircraft.IdleBehavior"; } } - public override string Description - { - get - { - return "ReturnOnIdle and FlyAwayOnIdle traits as well as LandWhenIdle boolean\n" - + "were replaced by Aircraft.IdleBehavior."; - } - } - - readonly List> returnOnIdles = new List>(); - - public override IEnumerable AfterUpdate(ModData modData) - { - var message = "ReturnOnIdle trait has been removed from the places listed below.\n" - + "Since this trait has been dysfunctional for a long time,\n" - + "IdleBehavior: ReturnToBase is NOT being set automatically.\n" - + "If you want your aircraft to return when idle, manually set it on the following definitions:\n" - + UpdateUtils.FormatMessageList(returnOnIdles.Select(n => n.Item1 + " (" + n.Item2 + ")")); - - if (returnOnIdles.Any()) - yield return message; - - returnOnIdles.Clear(); - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - var aircraft = actorNode.LastChildMatching("Aircraft"); - var returnOnIdle = actorNode.LastChildMatching("ReturnOnIdle"); - var flyAwayOnIdle = actorNode.LastChildMatching("FlyAwayOnIdle"); - - if (aircraft != null) - { - var landWhenIdle = false; - var landWhenIdleNode = aircraft.LastChildMatching("LandWhenIdle"); - if (landWhenIdleNode != null) - { - landWhenIdle = landWhenIdleNode.NodeValue(); - aircraft.RemoveNode(landWhenIdleNode); - } - - // FlyAwayOnIdle should have had higher priority than LandWhenIdle even if both were 'true'. - // ReturnOnIdle has been broken for so long that it's safer to ignore it here and only inform - // the modder of the places it's been removed from, so they can change the IdleBehavior manually if desired. - if (flyAwayOnIdle != null && !flyAwayOnIdle.IsRemoval()) - aircraft.AddNode(new MiniYamlNode("IdleBehavior", "LeaveMap")); - else if (landWhenIdle) - aircraft.AddNode(new MiniYamlNode("IdleBehavior", "Land")); - } - - if (flyAwayOnIdle != null) - actorNode.RemoveNode(flyAwayOnIdle); - - if (returnOnIdle != null) - { - returnOnIdles.Add(Tuple.Create(actorNode.Key, actorNode.Location.Filename)); - actorNode.RemoveNode(returnOnIdle); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddCanSlide.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddCanSlide.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddCanSlide.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/AddCanSlide.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class AddCanSlide : UpdateRule - { - public override string Name { get { return "Split CanSlide from CanHover"; } } - public override string Description - { - get - { - return "Aircraft.CanHover was split into two flags; CanHover now only makes aircraft hover when idle,\n" - + "while CanSlide toggles the ability to immediately changing direction without flying a curve."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - var aircraftTraits = actorNode.ChildrenMatching("Aircraft"); - foreach (var aircraft in aircraftTraits) - { - var canHover = false; - var canHoverNode = aircraft.LastChildMatching("CanHover"); - if (canHoverNode != null) - canHover = canHoverNode.NodeValue(); - else - yield break; - - aircraft.AddNode("CanSlide", canHover.ToString()); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MakeMobilePausableConditional.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MakeMobilePausableConditional.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MakeMobilePausableConditional.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MakeMobilePausableConditional.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class MakeMobilePausableConditional : UpdateRule - { - public override string Name { get { return "Change Mobile>RequiresCondition to PauseOnCondition"; } } - public override string Description - { - get - { - return "Mobile is now a PausableConditionalTrait instead of a ConditionalTrait.\n" + - "RequiresCondition is changed to PauseOnCondition."; - } - } - - bool displayedMessage; - public override IEnumerable AfterUpdate(ModData modData) - { - var message = "You may want to update the result of PauseOnCondition, as this update\n" + - "just adds ! prefix to RequiresCondition's value to reverse it."; - - if (!displayedMessage) - yield return message; - - displayedMessage = true; - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - foreach (var node in actorNode.ChildrenMatching("Mobile").Where(t => t.ChildrenMatching("RequiresCondition").Any())) - { - var rc = node.LastChildMatching("RequiresCondition"); - - rc.ReplaceValue("!(" + rc.Value.Value + ")"); - rc.RenameKey("PauseOnCondition"); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MoveAbortOnResupply.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MoveAbortOnResupply.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MoveAbortOnResupply.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MoveAbortOnResupply.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class MoveAbortOnResupply : UpdateRule - { - public override string Name { get { return "Moved AbortOnResupply from Aircraft to AttackAircraft"; } } - public override string Description - { - get - { - return "AbortOnResupply boolean was moved to AttackAircraft."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - var aircraft = actorNode.LastChildMatching("Aircraft"); - var attackAircraft = actorNode.ChildrenMatching("AttackAircraft"); - - if (aircraft != null) - { - var abortOnResupply = aircraft.LastChildMatching("AbortOnResupply"); - if (abortOnResupply == null) - yield break; - - // Only add field to AttackAircraft if explicitly set to 'false' - if (!abortOnResupply.NodeValue()) - { - if (attackAircraft.Any()) - foreach (var a in attackAircraft) - a.AddNode(abortOnResupply); - else - { - var newAttackAircraft = new MiniYamlNode("AttackAircraft", ""); - newAttackAircraft.AddNode(abortOnResupply); - actorNode.AddNode(newAttackAircraft); - } - } - - aircraft.RemoveNode(abortOnResupply); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MultipleDeploySounds.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MultipleDeploySounds.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MultipleDeploySounds.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/MultipleDeploySounds.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class MultipleDeploySounds : UpdateRule - { - public override string Name { get { return "'GrantConditionOnDeploy' now supports multiple (un)deploy sounds"; } } - public override string Description - { - get - { - return "Renamed 'DeploySound' to 'DeploySounds' and 'UndeploySound' to 'UndeploySounds'\n" + - "on 'GrantConditionOnDeploy'."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - var grants = actorNode.ChildrenMatching("GrantConditionOnDeploy"); - foreach (var g in grants) - { - var deploy = g.LastChildMatching("DeploySound"); - if (deploy != null) - deploy.RenameKey("DeploySounds"); - - var undeploy = g.LastChildMatching("UndeploySound"); - if (undeploy != null) - undeploy.RenameKey("UndeploySounds"); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RefactorHarvesterIdle.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RefactorHarvesterIdle.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RefactorHarvesterIdle.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RefactorHarvesterIdle.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class RefactorHarvesterIdle : UpdateRule - { - public override string Name { get { return "Refactor harvester idle behavior."; } } - public override string Description - { - get - { - return "The MaxIdleDuration parameter has been removed from the Harvester trait as part of a\n" + - " refactoring of harvester idling behavior."; - } - } - - readonly List locations = new List(); - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - foreach (var t in actorNode.ChildrenMatching("Harvester")) - if (t.RemoveNodes("MaxIdleDuration") > 0) - locations.Add("{0} ({1})".F(actorNode.Key, actorNode.Location.Filename)); - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemoveMoveIntoWorldFromExit.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemoveMoveIntoWorldFromExit.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemoveMoveIntoWorldFromExit.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemoveMoveIntoWorldFromExit.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class RemoveMoveIntoWorldFromExit : UpdateRule - { - public override string Name { get { return "Remove MoveIntoWorld from Exit."; } } - public override string Description - { - get - { - return "The MoveIntoWorld parameter has been removed from the Exit trait because it no\n" + - "longer serves a purpose (aircraft can now use the same exit procedure as other\n" + - "units)."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - foreach (var t in actorNode.ChildrenMatching("Exit")) - t.RemoveNodes("MoveIntoWorld"); - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemovePlaceBuildingPalettes.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemovePlaceBuildingPalettes.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemovePlaceBuildingPalettes.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemovePlaceBuildingPalettes.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class RemovePlaceBuildingPalettes : UpdateRule - { - public override string Name { get { return "Remove Palette and LineBuildSegmentPalette from PlaceBuilding"; } } - public override string Description - { - get - { - return "The Palette and LineBuildSegmentPalette fields have been moved from PlaceBuilding,\n" + - "to the *PlaceBuildingPreview traits."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - // Repairable isn't conditional or otherwise supports multiple traits, so LastChildMatching should be fine. - foreach (var placeBuilding in actorNode.ChildrenMatching("PlaceBuilding")) - { - placeBuilding.RemoveNodes("Palette"); - placeBuilding.RemoveNodes("LineBuildSegmentPalette"); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemoveSimpleBeacon.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemoveSimpleBeacon.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemoveSimpleBeacon.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemoveSimpleBeacon.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class RemoveSimpleBeacon : UpdateRule - { - public override string Name { get { return "Remove 'PlaceSimpleBeacon'."; } } - public override string Description - { - get - { - return "The 'PlaceSimpleBeacon' trait was removed.\n" + - "Use the new functionality of the 'PlaceBeacon' trait instead."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - var psb = actorNode.LastChildMatching("PlaceSimpleBeacon"); - if (psb == null) - yield break; - - psb.RenameKey("PlaceBeacon"); - - var palette = psb.LastChildMatching("Palette"); - var isPlayer = psb.LastChildMatching("IsPlayerPalette"); - var sequence = psb.LastChildMatching("BeaconSequence"); - - if (palette == null) - psb.AddNode("Palette", "effect"); - - if (isPlayer == null) - psb.AddNode("IsPlayerPalette", "false"); - - if (sequence == null) - psb.AddNode("BeaconSequence", "idle"); - - psb.AddNode("ArrowSequence", ""); - psb.AddNode("CircleSequence", ""); - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameAttackMoveConditions.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameAttackMoveConditions.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameAttackMoveConditions.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameAttackMoveConditions.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class RenameAttackMoveConditions : UpdateRule - { - public override string Name { get { return "Rename AttackMove *ScanConditions"; } } - public override string Description - { - get - { - return "AttackMove's AttackMoveScanCondition and AssaultMoveScanCondition\n" + - "now remain active while attacking, and are have been renamed to\n" + - "AttackMoveCondition and AssaultMoveCondition to reflect this.\n"; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - foreach (var at in actorNode.ChildrenMatching("AttackMove")) - { - foreach (var node in at.ChildrenMatching("AttackMoveScanCondition")) - node.RenameKey("AttackMoveCondition"); - - foreach (var node in at.ChildrenMatching("AssaultMoveScanCondition")) - node.RenameKey("AssaultMoveCondition"); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameCarryallDelays.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameCarryallDelays.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameCarryallDelays.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameCarryallDelays.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class RenameCarryallDelays : UpdateRule - { - public override string Name { get { return "Rename Carryall and Cargo delay parameters"; } } - public override string Description - { - get - { - return "Carryall's LoadingDelay and UnloadingDelay parameters have been renamed\n" - + "to BeforeLoadDelay and BeforeUnloadDelay to match new parameters on Cargo."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - foreach (var carryall in actorNode.ChildrenMatching("Carryall")) - { - foreach (var node in carryall.ChildrenMatching("LoadingDelay")) - node.RenameKey("BeforeLoadDelay"); - - foreach (var node in carryall.ChildrenMatching("UnloadingDelay")) - node.RenameKey("BeforeUnloadDelay"); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameChronoshiftFootprint.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameChronoshiftFootprint.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameChronoshiftFootprint.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameChronoshiftFootprint.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class RenameChronoshiftFootprint : UpdateRule - { - public override string Name { get { return "Rename footprint related ChronoshiftPower parameters"; } } - public override string Description - { - get - { - return "The parameters that define the footprint tiles to use in ChronoshiftPower\n" + - "are renamed to follow standard conventions."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - // Repairable isn't conditional or otherwise supports multiple traits, so LastChildMatching should be fine. - foreach (var placeBuilding in actorNode.ChildrenMatching("ChronoshiftPower")) - { - placeBuilding.RenameChildrenMatching("OverlaySpriteGroup", "FootprintImage"); - placeBuilding.RenameChildrenMatching("InvalidTileSequencePrefix", "InvalidFootprintSequence"); - placeBuilding.RenameChildrenMatching("SourceTileSequencePrefix", "SourceFootprintSequence"); - foreach (var valid in placeBuilding.ChildrenMatching("ValidTileSequencePrefix")) - { - valid.RenameKey("ValidFootprintSequence"); - valid.Value.Value = valid.Value.Value.Substring(0, valid.Value.Value.Length - 1); - } - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameHoversOffsetModifier.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameHoversOffsetModifier.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameHoversOffsetModifier.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameHoversOffsetModifier.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class RenameHoversOffsetModifier : UpdateRule - { - public override string Name { get { return "Rename Hovers OffsetModifier"; } } - public override string Description - { - get - { - return "Hovers' OffsetModifier was renamed to BobDistance,\n" + - "as 'Modifier' is a term we don't normally use for distance,\n" + - "while 'Offset' would imply a 3D vector, which isn't the case here."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - foreach (var h in actorNode.ChildrenMatching("Hovers")) - foreach (var node in h.ChildrenMatching("OffsetModifier")) - node.RenameKey("BobDistance"); - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameSearchRadius.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameSearchRadius.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameSearchRadius.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RenameSearchRadius.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - class RenameSearchRadius : UpdateRule - { - public override string Name { get { return "Rename SearchFromOrderRadius to SearchFromHarvesterRadius"; } } - public override string Description - { - get - { - return "Renamed 'SearchFromOrderRadius' to 'SearchFromHarvesterRadius'."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - foreach (var harvester in actorNode.ChildrenMatching("Harvester")) - harvester.RenameChildrenMatching("SearchFromOrderRadius", "SearchFromHarvesterRadius"); - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/ReplaceSpecialMoveConsiderations.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/ReplaceSpecialMoveConsiderations.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/ReplaceSpecialMoveConsiderations.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/ReplaceSpecialMoveConsiderations.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class ReplaceSpecialMoveConsiderations : UpdateRule - { - public override string Name { get { return "Replaced special-case movement type considerations"; } } - public override string Description - { - get - { - return "Removed AlwaysConsiderTurnAsMove from Mobile and ConsiderVerticalMovement\n" + - "from GrantConditionOnMovement. Add 'Turn' and/or 'Vertical' on new ValidMovementTypes\n" + - "fields on WithMoveAnimation and GrantConditionOnMovement instead."; - } - } - - readonly Dictionary> locations = new Dictionary>(); - - public override IEnumerable AfterUpdate(ModData modData) - { - if (locations.Any()) - yield return "The following definitions implement WithMoveAnimation\n" + - "or GrantConditionOnMovement. Check if they need updated ValidMovementTypes:\n" + - UpdateUtils.FormatMessageList(locations.Select( - kv => kv.Key + ":\n" + UpdateUtils.FormatMessageList(kv.Value))); - - locations.Clear(); - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - var mobileNode = actorNode.ChildrenMatching("Mobile").FirstOrDefault(m => !m.IsRemoval()); - if (mobileNode != null) - { - var considerTurnAsMoveNode = mobileNode.LastChildMatching("AlwaysConsiderTurnAsMove"); - if (considerTurnAsMoveNode != null) - mobileNode.RemoveNode(considerTurnAsMoveNode); - } - - var used = new List(); - var grantMoveConditions = actorNode.ChildrenMatching("GrantConditionOnMovement"); - foreach (var g in grantMoveConditions) - { - var considerVerticalNode = g.LastChildMatching("ConsiderVerticalMovement"); - if (considerVerticalNode != null) - g.RemoveNode(considerVerticalNode); - } - - if (grantMoveConditions.Any()) - used.Add("GrantConditionOnMovement"); - - var moveAnim = actorNode.LastChildMatching("WithMoveAnimation"); - if (moveAnim != null) - used.Add("WithMoveAnimation"); - - if (used.Any()) - { - var location = "{0} ({1})".F(actorNode.Key, actorNode.Location.Filename); - locations[location] = used; - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/SplitHarvesterSpriteBody.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/SplitHarvesterSpriteBody.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/SplitHarvesterSpriteBody.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/SplitHarvesterSpriteBody.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class SplitHarvesterSpriteBody : UpdateRule - { - public override string Name { get { return "Split fullness display from WithHarvestAnimation to new WithHarvesterSpriteBody"; } } - public override string Description - { - get - { - return "WithHarvestAnimation.PrefixByFullness logic was moved to a dedicated WithHarvesterSpriteBody."; - } - } - - readonly List> fullnessPrefixes = new List>(); - - public override IEnumerable AfterUpdate(ModData modData) - { - var message = "PrefixByFullness has been removed from WithHarvestAnimation.\n" - + "To display fullness levels, use the new WithHarvesterSpriteBody\n" - + "to switch between separate image sprites instead (see RA mod harvester for reference).\n" - + "The following places most likely need manual changes:\n" - + UpdateUtils.FormatMessageList(fullnessPrefixes.Select(n => n.Item1 + " (" + n.Item2 + ")")); - - if (fullnessPrefixes.Any()) - yield return message; - - fullnessPrefixes.Clear(); - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - var harvAnim = actorNode.LastChildMatching("WithHarvestAnimation"); - if (harvAnim != null) - { - var fullnessPrefix = harvAnim.LastChildMatching("PrefixByFullness"); - - // If PrefixByFullness is empty, no changes are needed. - if (fullnessPrefix == null) - yield break; - - harvAnim.RemoveNode(fullnessPrefix); - - fullnessPrefixes.Add(Tuple.Create(actorNode.Key, actorNode.Location.Filename)); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/StreamlineRepairableTraits.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/StreamlineRepairableTraits.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20190314/StreamlineRepairableTraits.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20190314/StreamlineRepairableTraits.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; - -namespace OpenRA.Mods.Common.UpdateRules.Rules -{ - public class StreamlineRepairableTraits : UpdateRule - { - public override string Name { get { return "Streamline RepairableNear and Repairable"; } } - public override string Description - { - get - { - return "Renamed Repairable.RepairBuildings and RepairableNear.Buildings to RepairActors,\n" + - "for consistency with RearmActors (and since repairing at other actors should already be possible).\n" + - "Additionally, removed internal 'fix' and 'spen, syrd' default values."; - } - } - - public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) - { - // Repairable isn't conditional or otherwise supports multiple traits, so LastChildMatching should be fine. - var repairableNode = actorNode.LastChildMatching("Repairable"); - if (repairableNode != null) - { - var repairBuildings = repairableNode.LastChildMatching("RepairBuildings"); - if (repairBuildings != null) - repairBuildings.RenameKey("RepairActors"); - else - repairableNode.AddNode(new MiniYamlNode("RepairActors", "fix")); - } - - // RepairableNear isn't conditional or otherwise supports multiple traits, so LastChildMatching should be fine. - var repairableNearNode = actorNode.LastChildMatching("RepairableNear"); - if (repairableNearNode != null) - { - var repairBuildings = repairableNearNode.LastChildMatching("Buildings"); - if (repairBuildings != null) - repairBuildings.RenameKey("RepairActors"); - else - repairableNearNode.AddNode(new MiniYamlNode("RepairActors", "spen, syrd")); - } - - yield break; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200202/ReformatChromeProvider.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200202/ReformatChromeProvider.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200202/ReformatChromeProvider.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200202/ReformatChromeProvider.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,12 +9,10 @@ */ #endregion -using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.Graphics; -using OpenRA.Mods.Common.Widgets; namespace OpenRA.Mods.Common.UpdateRules.Rules { diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200202/RenameSpins.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200202/RenameSpins.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200202/RenameSpins.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200202/RenameSpins.cs 2021-03-21 11:10:05.000000000 +0000 @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2019 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/AddPipDecorationTraits.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/AddPipDecorationTraits.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/AddPipDecorationTraits.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/AddPipDecorationTraits.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,270 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class AddPipDecorationTraits : UpdateRule + { + public override string Name { get { return "Add decoration traits for selection pips."; } } + public override string Description + { + get + { + return "The AmmoPool, Cargo, Harvester, and StoresResources traits no longer\n" + + "automatically add pips to the selection box. New traits WithAmmoPipsDecoration,\n" + + "WithCargoPipsDecoration, WithHarvesterPipsDecoration,\n" + + "WithResourceStoragePipsDecoration are added to provide the same functionality.\n\n" + + "Passenger.PipType has been replaced with CustomPipType, which now references a\n" + + "sequence defined in WithCargoDecoration.CustomPipTypeSequences.\n\n" + + "ResourceType.PipColor has been removed and resource pip colours are now defined\n" + + "in WithHarvesterPipsDecoration.ResourceSequences."; + } + } + + static readonly Dictionary PipReplacements = new Dictionary + { + { "transparent", "pip-empty" }, + { "green", "pip-green" }, + { "yellow", "pip-yellow" }, + { "red", "pip-red" }, + { "gray", "pip-gray" }, + { "blue", "pip-blue" }, + { "ammo", "pip-ammo" }, + { "ammoempty", "pip-ammoempty" }, + }; + + bool customPips; + readonly List locations = new List(); + readonly List cargoPipLocations = new List(); + readonly HashSet cargoCustomPips = new HashSet(); + readonly List harvesterPipLocations = new List(); + readonly Dictionary harvesterCustomPips = new Dictionary(); + + public override IEnumerable AfterUpdate(ModData modData) + { + if (customPips && locations.Any()) + yield return "Custom pip Images and Palettes are now defined on the individual With*PipsDecoration traits.\n" + + "You should review the following definitions and manually define the Image and Palette properties as required:\n" + + UpdateUtils.FormatMessageList(locations); + + if (cargoCustomPips.Any() && cargoPipLocations.Any()) + yield return "Some passenger types define custom cargo pips. Review the following definitions:\n" + + UpdateUtils.FormatMessageList(cargoPipLocations) + + "\nand, if required, add the following to the WithCargoPipsDecoration traits:\n" + + "CustomPipSequences:\n" + cargoCustomPips.Select(p => "\t{0}: {1}".F(p, PipReplacements[p])).JoinWith("\n"); + + if (harvesterCustomPips.Any() && harvesterPipLocations.Any()) + yield return "Review the following definitions:\n" + + UpdateUtils.FormatMessageList(harvesterPipLocations) + + "\nand, if required, add the following to the WithHarvesterPipsDecoration traits:\n" + + "ResourceSequences:\n" + harvesterCustomPips.Select(kv => "\t{0}: {1}".F(kv.Key, PipReplacements[kv.Value])).JoinWith("\n"); + + customPips = false; + locations.Clear(); + cargoPipLocations.Clear(); + harvesterPipLocations.Clear(); + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + var addNodes = new List(); + + foreach (var selectionDecorations in actorNode.ChildrenMatching("SelectionDecorations")) + { + customPips |= selectionDecorations.RemoveNodes("Palette") > 0; + customPips |= selectionDecorations.RemoveNodes("Image") > 0; + } + + foreach (var ammoPool in actorNode.ChildrenMatching("AmmoPool")) + { + var ammoPips = new MiniYamlNode("WithAmmoPipsDecoration", ""); + ammoPips.AddNode("Position", "BottomLeft"); + ammoPips.AddNode("RequiresSelection", "true"); + + var pipCountNode = ammoPool.LastChildMatching("PipCount"); + if (pipCountNode != null) + { + ammoPool.RemoveNode(pipCountNode); + var pipCount = pipCountNode.NodeValue(); + if (pipCount == 0) + { + addNodes.Add(new MiniYamlNode("-" + ammoPips.Key, "")); + continue; + } + + var ammoNode = ammoPool.LastChildMatching("Ammo"); + var maxAmmo = ammoNode != null ? ammoNode.NodeValue() : 0; + if (pipCount != maxAmmo) + ammoPips.AddNode("PipCount", pipCount); + } + + var pipTypeNode = ammoPool.LastChildMatching("PipType"); + if (pipTypeNode != null) + { + ammoPool.RemoveNode(pipTypeNode); + + if (PipReplacements.TryGetValue(pipTypeNode.Value.Value.ToLowerInvariant(), out var sequence)) + ammoPips.AddNode("FullSequence", sequence); + } + + var pipTypeEmptyNode = ammoPool.LastChildMatching("PipTypeEmpty"); + if (pipTypeEmptyNode != null) + { + ammoPool.RemoveNode(pipTypeEmptyNode); + + if (PipReplacements.TryGetValue(pipTypeEmptyNode.Value.Value.ToLowerInvariant(), out var sequence)) + ammoPips.AddNode("EmptySequence", sequence); + } + + addNodes.Add(ammoPips); + locations.Add("{0}: {1} ({2})".F(actorNode.Key, ammoPips.Key, actorNode.Location.Filename)); + } + + foreach (var cargo in actorNode.ChildrenMatching("Cargo")) + { + var cargoPips = new MiniYamlNode("WithCargoPipsDecoration", ""); + cargoPips.AddNode("Position", "BottomLeft"); + cargoPips.AddNode("RequiresSelection", "true"); + + var pipCountNode = cargo.LastChildMatching("PipCount"); + if (pipCountNode != null) + { + cargo.RemoveNode(pipCountNode); + + var pipCount = pipCountNode.NodeValue(); + if (pipCount == 0) + { + addNodes.Add(new MiniYamlNode("-" + cargoPips.Key, "")); + continue; + } + + var maxWeightNode = cargo.LastChildMatching("MaxWeight"); + var maxWeight = maxWeightNode != null ? maxWeightNode.NodeValue() : 0; + if (pipCount != maxWeight) + cargoPips.AddNode("PipCount", pipCount); + } + else + continue; + + addNodes.Add(cargoPips); + locations.Add("{0}: {1} ({2})".F(actorNode.Key, cargoPips.Key, actorNode.Location.Filename)); + cargoPipLocations.Add("{0} ({1})".F(actorNode.Key, actorNode.Location.Filename)); + } + + foreach (var passenger in actorNode.ChildrenMatching("Passenger")) + { + var pipTypeNode = passenger.LastChildMatching("PipType"); + if (pipTypeNode != null) + { + pipTypeNode.RenameKey("CustomPipType"); + pipTypeNode.Value.Value = pipTypeNode.Value.Value.ToLowerInvariant(); + cargoCustomPips.Add(pipTypeNode.Value.Value); + } + } + + foreach (var harvester in actorNode.ChildrenMatching("Harvester")) + { + var harvesterPips = new MiniYamlNode("WithHarvesterPipsDecoration", ""); + harvesterPips.AddNode("Position", "BottomLeft"); + harvesterPips.AddNode("RequiresSelection", "true"); + + // Harvester hardcoded a default PipCount > 0 so we can't use that to determine whether + // this is a definition or an override. Resources isn't ideal either, but is better than nothing + var resourcesNode = harvester.LastChildMatching("Resources"); + if (resourcesNode == null) + continue; + + var pipCountNode = harvester.LastChildMatching("PipCount"); + if (pipCountNode != null) + { + harvester.RemoveNode(pipCountNode); + + var pipCount = pipCountNode.NodeValue(); + if (pipCount == 0) + { + addNodes.Add(new MiniYamlNode("-" + harvesterPips.Key, "")); + continue; + } + + harvesterPips.AddNode("PipCount", pipCount); + } + else + harvesterPips.AddNode("PipCount", 7); + + addNodes.Add(harvesterPips); + locations.Add("{0}: {1} ({2})".F(actorNode.Key, harvesterPips.Key, actorNode.Location.Filename)); + harvesterPipLocations.Add("{0} ({1})".F(actorNode.Key, actorNode.Location.Filename)); + } + + foreach (var resourceType in actorNode.ChildrenMatching("ResourceType")) + { + var pipColor = "yellow"; + var pipCountNode = resourceType.LastChildMatching("PipColor"); + if (pipCountNode != null) + { + pipColor = pipCountNode.Value.Value.ToLowerInvariant(); + resourceType.RemoveNode(pipCountNode); + } + + var typeNode = resourceType.LastChildMatching("Type"); + if (typeNode != null) + harvesterCustomPips.Add(typeNode.Value.Value, pipColor); + } + + foreach (var storesResources in actorNode.ChildrenMatching("StoresResources")) + { + var storagePips = new MiniYamlNode("WithResourceStoragePipsDecoration", ""); + storagePips.AddNode("Position", "BottomLeft"); + storagePips.AddNode("RequiresSelection", "true"); + + var pipCountNode = storesResources.LastChildMatching("PipCount"); + if (pipCountNode != null) + { + storesResources.RemoveNode(pipCountNode); + var pipCount = pipCountNode.NodeValue(); + if (pipCount == 0) + { + addNodes.Add(new MiniYamlNode("-" + storagePips.Key, "")); + continue; + } + + storagePips.AddNode("PipCount", pipCount); + } + else + continue; + + // Default pip color changed from yellow to green for consistency with other pip traits + var pipColorNode = storesResources.LastChildMatching("PipColor"); + if (pipColorNode != null) + { + storesResources.RemoveNode(pipColorNode); + + var type = pipColorNode.Value.Value.ToLowerInvariant(); + if (type != "green" && PipReplacements.TryGetValue(type, out var sequence)) + storagePips.AddNode("FullSequence", sequence); + } + else + storagePips.AddNode("FullSequence", PipReplacements["yellow"]); + + addNodes.Add(storagePips); + locations.Add("{0}: {1} ({2})".F(actorNode.Key, storagePips.Key, actorNode.Location.Filename)); + } + + foreach (var addNode in addNodes) + actorNode.AddNode(addNode); + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ChangeTargetLineDelayToMilliseconds.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ChangeTargetLineDelayToMilliseconds.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ChangeTargetLineDelayToMilliseconds.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ChangeTargetLineDelayToMilliseconds.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,43 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + class ChangeTargetLineDelayToMilliseconds : UpdateRule + { + public override string Name { get { return "Changed DrawLineToTarget.Delay interpretation from ticks to milliseconds."; } } + public override string Description + { + get + { + return "Going forward, the value of the `Delay` attribute of the `DrawLineToTarget` trait will be\n" + + "interpreted as milliseconds instead of ticks.\n"; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var dltt in actorNode.ChildrenMatching("DrawLineToTarget", includeRemovals: false)) + { + var delayNode = dltt.LastChildMatching("Delay", false); + if (delayNode != null) + { + if (Exts.TryParseIntegerInvariant(delayNode.Value.Value, out var delay)) + delayNode.ReplaceValue((delay * 1000 / 25).ToString()); + } + } + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ConvertSupportPowerRangesToFootprint.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ConvertSupportPowerRangesToFootprint.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ConvertSupportPowerRangesToFootprint.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ConvertSupportPowerRangesToFootprint.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,101 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class ConvertSupportPowerRangesToFootprint : UpdateRule + { + public override string Name { get { return "Convert support power ranges to footprint"; } } + public override string Description + { + get + { + return "ChronoshiftPower and GrantExternalConditionPower use footprint areas\n" + + "instead of a circular range and they no longer have a fallback default area value.\n" + + "The old Range values will be converted to footprints as part of this update."; + } + } + + static readonly string[] AffectedTraits = new string[] { "GrantExternalConditionPower", "ChronoshiftPower" }; + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var at in AffectedTraits) + foreach (var trait in actorNode.ChildrenMatching(at)) + UpdatePower(trait); + + yield break; + } + + void UpdatePower(MiniYamlNode power) + { + var range = 1; + var rangeNode = power.LastChildMatching("Range"); + if (rangeNode != null) + { + range = rangeNode.NodeValue(); + if (range > 3) + locations.Add("{0} ({1})".F(rangeNode.Key, rangeNode.Location.Filename)); + + power.RemoveNode(rangeNode); + } + + var size = 2 * range + 1; + power.AddNode(new MiniYamlNode("Dimensions", size.ToString() + ", " + size.ToString())); + + var footprint = string.Empty; + + var emptycell = range; + var affectedcell = 1; + + for (var i = 0; i < size; i++) + { + for (var e = 0; e < emptycell; e++) + footprint += '_'; + + for (var a = 0; a < affectedcell; a++) + footprint += 'x'; + + for (var e = 0; e < emptycell; e++) + footprint += '_'; + + if (i < range) + { + emptycell--; + affectedcell += 2; + } + else + { + emptycell++; + affectedcell -= 2; + } + + footprint += ' '; + } + + power.AddNode(new MiniYamlNode("Footprint", footprint)); + } + + readonly List locations = new List(); + + public override IEnumerable AfterUpdate(ModData modData) + { + if (locations.Any()) + yield return "Please check and adjust the new auto-generated dimensions.\n" + + UpdateUtils.FormatMessageList(locations); + + locations.Clear(); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/CreateFlashPaletteEffectWarhead.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/CreateFlashPaletteEffectWarhead.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/CreateFlashPaletteEffectWarhead.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/CreateFlashPaletteEffectWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,61 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class CreateFlashPaletteEffectWarhead : UpdateRule + { + public override string Name { get { return "Create FlashPaletteEffectWarhead to replace hardcoded nuke flashing."; } } + + public override string Description + { + get + { + return "The trait NukePower (via the NukeLaunch projectile that it uses) no longer has built-in palette flashing."; + } + } + + readonly List> weaponsToUpdate = new List>(); + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + var nukePowerTraits = actorNode.ChildrenMatching("NukePower"); + foreach (var nukePowerTrait in nukePowerTraits) + { + var traitName = nukePowerTrait.Key; + var weaponNode = nukePowerTrait.ChildrenMatching("MissileWeapon").FirstOrDefault(); + if (weaponNode == null) + continue; + + var weaponName = weaponNode.Value.Value; + + weaponsToUpdate.Add(new Tuple(weaponName, traitName, "{0} ({1})".F(actorNode.Key, actorNode.Location.Filename))); + + nukePowerTrait.RemoveNodes("FlashType"); + } + + yield break; + } + + public override IEnumerable AfterUpdate(ModData modData) + { + if (weaponsToUpdate.Any()) + yield return "Add a FlashPaletteEffectWarhead to the following weapons:\n" + + UpdateUtils.FormatMessageList(weaponsToUpdate.Select(x => "Weapon `{0}`, used by trait `{1}` on actor {2}".F(x.Item1, x.Item2, x.Item3))); + + weaponsToUpdate.Clear(); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ModernizeDecorationTraits.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ModernizeDecorationTraits.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ModernizeDecorationTraits.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ModernizeDecorationTraits.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,122 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Mods.Common.Traits; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class ModernizeDecorationTraits : UpdateRule + { + public override string Name { get { return "Modernize SelectionDecorations and With*Decoration traits."; } } + public override string Description + { + get + { + return "The configuration properties exposed on the SelectionDecorations and With*Decoration\n" + + "traits have been reworked. RenderSelectionBars and RenderSelectionBox have been removed from\n" + + "SelectionDecorations. The obsolete ZOffset and ScreenOffset has been removed from With*Decoration, and ReferencePoint has\n" + + "been replaced by Position which takes a single value (TopLeft, TopRight, BottomLeft, BottomRight, Center, or Top).\n" + + "A new Margin property is available to control the decoration offset relative to the edges of the selection box.\n" + + "RenderNameTag has been renamed to WithNameTagDecoration and now behaves like a normal decoration trait.\n"; + } + } + + static readonly string[] LegacyDecorationTraits = { "WithDecoration", "WithSpriteControlGroupDecoration", "WithTextControlGroupDecoration", "WithTextDecoration", "WithBuildingRepairDecoration", "InfiltrateForDecoration" }; + static readonly string[] ModernDecorationTraits = { "WithAmmoPipsDecoration", "WithCargoPipsDecoration", "WithHarvesterPipsDecoration", "WithResourceStoragePipsDecoration", "WithNameTagDecoration" }; + + [Flags] + public enum LegacyReferencePoints + { + Center = 0, + Top = 1, + Bottom = 2, + Left = 4, + Right = 8, + } + + static readonly Dictionary PositionMap = new Dictionary() + { + { LegacyReferencePoints.Center, "Center" }, + { LegacyReferencePoints.Top, "Top" }, + { LegacyReferencePoints.Top | LegacyReferencePoints.Left, "TopLeft" }, + { LegacyReferencePoints.Top | LegacyReferencePoints.Right, "TopRight" }, + { LegacyReferencePoints.Bottom | LegacyReferencePoints.Left, "BottomLeft" }, + { LegacyReferencePoints.Bottom | LegacyReferencePoints.Right, "BottomRight" } + }; + + readonly Dictionary> locations = new Dictionary>(); + + public override IEnumerable AfterUpdate(ModData modData) + { + if (locations.Any()) + yield return "The way that decorations are positioned relative to the selection box has changed.\n" + + "Review the following definitions and define Margin properties as required:\n" + + UpdateUtils.FormatMessageList(locations.Select( + kv => kv.Key + ":\n" + UpdateUtils.FormatMessageList(kv.Value))); + + locations.Clear(); + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + var locationKey = "{0} ({1})".F(actorNode.Key, actorNode.Location.Filename); + + foreach (var trait in LegacyDecorationTraits) + { + foreach (var node in actorNode.ChildrenMatching(trait)) + { + node.RemoveNodes("ZOffset"); + node.RemoveNodes("ScreenOffset"); + + var positionNode = node.LastChildMatching("ReferencePoint"); + if (positionNode != null) + { + if (!PositionMap.TryGetValue(positionNode.NodeValue(), out var value)) + value = "TopLeft"; + + if (value != "TopLeft") + { + positionNode.RenameKey("Position"); + positionNode.ReplaceValue(FieldSaver.FormatValue(value)); + } + else + node.RemoveNode(positionNode); + } + + locations.GetOrAdd(locationKey).Add(node.Key); + } + } + + foreach (var trait in ModernDecorationTraits) + foreach (var node in actorNode.ChildrenMatching(trait)) + locations.GetOrAdd(locationKey).Add(node.Key); + + foreach (var selection in actorNode.ChildrenMatching("SelectionDecorations")) + { + selection.RemoveNodes("RenderSelectionBars"); + selection.RemoveNodes("RenderSelectionBox"); + } + + foreach (var nameTag in actorNode.ChildrenMatching("RenderNameTag")) + { + nameTag.RenameKey("WithNameTagDecoration"); + nameTag.AddNode("Position", "Top"); + nameTag.AddNode("UsePlayerColor", "true"); + locations.GetOrAdd(locationKey).Add(nameTag.Key); + } + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/MoveClassicFacingFudge.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/MoveClassicFacingFudge.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/MoveClassicFacingFudge.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/MoveClassicFacingFudge.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,79 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class MoveClassicFacingFudge : UpdateRule + { + public override string Name { get { return "UseClassicFacingFudge functionality was moved to Cnc-specific sequence/coordinate code."; } } + public override string Description + { + get + { + return "UseClassicFacingFudge has been replaced with ClassicFacingBodyOrientation trait\n" + + "and Classic* variants of *Sequence loaders respectively, both located in Mods.Cnc."; + } + } + + readonly List locations = new List(); + + public override IEnumerable AfterUpdate(ModData modData) + { + if (locations.Any()) + yield return "UseClassicFacingFudge property on BodyOrientation was replaced with ClassicFacingBodyOrientation trait.\n" + + "UseClassicFacingFudge for sequences was renamed to UseClassicFacings and moved to\n" + + "Classic(TileSetSpecific)SpriteSequence loaders in Mods.Cnc.\n" + + "Update SpriteSequenceFormat: in mod.yaml accordingly.\n" + + "Make sure that actors implementing the following places don't use or inherit the standard BodyOrientation:\n" + + UpdateUtils.FormatMessageList(locations); + + locations.Clear(); + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + var modId = modData.Manifest.Id; + + foreach (var bo in actorNode.ChildrenMatching("BodyOrientation")) + { + var usesClassicFacings = false; + var facingFudgeNode = bo.LastChildMatching("UseClassicFacingFudge"); + if (facingFudgeNode != null) + { + usesClassicFacings = facingFudgeNode.NodeValue(); + bo.RemoveNode(facingFudgeNode); + } + + if (usesClassicFacings) + { + bo.RenameKey("ClassicFacingBodyOrientation"); + locations.Add("{0} ({1})".F(actorNode.Key, actorNode.Location.Filename)); + } + } + + yield break; + } + + public override IEnumerable UpdateSequenceNode(ModData modData, MiniYamlNode sequenceNode) + { + foreach (var sequence in sequenceNode.Value.Nodes) + { + var facingFudgeNode = sequence.LastChildMatching("UseClassicFacingFudge"); + facingFudgeNode?.RenameKey("UseClassicFacings"); + } + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveConditionManager.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveConditionManager.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveConditionManager.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveConditionManager.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,34 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RemoveConditionManager : UpdateRule + { + public override string Name { get { return "ConditionManager trait has been removed."; } } + + public override string Description + { + get + { + return "ConditionManager trait has been removed. Its functionality has been integrated into the actor itself."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + actorNode.RemoveNodes("ConditionManager"); + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveLaysTerrain.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveLaysTerrain.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveLaysTerrain.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveLaysTerrain.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,35 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RemoveLaysTerrain : UpdateRule + { + public override string Name { get { return "'LaysTerrain' has been removed in favor of the new 'D2kBuilding' trait."; } } + public override string Description + { + get + { + return "'LaysTerrain' was removed."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + if (actorNode.RemoveNodes("LaysTerrain") > 0) + yield return "'LaysTerrain' was removed from {0} ({1}) without replacement.\n".F(actorNode.Key, actorNode.Location.Filename); + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveMuzzleSplitFacings.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveMuzzleSplitFacings.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveMuzzleSplitFacings.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RemoveMuzzleSplitFacings.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,51 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RemoveMuzzleSplitFacings : UpdateRule + { + public override string Name { get { return "Remove Armament.MuzzleSplitFacings."; } } + public override string Description + { + get + { + return "The legacy MuzzleSplitFacings option was removed from Armament.\n" + + "The same result can be created by using `Combine` in the sequence definitions to\n" + + "assemble the different facings sprites into a single sequence."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var a in actorNode.ChildrenMatching("Armament")) + { + var muzzleSplitFacings = a.LastChildMatching("MuzzleSplitFacings"); + var sequenceNode = a.LastChildMatching("MuzzleSequence"); + if (muzzleSplitFacings != null && sequenceNode != null) + { + var sequence = sequenceNode.Value.Value; + var facings = muzzleSplitFacings.NodeValue() - 1; + var actor = actorNode.Key.ToLowerInvariant(); + yield return "The Armament muzzle effect has been removed from {0} ({1}).\n".F(actor, actorNode.Location.Filename) + + "If you would like to restore the muzzle effect you must redefine `MuzzleSequence: {0}`\n".F(sequence) + + "and replace the {0}0-{1} sequence definitions with a single `{0}` sequence that uses\n".F(sequence, facings) + + "the Combine syntax to assemble the different facing sprites."; + + a.RemoveNode(muzzleSplitFacings); + a.RemoveNode(sequenceNode); + } + } + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameCircleOutline.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameCircleOutline.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameCircleOutline.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameCircleOutline.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,38 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RenameCircleContrast : UpdateRule + { + public override string Name { get { return "Rename 'ContrastColor' to 'BorderColor'."; } } + public override string Description + { + get + { + return "RenderDetectionCircle and RenderShroudCircle ContrastColor have been renamed to BorderColor for consistency."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var rdc in actorNode.ChildrenMatching("RenderDetectionCircle")) + rdc.RenameChildrenMatching("ContrastColor", "BorderColor"); + + foreach (var rsc in actorNode.ChildrenMatching("RenderShroudCircle")) + rsc.RenameChildrenMatching("ContrastColor", "BorderColor"); + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameHealCrateAction.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameHealCrateAction.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameHealCrateAction.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameHealCrateAction.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,35 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RenameHealCrateAction : UpdateRule + { + public override string Name { get { return "Rename 'HealUnitsCrateAction' to 'HealActorsCrateAction'."; } } + public override string Description + { + get + { + return "The 'HealUnitsCrateAction' has been renamed to 'HealActorsCrateAction'."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var huca in actorNode.ChildrenMatching("HealUnitsCrateAction")) + huca.RenameKey("HealActorsCrateAction"); + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameInfiltrationNotifications.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameInfiltrationNotifications.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameInfiltrationNotifications.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameInfiltrationNotifications.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,35 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + class RenameInfiltrationNotifications : UpdateRule + { + public override string Name { get { return "Renamed InfiltrateForCash Notification to InfiltratedNotification."; } } + public override string Description + { + get + { + return "The InfiltrateForCash Notification has been renamed to be in line with new notification properties added."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var rp in actorNode.ChildrenMatching("InfiltrateForCash")) + rp.RenameChildrenMatching("Notification", "InfiltratedNotification"); + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameSelfHealing.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameSelfHealing.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameSelfHealing.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameSelfHealing.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,42 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RenameSelfHealing : UpdateRule + { + public override string Name { get { return "SelfHealing was renamed as negative SelfHealing is a common usecase."; } } + public override string Description + { + get + { + return "SelfHealing was renamed to ChangesHealth\n" + + "HealIfBelow was renamed to StartIfBelow."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + var modId = modData.Manifest.Id; + + foreach (var sh in actorNode.ChildrenMatching("SelfHealing")) + { + sh.RenameChildrenMatching("HealIfBelow", "StartIfBelow"); + sh.RenameKey("ChangesHealth"); + } + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameStances.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameStances.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameStances.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameStances.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,104 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RenameStances : UpdateRule + { + public override string Name { get { return "Renamed player 'Stances' to 'Relationships'."; } } + public override string Description + { + get + { + return "'Stances' in regards to a player have been renamed to 'Relationships'.\n" + + "The yaml values did not change."; + } + } + + readonly (string TraitName, string OldName, string NewName)[] traits = + { + ("Disguise", "ValidStances", "ValidRelationships"), + ("Infiltrates", "ValidStances", "ValidRelationships"), + ("AcceptsDeliveredCash", "ValidStances", "ValidRelationships"), + ("AcceptsDeliveredExperience", "ValidStances", "ValidRelationships"), + ("Armament", "TargetStances", "TargetRelationships"), + ("Armament", "ForceTargetStances", "ForceTargetRelationships"), + ("AutoTargetPriority", "ValidStances", "ValidRelationships"), + ("CaptureManagerBotModule", "CapturableStances", "CapturableRelationships"), + ("Capturable", "ValidStances", "ValidRelationships"), + ("Captures", "PlayerExperienceStances", "PlayerExperienceRelationships"), + ("ProximityExternalCondition", "ValidStances", "ValidRelationships"), + ("CreatesShroud", "ValidStances", "ValidRelationships"), + ("Demolition", "TargetStances", "TargetRelationships"), + ("Demolition", "ForceTargetStances", "ForceTargetRelationships"), + ("EngineerRepair", "ValidStances", "ValidRelationships"), + ("GivesBounty", "ValidStances", "ValidRelationships"), + ("GivesExperience", "ValidStances", "ValidRelationships"), + ("JamsMissiles", "DeflectionStances", "DeflectionRelationships"), + ("FrozenUnderFog", "AlwaysVisibleStances", "AlwaysVisibleRelationships"), + ("HiddenUnderShroud", "AlwaysVisibleStances", "AlwaysVisibleRelationships"), + ("HiddenUnderFog", "AlwaysVisibleStances", "AlwaysVisibleRelationships"), + ("AppearsOnRadar", "ValidStances", "ValidRelationships"), + ("CashTricklerBar", "DisplayStances", "DisplayRelationships"), + ("SupportPowerChargeBar", "DisplayStances", "DisplayRelationships"), + ("WithAmmoPipsDecoration", "ValidStances", "ValidRelationships"), + ("WithCargoPipsDecoration", "ValidStances", "ValidRelationships"), + ("WithDecoration", "ValidStances", "ValidRelationships"), + ("WithHarvesterPipsDecoration", "ValidStances", "ValidRelationships"), + ("WithNameTagDecoration", "ValidStances", "ValidRelationships"), + ("WithResourceStoragePipsDecoration", "ValidStances", "ValidRelationships"), + ("WithTextDecoration", "ValidStances", "ValidRelationships"), + ("WithRangeCircle", "ValidStances", "ValidRelationships"), + ("RevealOnDeath", "RevealForStances", "RevealForRelationships"), + ("RevealOnFire", "RevealForStancesRelativeToTarget", "RevealForRelationships"), + ("RevealsMap", "ValidStances", "ValidRelationships"), + ("RevealsShroud", "ValidStances", "ValidRelationships"), + ("VoiceAnnouncement", "ValidStances", "ValidRelationships"), + ("GrantExternalConditionPower", "ValidStances", "ValidRelationships"), + ("NukePower", "CameraStances", "CameraRelationships"), + ("NukePower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("AttackOrderPower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("ChronoshiftPower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("DropPodsPower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("GpsPower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("GrantPrerequisiteChargeDrainPower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("IonCannonPower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("AirstrikePower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("GrantExternalConditionPower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("ParatroopersPower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("ProduceActorPower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("SpawnActorPower", "DisplayTimerStances", "DisplayTimerRelationships"), + ("TooltipDescription", "ValidStances", "ValidRelationships") + }; + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var field in traits) + foreach (var traitNode in actorNode.ChildrenMatching(field.TraitName)) + traitNode.RenameChildrenMatching(field.OldName, field.NewName); + + yield break; + } + + public override IEnumerable UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode) + { + foreach (var projectileNode in weaponNode.ChildrenMatching("Projectile")) + projectileNode.RenameChildrenMatching("ValidBounceBlockerStances", "ValidBounceBlockerRelationships"); + + foreach (var warheadNode in weaponNode.ChildrenMatching("Warhead")) + warheadNode.RenameChildrenMatching("ValidStances", "ValidRelationships"); + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameWithNukeLaunch.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameWithNukeLaunch.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameWithNukeLaunch.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/RenameWithNukeLaunch.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,35 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + class RenameWithNukeLaunch : UpdateRule + { + public override string Name { get { return "Renamed WithNukeLaunchAnimation and Overlay"; } } + public override string Description + { + get + { + return "`WithNukeLaunchAnimation` has been renamed to `WithSupportPowerActivationAnimation` and `WithNukeLaunchOverlay` to `WithSupportPowerActivationOverlay`."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + actorNode.RenameChildrenMatching("WithNukeLaunchAnimation", "WithSupportPowerActivationAnimation", true); + actorNode.RenameChildrenMatching("WithNukeLaunchOverlay", "WithSupportPowerActivationOverlay", true); + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ReplaceBurns.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ReplaceBurns.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ReplaceBurns.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ReplaceBurns.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,63 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class ReplaceBurns : UpdateRule + { + public override string Name { get { return "Replaced Burns with separate render and health change traits."; } } + public override string Description + { + get + { + return "Burns can be replaced using WithIdleOverlay and ChangesHealth."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + var addNodes = new List(); + + foreach (var burns in actorNode.ChildrenMatching("Burns")) + { + var anim = burns.LastChildMatching("Anim"); + var animValue = anim != null ? anim.NodeValue() : "1"; + + var damage = burns.LastChildMatching("Damage"); + var damageValue = damage != null ? damage.NodeValue() : 1; + + var interval = burns.LastChildMatching("Interval"); + var intervalValue = interval != null ? interval.NodeValue() : 8; + + var overlay = new MiniYamlNode("WithIdleOverlay@Burns", ""); + overlay.AddNode("Image", FieldSaver.FormatValue("fire")); + overlay.AddNode("Sequence", FieldSaver.FormatValue(animValue)); + overlay.AddNode("IsDecoration", FieldSaver.FormatValue(true)); + addNodes.Add(overlay); + + var changesHealth = new MiniYamlNode("ChangesHealth", ""); + changesHealth.AddNode("Step", FieldSaver.FormatValue(-damageValue)); + changesHealth.AddNode("StartIfBelow", FieldSaver.FormatValue(101)); + changesHealth.AddNode("Delay", FieldSaver.FormatValue(intervalValue)); + addNodes.Add(changesHealth); + } + + actorNode.RemoveNodes("Burns"); + + foreach (var addNode in addNodes) + actorNode.AddNode(addNode); + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ReplaceFacingAngles.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ReplaceFacingAngles.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ReplaceFacingAngles.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/ReplaceFacingAngles.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,115 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + class ReplaceFacingAngles : UpdateRule + { + static readonly Dictionary TraitFields = new Dictionary() + { + { "Aircraft", new[] { "InitialFacing", "PreviewFacing", "TurnSpeed", "IdleTurnSpeed" } }, + { "Mobile", new[] { "InitialFacing", "PreviewFacing", "TurnSpeed" } }, + { "Husk", new[] { "PreviewFacing" } }, + { "Turreted", new[] { "InitialFacing", "TurnSpeed" } }, + { "GrantConditionOnDeploy", new[] { "Facing" } }, + { "FreeActor", new[] { "Facing" } }, + { "ProductionAirdrop", new[] { "Facing" } }, + { "EditorCursorLayer", new[] { "PreviewFacing" } }, + { "MPStartUnits", new[] { "BaseActorFacing", "SupportActorsFacing" } }, + { "Refinery", new[] { "DockAngle" } }, + { "Cargo", new[] { "PassengerFacing" } }, + { "Exit", new[] { "Facing" } }, + { "ThrowsParticle", new[] { "TurnSpeed" } }, + { "Transforms", new[] { "Facing" } }, + { "FallsToEarth", new[] { "MaximumSpinSpeed" } }, + { "ConyardChronoReturn", new[] { "Facing" } }, + { "TDGunboat", new[] { "InitialFacing", "PreviewFacing" } }, + { "DropPodsPower", new[] { "PodFacing" } }, + { "TiberianSunRefinery", new[] { "DockAngle" } }, + { "AttackAircraft", new[] { "FacingTolerance" } }, + { "AttackBomber", new[] { "FacingTolerance" } }, + { "AttackCharges", new[] { "FacingTolerance" } }, + { "AttackFollow", new[] { "FacingTolerance" } }, + { "AttackFrontal", new[] { "FacingTolerance" } }, + { "AttackGarrisoned", new[] { "FacingTolerance" } }, + { "AttackOmni", new[] { "FacingTolerance" } }, + { "AttackTurreted", new[] { "FacingTolerance" } }, + { "AttackLeap", new[] { "FacingTolerance" } }, + { "AttackPopupTurreted", new[] { "DefaultFacing", "FacingTolerance" } }, + { "AttackTDGunboatTurreted", new[] { "FacingTolerance" } }, + { "AttackTesla", new[] { "FacingTolerance" } }, + }; + + static readonly Dictionary ProjectileFields = new Dictionary() + { + { "Missile", new[] { "HorizontalRateOfTurn", "VerticalRateOfTurn" } } + }; + + public override string Name { get { return "Increase facing angle resolution"; } } + public override string Description + { + get + { + return "Trait fields that defined facings (0-255) have been replaced with higher resolution angles (0-1023).\n" + + "Values for the following trait fields should be multiplied by 4, or if undefined (-1) replaced by an empty definition:\n" + + UpdateUtils.FormatMessageList(TraitFields.Select(t => t.Key + "\n" + UpdateUtils.FormatMessageList(t.Value))) + "\n" + + "Values for the following projectile files should be multiplied by 4:\n" + + UpdateUtils.FormatMessageList(ProjectileFields.Select(t => t.Key + "\n" + UpdateUtils.FormatMessageList(t.Value))); + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var kv in TraitFields) + { + foreach (var traitNode in actorNode.ChildrenMatching(kv.Key)) + { + foreach (var fieldName in kv.Value) + { + foreach (var fieldNode in traitNode.ChildrenMatching(fieldName)) + { + var value = fieldNode.NodeValue(); + fieldNode.Value.Value = value != -1 ? FieldSaver.FormatValue(value != 255 ? 4 * value : 1023) : ""; + } + } + } + } + + yield break; + } + + public override IEnumerable UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode) + { + foreach (var projectileNode in weaponNode.ChildrenMatching("Projectile")) + { + if (projectileNode.Value.Value == null) + continue; + + if (ProjectileFields.TryGetValue(projectileNode.Value.Value, out var fieldNames)) + { + foreach (var fieldName in fieldNames) + { + foreach (var fieldNode in projectileNode.ChildrenMatching(fieldName)) + { + var value = fieldNode.NodeValue(); + fieldNode.Value.Value = FieldSaver.FormatValue(value != 255 ? 4 * value : 1023); + } + } + } + } + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/SpawnActorPowerDefaultEffect.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/SpawnActorPowerDefaultEffect.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/SpawnActorPowerDefaultEffect.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/SpawnActorPowerDefaultEffect.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,39 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + class SpawnActorPowerDefaultEffect : UpdateRule + { + public override string Name { get { return "Set SpawnActorPower EffectSequence to it's previous default value."; } } + public override string Description + { + get + { + return "The 'EffectSequence' of 'SpawnActorPower' is unset by default."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var spawnActorPower in actorNode.ChildrenMatching("SpawnActorPower")) + { + var effectNode = spawnActorPower.LastChildMatching("EffectSequence"); + if (effectNode == null) + spawnActorPower.AddNode("EffectSequence", "idle"); + } + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/SplitDamagedByTerrain.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/SplitDamagedByTerrain.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/SplitDamagedByTerrain.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/SplitDamagedByTerrain.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,40 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class SplitDamagedByTerrain : UpdateRule + { + public override string Name { get { return "Several properties of 'DamagedByTerrain' have been moved to the new 'D2kBuilding' trait."; } } + public override string Description + { + get + { + return "'DamageThreshold' and 'StartOnThreshold' are no longer supported and removed from 'DamagedByTerrain'."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var damaged in actorNode.ChildrenMatching("DamagedByTerrain", includeRemovals: false)) + { + if (damaged.RemoveNodes("DamageThreshold") > 0) + yield return "'DamageThreshold' was removed from {0} ({1}) without replacement.\n".F(actorNode.Key, actorNode.Location.Filename); + if (damaged.RemoveNodes("StartOnThreshold") > 0) + yield return "'StartOnThreshold' was removed from {0} ({1}) without replacement.\n".F(actorNode.Key, actorNode.Location.Filename); + } + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/UpdateMapInits.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/UpdateMapInits.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/UpdateMapInits.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/UpdateMapInits.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,72 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + class UpdateMapInits : UpdateRule + { + public override string Name { get { return "Update map actor definitions"; } } + public override string Description + { + get + { + return "Several changes have been made to initial actor state in maps:\n" + + UpdateUtils.FormatMessageList(new[] + { + "Facing is now defined as a world angle", + "TurretFacing is now defined as a world angle relative to Facing", + "Plugs has been removed (use Plug instead)", + "TurretFacings has been removed (use TurretFacing instead)" + }) + + "\nMaps are automatically updated to keep the previous actor facings."; + } + } + + public override IEnumerable UpdateMapActorNode(ModData modData, MiniYamlNode actorNode) + { + if (actorNode.RemoveNodes("Plugs") > 0) + yield return "Initial plugs for actor {0} will need to be reconfigured using the map editor.".F(actorNode.Key); + + if (actorNode.RemoveNodes("TurretFacings") > 0) + yield return "Initial turret facings for actor {0} will need to be reconfigured using the map editor.".F(actorNode.Key); + + var bodyFacing = WAngle.Zero; + foreach (var facing in actorNode.ChildrenMatching("Facing")) + { + bodyFacing = WAngle.FromFacing(facing.NodeValue()); + facing.ReplaceValue(FieldSaver.FormatValue(bodyFacing)); + } + + var removeNodes = new List(); + foreach (var facing in actorNode.ChildrenMatching("TurretFacing")) + { + var turretFacing = WAngle.FromFacing(facing.NodeValue()) - bodyFacing; + if (turretFacing == WAngle.Zero) + removeNodes.Add(facing); + else + facing.ReplaceValue(FieldSaver.FormatValue(turretFacing)); + } + + foreach (var node in removeNodes) + actorNode.Value.Nodes.Remove(node); + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var turret in actorNode.ChildrenMatching("Turreted")) + turret.RemoveNodes("PreviewFacing"); + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/UpdateTilesetColors.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/UpdateTilesetColors.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/20200503/UpdateTilesetColors.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/20200503/UpdateTilesetColors.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,49 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + class UpdateTilesetColors : UpdateRule + { + public override string Name { get { return "Rename Tileset LeftColor and RightColor"; } } + public override string Description + { + get + { + return "The LeftColor and RightColor keys in tilesets have been renamed to MinColor and MaxColor to reflect their proper usage."; + } + } + + public override IEnumerable UpdateTilesetNode(ModData modData, MiniYamlNode tilesetNode) + { + if (tilesetNode.Key == "Templates") + { + foreach (var templateNode in tilesetNode.Value.Nodes) + { + foreach (var tilesNode in templateNode.ChildrenMatching("Tiles")) + { + foreach (var node in tilesNode.Value.Nodes) + { + foreach (var leftNode in node.ChildrenMatching("LeftColor")) + leftNode.RenameKey("MinColor"); + foreach (var leftNode in node.ChildrenMatching("RightColor")) + leftNode.RenameKey("MaxColor"); + } + } + } + } + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/CopyIsometricSelectableHeight.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/CopyIsometricSelectableHeight.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/CopyIsometricSelectableHeight.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/CopyIsometricSelectableHeight.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,84 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.IO; +using OpenRA.Mods.Common.FileFormats; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class CopyIsometricSelectableHeight : UpdateRule + { + public override string Name { get { return "Copy IsometricSelectable.Height from art*.ini definitions."; } } + public override string Description + { + get + { + return "Reads building Height entries art.ini/artfs.ini/artmd.ini from the current working directory\n" + + "and adds IsometricSelectable definitions to matching actors."; + } + } + + static readonly string[] SourceFiles = { "art.ini", "artfs.ini", "artmd.ini" }; + + readonly Dictionary selectionHeight = new Dictionary(); + + bool complete; + + public override IEnumerable BeforeUpdate(ModData modData) + { + if (complete) + yield break; + + var grid = Game.ModData.Manifest.Get(); + foreach (var filename in SourceFiles) + { + if (!File.Exists(filename)) + continue; + + var file = new IniFile(File.Open(filename, FileMode.Open)); + foreach (var section in file.Sections) + { + if (!section.Contains("Height")) + continue; + + selectionHeight[section.Name] = (int)(float.Parse(section.GetValue("Height", "1")) * grid.TileSize.Height); + } + } + } + + public override IEnumerable AfterUpdate(ModData modData) + { + // Rule only applies to the default ruleset - skip maps + complete = true; + yield break; + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + if (complete || actorNode.LastChildMatching("IsometricSelectable") != null) + yield break; + + var height = 0; + if (!selectionHeight.TryGetValue(actorNode.Key.ToLowerInvariant(), out height)) + yield break; + + // Don't redefine the default value + if (height == 24) + yield break; + + var selection = new MiniYamlNode("IsometricSelectable", ""); + selection.AddNode("Height", FieldSaver.FormatValue(height)); + + actorNode.AddNode(selection); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/RemoveTurnToDock.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/RemoveTurnToDock.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/RemoveTurnToDock.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/RemoveTurnToDock.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,61 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RemoveTurnToDock : UpdateRule + { + public override string Name { get { return "TurnToDock is removed from the Aircraft trait."; } } + public override string Description + { + get + { + return "TurnToDock is removed from the Aircraft trait in favor of letting the Exit trait on the host" + + "building determine whether or not turning is required and to what facing the aircraft must turn."; + } + } + + readonly List> turningAircraft = new List>(); + + public override IEnumerable AfterUpdate(ModData modData) + { + var message = "TurnToDock is now deprecated. The following actors had TurnToDock enabled:\n" + + UpdateUtils.FormatMessageList(turningAircraft.Select(n => n.Item1 + " (" + n.Item2 + ")")) + + "\n If you wish these units to keep their turning behaviour when docking with a host building" + + "you will need to define a 'Facing' parameter on the 'Exit' trait of the host building. This change" + + "does not affect the behaviour for landing on terrain which is governed by TurnToLand."; + + if (turningAircraft.Any()) + yield return message; + + turningAircraft.Clear(); + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + var aircraft = actorNode.LastChildMatching("Aircraft"); + if (aircraft != null) + { + var turnToDock = aircraft.LastChildMatching("TurnToDock"); + if (turnToDock != null || turnToDock.NodeValue()) + yield break; + + turningAircraft.Add(Tuple.Create(actorNode.Key, actorNode.Location.Filename)); + } + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/RenameSmudgeSmokeFields.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/RenameSmudgeSmokeFields.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/Rules/RenameSmudgeSmokeFields.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/Rules/RenameSmudgeSmokeFields.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,54 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RenameSmudgeSmokeFields : UpdateRule + { + public override string Name { get { return "Renamed smoke-related properties on SmudgeLayer."; } } + public override string Description + { + get + { + return "Renamed smoke-related properties on SmudgeLayer to be in line with comparable properties.\n" + + "Additionally, set the *Chance, *Image and *Sequences defaults to null."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var layer in actorNode.ChildrenMatching("SmudgeLayer")) + { + var chance = layer.LastChildMatching("SmokePercentage"); + if (chance != null) + chance.RenameKey("SmokeChance"); + else + layer.AddNode("SmokeChance", FieldSaver.FormatValue("25")); + + var image = layer.LastChildMatching("SmokeType"); + if (image != null) + image.RenameKey("SmokeImage"); + else + layer.AddNode("SmokeImage", FieldSaver.FormatValue("smoke_m")); + + var sequences = layer.LastChildMatching("SmokeSequence"); + if (sequences != null) + sequences.RenameKey("SmokeSequences"); + else + layer.AddNode("SmokeSequences", FieldSaver.FormatValue("idle")); + } + + yield break; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs 2021-03-21 11:10:05.000000000 +0000 @@ -34,36 +34,13 @@ Justification = "Extracting update lists to temporary variables obfuscates the definitions.")] static readonly UpdatePath[] Paths = { - new UpdatePath("release-20190314", "release-20191117", new UpdateRule[] - { - new MultipleDeploySounds(), - new RemoveSimpleBeacon(), - new MakeMobilePausableConditional(), - new StreamlineRepairableTraits(), - new ReplaceSpecialMoveConsiderations(), - new RefactorHarvesterIdle(), - new SplitHarvesterSpriteBody(), - new RenameAttackMoveConditions(), - new RemovePlaceBuildingPalettes(), - new RenameHoversOffsetModifier(), - new AddAirAttackTypes(), - new MoveAbortOnResupply(), - new RenameCarryallDelays(), - new AddCanSlide(), - new AddAircraftIdleBehavior(), - new RenameSearchRadius(), - new RenameChronoshiftFootprint(), - new RemoveMoveIntoWorldFromExit(), - }), - new UpdatePath("release-20191117", "release-20200202", new UpdateRule[] { new ReplaceAttackTypeStrafe() }), - new UpdatePath("release-20200202", new UpdateRule[] + new UpdatePath("release-20200202", "release-20200503", new UpdateRule[] { - // Bleed only changes here new RemoveYesNo(), new RemoveInitialFacingHardcoding(), new RemoveAirdropActorTypeDefault(), @@ -74,6 +51,34 @@ new RenameSpins(), new CreateScreenShakeWarhead(), new RenameRallyPointPath(), + }), + + new UpdatePath("release-20200503", new UpdateRule[] + { + // Bleed only changes here + new AddPipDecorationTraits(), + new ModernizeDecorationTraits(), + new RenameHealCrateAction(), + new RenameInfiltrationNotifications(), + new MoveClassicFacingFudge(), + new RenameWithNukeLaunch(), + new SpawnActorPowerDefaultEffect(), + new RemoveConditionManager(), + new ConvertSupportPowerRangesToFootprint(), + new UpdateTilesetColors(), + new UpdateMapInits(), + new CreateFlashPaletteEffectWarhead(), + new ChangeTargetLineDelayToMilliseconds(), + new ReplaceFacingAngles(), + new RenameSelfHealing(), + new ReplaceBurns(), + new RemoveMuzzleSplitFacings(), + new RenameStances(), + new RemoveTurnToDock(), + new RenameSmudgeSmokeFields(), + new RenameCircleContrast(), + new SplitDamagedByTerrain(), + new RemoveLaysTerrain(), }) }; diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/UpdateRule.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/UpdateRule.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/UpdateRule.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/UpdateRule.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,9 +28,11 @@ public virtual IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) { yield break; } public virtual IEnumerable UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode) { yield break; } + public virtual IEnumerable UpdateSequenceNode(ModData modData, MiniYamlNode sequenceNode) { yield break; } public virtual IEnumerable UpdateChromeNode(ModData modData, MiniYamlNode chromeNode) { yield break; } public virtual IEnumerable UpdateTilesetNode(ModData modData, MiniYamlNode tilesetNode) { yield break; } public virtual IEnumerable UpdateChromeProviderNode(ModData modData, MiniYamlNode chromeProviderNode) { yield break; } + public virtual IEnumerable UpdateMapActorNode(ModData modData, MiniYamlNode actorNode) { yield break; } public virtual IEnumerable BeforeUpdate(ModData modData) { yield break; } public virtual IEnumerable AfterUpdate(ModData modData) { yield break; } diff -Nru openra-20200503/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs openra-20210321/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs --- openra-20200503/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.UpdateRules { - using YamlFileSet = List>>; + using YamlFileSet = List<(IReadWritePackage, string, List)>; public static class UpdateUtils { @@ -29,15 +29,13 @@ var yaml = new YamlFileSet(); foreach (var filename in files) { - string name; - IReadOnlyPackage package; - if (!modData.ModFiles.TryGetPackageContaining(filename, out package, out name) || !(package is IReadWritePackage)) + if (!modData.ModFiles.TryGetPackageContaining(filename, out var package, out var name) || !(package is IReadWritePackage)) { Console.WriteLine("Failed to load file `{0}` for writing. It will not be updated.", filename); continue; } - yaml.Add(Tuple.Create((IReadWritePackage)package, name, MiniYaml.FromStream(package.GetStream(name), name, false))); + yaml.Add(((IReadWritePackage)package, name, MiniYaml.FromStream(package.GetStream(name), name, false))); } return yaml; @@ -62,7 +60,7 @@ { var fileSet = new YamlFileSet() { - Tuple.Create>(null, "map.yaml", yaml.Nodes) + (null, "map.yaml", yaml.Nodes) }; var files = FieldLoader.GetValue("value", yaml.Value); @@ -70,7 +68,7 @@ { // Ignore any files that aren't in the map bundle if (!filename.Contains("|") && mapPackage.Contains(filename)) - fileSet.Add(Tuple.Create(mapPackage, filename, MiniYaml.FromStream(mapPackage.GetStream(filename), filename, false))); + fileSet.Add((mapPackage, filename, MiniYaml.FromStream(mapPackage.GetStream(filename), filename, false))); else if (modData.ModFiles.Exists(filename)) externalFilenames.Add(filename); } @@ -97,10 +95,22 @@ } var yaml = new MiniYaml(null, MiniYaml.FromStream(mapStream, mapPackage.Name, false)); - files = new YamlFileSet() { Tuple.Create(mapPackage, "map.yaml", yaml.Nodes) }; + files = new YamlFileSet() { (mapPackage, "map.yaml", yaml.Nodes) }; manualSteps.AddRange(rule.BeforeUpdate(modData)); + var mapActorsNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Actors"); + if (mapActorsNode != null) + { + var mapActors = new YamlFileSet() + { + (null, "map.yaml", mapActorsNode.Value.Nodes) + }; + + manualSteps.AddRange(ApplyTopLevelTransform(modData, mapActors, rule.UpdateMapActorNode)); + files.AddRange(mapActors); + } + var mapRulesNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Rules"); if (mapRulesNode != null) { @@ -117,6 +127,14 @@ files.AddRange(mapWeapons); } + var mapSequencesNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Sequences"); + if (mapSequencesNode != null) + { + var mapSequences = LoadInternalMapYaml(modData, mapPackage, mapSequencesNode.Value, externalFilenames); + manualSteps.AddRange(ApplyTopLevelTransform(modData, mapSequences, rule.UpdateWeaponNode)); + files.AddRange(mapSequences); + } + manualSteps.AddRange(rule.AfterUpdate(modData)); } @@ -143,6 +161,7 @@ var modRules = LoadModYaml(modData, FilterExternalModFiles(modData, modData.Manifest.Rules, externalFilenames)); var modWeapons = LoadModYaml(modData, FilterExternalModFiles(modData, modData.Manifest.Weapons, externalFilenames)); + var modSequences = LoadModYaml(modData, FilterExternalModFiles(modData, modData.Manifest.Sequences, externalFilenames)); var modTilesets = LoadModYaml(modData, FilterExternalModFiles(modData, modData.Manifest.TileSets, externalFilenames)); var modChromeLayout = LoadModYaml(modData, FilterExternalModFiles(modData, modData.Manifest.ChromeLayout, externalFilenames)); var modChromeProvider = LoadModYaml(modData, FilterExternalModFiles(modData, modData.Manifest.Chrome, externalFilenames)); @@ -167,12 +186,19 @@ foreach (var f in LoadExternalMapYaml(modData, mapWeaponsNode.Value, externalFilenames)) if (!modWeapons.Any(m => m.Item1 == f.Item1 && m.Item2 == f.Item2)) modWeapons.Add(f); + + var mapSequencesNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Sequences"); + if (mapSequencesNode != null) + foreach (var f in LoadExternalMapYaml(modData, mapSequencesNode.Value, externalFilenames)) + if (!modSequences.Any(m => m.Item1 == f.Item1 && m.Item2 == f.Item2)) + modSequences.Add(f); } } manualSteps.AddRange(rule.BeforeUpdate(modData)); manualSteps.AddRange(ApplyTopLevelTransform(modData, modRules, rule.UpdateActorNode)); manualSteps.AddRange(ApplyTopLevelTransform(modData, modWeapons, rule.UpdateWeaponNode)); + manualSteps.AddRange(ApplyTopLevelTransform(modData, modSequences, rule.UpdateSequenceNode)); manualSteps.AddRange(ApplyTopLevelTransform(modData, modTilesets, rule.UpdateTilesetNode)); manualSteps.AddRange(ApplyChromeTransform(modData, modChromeLayout, rule.UpdateChromeNode)); manualSteps.AddRange(ApplyTopLevelTransform(modData, modChromeProvider, rule.UpdateChromeProviderNode)); @@ -180,6 +206,7 @@ files = modRules.ToList(); files.AddRange(modWeapons); + files.AddRange(modSequences); files.AddRange(modTilesets); files.AddRange(modChromeLayout); files.AddRange(modChromeProvider); @@ -236,8 +263,7 @@ public static void Save(this YamlFileSet files) { foreach (var file in files) - if (file.Item1 != null) - file.Item1.Update(file.Item2, Encoding.UTF8.GetBytes(file.Item3.WriteToString())); + file.Item1?.Update(file.Item2, Encoding.UTF8.GetBytes(file.Item3.WriteToString())); } /// Checks if node is a removal (has '-' prefix) diff -Nru openra-20200503/OpenRA.Mods.Common/Util.cs openra-20210321/OpenRA.Mods.Common/Util.cs --- openra-20200503/OpenRA.Mods.Common/Util.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Util.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,9 +11,9 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using OpenRA.GameRules; -using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; using OpenRA.Support; @@ -21,6 +21,8 @@ namespace OpenRA.Mods.Common { + public enum InaccuracyType { Maximum, PerCellIncrement, Absolute } + public static class Util { public static int TickFacing(int facing, int desiredFacing, int rot) @@ -35,46 +37,45 @@ return (facing - rot) & 0xFF; } - public static int GetNearestFacing(int facing, int desiredFacing) - { - var turn = desiredFacing - facing; - if (turn > 128) - turn -= 256; - if (turn < -128) - turn += 256; - - return facing + turn; - } - - public static int QuantizeFacing(int facing, int numFrames) + /// + /// Adds step angle units to facing in the direction that takes it closer to desiredFacing. + /// If facing is already within step of desiredFacing then desiredFacing is returned. + /// Step is given as an integer to allow negative values (step away from the desired facing) + /// + public static WAngle TickFacing(WAngle facing, WAngle desiredFacing, WAngle step) + { + var leftTurn = (facing - desiredFacing).Angle; + var rightTurn = (desiredFacing - facing).Angle; + if (leftTurn < step.Angle || rightTurn < step.Angle) + return desiredFacing; + + return rightTurn < leftTurn ? facing + step : facing - step; + } + + /// + /// Determines whether desiredFacing is clockwise (-1) or anticlockwise (+1) of facing. + /// If desiredFacing is equal to facing or directly behind facing we treat it as being anticlockwise + /// + public static int GetTurnDirection(WAngle facing, WAngle desiredFacing) + { + return (facing - desiredFacing).Angle < 512 ? -1 : 1; + } + + /// + /// Calculate the frame index (between 0..numFrames) that + /// should be used for the given facing value. + /// + public static int IndexFacing(WAngle facing, int numFrames) { - var step = 256 / numFrames; - var a = (facing + step / 2) & 0xff; + var step = 1024 / numFrames; + var a = (facing.Angle + step / 2) & 1023; return a / step; } - public static int QuantizeFacing(int facing, int numFrames, bool useClassicFacingFudge) + /// Rounds the given facing value to the nearest quantized step. + public static WAngle QuantizeFacing(WAngle facing, int steps) { - if (!useClassicFacingFudge || numFrames != 32) - return Util.QuantizeFacing(facing, numFrames); - - // TD and RA divided the facing artwork into 3 frames from (north|south) to (north|south)-(east|west) - // and then 5 frames from (north|south)-(east|west) to (east|west) - var quadrant = ((facing + 31) & 0xFF) / 64; - if (quadrant == 0 || quadrant == 2) - { - var frame = Util.QuantizeFacing(facing, 24); - if (frame > 18) - return frame + 6; - if (frame > 4) - return frame + 3; - return frame; - } - else - { - var frame = Util.QuantizeFacing(facing, 40); - return frame < 20 ? frame - 3 : frame - 8; - } + return new WAngle(IndexFacing(facing, steps) * (1024 / steps)); } /// Wraps an arbitrary integer facing value into the range 0 - 255 @@ -87,13 +88,13 @@ return negative == 0 ? 0 : 256 - negative; } - public static bool FacingWithinTolerance(int facing, int desiredFacing, int facingTolerance) + public static bool FacingWithinTolerance(WAngle facing, WAngle desiredFacing, WAngle facingTolerance) { - if (facingTolerance == 0 && facing == desiredFacing) + if (facingTolerance.Angle == 0 && facing == desiredFacing) return true; - var delta = Util.NormalizeFacing(desiredFacing - facing); - return delta <= facingTolerance || delta >= 256 - facingTolerance; + var delta = (desiredFacing - facing).Angle; + return delta <= facingTolerance.Angle || delta >= 1024 - facingTolerance.Angle; } public static WPos BetweenCells(World w, CPos from, CPos to) @@ -107,6 +108,15 @@ return WPos.Lerp(fromPos, toPos, 1, 2); } + public static WAngle GetVerticalAngle(WPos source, WPos target) + { + var delta = target - source; + var horizontalDelta = delta.HorizontalLength; + var verticalVector = new WVec(-delta.Z, -horizontalDelta, 0); + + return verticalVector.Yaw; + } + public static IEnumerable Shuffle(this IEnumerable ts, MersenneTwister random) { // Fisher-Yates @@ -152,7 +162,7 @@ return cells.SelectMany(c => Neighbours(c, allowDiagonal)).Distinct(); } - public static IEnumerable AdjacentCells(World w, Target target) + public static IEnumerable AdjacentCells(World w, in Target target) { var cells = target.Positions.Select(p => w.Map.CellContaining(p)).Distinct(); return ExpandFootprint(cells, true); @@ -208,6 +218,9 @@ if (t.IsGenericType && t.GetGenericTypeDefinition().GetInterfaces().Any(e => e.IsGenericType && e.GetGenericTypeDefinition() == typeof(IEnumerable<>))) return "Collection of {0}".F(FriendlyTypeName(t.GetGenericArguments().First())); + if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) + return "{0} (optional)".F(t.GetGenericArguments().Select(FriendlyTypeName).First()); + if (t == typeof(int) || t == typeof(uint)) return "Integer"; @@ -252,5 +265,22 @@ return t.Name; } + + public static int GetProjectileInaccuracy(int baseInaccuracy, InaccuracyType inaccuracyType, ProjectileArgs args) + { + var inaccuracy = ApplyPercentageModifiers(baseInaccuracy, args.InaccuracyModifiers); + switch (inaccuracyType) + { + case InaccuracyType.Maximum: + var weaponMaxRange = ApplyPercentageModifiers(args.Weapon.Range.Length, args.RangeModifiers); + return inaccuracy * (args.PassiveTarget - args.Source).Length / weaponMaxRange; + case InaccuracyType.PerCellIncrement: + return inaccuracy * (args.PassiveTarget - args.Source).Length / 1024; + case InaccuracyType.Absolute: + return inaccuracy; + default: + throw new InvalidEnumArgumentException("inaccuracyType", (int)inaccuracyType, typeof(InaccuracyType)); + } + } } } diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/CheckExplicitInterfacesCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/CheckExplicitInterfacesCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/CheckExplicitInterfacesCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/CheckExplicitInterfacesCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -46,7 +46,7 @@ var interfaceMembers = interfaceType.GetMembers(); foreach (var interfaceMember in interfaceMembers) { - if (interfaceMember.Name.StartsWith("get_") || interfaceMember.Name.StartsWith("set_")) + if (interfaceMember.Name.StartsWith("get_") || interfaceMember.Name.StartsWith("set_") || interfaceMember.Name.StartsWith("add_") || interfaceMember.Name.StartsWith("remove_")) continue; var interfaceMethod = interfaceMember as MethodInfo; diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/CheckMissingSprites.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/CheckMissingSprites.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/CheckMissingSprites.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/CheckMissingSprites.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,115 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; + +namespace OpenRA.Mods.Common.UtilityCommands +{ + class CheckMissingSprites : IUtilityCommand + { + string IUtilityCommand.Name { get { return "--check-missing-sprites"; } } + + bool IUtilityCommand.ValidateArguments(string[] args) + { + return true; + } + + [Desc("Check tileset and sequence definitions for missing sprite files.")] + void IUtilityCommand.Run(Utility utility, string[] args) + { + // HACK: The engine code assumes that Game.modData is set. + var modData = Game.ModData = utility.ModData; + var failed = false; + + // We need two levels of YamlException handling to provide the desired behaviour: + // Parse errors within a single tileset should skip that tileset and allow the rest to be tested + // however, certain errors will be thrown by the outer modData.DefaultSequences, which prevent + // any tilesets from being checked further. + try + { + // DefaultSequences is a dictionary of tileset: SequenceProvider + // so we can also use this to key our tileset checks + foreach (var kv in modData.DefaultSequences) + { + try + { + Console.WriteLine("Tileset: " + kv.Key); + var tileset = modData.DefaultTileSets[kv.Key]; + var missingImages = new HashSet(); + Action onMissingImage = (id, f) => + { + Console.WriteLine("\tTemplate `{0}` references sprite `{1}` that does not exist.", id, f); + missingImages.Add(f); + failed = true; + }; + + var theater = new Theater(tileset, onMissingImage); + foreach (var t in tileset.Templates) + { + for (var v = 0; v < t.Value.Images.Length; v++) + { + if (!missingImages.Contains(t.Value.Images[v])) + { + for (var i = 0; i < t.Value.TilesCount; i++) + { + if (t.Value[i] == null || theater.HasTileSprite(new TerrainTile(t.Key, (byte)i), v)) + continue; + + Console.WriteLine("\tTemplate `{0}` references frame {1} that does not exist in sprite `{2}`.", t.Key, i, t.Value.Images[v]); + failed = true; + } + } + } + } + + foreach (var image in kv.Value.Images) + { + foreach (var sequence in kv.Value.Sequences(image)) + { + var s = kv.Value.GetSequence(image, sequence) as FileNotFoundSequence; + if (s == null) + continue; + + Console.WriteLine("\tSequence `{0}.{1}` references sprite `{2}` that does not exist.", image, sequence, s.Filename); + failed = true; + } + } + } + catch (YamlException e) + { + // The stacktrace associated with yaml errors are not very useful + // Suppress them to make the lint output less intimidating for modders + Console.WriteLine("\t{0}".F(e.Message)); + failed = true; + } + catch (Exception e) + { + Console.WriteLine("Failed with exception: {0}".F(e)); + failed = true; + } + } + } + catch (YamlException e) + { + // The stacktrace associated with yaml errors are not very useful + // Suppress them to make the lint output less intimidating for modders + Console.WriteLine("{0}".F(e.Message)); + failed = true; + } + + if (failed) + Environment.Exit(1); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/CheckRuntimeAssembliesCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/CheckRuntimeAssembliesCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/CheckRuntimeAssembliesCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/CheckRuntimeAssembliesCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -36,7 +36,7 @@ .ToArray(); // Load the renderer assembly so we can check its dependencies - Assembly.LoadFile(Platform.ResolvePath(Path.Combine(".", "OpenRA.Platforms.Default.dll"))); + Assembly.LoadFile(Path.Combine(Platform.BinDir, "OpenRA.Platforms.Default.dll")); var missing = new List(); foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/CheckSequenceSprites.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/CheckSequenceSprites.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/CheckSequenceSprites.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/CheckSequenceSprites.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Linq; -using OpenRA.Graphics; - -namespace OpenRA.Mods.Common.UtilityCommands -{ - class CheckSquenceSprites : IUtilityCommand - { - string IUtilityCommand.Name { get { return "--check-sequence-sprites"; } } - - bool IUtilityCommand.ValidateArguments(string[] args) - { - return true; - } - - [Desc("Check the sequence definitions for missing sprite files.")] - void IUtilityCommand.Run(Utility utility, string[] args) - { - // HACK: The engine code assumes that Game.modData is set. - var modData = Game.ModData = utility.ModData; - - var failed = false; - modData.SpriteSequenceLoader.OnMissingSpriteError = s => { Console.WriteLine("\t" + s); failed = true; }; - - foreach (var t in modData.Manifest.TileSets) - { - var ts = new TileSet(modData.DefaultFileSystem, t); - Console.WriteLine("Tileset: " + ts.Name); - var sc = new SpriteCache(modData.DefaultFileSystem, modData.SpriteLoaders); - var nodes = MiniYaml.Merge(modData.Manifest.Sequences.Select(s => MiniYaml.FromStream(modData.DefaultFileSystem.Open(s), s))); - foreach (var n in nodes.Where(node => !node.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal))) - modData.SpriteSequenceLoader.ParseSequences(modData, ts, sc, n); - } - - if (failed) - Environment.Exit(1); - } - } -} diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs 2021-03-21 11:10:05.000000000 +0000 @@ -81,7 +81,7 @@ maps = modData.MapCache.EnumerateMapsWithoutCaching().ToList(); } else - maps.Add(new Map(modData, new Folder(".").OpenPackage(args[1], modData.ModFiles))); + maps.Add(new Map(modData, new Folder(Platform.EngineDir).OpenPackage(args[1], modData.ModFiles))); foreach (var testMap in maps) { @@ -134,7 +134,7 @@ try { var customRulesPass = (ILintRulesPass)modData.ObjectCreator.CreateBasic(customRulesPassType); - customRulesPass.Run(EmitError, EmitWarning, rules); + customRulesPass.Run(EmitError, EmitWarning, modData, rules); } catch (Exception e) { diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/ConvertSpriteToPngCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/ConvertSpriteToPngCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/ConvertSpriteToPngCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/ConvertSpriteToPngCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -49,8 +49,7 @@ for (var i = 0; i < Palette.Size; i++) palColors[i] = palette.GetColor(i); - TypeDictionary metadata; - var frames = FrameLoader.GetFrames(File.OpenRead(src), modData.SpriteLoaders, out metadata); + var frames = FrameLoader.GetFrames(File.OpenRead(src), modData.SpriteLoaders, out _); var usePadding = !args.Contains("--nopadding"); var count = 0; diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/DebugChromeRegions.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/DebugChromeRegions.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/DebugChromeRegions.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/DebugChromeRegions.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,8 +12,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; using OpenRA.Graphics; using OpenRA.Primitives; @@ -48,24 +46,24 @@ var pr = c.Value.PanelRegion; if (pr != null && pr.Length == 8) { - var sides = new[] + var sides = new (PanelSides PanelSides, Rectangle Bounds)[] { - Pair.New(PanelSides.Top | PanelSides.Left, new Rectangle(pr[0], pr[1], pr[2], pr[3])), - Pair.New(PanelSides.Top, new Rectangle(pr[0] + pr[2], pr[1], pr[4], pr[3])), - Pair.New(PanelSides.Top | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1], pr[6], pr[3])), - Pair.New(PanelSides.Left, new Rectangle(pr[0], pr[1] + pr[3], pr[2], pr[5])), - Pair.New(PanelSides.Center, new Rectangle(pr[0] + pr[2], pr[1] + pr[3], pr[4], pr[5])), - Pair.New(PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3], pr[6], pr[5])), - Pair.New(PanelSides.Bottom | PanelSides.Left, new Rectangle(pr[0], pr[1] + pr[3] + pr[5], pr[2], pr[7])), - Pair.New(PanelSides.Bottom, new Rectangle(pr[0] + pr[2], pr[1] + pr[3] + pr[5], pr[4], pr[7])), - Pair.New(PanelSides.Bottom | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3] + pr[5], pr[6], pr[7])) + (PanelSides.Top | PanelSides.Left, new Rectangle(pr[0], pr[1], pr[2], pr[3])), + (PanelSides.Top, new Rectangle(pr[0] + pr[2], pr[1], pr[4], pr[3])), + (PanelSides.Top | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1], pr[6], pr[3])), + (PanelSides.Left, new Rectangle(pr[0], pr[1] + pr[3], pr[2], pr[5])), + (PanelSides.Center, new Rectangle(pr[0] + pr[2], pr[1] + pr[3], pr[4], pr[5])), + (PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3], pr[6], pr[5])), + (PanelSides.Bottom | PanelSides.Left, new Rectangle(pr[0], pr[1] + pr[3] + pr[5], pr[2], pr[7])), + (PanelSides.Bottom, new Rectangle(pr[0] + pr[2], pr[1] + pr[3] + pr[5], pr[4], pr[7])), + (PanelSides.Bottom | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3] + pr[5], pr[6], pr[7])) }; foreach (var s in sides) { - var r = s.Second; - if (c.Value.PanelSides.HasSide(s.First)) - regions.Add("[\"{0}.<{1}>\",{2},{3},{4},{5}]".F(c.Key, s.First, r.X, r.Y, r.Width, r.Height)); + var r = s.Bounds; + if (c.Value.PanelSides.HasSide(s.PanelSides)) + regions.Add("[\"{0}.<{1}>\",{2},{3},{4},{5}]".F(c.Key, s.PanelSides, r.X, r.Y, r.Width, r.Height)); } } diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/DumpSequenceSheetsCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/DumpSequenceSheetsCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/DumpSequenceSheetsCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/DumpSequenceSheetsCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -35,7 +35,7 @@ var palette = new ImmutablePalette(args[1], new int[0]); SequenceProvider sequences = null; - var mapPackage = new Folder(".").OpenPackage(args[2], modData.ModFiles); + var mapPackage = new Folder(Platform.EngineDir).OpenPackage(args[2], modData.ModFiles); if (mapPackage != null) sequences = new Map(modData, mapPackage).Rules.Sequences; else if (!modData.DefaultSequences.TryGetValue(args[2], out sequences)) diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -37,12 +37,9 @@ foreach (var filename in modData.Manifest.ChromeLayout) { - string name; - OpenRA.FileSystem.IReadOnlyPackage package; - - modData.ModFiles.TryGetPackageContaining(filename, out package, out name); + modData.ModFiles.TryGetPackageContaining(filename, out var package, out var name); name = package.Name + "/" + name; - Console.WriteLine("# {0}:", name); + Console.WriteLine("# {0}:", filename); var yaml = MiniYaml.FromFile(name, false); FromChromeLayout(ref yaml, null, diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/ExtractLuaDocsCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/ExtractLuaDocsCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/ExtractLuaDocsCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/ExtractLuaDocsCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -37,24 +37,25 @@ Console.WriteLine("This is an automatically generated listing of the Lua map scripting API for version {0} of OpenRA.", version); Console.WriteLine(); - Console.WriteLine("OpenRA allows custom maps and missions to be scripted using Lua 5.1.\n" + - "These scripts run in a sandbox that prevents access to unsafe functions (e.g. OS or file access), " + + Console.WriteLine("OpenRA allows custom maps and missions to be scripted using Lua 5.1."); + Console.WriteLine("These scripts run in a sandbox that prevents access to unsafe functions (e.g. OS or file access), " + "and limits the memory and CPU usage of the scripts."); Console.WriteLine(); - Console.WriteLine("You can access this interface by adding the [LuaScript](Traits#luascript) trait to the world actor in your map rules " + + Console.WriteLine("You can access this interface by adding the [LuaScript](../traits/#luascript) trait to the world actor in your map rules " + "(note, you must replace the spaces in the snippet below with a single tab for each level of indentation):"); Console.WriteLine("```\nRules:\n\tWorld:\n\t\tLuaScript:\n\t\t\tScripts: myscript.lua\n```"); Console.WriteLine(); - Console.WriteLine("Map scripts can interact with the game engine in three ways:\n" + - "* Global tables provide functions for interacting with the global world state, or performing general helper tasks.\n" + - "They exist in the global namespace, and can be called directly using ```.```.\n" + - "* Individual actors expose a collection of properties and commands that query information or modify their state.\n" + - " * Some commands, marked as queued activity, are asynchronous. Activities are queued on the actor, and will run in " + + Console.WriteLine("Map scripts can interact with the game engine in three ways:"); + Console.WriteLine(); + Console.WriteLine("* Global tables provide functions for interacting with the global world state, or performing general helper tasks."); + Console.WriteLine("They exist in the global namespace, and can be called directly using ```
.```."); + Console.WriteLine("* Individual actors expose a collection of properties and commands that query information or modify their state."); + Console.WriteLine(" * Some commands, marked as queued activity, are asynchronous. Activities are queued on the actor, and will run in " + "sequence until the queue is empty or the Stop command is called. Actors that are not performing an activity are Idle " + "(actor.IsIdle will return true). The properties and commands available on each actor depends on the traits that the actor " + - "specifies in its rule definitions.\n" + - "* Individual players expose a collection of properties and commands that query information or modify their state.\n" + - "The properties and commands available on each actor depends on the traits that the actor specifies in its rule definitions.\n"); + "specifies in its rule definitions."); + Console.WriteLine("* Individual players expose a collection of properties and commands that query information or modify their state."); + Console.WriteLine("The properties and commands available on each actor depends on the traits that the actor specifies in its rule definitions."); Console.WriteLine(); Console.WriteLine("For a basic guide about map scripts see the [`Map Scripting` wiki page](https://github.com/OpenRA/OpenRA/wiki/Map-scripting)."); Console.WriteLine(); @@ -62,14 +63,15 @@ var tables = utility.ModData.ObjectCreator.GetTypesImplementing() .OrderBy(t => t.Name); - Console.WriteLine("

Global Tables

"); + Console.WriteLine("## Global Tables"); foreach (var t in tables) { var name = t.GetCustomAttributes(true).First().Name; var members = ScriptMemberWrapper.WrappableMembers(t); - Console.WriteLine("
", name); + Console.WriteLine("### " + name); + Console.WriteLine("
{0}
"); foreach (var m in members.OrderBy(m => m.Name)) { var desc = m.HasAttribute() ? m.GetCustomAttributes(true).First().Lines.JoinWith("\n") : ""; @@ -79,7 +81,7 @@ Console.WriteLine("
"); } - Console.WriteLine("

Actor Properties / Commands

"); + Console.WriteLine("### Actor Properties / Commands"); var actorCategories = utility.ModData.ObjectCreator.GetTypesImplementing().SelectMany(cg => { @@ -87,12 +89,13 @@ var category = catAttr != null ? catAttr.Category : "Unsorted"; var required = RequiredTraitNames(cg); - return ScriptMemberWrapper.WrappableMembers(cg).Select(mi => Tuple.Create(category, mi, required)); + return ScriptMemberWrapper.WrappableMembers(cg).Select(mi => (category, mi, required)); }).GroupBy(g => g.Item1).OrderBy(g => g.Key); foreach (var kv in actorCategories) { - Console.WriteLine("", kv.Key); + Console.WriteLine("### " + kv.Key); + Console.WriteLine("
{0}
"); foreach (var property in kv.OrderBy(p => p.Item2.Name)) { @@ -124,7 +127,7 @@ Console.WriteLine("
"); } - Console.WriteLine("

Player Properties / Commands

"); + Console.WriteLine("## Player Properties / Commands"); var playerCategories = utility.ModData.ObjectCreator.GetTypesImplementing().SelectMany(cg => { @@ -132,7 +135,7 @@ var category = catAttr != null ? catAttr.Category : "Unsorted"; var required = RequiredTraitNames(cg); - return ScriptMemberWrapper.WrappableMembers(cg).Select(mi => Tuple.Create(category, mi, required)); + return ScriptMemberWrapper.WrappableMembers(cg).Select(mi => (category, mi, required)); }).GroupBy(g => g.Item1).OrderBy(g => g.Key); foreach (var kv in playerCategories) diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/ExtractMapRules.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/ExtractMapRules.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/ExtractMapRules.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/ExtractMapRules.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,7 +52,7 @@ { var modData = Game.ModData = utility.ModData; - var map = new Map(modData, new Folder(".").OpenPackage(args[1], modData.ModFiles)); + var map = new Map(modData, new Folder(Platform.EngineDir).OpenPackage(args[1], modData.ModFiles)); MergeAndPrint(map, "Rules", map.RuleDefinitions); MergeAndPrint(map, "Sequences", map.SequenceDefinitions); MergeAndPrint(map, "ModelSequences", map.ModelSequenceDefinitions); diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -41,11 +41,10 @@ "automatically generated for version {0} of OpenRA.", version); Console.WriteLine(); - var toc = new StringBuilder(); var doc = new StringBuilder(); var currentNamespace = ""; - foreach (var t in Game.ModData.ObjectCreator.GetTypesImplementing().OrderBy(t => t.Namespace)) + foreach (var t in Game.ModData.ObjectCreator.GetTypesImplementing().OrderBy(t => t.Namespace)) { if (t.ContainsGenericParameters || t.IsAbstract) continue; // skip helpers like TraitInfo @@ -55,11 +54,9 @@ currentNamespace = t.Namespace; doc.AppendLine(); doc.AppendLine("## {0}".F(currentNamespace)); - toc.AppendLine("* [{0}](#{1})".F(currentNamespace, currentNamespace.Replace(".", "").ToLowerInvariant())); } var traitName = t.Name.EndsWith("Info") ? t.Name.Substring(0, t.Name.Length - 4) : t.Name; - toc.AppendLine(" * [{0}](#{1})".F(traitName, traitName.ToLowerInvariant())); var traitDescLines = t.GetCustomAttributes(false).SelectMany(d => d.Lines); doc.AppendLine(); doc.AppendLine("### {0}".F(traitName)); @@ -107,7 +104,6 @@ doc.AppendLine(""); } - Console.Write(toc.ToString()); Console.Write(doc.ToString()); } diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -43,7 +43,6 @@ "automatically generated for version {0} of OpenRA.", version); Console.WriteLine(); - var toc = new StringBuilder(); var doc = new StringBuilder(); var currentNamespace = ""; @@ -65,11 +64,9 @@ currentNamespace = t.Namespace; doc.AppendLine(); doc.AppendLine("## {0}".F(currentNamespace)); - toc.AppendLine("* [{0}](#{1})".F(currentNamespace, currentNamespace.Replace(".", "").ToLowerInvariant())); } var traitName = t.Name.EndsWith("Info") ? t.Name.Substring(0, t.Name.Length - 4) : t.Name; - toc.AppendLine(" * [{0}](#{1})".F(traitName, traitName.ToLowerInvariant())); doc.AppendLine(); doc.AppendLine("### {0}".F(traitName)); @@ -102,7 +99,6 @@ doc.AppendLine(""); } - Console.Write(toc.ToString()); Console.Write(doc.ToString()); } } diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,7 +26,7 @@ [Desc("MAPFILE", "Generate hash of specified oramap file.")] void IUtilityCommand.Run(Utility utility, string[] args) { - using (var package = new Folder(".").OpenPackage(args[1], utility.ModData.ModFiles)) + using (var package = new Folder(Platform.EngineDir).OpenPackage(args[1], utility.ModData.ModFiles)) Console.WriteLine(Map.ComputeUID(package)); } } diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,10 +15,10 @@ using System.Linq; using System.Text; using OpenRA.FileSystem; -using OpenRA.Graphics; using OpenRA.Mods.Common.FileFormats; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; +using OpenRA.Traits; namespace OpenRA.Mods.Common.UtilityCommands { @@ -182,19 +182,19 @@ switch (s.Key) { case "Intro": - videos.Add(new MiniYamlNode("BackgroundVideo", s.Value.ToLower() + ".vqa")); + videos.Add(new MiniYamlNode("BackgroundVideo", s.Value.ToLowerInvariant() + ".vqa")); break; case "Brief": - videos.Add(new MiniYamlNode("BriefingVideo", s.Value.ToLower() + ".vqa")); + videos.Add(new MiniYamlNode("BriefingVideo", s.Value.ToLowerInvariant() + ".vqa")); break; case "Action": - videos.Add(new MiniYamlNode("StartVideo", s.Value.ToLower() + ".vqa")); + videos.Add(new MiniYamlNode("StartVideo", s.Value.ToLowerInvariant() + ".vqa")); break; case "Win": - videos.Add(new MiniYamlNode("WinVideo", s.Value.ToLower() + ".vqa")); + videos.Add(new MiniYamlNode("WinVideo", s.Value.ToLowerInvariant() + ".vqa")); break; case "Lose": - videos.Add(new MiniYamlNode("LossVideo", s.Value.ToLower() + ".vqa")); + videos.Add(new MiniYamlNode("LossVideo", s.Value.ToLowerInvariant() + ".vqa")); break; } } @@ -251,17 +251,17 @@ var actorCount = Map.ActorDefinitions.Count; var wps = waypointSection .Where(kv => Exts.ParseIntegerInvariant(kv.Value) > 0) - .Select(kv => Pair.New(Exts.ParseIntegerInvariant(kv.Key), - LocationFromMapOffset(Exts.ParseIntegerInvariant(kv.Value), MapSize))); + .Select(kv => (WaypointNumber: Exts.ParseIntegerInvariant(kv.Key), + Location: LocationFromMapOffset(Exts.ParseIntegerInvariant(kv.Value), MapSize))); // Add waypoint actors skipping duplicate entries - foreach (var kv in wps.DistinctBy(location => location.Second)) + foreach (var kv in wps.DistinctBy(location => location.Location)) { - if (!singlePlayer && kv.First <= 7) + if (!singlePlayer && kv.WaypointNumber <= 7) { var ar = new ActorReference("mpspawn") { - new LocationInit((CPos)kv.Second), + new LocationInit((CPos)kv.Location), new OwnerInit("Neutral") }; @@ -272,11 +272,11 @@ { var ar = new ActorReference("waypoint") { - new LocationInit((CPos)kv.Second), + new LocationInit((CPos)kv.Location), new OwnerInit("Neutral") }; - SaveWaypoint(kv.First, ar); + SaveWaypoint(kv.WaypointNumber, ar); } } } @@ -409,14 +409,13 @@ new OwnerInit(parts[0]), }; - var initDict = actor.InitDict; if (health != 100) - initDict.Add(new HealthInit(health)); + actor.Add(new HealthInit(health)); if (facing != 0) - initDict.Add(new FacingInit(255 - facing)); + actor.Add(new FacingInit(new WAngle(1024 - 4 * facing))); if (section == "INFANTRY") - actor.Add(new SubCellInit(Exts.ParseByte(parts[4]))); + actor.Add(new SubCellInit((SubCell)Exts.ParseByte(parts[4]))); var actorCount = map.ActorDefinitions.Count; diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/LintInterfaces.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/LintInterfaces.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/LintInterfaces.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/LintInterfaces.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,5 +15,5 @@ { public interface ILintPass { void Run(Action emitError, Action emitWarning, ModData modData); } public interface ILintMapPass { void Run(Action emitError, Action emitWarning, ModData modData, Map map); } - public interface ILintRulesPass { void Run(Action emitError, Action emitWarning, Ruleset rules); } + public interface ILintRulesPass { void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules); } } diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/PngSheetImportMetadataCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/PngSheetImportMetadataCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/PngSheetImportMetadataCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/PngSheetImportMetadataCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,9 @@ #endregion using System.IO; +using System.Linq; using OpenRA.FileFormats; +using OpenRA.Primitives; namespace OpenRA.Mods.Common.UtilityCommands { @@ -30,7 +32,23 @@ using (var pngStream = File.OpenRead(args[1])) png = new Png(pngStream); - foreach (var node in MiniYaml.FromFile(Path.ChangeExtension(args[1], "yaml"))) + var yaml = MiniYaml.FromFile(Path.ChangeExtension(args[1], "yaml")); + + var frameSizeField = yaml.Where(y => y.Key == "FrameSize").Select(y => y.Value.Value).FirstOrDefault(); + if (frameSizeField != null) + { + var frameSize = FieldLoader.GetValue("FrameSize", frameSizeField); + + var frameAmountField = yaml.Where(y => y.Key == "FrameAmount").Select(y => y.Value.Value).FirstOrDefault(); + if (frameAmountField != null) + { + var frameAmount = FieldLoader.GetValue("FrameAmount", frameAmountField); + if (frameAmount > (png.Width / frameSize.Width) * (png.Height / frameSize.Height)) + throw new InvalidDataException(".png file is too small for given FrameSize and FrameAmount."); + } + } + + foreach (var node in yaml) png.EmbeddedData[node.Key] = node.Value.Value; png.Save(args[1]); diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/RefreshMapCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/RefreshMapCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/RefreshMapCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/RefreshMapCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,7 +28,7 @@ // HACK: The engine code assumes that Game.modData is set. // HACK: We know that maps can only be oramap or folders, which are ReadWrite var modData = Game.ModData = utility.ModData; - using (var package = new Folder(".").OpenPackage(args[1], modData.ModFiles)) + using (var package = new Folder(Platform.EngineDir).OpenPackage(args[1], modData.ModFiles)) new Map(modData, package).Save((IReadWritePackage)package); } } diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/ResizeMapCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/ResizeMapCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/ResizeMapCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/ResizeMapCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -48,7 +48,7 @@ void IUtilityCommand.Run(Utility utility, string[] args) { var modData = Game.ModData = utility.ModData; - map = new Map(modData, new Folder(".").OpenPackage(args[1], modData.ModFiles)); + map = new Map(modData, new Folder(Platform.EngineDir).OpenPackage(args[1], modData.ModFiles)); Console.WriteLine("Resizing map {0} from {1} to {2},{3}", map.Title, map.MapSize, width, height); map.Resize(width, height); @@ -57,10 +57,13 @@ foreach (var kv in map.ActorDefinitions) { var actor = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); - var location = actor.InitDict.Get().Value(null); - if (!map.Contains(location)) + var locationInit = actor.GetOrDefault(); + if (locationInit == null) + continue; + + if (!map.Contains(locationInit.Value)) { - Console.WriteLine("Removing actor {0} located at {1} due being outside of the new map boundaries.".F(actor.Type, location)); + Console.WriteLine("Removing actor {0} located at {1} due being outside of the new map boundaries.".F(actor.Type, locationInit.Value)); forRemoval.Add(kv); } } diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/Rgba2Hex.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/Rgba2Hex.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/Rgba2Hex.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/Rgba2Hex.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,6 @@ return PrintUsage(); var invalid = false; - byte component; for (int i = 1; i < args.Length; i++) { var parts = args[i].Split(Comma, StringSplitOptions.RemoveEmptyEntries); @@ -38,7 +37,7 @@ { foreach (var part in parts) { - if (!byte.TryParse(part, out component)) + if (!byte.TryParse(part, out _)) { invalid = true; Console.WriteLine("Invalid component in color (argument " + i + "): [" + part + "]: " + args[i]); @@ -114,7 +113,6 @@ return PrintUsage(); var invalid = false; - byte component; for (int i = 1; i < args.Length; i++) { var parts = args[i].Split(Comma, StringSplitOptions.RemoveEmptyEntries); @@ -127,7 +125,7 @@ { foreach (var part in parts) { - if (!byte.TryParse(part, out component)) + if (!byte.TryParse(part, out _)) { invalid = true; Console.WriteLine("Invalid component in color (argument " + i + "): [" + part + "]: " + args[i]); diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/UpdateMapCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/UpdateMapCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/UpdateMapCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/UpdateMapCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.UtilityCommands { - using YamlFileSet = List>>; + using YamlFileSet = List<(IReadWritePackage, string, List)>; class UpdateMapCommand : IUtilityCommand { @@ -36,7 +36,7 @@ var modData = Game.ModData = utility.ModData; // HACK: We know that maps can only be oramap or folders, which are ReadWrite - var package = new Folder(".").OpenPackage(args[1], modData.ModFiles) as IReadWritePackage; + var package = new Folder(Platform.EngineDir).OpenPackage(args[1], modData.ModFiles) as IReadWritePackage; if (package == null) throw new FileNotFoundException(args[1]); diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/UpdateModCommand.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/UpdateModCommand.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/UpdateModCommand.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/UpdateModCommand.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.UtilityCommands { - using YamlFileSet = List>>; + using YamlFileSet = List<(IReadWritePackage, string, List)>; class UpdateModCommand : IUtilityCommand { @@ -202,8 +202,7 @@ { try { - YamlFileSet mapFiles; - var mapSteps = UpdateUtils.UpdateMap(modData, package, rule, out mapFiles, mapExternalFilenames); + var mapSteps = UpdateUtils.UpdateMap(modData, package, rule, out var mapFiles, mapExternalFilenames); allFiles.AddRange(mapFiles); if (mapSteps.Any()) diff -Nru openra-20200503/OpenRA.Mods.Common/UtilityCommands/Utilities.cs openra-20210321/OpenRA.Mods.Common/UtilityCommands/Utilities.cs --- openra-20200503/OpenRA.Mods.Common/UtilityCommands/Utilities.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/UtilityCommands/Utilities.cs 2021-03-21 11:10:05.000000000 +0000 @@ -32,7 +32,7 @@ { try { - map = new Map(modData, new Folder(".").OpenPackage(mapPath, modData.ModFiles)); + map = new Map(modData, new Folder(Platform.EngineDir).OpenPackage(mapPath, modData.ModFiles)); } catch (InvalidDataException ex) { diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/ChangeOwnerWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/ChangeOwnerWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/ChangeOwnerWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/ChangeOwnerWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Collections.Generic; using OpenRA.GameRules; using OpenRA.Mods.Common.Traits; using OpenRA.Traits; @@ -24,7 +23,7 @@ public readonly WDist Range = WDist.FromCells(1); - public override void DoImpact(Target target, WarheadArgs args) + public override void DoImpact(in Target target, WarheadArgs args) { var firedBy = args.SourceActor; var actors = target.Type == TargetType.Actor ? new[] { target.Actor } : @@ -32,6 +31,9 @@ foreach (var a in actors) { + if (!IsValidAgainst(a, firedBy)) + continue; + // Don't do anything on friendly fire if (a.Owner == firedBy.Owner) continue; diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/CreateEffectWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/CreateEffectWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/CreateEffectWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/CreateEffectWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Collections.Generic; using System.Linq; using OpenRA.GameRules; using OpenRA.Mods.Common.Effects; @@ -21,14 +20,14 @@ { public class CreateEffectWarhead : Warhead { - [SequenceReference("Image")] + [SequenceReference(nameof(Image), allowNullImage: true)] [Desc("List of explosion sequences that can be used.")] public readonly string[] Explosions = new string[0]; [Desc("Image containing explosion effect sequence.")] public readonly string Image = "explosion"; - [PaletteReference("UsePlayerPalette")] + [PaletteReference(nameof(UsePlayerPalette))] [Desc("Palette to use for explosion effect.")] public readonly string ExplosionPalette = "effect"; @@ -44,93 +43,88 @@ [Desc("Chance of impact sound to play.")] public readonly int ImpactSoundChance = 100; - [Desc("Consider explosion above this altitude an air explosion.", - "If that's the case, this warhead will consider the explosion position to have the 'Air' TargetType (in addition to any nearby actor's TargetTypes).")] - public readonly WDist AirThreshold = new WDist(128); - [Desc("Whether to consider actors in determining whether the explosion should happen. If false, only terrain will be considered.")] public readonly bool ImpactActors = true; - static readonly BitSet TargetTypeAir = new BitSet("Air"); - - public ImpactType GetImpactType(World world, CPos cell, WPos pos, Actor firedBy) - { - // Matching target actor - if (ImpactActors) - { - var targetType = GetDirectHitTargetType(world, cell, pos, firedBy, true); - if (targetType == ImpactTargetType.ValidActor) - return ImpactType.TargetHit; - if (targetType == ImpactTargetType.InvalidActor) - return ImpactType.None; - } - - var dat = world.Map.DistanceAboveTerrain(pos); - if (dat > AirThreshold) - return ImpactType.Air; + [Desc("The maximum inaccuracy of the effect spawn position relative to actual impact position.")] + public readonly WDist Inaccuracy = WDist.Zero; - return ImpactType.Ground; - } + static readonly BitSet TargetTypeAir = new BitSet("Air"); - public ImpactTargetType GetDirectHitTargetType(World world, CPos cell, WPos pos, Actor firedBy, bool checkTargetValidity = false) + /// Checks if there are any actors at impact position and if the warhead is valid against any of them. + ImpactActorType ActorTypeAtImpact(World world, WPos pos, Actor firedBy) { - var victims = world.FindActorsOnCircle(pos, WDist.Zero); - var invalidHit = false; + var anyInvalidActor = false; - foreach (var victim in victims) + // Check whether the impact position overlaps with an actor's hitshape + foreach (var victim in world.FindActorsOnCircle(pos, WDist.Zero)) { if (!AffectsParent && victim == firedBy) continue; - if (!victim.Info.HasTraitInfo()) - continue; - - // If the impact position is within any HitShape, we have a direct hit var activeShapes = victim.TraitsImplementing().Where(Exts.IsTraitEnabled); - var directHit = activeShapes.Any(i => i.DistanceFromEdge(victim, pos).Length <= 0); - - // If the warhead landed outside the actor's hit-shape(s), we need to skip the rest so it won't be considered an invalidHit - if (!directHit) + if (!activeShapes.Any(s => s.DistanceFromEdge(victim, pos).Length <= 0)) continue; - if (!checkTargetValidity || IsValidAgainst(victim, firedBy)) - return ImpactTargetType.ValidActor; + if (IsValidAgainst(victim, firedBy)) + return ImpactActorType.Valid; - // If we got here, it must be an invalid target - invalidHit = true; + anyInvalidActor = true; } - // If there was at least a single direct hit, but none on valid target(s), we return InvalidActor - return invalidHit ? ImpactTargetType.InvalidActor : ImpactTargetType.NoActor; + return anyInvalidActor ? ImpactActorType.Invalid : ImpactActorType.None; } - public override void DoImpact(Target target, WarheadArgs args) + // ActorTypeAtImpact already checks AffectsParent beforehand, to avoid parent HitShape look-ups + // (and to prevent returning ImpactActorType.Invalid on AffectsParent=false) + public override bool IsValidAgainst(Actor victim, Actor firedBy) { - var firedBy = args.SourceActor; - if (!target.IsValidFor(firedBy)) + var stance = firedBy.Owner.RelationshipWith(victim.Owner); + if (!ValidRelationships.HasStance(stance)) + return false; + + // A target type is valid if it is in the valid targets list, and not in the invalid targets list. + if (!IsValidTarget(victim.GetEnabledTargetTypes())) + return false; + + return true; + } + + public override void DoImpact(in Target target, WarheadArgs args) + { + if (target.Type == TargetType.Invalid) return; + var firedBy = args.SourceActor; var pos = target.CenterPosition; var world = firedBy.World; - var targetTile = world.Map.CellContaining(pos); - var isValid = IsValidImpact(pos, firedBy); + var actorAtImpact = ImpactActors ? ActorTypeAtImpact(world, pos, firedBy) : ImpactActorType.None; - if ((!world.Map.Contains(targetTile)) || (!isValid)) + // Ignore the impact if there are only invalid actors within range + if (actorAtImpact == ImpactActorType.Invalid) return; - var palette = ExplosionPalette; - if (UsePlayerPalette) - palette += firedBy.Owner.InternalName; + // Ignore the impact if there are no valid actors and no valid terrain + // (impacts are allowed on valid actors sitting on invalid terrain!) + if (actorAtImpact == ImpactActorType.None && !IsValidAgainstTerrain(world, pos)) + return; var explosion = Explosions.RandomOrDefault(world.LocalRandom); if (Image != null && explosion != null) { + if (Inaccuracy.Length > 0) + pos += WVec.FromPDF(world.SharedRandom, 2) * Inaccuracy.Length / 1024; + if (ForceDisplayAtGroundLevel) { var dat = world.Map.DistanceAboveTerrain(pos); - pos = new WPos(pos.X, pos.Y, pos.Z - dat.Length); + pos -= new WVec(0, 0, dat.Length); } + var palette = ExplosionPalette; + if (UsePlayerPalette) + palette += firedBy.Owner.InternalName; + world.AddFrameEndTask(w => w.Add(new SpriteEffect(pos, w, Image, explosion, palette))); } @@ -139,26 +133,15 @@ Game.Sound.Play(SoundType.World, impactSound, pos); } - public bool IsValidImpact(WPos pos, Actor firedBy) + /// Checks if the warhead is valid against the terrain at impact position. + bool IsValidAgainstTerrain(World world, WPos pos) { - var world = firedBy.World; - var targetTile = world.Map.CellContaining(pos); - if (!world.Map.Contains(targetTile)) + var cell = world.Map.CellContaining(pos); + if (!world.Map.Contains(cell)) return false; - var impactType = GetImpactType(world, targetTile, pos, firedBy); - switch (impactType) - { - case ImpactType.TargetHit: - return true; - case ImpactType.Air: - return IsValidTarget(TargetTypeAir); - case ImpactType.Ground: - var tileInfo = world.Map.GetTerrainInfo(targetTile); - return IsValidTarget(tileInfo.TargetTypes); - default: - return false; - } + var dat = world.Map.DistanceAboveTerrain(pos); + return IsValidTarget(dat > AirThreshold ? TargetTypeAir : world.Map.GetTerrainInfo(cell).TargetTypes); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/CreateResourceWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/CreateResourceWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/CreateResourceWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/CreateResourceWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Collections.Generic; using System.Linq; using OpenRA.GameRules; using OpenRA.Mods.Common.Traits; @@ -17,43 +16,54 @@ namespace OpenRA.Mods.Common.Warheads { - public class CreateResourceWarhead : Warhead + public class CreateResourceWarhead : Warhead, IRulesetLoaded { [Desc("Size of the area. The resources are seeded within this area.", "Provide 2 values for a ring effect (outer/inner).")] public readonly int[] Size = { 0, 0 }; [Desc("Will this splatter resources and which?")] + [FieldLoader.Require] public readonly string AddsResourceType = null; + void IRulesetLoaded.RulesetLoaded(Ruleset rules, WeaponInfo info) + { + var world = rules.Actors["world"]; + var resourceType = world.TraitInfos() + .FirstOrDefault(t => t.Type == AddsResourceType); + + if (resourceType == null) + throw new YamlException("CreateResourceWarhead defines an invalid resource type '{0}'".F(AddsResourceType)); + } + // TODO: Allow maximum resource splatter to be defined. (Per tile, and in total). - public override void DoImpact(Target target, WarheadArgs args) + public override void DoImpact(in Target target, WarheadArgs args) { - if (string.IsNullOrEmpty(AddsResourceType)) + if (target.Type == TargetType.Invalid) return; var firedBy = args.SourceActor; + var pos = target.CenterPosition; var world = firedBy.World; - var targetTile = world.Map.CellContaining(target.CenterPosition); - var resLayer = world.WorldActor.Trait(); + var dat = world.Map.DistanceAboveTerrain(pos); + if (dat > AirThreshold) + return; + + var targetTile = world.Map.CellContaining(pos); var minRange = (Size.Length > 1 && Size[1] > 0) ? Size[1] : 0; var allCells = world.Map.FindTilesInAnnulus(targetTile, minRange, Size[0]); var resourceType = world.WorldActor.TraitsImplementing() - .FirstOrDefault(t => t.Info.Type == AddsResourceType); + .First(t => t.Info.Type == AddsResourceType); - if (resourceType == null) - Log.Write("debug", "Warhead defines an invalid resource type '{0}'".F(AddsResourceType)); - else + var resLayer = world.WorldActor.Trait(); + foreach (var cell in allCells) { - foreach (var cell in allCells) - { - if (!resLayer.CanSpawnResourceAt(resourceType, cell)) - continue; - - var splash = world.SharedRandom.Next(1, resourceType.Info.MaxDensity - resLayer.GetResourceDensity(cell)); - resLayer.AddResource(resourceType, cell, splash); - } + if (!resLayer.CanSpawnResourceAt(resourceType, cell)) + continue; + + var splash = world.SharedRandom.Next(1, resourceType.Info.MaxDensity - resLayer.GetResourceDensity(cell)); + resLayer.AddResource(resourceType, cell, splash); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/DamageWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/DamageWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/DamageWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/DamageWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -38,27 +38,7 @@ return base.IsValidAgainst(victim, firedBy); } - public int DamageVersus(Actor victim, HitShapeInfo shapeInfo) - { - // If no Versus values are defined, DamageVersus would return 100 anyway, so we might as well do that early. - if (Versus.Count == 0) - return 100; - - var armor = victim.TraitsImplementing() - .Where(a => !a.IsTraitDisabled && a.Info.Type != null && Versus.ContainsKey(a.Info.Type) && - (shapeInfo.ArmorTypes == default(BitSet) || shapeInfo.ArmorTypes.Contains(a.Info.Type))) - .Select(a => Versus[a.Info.Type]); - - return Util.ApplyPercentageModifiers(100, armor); - } - - protected virtual void InflictDamage(Actor victim, Actor firedBy, HitShapeInfo hitshapeInfo, IEnumerable damageModifiers) - { - var damage = Util.ApplyPercentageModifiers(Damage, damageModifiers.Append(DamageVersus(victim, hitshapeInfo))); - victim.InflictDamage(firedBy, new Damage(damage, DamageTypes)); - } - - public override void DoImpact(Target target, WarheadArgs args) + public override void DoImpact(in Target target, WarheadArgs args) { var firedBy = args.SourceActor; @@ -77,12 +57,32 @@ if (closestActiveShape == null) return; - InflictDamage(victim, firedBy, closestActiveShape.Info, args.DamageModifiers); + InflictDamage(victim, firedBy, closestActiveShape, args); } else if (target.Type != TargetType.Invalid) - DoImpact(target.CenterPosition, firedBy, args.DamageModifiers); + DoImpact(target.CenterPosition, firedBy, args); + } + + protected virtual int DamageVersus(Actor victim, HitShape shape, WarheadArgs args) + { + // If no Versus values are defined, DamageVersus would return 100 anyway, so we might as well do that early. + if (Versus.Count == 0) + return 100; + + var armor = victim.TraitsImplementing() + .Where(a => !a.IsTraitDisabled && a.Info.Type != null && Versus.ContainsKey(a.Info.Type) && + (shape.Info.ArmorTypes.IsEmpty || shape.Info.ArmorTypes.Contains(a.Info.Type))) + .Select(a => Versus[a.Info.Type]); + + return Util.ApplyPercentageModifiers(100, armor); + } + + protected virtual void InflictDamage(Actor victim, Actor firedBy, HitShape shape, WarheadArgs args) + { + var damage = Util.ApplyPercentageModifiers(Damage, args.DamageModifiers.Append(DamageVersus(victim, shape, args))); + victim.InflictDamage(firedBy, new Damage(damage, DamageTypes)); } - public abstract void DoImpact(WPos pos, Actor firedBy, IEnumerable damageModifiers); + protected abstract void DoImpact(WPos pos, Actor firedBy, WarheadArgs args); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/DestroyResourceWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/DestroyResourceWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/DestroyResourceWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/DestroyResourceWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Collections.Generic; using OpenRA.GameRules; using OpenRA.Mods.Common.Traits; using OpenRA.Traits; @@ -22,11 +21,19 @@ public readonly int[] Size = { 0, 0 }; // TODO: Allow maximum resource removal to be defined. (Per tile, and in total). - public override void DoImpact(Target target, WarheadArgs args) + public override void DoImpact(in Target target, WarheadArgs args) { + if (target.Type == TargetType.Invalid) + return; + var firedBy = args.SourceActor; + var pos = target.CenterPosition; var world = firedBy.World; - var targetTile = world.Map.CellContaining(target.CenterPosition); + var dat = world.Map.DistanceAboveTerrain(pos); + if (dat > AirThreshold) + return; + + var targetTile = world.Map.CellContaining(pos); var resLayer = world.WorldActor.Trait(); var minRange = (Size.Length > 1 && Size[1] > 0) ? Size[1] : 0; diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/FireClusterWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/FireClusterWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/FireClusterWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/FireClusterWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System.Collections.Generic; using System.Linq; using OpenRA.GameRules; -using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.Common.Warheads @@ -44,19 +43,18 @@ throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(Weapon.ToLowerInvariant())); } - public override void DoImpact(Target target, WarheadArgs args) + public override void DoImpact(in Target target, WarheadArgs args) { - var firedBy = args.SourceActor; - if (!target.IsValidFor(firedBy)) + if (target.Type == TargetType.Invalid) return; + var firedBy = args.SourceActor; var map = firedBy.World.Map; var targetCell = map.CellContaining(target.CenterPosition); - var damageModifiers = args.DamageModifiers; var targetCells = CellsMatching(targetCell, false); foreach (var c in targetCells) - FireProjectileAtCell(map, firedBy, target, c, damageModifiers); + FireProjectileAtCell(map, firedBy, target, c, args); if (RandomClusterCount != 0) { @@ -64,23 +62,24 @@ var clusterCount = RandomClusterCount < 0 ? randomTargetCells.Count() : RandomClusterCount; if (randomTargetCells.Any()) for (var i = 0; i < clusterCount; i++) - FireProjectileAtCell(map, firedBy, target, randomTargetCells.Random(firedBy.World.SharedRandom), damageModifiers); + FireProjectileAtCell(map, firedBy, target, randomTargetCells.Random(firedBy.World.SharedRandom), args); } } - void FireProjectileAtCell(Map map, Actor firedBy, Target target, CPos targetCell, IEnumerable damageModifiers) + void FireProjectileAtCell(Map map, Actor firedBy, Target target, CPos targetCell, WarheadArgs args) { var tc = Target.FromCell(firedBy.World, targetCell); if (!weapon.IsValidAgainst(tc, firedBy.World, firedBy)) return; - var args = new ProjectileArgs + var projectileArgs = new ProjectileArgs { Weapon = weapon, - Facing = (map.CenterOfCell(targetCell) - target.CenterPosition).Yaw.Facing, + Facing = (map.CenterOfCell(targetCell) - target.CenterPosition).Yaw, + CurrentMuzzleFacing = () => (map.CenterOfCell(targetCell) - target.CenterPosition).Yaw, - DamageModifiers = damageModifiers.ToArray(), + DamageModifiers = args.DamageModifiers, InaccuracyModifiers = new int[0], RangeModifiers = new int[0], @@ -91,14 +90,14 @@ GuidedTarget = tc }; - if (args.Weapon.Projectile != null) + if (projectileArgs.Weapon.Projectile != null) { - var projectile = args.Weapon.Projectile.Create(args); + var projectile = projectileArgs.Weapon.Projectile.Create(projectileArgs); if (projectile != null) firedBy.World.AddFrameEndTask(w => w.Add(projectile)); - if (args.Weapon.Report != null && args.Weapon.Report.Any()) - Game.Sound.Play(SoundType.World, args.Weapon.Report, firedBy.World, target.CenterPosition); + if (projectileArgs.Weapon.Report != null && projectileArgs.Weapon.Report.Any()) + Game.Sound.Play(SoundType.World, projectileArgs.Weapon.Report, firedBy.World, target.CenterPosition); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/FlashPaletteEffectWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/FlashPaletteEffectWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/FlashPaletteEffectWarhead.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/FlashPaletteEffectWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,35 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using OpenRA.GameRules; +using OpenRA.Mods.Common.Traits; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Warheads +{ + [Desc("Used to trigger a FlashPaletteEffect trait on the world actor.")] + public class FlashPaletteEffectWarhead : Warhead + { + [Desc("Corresponds to `Type` from `FlashPaletteEffect` on the world actor.")] + public readonly string FlashType = null; + + [FieldLoader.Require] + [Desc("Duration of the flashing, measured in ticks. Set to -1 to default to the `Length` of the `FlashPaletteEffect`.")] + public readonly int Duration = 0; + + public override void DoImpact(in Target target, WarheadArgs args) + { + foreach (var flash in args.SourceActor.World.WorldActor.TraitsImplementing()) + if (flash.Info.Type == FlashType) + flash.Enable(Duration); + } + } +} diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/GrantExternalConditionWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/GrantExternalConditionWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/GrantExternalConditionWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/GrantExternalConditionWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Collections.Generic; using System.Linq; using OpenRA.GameRules; using OpenRA.Mods.Common.Traits; @@ -28,7 +27,7 @@ public readonly WDist Range = WDist.FromCells(1); - public override void DoImpact(Target target, WarheadArgs args) + public override void DoImpact(in Target target, WarheadArgs args) { var firedBy = args.SourceActor; var actors = target.Type == TargetType.Actor ? new[] { target.Actor } : @@ -39,11 +38,9 @@ if (!IsValidAgainst(a, firedBy)) continue; - var external = a.TraitsImplementing() - .FirstOrDefault(t => t.Info.Condition == Condition && t.CanGrantCondition(a, firedBy)); - - if (external != null) - external.GrantCondition(a, firedBy, Duration); + a.TraitsImplementing() + .FirstOrDefault(t => t.Info.Condition == Condition && t.CanGrantCondition(a, firedBy)) + ?.GrantCondition(a, firedBy, Duration); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/HealthPercentageDamageWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/HealthPercentageDamageWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/HealthPercentageDamageWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/HealthPercentageDamageWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,7 @@ */ #endregion -using System.Collections.Generic; +using OpenRA.GameRules; using OpenRA.Mods.Common.Traits; using OpenRA.Traits; @@ -17,10 +17,10 @@ { public class HealthPercentageDamageWarhead : TargetDamageWarhead { - protected override void InflictDamage(Actor victim, Actor firedBy, HitShapeInfo hitshapeInfo, IEnumerable damageModifiers) + protected override void InflictDamage(Actor victim, Actor firedBy, HitShape shape, WarheadArgs args) { var healthInfo = victim.Info.TraitInfo(); - var damage = Util.ApplyPercentageModifiers(healthInfo.HP, damageModifiers.Append(Damage, DamageVersus(victim, hitshapeInfo))); + var damage = Util.ApplyPercentageModifiers(healthInfo.HP, args.DamageModifiers.Append(Damage, DamageVersus(victim, shape, args))); victim.InflictDamage(firedBy, new Damage(damage, DamageTypes)); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/LeaveSmudgeWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/LeaveSmudgeWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/LeaveSmudgeWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/LeaveSmudgeWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,14 +26,14 @@ [Desc("Type of smudge to apply to terrain.")] public readonly HashSet SmudgeType = new HashSet(); - [Desc("How close to ground must the impact happen to spawn smudges.")] - public readonly WDist AirThreshold = new WDist(128); - [Desc("Percentual chance the smudge is created.")] public readonly int Chance = 100; - public override void DoImpact(Target target, WarheadArgs args) + public override void DoImpact(in Target target, WarheadArgs args) { + if (target.Type == TargetType.Invalid) + return; + var firedBy = args.SourceActor; var world = firedBy.World; @@ -63,8 +63,7 @@ if (cellActors.Any(a => !IsValidAgainst(a, firedBy))) continue; - SmudgeLayer smudgeLayer; - if (!smudgeLayers.TryGetValue(smudgeType, out smudgeLayer)) + if (!smudgeLayers.TryGetValue(smudgeType, out var smudgeLayer)) throw new NotImplementedException("Unknown smudge type `{0}`".F(smudgeType)); smudgeLayer.AddSmudge(sc); diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/ShakeScreenWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/ShakeScreenWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/ShakeScreenWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/ShakeScreenWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,7 +26,7 @@ [Desc("Shake multipliers by the X and Y axis, comma-separated.")] public readonly float2 Multiplier = new float2(0, 0); - public override void DoImpact(Target target, WarheadArgs args) + public override void DoImpact(in Target target, WarheadArgs args) { args.SourceActor.World.WorldActor.Trait().AddEffect(Duration, target.CenterPosition, Intensity, Multiplier); } diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/SpreadDamageWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/SpreadDamageWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/SpreadDamageWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/SpreadDamageWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Collections.Generic; using System.Linq; using OpenRA.GameRules; using OpenRA.Mods.Common.Traits; @@ -18,6 +17,8 @@ namespace OpenRA.Mods.Common.Warheads { + public enum DamageCalculationType { HitShape, ClosestTargetablePosition, CenterPosition } + public class SpreadDamageWarhead : DamageWarhead, IRulesetLoaded { [Desc("Range between falloff steps.")] @@ -29,6 +30,9 @@ [Desc("Ranges at which each Falloff step is defined. Overrides Spread.")] public WDist[] Range = null; + [Desc("Controls the way damage is calculated. Possible values are 'HitShape', 'ClosestTargetablePosition' and 'CenterPosition'.")] + public readonly DamageCalculationType DamageCalculationType = DamageCalculationType.HitShape; + void IRulesetLoaded.RulesetLoaded(Ruleset rules, WeaponInfo info) { if (Range != null) @@ -44,7 +48,7 @@ Range = Exts.MakeArray(Falloff.Length, i => i * Spread); } - public override void DoImpact(WPos pos, Actor firedBy, IEnumerable damageModifiers) + protected override void DoImpact(WPos pos, Actor firedBy, WarheadArgs args) { var debugVis = firedBy.World.WorldActor.TraitOrDefault(); if (debugVis != null && debugVis.CombatGeometry) @@ -57,15 +61,50 @@ var closestActiveShape = victim.TraitsImplementing() .Where(Exts.IsTraitEnabled) - .Select(s => Pair.New(s, s.DistanceFromEdge(victim, pos))) - .MinByOrDefault(s => s.Second); + .Select(s => (HitShape: s, Distance: s.DistanceFromEdge(victim, pos))) + .MinByOrDefault(s => s.Distance); - // Cannot be damaged without an active HitShape - if (closestActiveShape.First == null) + // Cannot be damaged without an active HitShape. + if (closestActiveShape.HitShape == null) continue; - var localModifiers = damageModifiers.Append(GetDamageFalloff(closestActiveShape.Second.Length)); - InflictDamage(victim, firedBy, closestActiveShape.First.Info, localModifiers); + var falloffDistance = 0; + switch (DamageCalculationType) + { + case DamageCalculationType.HitShape: + falloffDistance = closestActiveShape.Distance.Length; + break; + case DamageCalculationType.ClosestTargetablePosition: + falloffDistance = victim.GetTargetablePositions().Select(x => (x - pos).Length).Min(); + break; + case DamageCalculationType.CenterPosition: + falloffDistance = (victim.CenterPosition - pos).Length; + break; + } + + // The range to target is more than the range the warhead covers, so GetDamageFalloff() is going to give us 0 and we're going to do 0 damage anyway, so bail early. + if (falloffDistance > Range[Range.Length - 1].Length) + continue; + + var localModifiers = args.DamageModifiers.Append(GetDamageFalloff(falloffDistance)); + var impactOrientation = args.ImpactOrientation; + + // If a warhead lands outside the victim's HitShape, we need to calculate the vertical and horizontal impact angles + // from impact position, rather than last projectile facing/angle. + if (falloffDistance > 0) + { + var towardsTargetYaw = (victim.CenterPosition - args.ImpactPosition).Yaw; + var impactAngle = Util.GetVerticalAngle(args.ImpactPosition, victim.CenterPosition); + impactOrientation = new WRot(WAngle.Zero, impactAngle, towardsTargetYaw); + } + + var updatedWarheadArgs = new WarheadArgs(args) + { + DamageModifiers = localModifiers.ToArray(), + ImpactOrientation = impactOrientation, + }; + + InflictDamage(victim, firedBy, closestActiveShape.HitShape, updatedWarheadArgs); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/TargetDamageWarhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/TargetDamageWarhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/TargetDamageWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/TargetDamageWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,8 +9,8 @@ */ #endregion -using System.Collections.Generic; using System.Linq; +using OpenRA.GameRules; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; using OpenRA.Traits; @@ -22,7 +22,7 @@ [Desc("Damage will be applied to actors in this area. A value of zero means only targeted actor will be damaged.")] public readonly WDist Spread = WDist.Zero; - public override void DoImpact(WPos pos, Actor firedBy, IEnumerable damageModifiers) + protected override void DoImpact(WPos pos, Actor firedBy, WarheadArgs args) { if (Spread == WDist.Zero) return; @@ -38,14 +38,18 @@ var closestActiveShape = victim.TraitsImplementing() .Where(Exts.IsTraitEnabled) - .Select(s => Pair.New(s, s.DistanceFromEdge(victim, pos))) - .MinByOrDefault(s => s.Second); + .Select(s => (HitShape: s, Distance: s.DistanceFromEdge(victim, pos))) + .MinByOrDefault(s => s.Distance); - // Cannot be damaged without an active HitShape or if HitShape is outside Spread - if (closestActiveShape.First == null || closestActiveShape.Second > Spread) + // Cannot be damaged without an active HitShape. + if (closestActiveShape.HitShape == null) continue; - InflictDamage(victim, firedBy, closestActiveShape.First.Info, damageModifiers); + // Cannot be damaged if HitShape is outside Spread. + if (closestActiveShape.Distance > Spread) + continue; + + InflictDamage(victim, firedBy, closestActiveShape.HitShape, args); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Warheads/Warhead.cs openra-20210321/OpenRA.Mods.Common/Warheads/Warhead.cs --- openra-20200503/OpenRA.Mods.Common/Warheads/Warhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Warheads/Warhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,26 +9,17 @@ */ #endregion -using System.Collections.Generic; using OpenRA.GameRules; using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Warheads { - public enum ImpactType + public enum ImpactActorType { None, - Ground, - Air, - TargetHit - } - - public enum ImpactTargetType - { - NoActor, - ValidActor, - InvalidActor + Invalid, + Valid, } [Desc("Base warhead class. This can be used to derive other warheads from.")] @@ -40,12 +31,15 @@ [Desc("What types of targets are unaffected.", "Overrules ValidTargets.")] public readonly BitSet InvalidTargets; - [Desc("What diplomatic stances are affected.")] - public readonly Stance ValidStances = Stance.Ally | Stance.Neutral | Stance.Enemy; + [Desc("What player relationships are affected.")] + public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy; [Desc("Can this warhead affect the actor that fired it.")] public readonly bool AffectsParent = false; + [Desc("If impact is above this altitude, warheads that would affect terrain ignore terrain target types (and either do nothing or perform their own checks).")] + public readonly WDist AirThreshold = new WDist(128); + [Desc("Delay in ticks before applying the warhead effect.", "0 = instant (old model).")] public readonly int Delay = 0; @@ -54,13 +48,13 @@ [Desc("The color used for this warhead's visualization in the world's `WarheadDebugOverlay` trait.")] public readonly Color DebugOverlayColor = Color.Red; - public bool IsValidTarget(BitSet targetTypes) + protected bool IsValidTarget(BitSet targetTypes) { return ValidTargets.Overlaps(targetTypes) && !InvalidTargets.Overlaps(targetTypes); } /// Applies the warhead's effect against the target. - public abstract void DoImpact(Target target, WarheadArgs args); + public abstract void DoImpact(in Target target, WarheadArgs args); /// Checks if the warhead is valid against (can do something to) the actor. public virtual bool IsValidAgainst(Actor victim, Actor firedBy) @@ -68,8 +62,8 @@ if (!AffectsParent && victim == firedBy) return false; - var stance = firedBy.Owner.Stances[victim.Owner]; - if (!ValidStances.HasStance(stance)) + var stance = firedBy.Owner.RelationshipWith(victim.Owner); + if (!ValidRelationships.HasStance(stance)) return false; // A target type is valid if it is in the valid targets list, and not in the invalid targets list. @@ -86,8 +80,8 @@ return false; // AffectsParent checks do not make sense for FrozenActors, so skip to stance checks - var stance = firedBy.Owner.Stances[victim.Owner]; - if (!ValidStances.HasStance(stance)) + var stance = firedBy.Owner.RelationshipWith(victim.Owner); + if (!ValidRelationships.HasStance(stance)) return false; // A target type is valid if it is in the valid targets list, and not in the invalid targets list. diff -Nru openra-20200503/OpenRA.Mods.Common/WebServices.cs openra-20210321/OpenRA.Mods.Common/WebServices.cs --- openra-20200503/OpenRA.Mods.Common/WebServices.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/WebServices.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,6 +23,7 @@ public readonly string ServerAdvertise = "https://master.openra.net/ping"; public readonly string MapRepository = "https://resource.openra.net/map/"; public readonly string GameNews = "https://master.openra.net/gamenews"; + public readonly string GameNewsFileName = "news.yaml"; public readonly string VersionCheck = "https://master.openra.net/versioncheck"; public ModVersionStatus ModVersionStatus { get; private set; } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -67,7 +67,7 @@ renderables = preview .SelectMany(p => p.RenderUI(worldRenderer, origin, scale)) - .OrderBy(WorldRenderer.RenderableScreenZPositionComparisonKey) + .OrderBy(WorldRenderer.RenderableZPositionComparisonKey) .Select(r => r.PrepareRender(worldRenderer)) .ToArray(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ButtonWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ButtonWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ButtonWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ButtonWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -249,7 +249,8 @@ var position = GetTextPosition(text, font, rb); - var hover = Ui.MouseOverWidget == this || Children.Any(c => c == Ui.MouseOverWidget); + // PERF: Avoid LINQ by using Children.Find(...) != null instead of Children.Any(...) + var hover = Ui.MouseOverWidget == this || Children.Find(c => c == Ui.MouseOverWidget) != null; DrawBackground(rb, disabled, Depressed, hover, highlighted); if (Contrast) font.DrawTextWithContrast(text, position + stateOffset, @@ -292,13 +293,10 @@ if (string.IsNullOrEmpty(baseName)) return; - var variant = highlighted ? "-highlighted" : ""; - var state = disabled ? "-disabled" : - pressed ? "-pressed" : - hover ? "-hover" : - ""; + var variantName = highlighted ? baseName + "-highlighted" : baseName; + var imageName = WidgetUtils.GetStatefulImageName(variantName, disabled, pressed, hover); - WidgetUtils.DrawPanel(baseName + variant + state, rect); + WidgetUtils.DrawPanel(imageName, rect); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/CheckboxWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/CheckboxWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/CheckboxWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/CheckboxWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -44,7 +44,6 @@ public override void Draw() { var disabled = IsDisabled(); - var highlighted = IsHighlighted(); var font = Game.Renderer.Fonts[Font]; var color = GetColor(); var colordisabled = GetColorDisabled(); @@ -54,11 +53,8 @@ var text = GetText(); var textSize = font.Measure(text); var check = new Rectangle(rect.Location, new Size(Bounds.Height, Bounds.Height)); - var state = disabled ? "checkbox-disabled" : - highlighted ? "checkbox-highlighted" : - Depressed && HasPressedState ? "checkbox-pressed" : - Ui.MouseOverWidget == this ? "checkbox-hover" : - "checkbox"; + var baseName = IsHighlighted() ? "checkbox-highlighted" : "checkbox"; + var state = WidgetUtils.GetStatefulImageName(baseName, disabled, Depressed && HasPressedState, Ui.MouseOverWidget == this); WidgetUtils.DrawPanel(state, check); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ColorMixerWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ColorMixerWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ColorMixerWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ColorMixerWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -235,9 +235,7 @@ public void Set(Color color) { - float h, s, v; - int a; - color.ToAhsv(out a, out h, out s, out v); + color.ToAhsv(out _, out var h, out var s, out var v); if (H != h || S != s || V != v) { diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ConfirmationDialogs.cs openra-20210321/OpenRA.Mods.Common/Widgets/ConfirmationDialogs.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ConfirmationDialogs.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ConfirmationDialogs.cs 2021-03-21 11:10:05.000000000 +0000 @@ -71,11 +71,10 @@ cancelButton.OnClick = () => { Ui.CloseWindow(); - if (onCancel != null) - onCancel(); + onCancel(); }; - if (!string.IsNullOrEmpty(cancelText) && cancelButton != null) + if (!string.IsNullOrEmpty(cancelText)) cancelButton.GetText = () => cancelText; } @@ -85,11 +84,10 @@ otherButton.Bounds.Y += headerHeight; otherButton.OnClick = () => { - if (onOther != null) - onOther(); + onOther(); }; - if (!string.IsNullOrEmpty(otherText) && otherButton != null) + if (!string.IsNullOrEmpty(otherText)) otherButton.GetText = () => otherText; } } @@ -156,8 +154,7 @@ cancelButton.OnClick = () => { Ui.CloseWindow(); - if (onCancel != null) - onCancel(); + onCancel?.Invoke(); }; // Validation diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/DropDownButtonWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/DropDownButtonWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/DropDownButtonWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/DropDownButtonWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenRA.Graphics; using OpenRA.Primitives; using OpenRA.Widgets; @@ -19,7 +20,9 @@ { public class DropDownButtonWidget : ButtonWidget { - public readonly string SeparatorCollection = "dropdown"; + public readonly string Decorations = "dropdown-decorations"; + public readonly string DecorationMarker = "marker"; + public readonly string Separators = "dropdown-separators"; public readonly string SeparatorImage = "separator"; public readonly TextAlign PanelAlign = TextAlign.Left; @@ -45,13 +48,20 @@ base.Draw(); var stateOffset = Depressed ? new int2(VisualHeight, VisualHeight) : new int2(0, 0); - var image = ChromeProvider.GetImage("scrollbar", IsDisabled() ? "down_pressed" : "down_arrow"); var rb = RenderBounds; + var isDisabled = IsDisabled(); + var isHover = Ui.MouseOverWidget == this || Children.Any(c => c == Ui.MouseOverWidget); - WidgetUtils.DrawRGBA(image, stateOffset + new float2(rb.Right - (int)((rb.Height + image.Size.X) / 2), rb.Top + (int)((rb.Height - image.Size.Y) / 2))); + var markerImageName = WidgetUtils.GetStatefulImageName(DecorationMarker, isDisabled, Depressed, isHover); + var arrowImage = ChromeProvider.GetImage(Decorations, markerImageName) ?? ChromeProvider.GetImage(Decorations, DecorationMarker); - var separator = ChromeProvider.GetImage(SeparatorCollection, SeparatorImage); - WidgetUtils.DrawRGBA(separator, stateOffset + new float2(-3, 0) + new float2(rb.Right - rb.Height + 4, rb.Top + (rb.Height - separator.Size.Y) / 2)); + WidgetUtils.DrawRGBA(arrowImage, stateOffset + new float2(rb.Right - (int)((rb.Height + arrowImage.Size.X) / 2), rb.Top + (int)((rb.Height - arrowImage.Size.Y) / 2))); + + var separatorImageName = WidgetUtils.GetStatefulImageName(SeparatorImage, isDisabled, Depressed, isHover); + var separatorImage = ChromeProvider.GetImage(Separators, separatorImageName) ?? ChromeProvider.GetImage(Separators, SeparatorImage); + + if (separatorImage != null) + WidgetUtils.DrawRGBA(separatorImage, stateOffset + new float2(-3, 0) + new float2(rb.Right - rb.Height + 4, rb.Top + (int)((rb.Height - separatorImage.Size.Y) / 2))); } public override Widget Clone() { return new DropDownButtonWidget(this); } @@ -119,9 +129,7 @@ oldBounds.Height); panelRoot.AddChild(panel); - var scrollPanel = panel as ScrollPanelWidget; - if (scrollPanel != null) - scrollPanel.ScrollToSelectedItem(); + (panel as ScrollPanelWidget)?.ScrollToSelectedItem(); } public void ShowDropDown(string panelTemplate, int maxHeight, IEnumerable options, Func setupItem) diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/EditorViewportControllerWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/EditorViewportControllerWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/EditorViewportControllerWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/EditorViewportControllerWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -52,8 +52,7 @@ public void ClearBrush() { SetBrush(null); } public void SetBrush(IEditorBrush brush) { - if (CurrentBrush != null) - CurrentBrush.Dispose(); + CurrentBrush?.Dispose(); CurrentBrush = brush ?? DefaultBrush; } @@ -87,7 +86,7 @@ { if (mi.Event == MouseInputEvent.Scroll && mi.Modifiers.HasModifier(Game.Settings.Game.ZoomModifier)) { - worldRenderer.Viewport.AdjustZoom(mi.Delta.Y * Game.Settings.Game.ZoomSpeed); + worldRenderer.Viewport.AdjustZoom(mi.Delta.Y * Game.Settings.Game.ZoomSpeed, mi.Location); return true; } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/HotkeyEntryWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/HotkeyEntryWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/HotkeyEntryWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/HotkeyEntryWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,6 +24,7 @@ public int LeftMargin = 5; public int RightMargin = 5; + public Action OnEscKey = () => { }; public Action OnLoseFocus = () => { }; public Func IsDisabled = () => false; @@ -86,7 +87,8 @@ Keycode.RSHIFT, Keycode.LSHIFT, Keycode.RCTRL, Keycode.LCTRL, Keycode.RALT, Keycode.LALT, - Keycode.RGUI, Keycode.LGUI + Keycode.RGUI, Keycode.LGUI, + Keycode.RETURN, Keycode.KP_ENTER }; public override bool HandleKeyPress(KeyInput e) @@ -97,8 +99,16 @@ if (!HasKeyboardFocus || IgnoreKeys.Contains(e.Key)) return false; - if (e.Key != Keycode.ESCAPE && e.Key != Keycode.RETURN && e.Key != Keycode.KP_ENTER) - Key = Hotkey.FromKeyInput(e); + switch (e.Key) + { + case Keycode.ESCAPE: + OnEscKey(); + break; + + default: + Key = Hotkey.FromKeyInput(e); + break; + } YieldKeyboardFocus(); @@ -128,10 +138,7 @@ var disabled = IsDisabled(); var valid = IsValid(); - var state = disabled ? "textfield-disabled" : - HasKeyboardFocus ? "textfield-focused" : - Ui.MouseOverWidget == this ? "textfield-hover" : - "textfield"; + var state = WidgetUtils.GetStatefulImageName("textfield", disabled, false, Ui.MouseOverWidget == this, HasKeyboardFocus); WidgetUtils.DrawPanel(state, RenderBounds); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/HueSliderWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/HueSliderWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/HueSliderWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/HueSliderWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,6 +18,7 @@ public class HueSliderWidget : SliderWidget { Sprite hueSprite; + Sprite pickerSprite; public HueSliderWidget() { } public HueSliderWidget(HueSliderWidget other) @@ -35,6 +36,8 @@ hueData[0, x] = (uint)Color.FromAhsv(x / 255f, 1, 1).ToArgb(); hueSheet.GetTexture().SetData(hueData); + + pickerSprite = ChromeProvider.GetImage("lobby-bits", "huepicker"); } public override void Draw() @@ -46,9 +49,8 @@ var rb = RenderBounds; Game.Renderer.RgbaSpriteRenderer.DrawSprite(hueSprite, ro, new float2(rb.Size)); - var sprite = ChromeProvider.GetImage("lobby-bits", "huepicker"); - var pos = RenderOrigin + new int2(PxFromValue(Value).Clamp(0, rb.Width - 1) - (int)sprite.Size.X / 2, (rb.Height - (int)sprite.Size.Y) / 2); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(sprite, pos); + var pos = RenderOrigin + new int2(PxFromValue(Value).Clamp(0, rb.Width - 1) - (int)pickerSprite.Size.X / 2, (rb.Height - (int)pickerSprite.Size.Y) / 2); + Game.Renderer.RgbaSpriteRenderer.DrawSprite(pickerSprite, pos); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/LabelWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/LabelWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/LabelWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/LabelWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -68,8 +68,7 @@ public override void Draw() { - SpriteFont font; - if (!Game.Renderer.Fonts.TryGetValue(Font, out font)) + if (!Game.Renderer.Fonts.TryGetValue(Font, out var font)) throw new ArgumentException("Requested font '{0}' was not found.".F(Font)); var text = GetText(); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/LabelWithHighlightWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/LabelWithHighlightWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/LabelWithHighlightWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/LabelWithHighlightWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System; using System.Collections.Generic; -using System.Linq; using OpenRA.Graphics; using OpenRA.Primitives; using OpenRA.Widgets; @@ -21,25 +20,25 @@ public class LabelWithHighlightWidget : LabelWidget { public Color HighlightColor = ChromeMetrics.Get("TextHighlightColor"); - readonly CachedTransform[]> textComponents; + readonly CachedTransform textComponents; [ObjectCreator.UseCtor] public LabelWithHighlightWidget() : base() { - textComponents = new CachedTransform[]>(MakeComponents); + textComponents = new CachedTransform(MakeComponents); } protected LabelWithHighlightWidget(LabelWithHighlightWidget other) : base(other) { HighlightColor = other.HighlightColor; - textComponents = new CachedTransform[]>(MakeComponents); + textComponents = new CachedTransform(MakeComponents); } - Pair[] MakeComponents(string text) + (string, bool)[] MakeComponents(string text) { - List> components = new List>(); + var components = new List<(string, bool)>(); foreach (var l in text.Split(new[] { "\\n" }, StringSplitOptions.None)) { var line = l; @@ -51,22 +50,19 @@ if (highlightStart > 0 && highlightEnd > highlightStart) { - if (highlightStart > 0) - { - // Normal line segment before highlight - var lineNormal = line.Substring(0, highlightStart); - components.Add(Pair.New(lineNormal, false)); - } + // Normal line segment before highlight + var lineNormal = line.Substring(0, highlightStart); + components.Add((lineNormal, false)); // Highlight line segment var lineHighlight = line.Substring(highlightStart + 1, highlightEnd - highlightStart - 1); - components.Add(Pair.New(lineHighlight, true)); + components.Add((lineHighlight, true)); line = line.Substring(highlightEnd + 1); } else { // Final normal line segment - components.Add(Pair.New(line, false)); + components.Add((line, false)); break; } } @@ -80,8 +76,8 @@ var advance = 0; foreach (var c in textComponents.Update(text)) { - base.DrawInner(c.First, font, c.Second ? HighlightColor : color, position + new int2(advance, 0)); - advance += font.Measure(c.First).X; + base.DrawInner(c.Text, font, c.Highlighted ? HighlightColor : color, position + new int2(advance, 0)); + advance += font.Measure(c.Text).X; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -69,14 +69,8 @@ if (sourceDropdown != null) { sourceDropdown.OnMouseDown = _ => ShowSourceDropdown(sourceDropdown); - sourceDropdown.GetText = () => - { - var name = assetSource != null ? Platform.UnresolvePath(assetSource.Name) : "All Packages"; - if (name.Length > 15) - name = "..." + name.Substring(name.Length - 15); - - return name; - }; + var sourceName = new CachedTransform(GetSourceDisplayName); + sourceDropdown.GetText = () => sourceName.Update(assetSource); } var spriteWidget = panel.GetOrNull("SPRITE"); @@ -124,7 +118,7 @@ frameContainer.IsVisible = () => (currentSprites != null && currentSprites.Length > 1) || (isVideoLoaded && player != null && player.Video != null && player.Video.Frames > 1); - frameSlider = panel.Get("FRAME_SLIDER"); + frameSlider = panel.GetOrNull("FRAME_SLIDER"); if (frameSlider != null) { frameSlider.OnChange += x => @@ -183,7 +177,9 @@ player.Stop(); else { - frameSlider.Value = 0; + if (frameSlider != null) + frameSlider.Value = 0; + currentFrame = 0; animateFrames = false; } @@ -272,10 +268,8 @@ // Select the first visible var firstVisible = assetVisByName.FirstOrDefault(kvp => kvp.Value); - IReadOnlyPackage package; - string filename; - if (firstVisible.Key != null && modData.DefaultFileSystem.TryGetPackageContaining(firstVisible.Key, out package, out filename)) + if (firstVisible.Key != null && modData.DefaultFileSystem.TryGetPackageContaining(firstVisible.Key, out var package, out var filename)) LoadAsset(package, filename); } @@ -290,8 +284,7 @@ item.IsVisible = () => { - bool visible; - if (assetVisByName.TryGetValue(filepath, out visible)) + if (assetVisByName.TryGetValue(filepath, out var visible)) return visible; visible = FilterAsset(filepath); @@ -339,15 +332,23 @@ player.Load(prefix + filename); player.DrawOverlay = false; isVideoLoaded = true; - frameSlider.MaximumValue = (float)player.Video.Frames - 1; - frameSlider.Ticks = 0; + + if (frameSlider != null) + { + frameSlider.MaximumValue = (float)player.Video.Frames - 1; + frameSlider.Ticks = 0; + } + return true; } currentSprites = world.Map.Rules.Sequences.SpriteCache[prefix + filename]; currentFrame = 0; - frameSlider.MaximumValue = (float)currentSprites.Length - 1; - frameSlider.Ticks = currentSprites.Length; + if (frameSlider != null) + { + frameSlider.MaximumValue = (float)currentSprites.Length - 1; + frameSlider.Ticks = currentSprites.Length; + } } catch (Exception ex) { @@ -363,12 +364,14 @@ bool ShowSourceDropdown(DropDownButtonWidget dropdown) { + var sourceName = new CachedTransform(GetSourceDisplayName); Func setupItem = (source, itemTemplate) => { var item = ScrollItemWidget.Setup(itemTemplate, () => assetSource == source, () => { assetSource = source; PopulateAssetList(); }); - item.Get("LABEL").GetText = () => source != null ? Platform.UnresolvePath(source.Name) : "All Packages"; + + item.Get("LABEL").GetText = () => sourceName.Update(source); return item; }; @@ -427,5 +430,33 @@ dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, palettes, setupItem); return true; } + + string GetSourceDisplayName(IReadOnlyPackage source) + { + if (source == null) + return "All Packages"; + + // Packages that are explicitly mounted in the filesystem use their explicit mount name + var fs = (OpenRA.FileSystem.FileSystem)modData.DefaultFileSystem; + var name = fs.GetPrefix(source); + + // Fall back to the path relative to the mod, engine, or support dir + if (name == null) + { + name = source.Name; + var compare = Platform.CurrentPlatform == PlatformType.Windows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + if (name.StartsWith(modData.Manifest.Package.Name, compare)) + name = "$" + modData.Manifest.Id + "/" + name.Substring(modData.Manifest.Package.Name.Length + 1); + else if (name.StartsWith(Platform.EngineDir, compare)) + name = "./" + name.Substring(Platform.EngineDir.Length); + else if (name.StartsWith(Platform.SupportDir, compare)) + name = "^" + name.Substring(Platform.SupportDir.Length); + } + + if (name.Length > 18) + name = "..." + name.Substring(name.Length - 15); + + return name; + } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; using OpenRA.Widgets; @@ -28,8 +27,7 @@ public ColorPickerLogic(Widget widget, ModData modData, World world, Color initialColor, string initialFaction, Action onChange, Dictionary logicArgs) { - string actorType; - if (initialFaction == null || !ChromeMetrics.TryGet("ColorPickerActorType-" + initialFaction, out actorType)) + if (initialFaction == null || !ChromeMetrics.TryGet("ColorPickerActorType-" + initialFaction, out string actorType)) actorType = ChromeMetrics.Get("ColorPickerActorType"); var preview = widget.GetOrNull("PREVIEW"); @@ -42,8 +40,7 @@ foreach (var o in api.ActorPreviewInits(actor, ActorPreviewType.ColorPicker)) td.Add(o); - if (preview != null) - preview.SetPreview(actor, td); + preview?.SetPreview(actor, td); var hueSlider = widget.Get("HUE"); var mixer = widget.Get("MIXER"); @@ -104,8 +101,7 @@ var palettePresetRows = 2; var paletteCustomRows = 1; - MiniYaml yaml; - if (logicArgs.TryGetValue("PaletteColumns", out yaml)) + if (logicArgs.TryGetValue("PaletteColumns", out var yaml)) if (!int.TryParse(yaml.Value, out paletteCols)) throw new YamlException("Invalid value for PaletteColumns: {0}".F(yaml.Value)); if (logicArgs.TryGetValue("PalettePresetRows", out yaml)) @@ -190,9 +186,7 @@ static float HueFromColor(Color c) { - float h, s, v; - int a; - c.ToAhsv(out a, out h, out s, out v); + c.ToAhsv(out _, out var h, out _, out _); return h; } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System; using OpenRA.Network; -using OpenRA.Primitives; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic @@ -49,7 +48,7 @@ } [ObjectCreator.UseCtor] - public ConnectionLogic(Widget widget, string host, int port, Action onConnect, Action onAbort, Action onRetry) + public ConnectionLogic(Widget widget, ConnectionTarget endpoint, Action onConnect, Action onAbort, Action onRetry) { this.onConnect = onConnect; this.onAbort = onAbort; @@ -61,18 +60,17 @@ panel.Get("ABORT_BUTTON").OnClick = () => { CloseWindow(); onAbort(); }; widget.Get("CONNECTING_DESC").GetText = () => - "Connecting to {0}:{1}...".F(host, port); + "Connecting to {0}...".F(endpoint); } - public static void Connect(string host, int port, string password, Action onConnect, Action onAbort) + public static void Connect(ConnectionTarget endpoint, string password, Action onConnect, Action onAbort) { - Game.JoinServer(host, port, password); - Action onRetry = newPassword => Connect(host, port, newPassword, onConnect, onAbort); + Game.JoinServer(endpoint, password); + Action onRetry = newPassword => Connect(endpoint, newPassword, onConnect, onAbort); Ui.OpenWindow("CONNECTING_PANEL", new WidgetArgs() { - { "host", host }, - { "port", port }, + { "endpoint", endpoint }, { "onConnect", onConnect }, { "onAbort", onAbort }, { "onRetry", onRetry } @@ -105,10 +103,10 @@ }; widget.Get("CONNECTING_DESC").GetText = () => - "Could not connect to {0}:{1}".F(orderManager.Host, orderManager.Port); + "Could not connect to {0}".F(orderManager.Endpoint); var connectionError = widget.Get("CONNECTION_ERROR"); - connectionError.GetText = () => orderManager.ServerError; + connectionError.GetText = () => orderManager.ServerError ?? orderManager.Connection.ErrorMessage ?? "Unknown error"; var panelTitle = widget.Get("TITLE"); panelTitle.GetText = () => orderManager.AuthenticationFailed ? "Password Required" : "Connection Failed"; @@ -165,7 +163,7 @@ switchButton.OnClick = () => { - var launchCommand = "Launch.Connect=" + orderManager.Host + ":" + orderManager.Port; + var launchCommand = "Launch.URI={0}".F(new UriBuilder("tcp", orderManager.Connection.EndPoint.Address.ToString(), orderManager.Connection.EndPoint.Port)); Game.SwitchToExternalMod(orderManager.ServerExternalMod, new[] { launchCommand }, () => { orderManager.ServerError = "Failed to switch mod."; @@ -219,23 +217,23 @@ return mod.Icon; }; - } - - if (logo != null && mod.Icon == null) - { - // Hide the logo and center just the text - if (title != null) - title.Bounds.X = logo.Bounds.Left; - - if (version != null) - version.Bounds.X = logo.Bounds.X; - width -= logo.Bounds.Width; - } - else - { - // Add an equal logo margin on the right of the text - width += logo.Bounds.Width; + if (mod.Icon == null) + { + // Hide the logo and center just the text + if (title != null) + title.Bounds.X = logo.Bounds.X; + + if (version != null) + version.Bounds.X = logo.Bounds.X; + + width -= logo.Bounds.Width; + } + else + { + // Add an equal logo margin on the right of the text + width += logo.Bounds.Width; + } } var container = panel.GetOrNull("MOD_CONTAINER"); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/DirectConnectLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/DirectConnectLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/DirectConnectLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/DirectConnectLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,6 +10,7 @@ #endregion using System; +using OpenRA.Network; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic @@ -19,15 +20,24 @@ static readonly Action DoNothing = () => { }; [ObjectCreator.UseCtor] - public DirectConnectLogic(Widget widget, Action onExit, Action openLobby, string directConnectHost, int directConnectPort) + public DirectConnectLogic(Widget widget, Action onExit, Action openLobby, ConnectionTarget directConnectEndPoint) { var panel = widget; var ipField = panel.Get("IP"); var portField = panel.Get("PORT"); - var last = Game.Settings.Player.LastServer.Split(':'); - ipField.Text = last.Length > 1 ? last[0] : "localhost"; - portField.Text = last.Length == 2 ? last[1] : "1234"; + var text = Game.Settings.Player.LastServer; + var last = text.LastIndexOf(':'); + if (last < 0) + { + ipField.Text = "localhost"; + portField.Text = "1234"; + } + else + { + ipField.Text = text.Substring(0, last); + portField.Text = text.Substring(last + 1); + } panel.Get("JOIN_BUTTON").OnClick = () => { @@ -36,19 +46,19 @@ Game.Settings.Player.LastServer = "{0}:{1}".F(ipField.Text, port); Game.Settings.Save(); - ConnectionLogic.Connect(ipField.Text, port, "", () => { Ui.CloseWindow(); openLobby(); }, DoNothing); + ConnectionLogic.Connect(new ConnectionTarget(ipField.Text, port), "", () => { Ui.CloseWindow(); openLobby(); }, DoNothing); }; panel.Get("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; - if (directConnectHost != null) + if (directConnectEndPoint != null) { // The connection window must be opened at the end of the tick for the widget hierarchy to // work out, but we also want to prevent the server browser from flashing visible for one tick. widget.Visible = false; Game.RunAfterTick(() => { - ConnectionLogic.Connect(directConnectHost, directConnectPort, "", () => { Ui.CloseWindow(); openLobby(); }, DoNothing); + ConnectionLogic.Connect(directConnectEndPoint, "", () => { Ui.CloseWindow(); openLobby(); }, DoNothing); widget.Visible = true; }); } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorEditLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorEditLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorEditLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/ActorEditLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -106,8 +106,7 @@ actorIDErrorLabel.GetText = () => actorIDStatus == ActorIDStatus.Duplicate ? "Duplicate Actor ID" : "Enter an Actor ID"; - MiniYaml yaml; - if (logicArgs.TryGetValue("EditPanelPadding", out yaml)) + if (logicArgs.TryGetValue("EditPanelPadding", out var yaml)) editPanelPadding = FieldLoader.GetValue("EditPanelPadding", yaml.Value); okButton.IsDisabled = () => !IsValid() || !editActorPreview.IsDirty; @@ -309,6 +308,20 @@ slider.OnChange += value => so.OnChange(actor, value); slider.OnChange += value => editorActionHandle.OnChange(value); + var valueField = sliderContainer.GetOrNull("VALUE"); + if (valueField != null) + { + Action updateValueField = f => valueField.Text = ((int)f).ToString(); + updateValueField(so.GetValue(actor)); + slider.OnChange += updateValueField; + + valueField.OnTextEdited = () => + { + if (float.TryParse(valueField.Text, out var result)) + slider.UpdateValue(result); + }; + } + initContainer.AddChild(sliderContainer); } else if (o is EditorActorDropdown) @@ -376,8 +389,7 @@ void Reset() { - if (editActorPreview != null) - editActorPreview.Reset(); + editActorPreview?.Reset(); } void Close() diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/CommonSelectorLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/CommonSelectorLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/CommonSelectorLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/CommonSelectorLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -71,8 +71,7 @@ categorySelector.OnMouseDown = _ => { - if (SearchTextField != null) - SearchTextField.YieldKeyboardFocus(); + SearchTextField?.YieldKeyboardFocus(); categorySelector.RemovePanel(); categorySelector.AttachPanel(CreateCategoriesPanel(Panel)); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/HistoryLogLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/HistoryLogLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/HistoryLogLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/HistoryLogLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System.Collections.Generic; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,8 +9,6 @@ */ #endregion -using System; -using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Lint; @@ -30,10 +28,9 @@ var editorViewport = widget.Get("MAP_EDITOR"); var gridButton = widget.GetOrNull("GRID_BUTTON"); - var terrainGeometryTrait = world.WorldActor.Trait(); - - if (gridButton != null && terrainGeometryTrait != null) + if (gridButton != null) { + var terrainGeometryTrait = world.WorldActor.Trait(); gridButton.OnClick = () => terrainGeometryTrait.Enabled ^= true; gridButton.IsHighlighted = () => terrainGeometryTrait.Enabled; } @@ -82,17 +79,13 @@ cashLabel.GetText = () => "$ {0}".F(reslayer.NetWorth); } - var actionManager = world.WorldActor.Trait(); var undoButton = widget.GetOrNull("UNDO_BUTTON"); - if (undoButton != null) + var redoButton = widget.GetOrNull("REDO_BUTTON"); + if (undoButton != null && redoButton != null) { + var actionManager = world.WorldActor.Trait(); undoButton.IsDisabled = () => !actionManager.HasUndos(); undoButton.OnClick = () => actionManager.Undo(); - } - - var redoButton = widget.GetOrNull("REDO_BUTTON"); - if (redoButton != null) - { redoButton.IsDisabled = () => !actionManager.HasRedos(); redoButton.OnClick = () => actionManager.Redo(); } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/NewMapLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/NewMapLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/NewMapLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/NewMapLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -45,9 +45,8 @@ panel.Get("CREATE_BUTTON").OnClick = () => { - int width, height; - int.TryParse(widthTextField.Text, out width); - int.TryParse(heightTextField.Text, out height); + int.TryParse(widthTextField.Text, out var width); + int.TryParse(heightTextField.Text, out var height); // Require at least a 2x2 playable area so that the // ground is visible through the edge shroud @@ -71,8 +70,7 @@ // It's not clear why this is needed here, but not in the other places that load maps. Game.RunAfterTick(() => { - ConnectionLogic.Connect(System.Net.IPAddress.Loopback.ToString(), - Game.CreateLocalServer(uid), "", + ConnectionLogic.Connect(Game.CreateLocalServer(uid), "", () => Game.LoadEditor(uid), () => { Game.CloseServer(); onExit(); }); }); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/SaveMapLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/SaveMapLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Editor/SaveMapLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Editor/SaveMapLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -34,10 +34,10 @@ public readonly string DisplayName; public readonly MapClassification Classification; - public SaveDirectory(Folder folder, MapClassification classification) + public SaveDirectory(Folder folder, string displayName, MapClassification classification) { Folder = folder; - DisplayName = Platform.UnresolvePath(Folder.Name); + DisplayName = displayName; Classification = classification; } } @@ -103,7 +103,7 @@ // Do nothing: we just want to test whether we can create the file } - writableDirectories.Add(new SaveDirectory(folder, kv.Value)); + writableDirectories.Add(new SaveDirectory(folder, kv.Value.ToString(), kv.Value)); } catch { diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/GameSaveBrowserLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/GameSaveBrowserLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/GameSaveBrowserLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/GameSaveBrowserLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -55,7 +55,7 @@ var newTemplate = panel.Get("NEW_TEMPLATE"); var mod = modData.Manifest; - baseSavePath = Platform.ResolvePath(Platform.SupportDirPrefix, "Saves", mod.Id, mod.Metadata.Version); + baseSavePath = Path.Combine(Platform.SupportDir, "Saves", mod.Id, mod.Metadata.Version); // Avoid filename conflicts when creating new saves if (isSavePanel) @@ -304,8 +304,8 @@ void Save(World world) { var filename = saveTextField.Text + ".orasav"; - var testPath = Platform.ResolvePath( - Platform.SupportDirPrefix, + var testPath = Path.Combine( + Platform.SupportDir, "Saves", modData.Manifest.Id, modData.Manifest.Metadata.Version, @@ -351,7 +351,7 @@ public static bool IsLoadPanelEnabled(Manifest mod) { - var baseSavePath = Platform.ResolvePath(Platform.SupportDirPrefix, "Saves", mod.Id, mod.Metadata.Version); + var baseSavePath = Path.Combine(Platform.SupportDir, "Saves", mod.Id, mod.Metadata.Version); if (!Directory.Exists(baseSavePath)) return false; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/AddFactionSuffixLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/AddFactionSuffixLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/AddFactionSuffixLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/AddFactionSuffixLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -19,8 +19,7 @@ [ObjectCreator.UseCtor] public AddFactionSuffixLogic(Widget widget, World world) { - string faction; - if (!ChromeMetrics.TryGet("FactionSuffix-" + world.LocalPlayer.Faction.InternalName, out faction)) + if (!ChromeMetrics.TryGet("FactionSuffix-" + world.LocalPlayer.Faction.InternalName, out string faction)) faction = world.LocalPlayer.Faction.InternalName; var suffix = "-" + faction; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/ArmyTooltipLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/ArmyTooltipLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/ArmyTooltipLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/ArmyTooltipLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System; -using System.Linq; using OpenRA.Mods.Common.Traits; using OpenRA.Widgets; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/CommandBarLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/CommandBarLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/CommandBarLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/CommandBarLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Graphics; using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Traits; using OpenRA.Orders; @@ -54,7 +53,7 @@ var attackMoveButton = widget.GetOrNull("ATTACK_MOVE"); if (attackMoveButton != null) { - BindButtonIcon(attackMoveButton); + WidgetUtils.BindButtonIcon(attackMoveButton); attackMoveButton.IsDisabled = () => { UpdateStateIfNecessary(); return attackMoveDisabled; }; attackMoveButton.IsHighlighted = () => world.OrderGenerator is AttackMoveOrderGenerator; @@ -77,7 +76,7 @@ var forceMoveButton = widget.GetOrNull("FORCE_MOVE"); if (forceMoveButton != null) { - BindButtonIcon(forceMoveButton); + WidgetUtils.BindButtonIcon(forceMoveButton); forceMoveButton.IsDisabled = () => { UpdateStateIfNecessary(); return forceMoveDisabled; }; forceMoveButton.IsHighlighted = () => !forceMoveButton.IsDisabled() && IsForceModifiersActive(Modifiers.Alt); @@ -93,7 +92,7 @@ var forceAttackButton = widget.GetOrNull("FORCE_ATTACK"); if (forceAttackButton != null) { - BindButtonIcon(forceAttackButton); + WidgetUtils.BindButtonIcon(forceAttackButton); forceAttackButton.IsDisabled = () => { UpdateStateIfNecessary(); return forceAttackDisabled; }; forceAttackButton.IsHighlighted = () => !forceAttackButton.IsDisabled() && IsForceModifiersActive(Modifiers.Ctrl) @@ -111,7 +110,7 @@ var guardButton = widget.GetOrNull("GUARD"); if (guardButton != null) { - BindButtonIcon(guardButton); + WidgetUtils.BindButtonIcon(guardButton); guardButton.IsDisabled = () => { UpdateStateIfNecessary(); return guardDisabled; }; guardButton.IsHighlighted = () => world.OrderGenerator is GuardOrderGenerator; @@ -135,7 +134,7 @@ var scatterButton = widget.GetOrNull("SCATTER"); if (scatterButton != null) { - BindButtonIcon(scatterButton); + WidgetUtils.BindButtonIcon(scatterButton); scatterButton.IsDisabled = () => { UpdateStateIfNecessary(); return scatterDisabled; }; scatterButton.IsHighlighted = () => scatterHighlighted > 0; @@ -153,7 +152,7 @@ var deployButton = widget.GetOrNull("DEPLOY"); if (deployButton != null) { - BindButtonIcon(deployButton); + WidgetUtils.BindButtonIcon(deployButton); deployButton.IsDisabled = () => { @@ -179,7 +178,7 @@ var stopButton = widget.GetOrNull("STOP"); if (stopButton != null) { - BindButtonIcon(stopButton); + WidgetUtils.BindButtonIcon(stopButton); stopButton.IsDisabled = () => { UpdateStateIfNecessary(); return stopDisabled; }; stopButton.IsHighlighted = () => stopHighlighted > 0; @@ -197,7 +196,7 @@ var queueOrdersButton = widget.GetOrNull("QUEUE_ORDERS"); if (queueOrdersButton != null) { - BindButtonIcon(queueOrdersButton); + WidgetUtils.BindButtonIcon(queueOrdersButton); queueOrdersButton.IsDisabled = () => { UpdateStateIfNecessary(); return waypointModeDisabled; }; queueOrdersButton.IsHighlighted = () => !queueOrdersButton.IsDisabled() && IsForceModifiersActive(Modifiers.Shift); @@ -272,20 +271,6 @@ base.Tick(); } - void BindButtonIcon(ButtonWidget button) - { - var icon = button.Get("ICON"); - var hasDisabled = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-disabled") != null; - var hasActive = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-active") != null; - var hasActiveHover = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-active-hover") != null; - var hasHover = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-hover") != null; - - icon.GetImageName = () => hasActive && button.IsHighlighted() ? - (hasActiveHover && Ui.MouseOverWidget == button ? icon.ImageName + "-active-hover" : icon.ImageName + "-active") : - hasDisabled && button.IsDisabled() ? icon.ImageName + "-disabled" : - hasHover && Ui.MouseOverWidget == button ? icon.ImageName + "-hover" : icon.ImageName; - } - bool IsForceModifiersActive(Modifiers modifiers) { var fmog = world.OrderGenerator as ForceModifiersOrderGenerator; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/DebugLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/DebugLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/DebugLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/DebugLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Network; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/DebugMenuLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/DebugMenuLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/DebugMenuLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/DebugMenuLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -85,7 +85,7 @@ showScreenMapCheckbox.OnClick = () => debugVis.ScreenMap ^= true; } - var terrainGeometryTrait = world.WorldActor.Trait(); + var terrainGeometryTrait = world.WorldActor.TraitOrDefault(); var showTerrainGeometryCheckbox = widget.GetOrNull("SHOW_TERRAIN_OVERLAY"); if (showTerrainGeometryCheckbox != null && terrainGeometryTrait != null) { diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/GameInfoStatsLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/GameInfoStatsLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/GameInfoStatsLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/GameInfoStatsLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -66,10 +66,10 @@ playerPanel.RemoveChildren(); var teams = world.Players.Where(p => !p.NonCombatant && p.Playable) - .Select(p => new Pair(p, p.PlayerActor.TraitOrDefault())) - .OrderByDescending(p => p.Second != null ? p.Second.Experience : 0) - .GroupBy(p => (world.LobbyInfo.ClientWithIndex(p.First.ClientIndex) ?? new Session.Client()).Team) - .OrderByDescending(g => g.Sum(gg => gg.Second != null ? gg.Second.Experience : 0)); + .Select(p => (Player: p, PlayerStatistics: p.PlayerActor.TraitOrDefault())) + .OrderByDescending(p => p.PlayerStatistics != null ? p.PlayerStatistics.Experience : 0) + .GroupBy(p => (world.LobbyInfo.ClientWithIndex(p.Player.ClientIndex) ?? new Session.Client()).Team) + .OrderByDescending(g => g.Sum(gg => gg.PlayerStatistics != null ? gg.PlayerStatistics.Experience : 0)); foreach (var t in teams) { @@ -79,7 +79,7 @@ teamHeader.Get("TEAM").GetText = () => t.Key == 0 ? "No Team" : "Team {0}".F(t.Key); var teamRating = teamHeader.Get("TEAM_SCORE"); var scoreCache = new CachedTransform(s => s.ToString()); - var teamMemberScores = t.Select(tt => tt.Second).Where(s => s != null).ToArray().Select(s => s.Experience); + var teamMemberScores = t.Select(tt => tt.PlayerStatistics).Where(s => s != null).ToArray().Select(s => s.Experience); teamRating.GetText = () => scoreCache.Update(teamMemberScores.Sum()); playerPanel.AddChild(teamHeader); @@ -87,31 +87,18 @@ foreach (var p in t.ToList()) { - var pp = p.First; + var pp = p.Player; var client = world.LobbyInfo.ClientWithIndex(pp.ClientIndex); var item = playerTemplate.Clone(); LobbyUtils.SetupProfileWidget(item, client, orderManager, worldRenderer); var nameLabel = item.Get("NAME"); - var nameFont = Game.Renderer.Fonts[nameLabel.Font]; - - var suffixLength = new CachedTransform(s => nameFont.Measure(s).X); - var name = new CachedTransform, string>(c => - WidgetUtils.TruncateText(c.First, nameLabel.Bounds.Width - suffixLength.Update(c.Second), nameFont) + c.Second); - - nameLabel.GetText = () => - { - var suffix = pp.WinState == WinState.Undefined ? "" : " (" + pp.WinState + ")"; - if (client != null && client.State == Session.ClientState.Disconnected) - suffix = " (Gone)"; - - return name.Update(Pair.New(pp.PlayerName, suffix)); - }; + WidgetUtils.BindPlayerNameAndStatus(nameLabel, pp); nameLabel.GetColor = () => pp.Color; var flag = item.Get("FACTIONFLAG"); flag.GetImageCollection = () => "flags"; - if (player == null || player.Stances[pp] == Stance.Ally || player.WinState != WinState.Undefined) + if (player == null || player.RelationshipWith(pp) == PlayerRelationship.Ally || player.WinState != WinState.Undefined) { flag.GetImageName = () => pp.Faction.InternalName; item.Get("FACTION").GetText = () => pp.Faction.Name; @@ -123,7 +110,7 @@ } var scoreCache = new CachedTransform(s => s.ToString()); - item.Get("SCORE").GetText = () => scoreCache.Update(p.Second != null ? p.Second.Experience : 0); + item.Get("SCORE").GetText = () => scoreCache.Update(p.PlayerStatistics != null ? p.PlayerStatistics.Experience : 0); playerPanel.AddChild(item); } @@ -146,13 +133,13 @@ var nameFont = Game.Renderer.Fonts[nameLabel.Font]; var suffixLength = new CachedTransform(s => nameFont.Measure(s).X); - var name = new CachedTransform, string>(c => - WidgetUtils.TruncateText(c.First, nameLabel.Bounds.Width - suffixLength.Update(c.Second), nameFont) + c.Second); + var name = new CachedTransform<(string Name, string Suffix), string>(c => + WidgetUtils.TruncateText(c.Name, nameLabel.Bounds.Width - suffixLength.Update(c.Suffix), nameFont) + c.Suffix); nameLabel.GetText = () => { var suffix = client.State == Session.ClientState.Disconnected ? " (Gone)" : ""; - return name.Update(Pair.New(client.Name, suffix)); + return name.Update((client.Name, suffix)); }; var kickButton = item.Get("KICK"); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/Hotkeys/CycleProductionActorsHotkeyLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/Hotkeys/CycleProductionActorsHotkeyLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/Hotkeys/CycleProductionActorsHotkeyLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/Hotkeys/CycleProductionActorsHotkeyLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -36,8 +36,7 @@ selection = world.Selection; this.world = world; - MiniYaml yaml; - if (logicArgs.TryGetValue("ClickSound", out yaml)) + if (logicArgs.TryGetValue("ClickSound", out var yaml)) clickSound = yaml.Value; } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameChatLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameChatLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameChatLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameChatLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -209,8 +209,7 @@ }); } - MiniYaml yaml; - if (logicArgs.TryGetValue("ChatLineSound", out yaml)) + if (logicArgs.TryGetValue("ChatLineSound", out var yaml)) chatLineSound = yaml.Value; } @@ -234,8 +233,7 @@ public void AddChatLineWrapper(string name, Color nameColor, string text, Color textColor) { - if (chatOverlayDisplay != null) - chatOverlayDisplay.AddLine(name, nameColor, text, textColor); + chatOverlayDisplay?.AddLine(name, nameColor, text, textColor); // HACK: Force disable the chat notification sound for the in-menu chat dialog // This works around our inability to disable the sounds for the in-game dialog when it is hidden diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -64,8 +64,7 @@ menu = widget.Get("INGAME_MENU"); mpe = world.WorldActor.TraitOrDefault(); - if (mpe != null) - mpe.Fade(mpe.Info.MenuEffect); + mpe?.Fade(mpe.Info.MenuEffect); menu.Get("VERSION_LABEL").Text = modData.Manifest.Metadata.Version; @@ -74,20 +73,17 @@ buttonContainer.RemoveChild(buttonTemplate); buttonContainer.IsVisible = () => !hideMenu; - MiniYaml buttonStrideNode; - if (logicArgs.TryGetValue("ButtonStride", out buttonStrideNode)) + if (logicArgs.TryGetValue("ButtonStride", out var buttonStrideNode)) buttonStride = FieldLoader.GetValue("ButtonStride", buttonStrideNode.Value); var scriptContext = world.WorldActor.TraitOrDefault(); hasError = scriptContext != null && scriptContext.FatalErrorOccurred; - MiniYaml buttonsNode; - if (logicArgs.TryGetValue("Buttons", out buttonsNode)) + if (logicArgs.TryGetValue("Buttons", out var buttonsNode)) { - Action createHandler; var buttonIds = FieldLoader.GetValue("Buttons", buttonsNode.Value); foreach (var button in buttonIds) - if (buttonHandlers.TryGetValue(button, out createHandler)) + if (buttonHandlers.TryGetValue(button, out var createHandler)) createHandler(); } @@ -161,9 +157,9 @@ void CloseMenu() { Ui.CloseWindow(); - if (mpe != null) - mpe.Fade(MenuPaletteEffect.EffectType.None); + mpe?.Fade(MenuPaletteEffect.EffectType.None); onExit(); + Ui.ResetTooltips(); } ButtonWidget AddButton(string id, string text) diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/LoadIngamePlayerOrObserverUILogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/LoadIngamePlayerOrObserverUILogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/LoadIngamePlayerOrObserverUILogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/LoadIngamePlayerOrObserverUILogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using OpenRA.Mods.Common.Commands; using OpenRA.Mods.Common.Scripting; using OpenRA.Mods.Common.Traits; using OpenRA.Widgets; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/MenuButtonsChromeLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/MenuButtonsChromeLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/MenuButtonsChromeLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/MenuButtonsChromeLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -35,8 +35,6 @@ worldRoot = Ui.Root.Get("WORLD_ROOT"); menuRoot = Ui.Root.Get("MENU_ROOT"); - MiniYaml yaml; - // System buttons var options = widget.GetOrNull("OPTIONS_BUTTON"); if (options != null) @@ -85,7 +83,7 @@ }); } - if (logicArgs.TryGetValue("ClickSound", out yaml)) + if (logicArgs.TryGetValue("ClickSound", out var yaml)) clickSound = yaml.Value; } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverShroudSelectorLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverShroudSelectorLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverShroudSelectorLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverShroudSelectorLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -33,6 +33,7 @@ readonly World world; CameraOption selected; + LabelWidget shroudLabel; class CameraOption { @@ -50,7 +51,13 @@ Color = p.Color; Faction = p.Faction.InternalName; IsSelected = () => p.World.RenderPlayer == p; - OnClick = () => { p.World.RenderPlayer = p; logic.selected = this; p.World.Selection.Clear(); }; + OnClick = () => + { + p.World.RenderPlayer = p; + logic.selected = this; + p.World.Selection.Clear(); + WidgetUtils.BindPlayerNameAndStatus(logic.shroudLabel, p); + }; } public CameraOption(ObserverShroudSelectorLogic logic, World w, string label, Player p) @@ -69,8 +76,7 @@ { this.world = world; - MiniYaml yaml; - if (logicArgs.TryGetValue("CombinedViewKey", out yaml)) + if (logicArgs.TryGetValue("CombinedViewKey", out var yaml)) combinedViewKey = modData.Hotkeys[yaml.Value]; if (logicArgs.TryGetValue("WorldViewKey", out yaml)) @@ -107,9 +113,13 @@ var label = item.Get("LABEL"); label.IsVisible = () => showFlag; - label.GetText = () => option.Label; label.GetColor = () => option.Color; + if (showFlag) + WidgetUtils.BindPlayerNameAndStatus(label, option.Player); + else + label.GetText = () => option.Label; + var flag = item.Get("FLAG"); flag.IsVisible = () => showFlag; flag.GetImageCollection = () => "flags"; @@ -126,7 +136,7 @@ shroudSelector.ShowDropDown("SPECTATOR_DROPDOWN_TEMPLATE", 400, groups, setupItem); }; - var shroudLabel = shroudSelector.Get("LABEL"); + shroudLabel = shroudSelector.Get("LABEL"); shroudLabel.IsVisible = () => selected.Faction != null; shroudLabel.GetText = () => selected.Label; shroudLabel.GetColor = () => selected.Color; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverStatsLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverStatsLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverStatsLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverStatsLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -386,11 +386,11 @@ SetupPlayerColor(player, template, playerColor, playerGradient); - var res = player.PlayerActor.Trait(); var stats = player.PlayerActor.TraitOrDefault(); if (stats == null) return template; + var res = player.PlayerActor.Trait(); var cashText = new CachedTransform(i => "$" + i); template.Get("CASH").GetText = () => cashText.Update(res.Cash + res.Resources); @@ -404,10 +404,7 @@ template.Get("SPENT").GetText = () => spentText.Update(res.Spent); var assetsText = new CachedTransform(i => "$" + i); - var assets = template.Get("ASSETS"); - assets.GetText = () => assetsText.Update(world.ActorsHavingTrait() - .Where(a => a.Owner == player && !a.IsDead) - .Sum(a => a.Info.TraitInfos().First().Cost)); + template.Get("ASSETS").GetText = () => assetsText.Update(stats.AssetsValue); var harvesters = template.Get("HARVESTERS"); harvesters.GetText = () => world.ActorsHavingTrait().Count(a => a.Owner == player && !a.IsDead).ToString(); @@ -442,8 +439,8 @@ if (powerRes != null) { var power = template.Get("POWER"); - var powerText = new CachedTransform, string>(p => p.First + "/" + p.Second); - power.GetText = () => powerText.Update(new Pair(powerRes.PowerDrained, powerRes.PowerProvided)); + var powerText = new CachedTransform<(int PowerDrained, int PowerProvided), string>(p => p.PowerDrained + "/" + p.PowerProvided); + power.GetText = () => powerText.Update((powerRes.PowerDrained, powerRes.PowerProvided)); power.GetColor = () => GetPowerColor(powerRes.PowerState); } @@ -525,22 +522,8 @@ flag.GetImageCollection = () => "flags"; flag.GetImageName = () => player.Faction.InternalName; - var client = player.World.LobbyInfo.ClientWithIndex(player.ClientIndex); var playerName = template.Get("PLAYER"); - var playerNameFont = Game.Renderer.Fonts[playerName.Font]; - var suffixLength = new CachedTransform(s => playerNameFont.Measure(s).X); - var name = new CachedTransform, string>(c => - WidgetUtils.TruncateText(c.First, playerName.Bounds.Width - c.Second, playerNameFont)); - - playerName.GetText = () => - { - var suffix = player.WinState == WinState.Undefined ? "" : " (" + player.WinState + ")"; - if (client != null && client.State == Session.ClientState.Disconnected) - suffix = " (Gone)"; - - var sl = suffixLength.Update(suffix); - return name.Update(Pair.New(player.PlayerName, sl)) + suffix; - }; + WidgetUtils.BindPlayerNameAndStatus(playerName, player); playerName.GetColor = () => player.Color; } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -165,8 +165,7 @@ static string ActorName(Ruleset rules, string a) { - ActorInfo ai; - if (rules.Actors.TryGetValue(a.ToLowerInvariant(), out ai)) + if (rules.Actors.TryGetValue(a.ToLowerInvariant(), out var ai)) { var actorTooltip = ai.TraitInfos().FirstOrDefault(info => info.EnabledByDefault); if (actorTooltip != null) diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/StanceSelectorLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/StanceSelectorLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/StanceSelectorLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/StanceSelectorLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,7 +10,6 @@ #endregion using System.Linq; -using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Widgets; @@ -47,16 +46,7 @@ void BindStanceButton(ButtonWidget button, UnitStance stance) { - var icon = button.Get("ICON"); - var hasDisabled = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-disabled") != null; - var hasActive = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-active") != null; - var hasActiveHover = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-active-hover") != null; - var hasHover = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-hover") != null; - - icon.GetImageName = () => hasActive && button.IsHighlighted() ? - (hasActiveHover && Ui.MouseOverWidget == button ? icon.ImageName + "-active-hover" : icon.ImageName + "-active") : - hasDisabled && button.IsDisabled() ? icon.ImageName + "-disabled" : - hasHover && Ui.MouseOverWidget == button ? icon.ImageName + "-hover" : icon.ImageName; + WidgetUtils.BindButtonIcon(button); button.IsDisabled = () => { UpdateStateIfNecessary(); return !actorStances.Any(); }; button.IsHighlighted = () => actorStances.Any( diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/WorldTooltipLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/WorldTooltipLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Ingame/WorldTooltipLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Ingame/WorldTooltipLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,7 +29,6 @@ var font = Game.Renderer.Fonts[label.Font]; var ownerFont = Game.Renderer.Fonts[owner.Font]; - var cachedWidth = 0; var labelText = ""; var showOwner = false; var flagFaction = ""; @@ -65,7 +64,7 @@ o = viewport.ActorTooltip.Owner; showOwner = o != null && !o.NonCombatant && viewport.ActorTooltip.TooltipInfo.IsOwnerRowVisible; - var stance = o == null || world.RenderPlayer == null ? Stance.None : o.Stances[world.RenderPlayer]; + var stance = o == null || world.RenderPlayer == null ? PlayerRelationship.None : o.RelationshipWith(world.RenderPlayer); labelText = viewport.ActorTooltip.TooltipInfo.TooltipForPlayerStance(stance); break; } @@ -75,7 +74,7 @@ o = viewport.FrozenActorTooltip.TooltipOwner; showOwner = o != null && !o.NonCombatant && viewport.FrozenActorTooltip.TooltipInfo.IsOwnerRowVisible; - var stance = o == null || world.RenderPlayer == null ? Stance.None : o.Stances[world.RenderPlayer]; + var stance = o == null || world.RenderPlayer == null ? PlayerRelationship.None : o.RelationshipWith(world.RenderPlayer); labelText = viewport.FrozenActorTooltip.TooltipInfo.TooltipForPlayerStance(stance); break; } @@ -96,12 +95,8 @@ } var textWidth = Math.Max(font.Measure(labelText).X, font.Measure(extraText).X); - - if (textWidth != cachedWidth) - { - label.Bounds.Width = textWidth; - widget.Bounds.Width = 2 * label.Bounds.X + textWidth; - } + label.Bounds.Width = textWidth; + widget.Bounds.Width = 2 * label.Bounds.X + textWidth; if (showOwner) { diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackageLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackageLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackageLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackageLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,6 @@ using System.Net; using System.Text; using ICSharpCode.SharpZipLib.Zip; -using OpenRA.Primitives; using OpenRA.Support; using OpenRA.Widgets; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -268,11 +268,8 @@ case "delete": { - var sourcePath = Path.Combine(path, i.Value.Value); - - // Try as an absolute path - if (!File.Exists(sourcePath)) - sourcePath = Platform.ResolvePath(i.Value.Value); + // Yaml path may be specified relative to a named directory (e.g. ^SupportDir) or the detected disc path + var sourcePath = i.Value.Value.StartsWith("^") ? Platform.ResolvePath(i.Value.Value) : Path.Combine(path, i.Value.Value); Log.Write("debug", "Deleting {0}", sourcePath); File.Delete(sourcePath); @@ -317,8 +314,7 @@ output.Write(buffer, 0, write); copied += write; - if (onProgress != null) - onProgress(copied); + onProgress?.Invoke(copied); } } @@ -326,11 +322,8 @@ static void ExtractFromPackage(ExtractionType type, string path, MiniYaml actionYaml, List extractedFiles, Action updateMessage) { - var sourcePath = Path.Combine(path, actionYaml.Value); - - // Try as an absolute path - if (!File.Exists(sourcePath)) - sourcePath = Platform.ResolvePath(actionYaml.Value); + // Yaml path may be specified relative to a named directory (e.g. ^SupportDir) or the detected disc path + var sourcePath = actionYaml.Value.StartsWith("^") ? Platform.ResolvePath(actionYaml.Value) : Path.Combine(path, actionYaml.Value); using (var source = File.OpenRead(sourcePath)) { @@ -375,15 +368,7 @@ { Log.Write("install", "Extracting {0} -> {1}".F(sourcePath, targetPath)); if (type == ExtractionType.Blast) - { - Action onBlastProgress = (read, _) => - { - if (onProgress != null) - onProgress(read); - }; - - Blast.Decompress(source, target, onBlastProgress); - } + Blast.Decompress(source, target, (read, _) => onProgress?.Invoke(read)); else CopyStream(source, target, length, onProgress); } @@ -393,11 +378,8 @@ static void ExtractFromMSCab(string path, MiniYaml actionYaml, List extractedFiles, Action updateMessage) { - var sourcePath = Path.Combine(path, actionYaml.Value); - - // Try as an absolute path - if (!File.Exists(sourcePath)) - sourcePath = Platform.ResolvePath(actionYaml.Value); + // Yaml path may be specified relative to a named directory (e.g. ^SupportDir) or the detected disc path + var sourcePath = actionYaml.Value.StartsWith("^") ? Platform.ResolvePath(actionYaml.Value) : Path.Combine(path, actionYaml.Value); using (var source = File.OpenRead(sourcePath)) { @@ -427,11 +409,8 @@ static void ExtractFromISCab(string path, MiniYaml actionYaml, List extractedFiles, Action updateMessage) { - var sourcePath = Path.Combine(path, actionYaml.Value); - - // Try as an absolute path - if (!File.Exists(sourcePath)) - sourcePath = Platform.ResolvePath(actionYaml.Value); + // Yaml path may be specified relative to a named directory (e.g. ^SupportDir) or the detected disc path + var sourcePath = actionYaml.Value.StartsWith("^") ? Platform.ResolvePath(actionYaml.Value) : Path.Combine(path, actionYaml.Value); var volumeNode = actionYaml.Nodes.FirstOrDefault(n => n.Key == "Volumes"); if (volumeNode == null) diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,15 +10,7 @@ #endregion using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; using OpenRA.Graphics; -using OpenRA.Primitives; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -60,7 +60,10 @@ MapPreview map; bool addBotOnMapLoad; bool disableTeamChat; + bool insufficientPlayerSpawns; bool teamChat; + bool updateDiscordStatus = true; + Dictionary spawnOccupants = new Dictionary(); readonly string chatLineSound = ChromeMetrics.Get("ChatLineSound"); @@ -82,7 +85,7 @@ }); }; - Action onRetry = password => ConnectionLogic.Connect(om.Host, om.Port, password, onConnect, onExit); + Action onRetry = password => ConnectionLogic.Connect(om.Endpoint, password, onConnect, onExit); var switchPanel = om.ServerExternalMod != null ? "CONNECTION_SWITCHMOD_PANEL" : "CONNECTIONFAILED_PANEL"; Ui.OpenWindow(switchPanel, new WidgetArgs() @@ -116,6 +119,8 @@ orderManager.AddChatLine += AddChatLine; Game.LobbyInfoChanged += UpdateCurrentMap; Game.LobbyInfoChanged += UpdatePlayerList; + Game.LobbyInfoChanged += UpdateDiscordStatus; + Game.LobbyInfoChanged += UpdateSpawnOccupants; Game.BeforeGameStart += OnGameStart; Game.ConnectionStateChanged += ConnectionStateChanged; @@ -131,10 +136,8 @@ "onMouseDown", (Action)((preview, mapPreview, mi) => LobbyUtils.SelectSpawnPoint(orderManager, preview, mapPreview, mi)) }, - { - "getSpawnOccupants", (Func>)(mapPreview => - LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, mapPreview)) - }, + { "getSpawnOccupants", (Func>)(() => spawnOccupants) }, + { "getDisabledSpawnPoints", (Func>)(() => orderManager.LobbyInfo.DisabledSpawnPoints) }, { "showUnoccupiedSpawnpoints", true }, }); @@ -366,7 +369,8 @@ { startGameButton.IsDisabled = () => configurationDisabled() || map.Status != MapStatus.Available || orderManager.LobbyInfo.Slots.Any(sl => sl.Value.Required && orderManager.LobbyInfo.ClientInSlot(sl.Key) == null) || - (!orderManager.LobbyInfo.GlobalSettings.EnableSingleplayer && orderManager.LobbyInfo.NonBotPlayers.Count() < 2); + (!orderManager.LobbyInfo.GlobalSettings.EnableSingleplayer && orderManager.LobbyInfo.NonBotPlayers.Count() < 2) || + insufficientPlayerSpawns; startGameButton.OnClick = () => { @@ -448,8 +452,7 @@ if (skirmishMode) addBotOnMapLoad = true; - MiniYaml yaml; - if (logicArgs.TryGetValue("ChatLineSound", out yaml)) + if (logicArgs.TryGetValue("ChatLineSound", out var yaml)) chatLineSound = yaml.Value; } @@ -462,6 +465,8 @@ orderManager.AddChatLine -= AddChatLine; Game.LobbyInfoChanged -= UpdateCurrentMap; Game.LobbyInfoChanged -= UpdatePlayerList; + Game.LobbyInfoChanged -= UpdateDiscordStatus; + Game.LobbyInfoChanged -= UpdateSpawnOccupants; Game.BeforeGameStart -= OnGameStart; Game.ConnectionStateChanged -= ConnectionStateChanged; } @@ -568,6 +573,8 @@ c.Bot == null && c.Team == orderManager.LocalClient.Team); + insufficientPlayerSpawns = LobbyUtils.InsufficientEnabledSpawnPoints(map, orderManager.LobbyInfo); + if (disableTeamChat) teamChat = false; @@ -617,6 +624,7 @@ LobbyUtils.SetupEditableColorWidget(template, slot, client, orderManager, shellmapWorld, colorPreview); LobbyUtils.SetupEditableFactionWidget(template, slot, client, orderManager, factions); LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, map); + LobbyUtils.SetupEditableHandicapWidget(template, slot, client, orderManager, map); LobbyUtils.SetupEditableSpawnWidget(template, slot, client, orderManager, map); LobbyUtils.SetupEditableReadyWidget(template, slot, client, orderManager, map); } @@ -633,6 +641,7 @@ if (isHost) { LobbyUtils.SetupEditableTeamWidget(template, slot, client, orderManager, map); + LobbyUtils.SetupEditableHandicapWidget(template, slot, client, orderManager, map); LobbyUtils.SetupEditableSpawnWidget(template, slot, client, orderManager, map); LobbyUtils.SetupPlayerActionWidget(template, slot, client, orderManager, worldRenderer, lobby, () => panel = PanelType.Kick, () => panel = PanelType.Players); @@ -641,6 +650,7 @@ { LobbyUtils.SetupNameWidget(template, slot, client, orderManager, worldRenderer); LobbyUtils.SetupTeamWidget(template, slot, client); + LobbyUtils.SetupHandicapWidget(template, slot, client); LobbyUtils.SetupSpawnWidget(template, slot, client); } @@ -743,9 +753,69 @@ tabCompletion.Names = orderManager.LobbyInfo.Clients.Select(c => c.Name).Distinct().ToList(); } + void UpdateDiscordStatus() + { + var numberOfPlayers = 0; + var slots = 0; + + if (!skirmishMode) + { + foreach (var kv in orderManager.LobbyInfo.Slots) + { + if (kv.Value.Closed) + continue; + + slots++; + var client = orderManager.LobbyInfo.ClientInSlot(kv.Key); + + if (client != null) + numberOfPlayers++; + } + } + + // Add extra slots to keep the join button active for spectators + if (numberOfPlayers == slots && orderManager.LobbyInfo.GlobalSettings.AllowSpectators) + slots = numberOfPlayers + 1; + + var details = map.Title + " - " + orderManager.LobbyInfo.GlobalSettings.ServerName; + if (updateDiscordStatus) + { + string secret = null; + if (orderManager.LobbyInfo.GlobalSettings.Dedicated) + { + var endpoint = orderManager.Endpoint.GetConnectEndPoints().First(); + secret = string.Concat(endpoint.Address, "|", endpoint.Port); + } + + var state = skirmishMode ? DiscordState.InSkirmishLobby : DiscordState.InMultiplayerLobby; + + DiscordService.UpdateStatus(state, details, secret, numberOfPlayers, slots); + updateDiscordStatus = false; + } + else + { + if (!skirmishMode) + DiscordService.UpdatePlayers(numberOfPlayers, slots); + + DiscordService.UpdateDetails(details); + } + } + + void UpdateSpawnOccupants() + { + spawnOccupants = orderManager.LobbyInfo.Clients + .Where(c => c.SpawnPoint != 0) + .ToDictionary(c => c.SpawnPoint, c => new SpawnOccupant(c)); + } + void OnGameStart() { Ui.CloseWindow(); + + var state = skirmishMode ? DiscordState.PlayingSkirmish : DiscordState.PlayingMultiplayer; + var details = map.Title + " - " + orderManager.LobbyInfo.GlobalSettings.ServerName; + DiscordService.UpdateStatus(state, details); + onStart(); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyOptionsLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyOptionsLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyOptionsLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyOptionsLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -138,8 +138,7 @@ var getOptionLabel = new CachedTransform(id => { - string value; - if (id == null || !option.Values.TryGetValue(id, out value)) + if (id == null || !option.Values.TryGetValue(id, out var value)) return "Not Available"; return value; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Net; using OpenRA.Graphics; using OpenRA.Network; using OpenRA.Primitives; @@ -147,6 +146,25 @@ dropdown.ShowDropDown("TEAM_DROPDOWN_TEMPLATE", 150, options, setupItem); } + public static void ShowHandicapDropDown(DropDownButtonWidget dropdown, Session.Client client, + OrderManager orderManager) + { + Func setupItem = (ii, itemTemplate) => + { + var item = ScrollItemWidget.Setup(itemTemplate, + () => client.Handicap == ii, + () => orderManager.IssueOrder(Order.Command("handicap {0} {1}".F(client.Index, ii)))); + + var label = "{0}%".F(ii); + item.Get("LABEL").GetText = () => label; + return item; + }; + + // Handicaps may be set between 0 - 95% in steps of 5% + var options = Enumerable.Range(0, 20).Select(i => 5 * i); + dropdown.ShowDropDown("TEAM_DROPDOWN_TEMPLATE", 150, options, setupItem); + } + public static void ShowSpawnDropDown(DropDownButtonWidget dropdown, Session.Client client, OrderManager orderManager, IEnumerable spawnPoints) { @@ -163,15 +181,15 @@ } /// Splits a string into two parts on the first instance of a given token. - static Pair SplitOnFirstToken(string input, string token = "\\n") + static (string First, string Second) SplitOnFirstToken(string input, string token = "\\n") { if (string.IsNullOrEmpty(input)) - return Pair.New(null, null); + return (null, null); var split = input.IndexOf(token, StringComparison.Ordinal); var first = split > 0 ? input.Substring(0, split) : input; var second = split > 0 ? input.Substring(split + token.Length) : null; - return Pair.New(first, second); + return (first, second); } public static void ShowFactionDropDown(DropDownButtonWidget dropdown, Session.Client client, @@ -228,47 +246,65 @@ color.AttachPanel(colorChooser, onExit); } - public static Dictionary GetSpawnOccupants(Session lobbyInfo, MapPreview preview) + public static void SelectSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi) { - var spawns = preview.SpawnPoints; - return lobbyInfo.Clients - .Where(c => (c.SpawnPoint - 1 >= 0) && (c.SpawnPoint - 1 < spawns.Length)) - .ToDictionary(c => spawns[c.SpawnPoint - 1], c => new SpawnOccupant(c)); + if (orderManager.LocalClient.State == Session.ClientState.Ready) + return; + + if (mi.Button == MouseButton.Left) + SelectPlayerSpawnPoint(orderManager, mapPreview, preview, mi); + + if (mi.Button == MouseButton.Right) + ClearPlayerSpawnPoint(orderManager, mapPreview, preview, mi); } - public static Dictionary GetSpawnOccupants(IEnumerable players, MapPreview preview) + static void SelectPlayerSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi) { - var spawns = preview.SpawnPoints; - return players - .Where(c => (c.SpawnPoint - 1 >= 0) && (c.SpawnPoint - 1 < spawns.Length)) - .ToDictionary(c => spawns[c.SpawnPoint - 1], c => new SpawnOccupant(c)); + var selectedSpawn = DetermineSelectedSpawnPoint(mapPreview, preview, mi); + + var locals = orderManager.LobbyInfo.Clients.Where(c => c.Index == orderManager.LocalClient.Index || (Game.IsHost && c.Bot != null)); + var playerToMove = locals.FirstOrDefault(c => ((selectedSpawn == 0) ^ (c.SpawnPoint == 0) && !c.IsObserver)); + SetSpawnPoint(orderManager, playerToMove, selectedSpawn); } - public static void SelectSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi) + static void ClearPlayerSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi) { - if (mi.Button != MouseButton.Left) - return; - - if (!orderManager.LocalClient.IsObserver && orderManager.LocalClient.State == Session.ClientState.Ready) - return; + var selectedSpawn = DetermineSelectedSpawnPoint(mapPreview, preview, mi); + if (Game.IsHost || orderManager.LobbyInfo.Clients.FirstOrDefault(cc => cc.SpawnPoint == selectedSpawn) == orderManager.LocalClient) + orderManager.IssueOrder(Order.Command("clear_spawn {0}".F(selectedSpawn))); + } + static int DetermineSelectedSpawnPoint(MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi) + { var spawnSize = ChromeProvider.GetImage("lobby-bits", "spawn-unclaimed").Size.XY; var selectedSpawn = preview.SpawnPoints - .Select((sp, i) => Pair.New(mapPreview.ConvertToPreview(sp, preview.GridType), i)) - .Where(a => ((a.First - mi.Location).ToFloat2() / spawnSize * 2).LengthSquared <= 1) - .Select(a => a.Second + 1) + .Select((sp, i) => (SpawnLocation: mapPreview.ConvertToPreview(sp, preview.GridType), Index: i)) + .Where(a => ((a.SpawnLocation - mi.Location).ToFloat2() / spawnSize * 2).LengthSquared <= 1) + .Select(a => a.Index + 1) .FirstOrDefault(); + return selectedSpawn; + } - var locals = orderManager.LobbyInfo.Clients.Where(c => c.Index == orderManager.LocalClient.Index || (Game.IsHost && c.Bot != null)); - var playerToMove = locals.FirstOrDefault(c => ((selectedSpawn == 0) ^ (c.SpawnPoint == 0) && !c.IsObserver)); - SetSpawnPoint(orderManager, playerToMove, selectedSpawn); + static void SetSpawnPoint(OrderManager orderManager, Session.Client playerToMove, int selectedSpawnPoint) + { + var owned = orderManager.LobbyInfo.Clients.Any(c => c.SpawnPoint == selectedSpawnPoint) || orderManager.LobbyInfo.DisabledSpawnPoints.Contains(selectedSpawnPoint); + if (selectedSpawnPoint == 0 || !owned) + orderManager.IssueOrder(Order.Command("spawn {0} {1}".F((playerToMove ?? orderManager.LocalClient).Index, selectedSpawnPoint))); + } + + public static List AvailableSpawnPoints(int spawnPoints, Session lobbyInfo) + { + return Enumerable.Range(1, spawnPoints).Except(lobbyInfo.DisabledSpawnPoints).ToList(); } - private static void SetSpawnPoint(OrderManager orderManager, Session.Client playerToMove, int selectedSpawn) + public static bool InsufficientEnabledSpawnPoints(MapPreview map, Session lobbyInfo) { - var owned = orderManager.LobbyInfo.Clients.Any(c => c.SpawnPoint == selectedSpawn); - if (selectedSpawn == 0 || !owned) - orderManager.IssueOrder(Order.Command("spawn {0} {1}".F((playerToMove ?? orderManager.LocalClient).Index, selectedSpawn))); + // If a map doesn't define spawn points we always have enough space + var spawnPoints = map.SpawnPoints.Length; + if (spawnPoints == 0) + return false; + + return AvailableSpawnPoints(spawnPoints, lobbyInfo).Count < lobbyInfo.Clients.Count(c => !c.IsObserver); } public static Color LatencyColor(Session.ClientPing ping) @@ -545,6 +581,29 @@ HideChildWidget(parent, "TEAM_DROPDOWN"); } + public static void SetupEditableHandicapWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, MapPreview map) + { + var dropdown = parent.Get("HANDICAP_DROPDOWN"); + dropdown.IsVisible = () => true; + dropdown.IsDisabled = () => s.LockTeam || orderManager.LocalClient.IsReady; + dropdown.OnMouseDown = _ => ShowHandicapDropDown(dropdown, c, orderManager); + + var handicapLabel = new CachedTransform(h => "{0}%".F(h)); + dropdown.GetText = () => handicapLabel.Update(c.Handicap); + + HideChildWidget(parent, "HANDICAP"); + } + + public static void SetupHandicapWidget(Widget parent, Session.Slot s, Session.Client c) + { + var team = parent.Get("HANDICAP"); + team.IsVisible = () => true; + + var handicapLabel = new CachedTransform(h => "{0}%".F(h)); + team.GetText = () => handicapLabel.Update(c.Handicap); + HideChildWidget(parent, "HANDICAP_DROPDOWN"); + } + public static void SetupEditableSpawnWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, MapPreview map) { var dropdown = parent.Get("SPAWN_DROPDOWN"); @@ -554,7 +613,8 @@ { var spawnPoints = Enumerable.Range(0, map.SpawnPoints.Length + 1).Except( orderManager.LobbyInfo.Clients.Where( - client => client != c && client.SpawnPoint != 0).Select(client => client.SpawnPoint)); + client => client != c && client.SpawnPoint != 0).Select(client => client.SpawnPoint)) + .Except(orderManager.LobbyInfo.DisabledSpawnPoints); ShowSpawnDropDown(dropdown, c, orderManager, spawnPoints); }; dropdown.GetText = () => (c.SpawnPoint == 0) ? "-" : Convert.ToChar('A' - 1 + c.SpawnPoint).ToString(); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Lobby/MapPreviewLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Lobby/MapPreviewLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Lobby/MapPreviewLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Lobby/MapPreviewLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -24,8 +24,8 @@ int blinkTick; [ObjectCreator.UseCtor] - internal MapPreviewLogic(Widget widget, ModData modData, OrderManager orderManager, Func getMap, - Action onMouseDown, Func> getSpawnOccupants, bool showUnoccupiedSpawnpoints) + internal MapPreviewLogic(Widget widget, ModData modData, OrderManager orderManager, Func getMap, Action onMouseDown, + Func> getSpawnOccupants, Func> getDisabledSpawnPoints, bool showUnoccupiedSpawnpoints) { var mapRepository = modData.Manifest.Get().MapRepository; @@ -38,7 +38,7 @@ return map.Status == MapStatus.Available && (!map.RulesLoaded || !map.InvalidCustomRules); }; - SetupWidgets(available, getMap, onMouseDown, getSpawnOccupants, showUnoccupiedSpawnpoints); + SetupWidgets(available, getMap, onMouseDown, getSpawnOccupants, getDisabledSpawnPoints, showUnoccupiedSpawnpoints); } var invalid = widget.GetOrNull("MAP_INVALID"); @@ -50,14 +50,14 @@ return map.Status == MapStatus.Available && map.InvalidCustomRules; }; - SetupWidgets(invalid, getMap, onMouseDown, getSpawnOccupants, showUnoccupiedSpawnpoints); + SetupWidgets(invalid, getMap, onMouseDown, getSpawnOccupants, getDisabledSpawnPoints, showUnoccupiedSpawnpoints); } var download = widget.GetOrNull("MAP_DOWNLOADABLE"); if (download != null) { download.IsVisible = () => getMap().Status == MapStatus.DownloadAvailable; - SetupWidgets(download, getMap, onMouseDown, getSpawnOccupants, showUnoccupiedSpawnpoints); + SetupWidgets(download, getMap, onMouseDown, getSpawnOccupants, getDisabledSpawnPoints, showUnoccupiedSpawnpoints); var install = download.GetOrNull("MAP_INSTALL"); if (install != null) @@ -86,7 +86,7 @@ return map.Status != MapStatus.Available && map.Status != MapStatus.DownloadAvailable; }; - SetupWidgets(progress, getMap, onMouseDown, getSpawnOccupants, showUnoccupiedSpawnpoints); + SetupWidgets(progress, getMap, onMouseDown, getSpawnOccupants, getDisabledSpawnPoints, showUnoccupiedSpawnpoints); var statusSearching = progress.GetOrNull("MAP_STATUS_SEARCHING"); if (statusSearching != null) @@ -172,12 +172,13 @@ } void SetupWidgets(Widget parent, Func getMap, - Action onMouseDown, Func> getSpawnOccupants, bool showUnoccupiedSpawnpoints) + Action onMouseDown, Func> getSpawnOccupants, Func> getDisabledSpawnPoints, bool showUnoccupiedSpawnpoints) { var preview = parent.Get("MAP_PREVIEW"); preview.Preview = () => getMap(); preview.OnMouseDown = mi => onMouseDown(preview, getMap(), mi); - preview.SpawnOccupants = () => getSpawnOccupants(getMap()); + preview.SpawnOccupants = getSpawnOccupants; + preview.DisabledSpawnPoints = getDisabledSpawnPoints; preview.ShowUnoccupiedSpawnpoints = showUnoccupiedSpawnpoints; var titleLabel = parent.GetOrNull("MAP_TITLE"); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Lobby/SpawnSelectorTooltipLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Lobby/SpawnSelectorTooltipLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/Lobby/SpawnSelectorTooltipLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/Lobby/SpawnSelectorTooltipLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -33,7 +33,6 @@ // Width specified in YAML is used as the margin between flag / label and label / border var labelMargin = widget.Bounds.Width; - var cachedWidth = 0; var labelText = ""; string playerFaction = null; var playerTeam = -1; @@ -41,10 +40,17 @@ tooltipContainer.BeforeRender = () => { showTooltip = true; - var occupant = preview.SpawnOccupants().Values.FirstOrDefault(c => c.SpawnPoint == preview.TooltipSpawnIndex); var teamWidth = 0; - if (occupant == null) + if (preview.SpawnOccupants().TryGetValue(preview.TooltipSpawnIndex, out var occupant)) + { + labelText = occupant.PlayerName; + playerFaction = occupant.Faction; + playerTeam = occupant.Team; + widget.Bounds.Height = playerTeam > 0 ? doubleHeight : singleHeight; + teamWidth = teamFont.Measure(team.GetText()).X; + } + else { if (!showUnoccupiedSpawnpoints) { @@ -52,28 +58,14 @@ return; } - labelText = "Available spawn"; + labelText = preview.DisabledSpawnPoints().Contains(preview.TooltipSpawnIndex) ? "Disabled spawn" : "Available spawn"; playerFaction = null; playerTeam = 0; widget.Bounds.Height = singleHeight; } - else - { - labelText = occupant.PlayerName; - playerFaction = occupant.Faction; - playerTeam = occupant.Team; - widget.Bounds.Height = playerTeam > 0 ? doubleHeight : singleHeight; - teamWidth = teamFont.Measure(team.GetText()).X; - } label.Bounds.X = playerFaction != null ? flag.Bounds.Right + labelMargin : labelMargin; - - var textWidth = ownerFont.Measure(labelText).X; - if (textWidth != cachedWidth) - { - label.Bounds.Width = textWidth; - widget.Bounds.Width = 2 * label.Bounds.X + textWidth; - } + label.Bounds.Width = ownerFont.Measure(labelText).X; widget.Bounds.Width = Math.Max(teamWidth + 2 * labelMargin, label.Bounds.Right + labelMargin); team.Bounds.Width = widget.Bounds.Width; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,12 +12,9 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; using System.IO; using System.Linq; -using System.Net; -using OpenRA.Primitives; +using OpenRA.Network; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic @@ -45,6 +42,8 @@ { menuType = type; + DiscordService.UpdateStatus(DiscordState.InMenu); + // Update button mouseover Game.RunAfterTick(Ui.ResetTooltips); } @@ -231,7 +230,7 @@ { Action onSysInfoComplete = () => { - LoadAndDisplayNews(webServices.GameNews, newsBG); + LoadAndDisplayNews(webServices, newsBG); SwitchMenu(MenuType.Main); }; @@ -257,13 +256,15 @@ onIntroductionComplete(); Game.OnShellmapLoaded += OpenMenuBasedOnLastGame; + + DiscordService.UpdateStatus(DiscordState.InMenu); } - void LoadAndDisplayNews(string newsURL, Widget newsBG) + void LoadAndDisplayNews(WebServices webServices, Widget newsBG) { if (newsBG != null && Game.Settings.Game.FetchNews) { - var cacheFile = Platform.ResolvePath(Platform.SupportDirPrefix, "news.yaml"); + var cacheFile = Path.Combine(Platform.SupportDir, webServices.GameNewsFileName); var currentNews = ParseNews(cacheFile); if (currentNews != null) DisplayNews(currentNews); @@ -274,7 +275,8 @@ if (!fetchedNews) { // Send the mod and engine version to support version-filtered news (update prompts) - newsURL += "?version={0}&mod={1}&modversion={2}".F( + var newsURL = "{0}?version={1}&mod={2}&modversion={3}".F( + webServices.GameNews, Uri.EscapeUriString(Game.EngineVersion), Uri.EscapeUriString(Game.ModData.Manifest.Id), Uri.EscapeUriString(Game.ModData.Manifest.Metadata.Version)); @@ -298,26 +300,26 @@ button.AttachPanel(newsPanel, () => newsOpen = false); } - void OnRemoteDirectConnect(string host, int port) + void OnRemoteDirectConnect(ConnectionTarget endpoint) { SwitchMenu(MenuType.None); Ui.OpenWindow("MULTIPLAYER_PANEL", new WidgetArgs { { "onStart", RemoveShellmapUI }, { "onExit", () => SwitchMenu(MenuType.Main) }, - { "directConnectHost", host }, - { "directConnectPort", port }, + { "directConnectEndPoint", endpoint }, }); } void LoadMapIntoEditor(string uid) { - ConnectionLogic.Connect(IPAddress.Loopback.ToString(), - Game.CreateLocalServer(uid), + ConnectionLogic.Connect(Game.CreateLocalServer(uid), "", () => { Game.LoadEditor(uid); }, () => { Game.CloseServer(); SwitchMenu(MenuType.MapEditor); }); + DiscordService.UpdateStatus(DiscordState.InMapEditor); + lastGameState = MenuPanel.MapEditor; } @@ -425,8 +427,7 @@ Game.Settings.Server.Map = map; Game.Settings.Save(); - ConnectionLogic.Connect(IPAddress.Loopback.ToString(), - Game.CreateLocalServer(map), + ConnectionLogic.Connect(Game.CreateLocalServer(map), "", OpenSkirmishLobbyPanel, () => { Game.CloseServer(); SwitchMenu(MenuType.Main); }); @@ -460,8 +461,7 @@ { { "onStart", () => { RemoveShellmapUI(); lastGameState = MenuPanel.Multiplayer; } }, { "onExit", () => SwitchMenu(MenuType.Main) }, - { "directConnectHost", null }, - { "directConnectPort", 0 }, + { "directConnectEndPoint", null }, }); } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MapChooserLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MapChooserLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MapChooserLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MapChooserLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.Linq; -using OpenRA.Primitives; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic @@ -44,7 +43,12 @@ this.modData = modData; this.onSelect = onSelect; - var approving = new Action(() => { Ui.CloseWindow(); onSelect(selectedUid); }); + var approving = new Action(() => + { + Ui.CloseWindow(); + onSelect?.Invoke(selectedUid); + }); + var canceling = new Action(() => { Ui.CloseWindow(); onExit(); }); var okButton = widget.Get("BUTTON_OK"); @@ -182,20 +186,20 @@ // Order categories alphabetically var categories = categoryDict - .Select(kv => Pair.New(kv.Key, kv.Value)) - .OrderBy(p => p.First) + .Select(kv => (Category: kv.Key, Count: kv.Value)) + .OrderBy(p => p.Category) .ToList(); // 'all game types' extra item - categories.Insert(0, Pair.New(null as string, tabMaps[tab].Count())); + categories.Insert(0, (null as string, tabMaps[tab].Count())); - Func, string> showItem = x => "{0} ({1})".F(x.First ?? "All Maps", x.Second); + Func<(string Category, int Count), string> showItem = x => "{0} ({1})".F(x.Category ?? "All Maps", x.Count); - Func, ScrollItemWidget, ScrollItemWidget> setupItem = (ii, template) => + Func<(string Category, int Count), ScrollItemWidget, ScrollItemWidget> setupItem = (ii, template) => { var item = ScrollItemWidget.Setup(template, - () => category == ii.First, - () => { category = ii.First; EnumerateMaps(tab, itemTemplate); }); + () => category == ii.Category, + () => { category = ii.Category; EnumerateMaps(tab, itemTemplate); }); item.Get("LABEL").GetText = () => showItem(ii); return item; }; @@ -205,9 +209,9 @@ gameModeDropdown.GetText = () => { - var item = categories.FirstOrDefault(m => m.First == category); - if (item == default(Pair)) - item.First = "No matches"; + var item = categories.FirstOrDefault(m => m.Category == category); + if (item == default((string, int))) + item.Category = "No matches"; return showItem(item); }; @@ -216,8 +220,7 @@ void EnumerateMaps(MapClassification tab, ScrollItemWidget template) { - int playerCountFilter; - if (!int.TryParse(mapFilter, out playerCountFilter)) + if (!int.TryParse(mapFilter, out var playerCountFilter)) playerCountFilter = -1; var maps = tabMaps[tab] @@ -332,8 +335,7 @@ onConfirm: () => { var newUid = DeleteMap(map); - if (after != null) - after(newUid); + after?.Invoke(newUid); }, confirmText: "Delete", onCancel: () => { }); @@ -347,8 +349,7 @@ onConfirm: () => { maps.Do(m => DeleteMap(m)); - if (after != null) - after(Game.ModData.MapCache.ChooseInitialMap(null, Game.CosmeticRandom)); + after?.Invoke(Game.ModData.MapCache.ChooseInitialMap(null, Game.CosmeticRandom)); }, confirmText: "Delete", onCancel: () => { }); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MissionBrowserLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -164,6 +164,9 @@ void OnGameStart() { Ui.CloseWindow(); + + DiscordService.UpdateStatus(DiscordState.PlayingCampaign); + onStart(); } @@ -347,8 +350,7 @@ player.PlayThen(() => { StopVideo(player); - if (onComplete != null) - onComplete(); + onComplete?.Invoke(); }); // Mute other distracting sounds diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MultiplayerLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,7 @@ readonly ServerListLogic serverListLogic; [ObjectCreator.UseCtor] - public MultiplayerLogic(Widget widget, ModData modData, Action onStart, Action onExit, string directConnectHost, int directConnectPort) + public MultiplayerLogic(Widget widget, ModData modData, Action onStart, Action onExit, ConnectionTarget directConnectEndPoint) { // MultiplayerLogic is a superset of the ServerListLogic // but cannot be a direct subclass because it needs to pass object-level state to the constructor @@ -41,8 +41,7 @@ { { "openLobby", OpenLobby }, { "onExit", DoNothing }, - { "directConnectHost", null }, - { "directConnectPort", 0 }, + { "directConnectEndPoint", null }, }); }; @@ -61,7 +60,7 @@ widget.Get("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; - if (directConnectHost != null) + if (directConnectEndPoint != null) { // The connection window must be opened at the end of the tick for the widget hierarchy to // work out, but we also want to prevent the server browser from flashing visible for one tick. @@ -72,8 +71,7 @@ { { "openLobby", OpenLobby }, { "onExit", DoNothing }, - { "directConnectHost", directConnectHost }, - { "directConnectPort", directConnectPort }, + { "directConnectEndPoint", directConnectEndPoint }, }); widget.Visible = true; @@ -93,11 +91,12 @@ { { "onStart", onStart }, { "onExit", onExit }, - { "directConnectHost", null }, - { "directConnectPort", 0 }, + { "directConnectEndPoint", null }, }); Game.Disconnect(); + + DiscordService.UpdateStatus(DiscordState.InMenu); }; Game.OpenWindow("SERVER_LOBBY", new WidgetArgs @@ -116,7 +115,7 @@ var host = server.Address.Split(':')[0]; var port = Exts.ParseIntegerInvariant(server.Address.Split(':')[1]); - ConnectionLogic.Connect(host, port, "", OpenLobby, DoNothing); + ConnectionLogic.Connect(new ConnectionTarget(host, port), "", OpenLobby, DoNothing); } bool disposed; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MusicHotkeyLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MusicHotkeyLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MusicHotkeyLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MusicHotkeyLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,9 +26,8 @@ { musicPlaylist = world.WorldActor.Trait(); - MiniYaml yaml; var stopKey = new HotkeyReference(); - if (logicArgs.TryGetValue("StopMusicKey", out yaml)) + if (logicArgs.TryGetValue("StopMusicKey", out var yaml)) stopKey = modData.Hotkeys[yaml.Value]; var pauseKey = new HotkeyReference(); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MuteHotkeyLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MuteHotkeyLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/MuteHotkeyLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/MuteHotkeyLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System.Collections.Generic; using OpenRA.Mods.Common.Lint; -using OpenRA.Primitives; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -63,7 +63,7 @@ var template = panel.Get("REPLAY_TEMPLATE"); var mod = modData.Manifest; - var dir = Platform.ResolvePath(Platform.SupportDirPrefix, "Replays", mod.Id, mod.Metadata.Version); + var dir = Path.Combine(Platform.SupportDir, "Replays", mod.Id, mod.Metadata.Version); if (Directory.Exists(dir)) ThreadPool.QueueUserWorkItem(_ => LoadReplays(dir, template)); @@ -76,15 +76,27 @@ mapPreviewRoot.IsVisible = () => selectedReplay != null; panel.Get("REPLAY_INFO").IsVisible = () => selectedReplay != null; + var spawnOccupants = new CachedTransform>(r => + { + // Avoid using .ToDictionary to improve robustness against replays defining duplicate spawn assignments + var occupants = new Dictionary(); + foreach (var p in r.GameInfo.Players) + if (p.SpawnPoint != 0) + occupants[p.SpawnPoint] = new SpawnOccupant(p); + + return occupants; + }); + + var noSpawns = new HashSet(); + var disabledSpawnPoints = new CachedTransform>(r => r.GameInfo.DisabledSpawnPoints ?? noSpawns); + Ui.LoadWidget("MAP_PREVIEW", mapPreviewRoot, new WidgetArgs { { "orderManager", null }, { "getMap", (Func)(() => map) }, { "onMouseDown", (Action)((preview, mapPreview, mi) => { }) }, - { - "getSpawnOccupants", (Func>)(mapPreview => - LobbyUtils.GetSpawnOccupants(selectedReplay.GameInfo.Players, mapPreview)) - }, + { "getSpawnOccupants", (Func>)(() => spawnOccupants.Update(selectedReplay)) }, + { "getDisabledSpawnPoints", (Func>)(() => disabledSpawnPoints.Update(selectedReplay)) }, { "showUnoccupiedSpawnpoints", false }, }); @@ -138,25 +150,25 @@ if (ddb != null) { // Using list to maintain the order - var options = new List> + var options = new List<(GameType GameType, string Text)> { - Pair.New(GameType.Any, ddb.GetText()), - Pair.New(GameType.Singleplayer, "Singleplayer"), - Pair.New(GameType.Multiplayer, "Multiplayer") + (GameType.Any, ddb.GetText()), + (GameType.Singleplayer, "Singleplayer"), + (GameType.Multiplayer, "Multiplayer") }; - var lookup = options.ToDictionary(kvp => kvp.First, kvp => kvp.Second); + var lookup = options.ToDictionary(kvp => kvp.GameType, kvp => kvp.Text); ddb.GetText = () => lookup[filter.Type]; ddb.OnMouseDown = _ => { - Func, ScrollItemWidget, ScrollItemWidget> setupItem = (option, tpl) => + Func<(GameType GameType, string Text), ScrollItemWidget, ScrollItemWidget> setupItem = (option, tpl) => { var item = ScrollItemWidget.Setup( tpl, - () => filter.Type == option.First, - () => { filter.Type = option.First; ApplyFilter(); }); - item.Get("LABEL").GetText = () => option.Second; + () => filter.Type == option.GameType, + () => { filter.Type = option.GameType; ApplyFilter(); }); + item.Get("LABEL").GetText = () => option.Text; return item; }; @@ -171,28 +183,28 @@ if (ddb != null) { // Using list to maintain the order - var options = new List> + var options = new List<(DateType DateType, string Text)> { - Pair.New(DateType.Any, ddb.GetText()), - Pair.New(DateType.Today, "Today"), - Pair.New(DateType.LastWeek, "Last 7 days"), - Pair.New(DateType.LastFortnight, "Last 14 days"), - Pair.New(DateType.LastMonth, "Last 30 days") + (DateType.Any, ddb.GetText()), + (DateType.Today, "Today"), + (DateType.LastWeek, "Last 7 days"), + (DateType.LastFortnight, "Last 14 days"), + (DateType.LastMonth, "Last 30 days") }; - var lookup = options.ToDictionary(kvp => kvp.First, kvp => kvp.Second); + var lookup = options.ToDictionary(kvp => kvp.DateType, kvp => kvp.Text); ddb.GetText = () => lookup[filter.Date]; ddb.OnMouseDown = _ => { - Func, ScrollItemWidget, ScrollItemWidget> setupItem = (option, tpl) => + Func<(DateType DateType, string Text), ScrollItemWidget, ScrollItemWidget> setupItem = (option, tpl) => { var item = ScrollItemWidget.Setup( tpl, - () => filter.Date == option.First, - () => { filter.Date = option.First; ApplyFilter(); }); + () => filter.Date == option.DateType, + () => { filter.Date = option.DateType; ApplyFilter(); }); - item.Get("LABEL").GetText = () => option.Second; + item.Get("LABEL").GetText = () => option.Text; return item; }; @@ -207,27 +219,27 @@ if (ddb != null) { // Using list to maintain the order - var options = new List> + var options = new List<(DurationType DurationType, string Text)> { - Pair.New(DurationType.Any, ddb.GetText()), - Pair.New(DurationType.VeryShort, "Under 5 min"), - Pair.New(DurationType.Short, "Short (10 min)"), - Pair.New(DurationType.Medium, "Medium (30 min)"), - Pair.New(DurationType.Long, "Long (60+ min)") + (DurationType.Any, ddb.GetText()), + (DurationType.VeryShort, "Under 5 min"), + (DurationType.Short, "Short (10 min)"), + (DurationType.Medium, "Medium (30 min)"), + (DurationType.Long, "Long (60+ min)") }; - var lookup = options.ToDictionary(kvp => kvp.First, kvp => kvp.Second); + var lookup = options.ToDictionary(kvp => kvp.DurationType, kvp => kvp.Text); ddb.GetText = () => lookup[filter.Duration]; ddb.OnMouseDown = _ => { - Func, ScrollItemWidget, ScrollItemWidget> setupItem = (option, tpl) => + Func<(DurationType DurationType, string Text), ScrollItemWidget, ScrollItemWidget> setupItem = (option, tpl) => { var item = ScrollItemWidget.Setup( tpl, - () => filter.Duration == option.First, - () => { filter.Duration = option.First; ApplyFilter(); }); - item.Get("LABEL").GetText = () => option.Second; + () => filter.Duration == option.DurationType, + () => { filter.Duration = option.DurationType; ApplyFilter(); }); + item.Get("LABEL").GetText = () => option.Text; return item; }; @@ -244,25 +256,25 @@ ddb.IsDisabled = () => string.IsNullOrEmpty(filter.PlayerName); // Using list to maintain the order - var options = new List> + var options = new List<(WinState WinState, string Text)> { - Pair.New(WinState.Undefined, ddb.GetText()), - Pair.New(WinState.Lost, "Defeat"), - Pair.New(WinState.Won, "Victory") + (WinState.Undefined, ddb.GetText()), + (WinState.Lost, "Defeat"), + (WinState.Won, "Victory") }; - var lookup = options.ToDictionary(kvp => kvp.First, kvp => kvp.Second); + var lookup = options.ToDictionary(kvp => kvp.WinState, kvp => kvp.Text); ddb.GetText = () => lookup[filter.Outcome]; ddb.OnMouseDown = _ => { - Func, ScrollItemWidget, ScrollItemWidget> setupItem = (option, tpl) => + Func<(WinState WinState, string Text), ScrollItemWidget, ScrollItemWidget> setupItem = (option, tpl) => { var item = ScrollItemWidget.Setup( tpl, - () => filter.Outcome == option.First, - () => { filter.Outcome = option.First; ApplyFilter(); }); - item.Get("LABEL").GetText = () => option.Second; + () => filter.Outcome == option.WinState, + () => { filter.Outcome = option.WinState; ApplyFilter(); }); + item.Get("LABEL").GetText = () => option.Text; return item; }; @@ -415,8 +427,7 @@ onConfirm: () => { DeleteReplay(r); - if (after != null) - after.Invoke(); + after?.Invoke(); }, confirmText: "Delete", onCancel: () => { }); @@ -688,6 +699,9 @@ if (selectedReplay != null && ReplayUtils.PromptConfirmReplayCompatibility(selectedReplay)) { cancelLoadingReplays = true; + + DiscordService.UpdateStatus(DiscordState.WatchingReplay); + Game.JoinReplay(selectedReplay.FilePath); } } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/ServerCreationLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/ServerCreationLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/ServerCreationLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/ServerCreationLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,7 +11,6 @@ using System; using System.Linq; -using System.Net; using OpenRA.Network; using OpenRA.Primitives; using OpenRA.Widgets; @@ -178,8 +177,7 @@ void CreateAndJoin() { var name = Settings.SanitizedServerName(panel.Get("SERVER_NAME").Text); - int listenPort; - if (!Exts.TryParseIntegerInvariant(panel.Get("LISTEN_PORT").Text, out listenPort)) + if (!Exts.TryParseIntegerInvariant(panel.Get("LISTEN_PORT").Text, out var listenPort)) listenPort = 1234; var passwordField = panel.GetOrNull("PASSWORD"); @@ -199,7 +197,10 @@ // Create and join the server try { - Game.CreateServer(settings); + var endpoint = Game.CreateServer(settings); + + Ui.CloseWindow(); + ConnectionLogic.Connect(endpoint, password, onCreate, onExit); } catch (System.Net.Sockets.SocketException e) { @@ -212,11 +213,7 @@ message += "\nError is: \"{0}\" ({1})".F(e.Message, e.ErrorCode); ConfirmationDialogs.ButtonPrompt("Server Creation Failed", message, onCancel: () => { }, cancelText: "Back"); - return; } - - Ui.CloseWindow(); - ConnectionLogic.Connect(IPAddress.Loopback.ToString(), Game.Settings.Server.ListenPort, password, onCreate, onExit); } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/ServerListLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/ServerListLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/ServerListLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/ServerListLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -334,14 +334,24 @@ List games = null; if (i.Error == null) { + games = new List(); try { var data = Encoding.UTF8.GetString(i.Result); var yaml = MiniYaml.FromString(data); - - games = yaml.Select(a => new GameServer(a.Value)) - .Where(gs => gs.Address != null) - .ToList(); + foreach (var node in yaml) + { + try + { + var gs = new GameServer(node.Value); + if (gs.Address != null) + games.Add(gs); + } + catch + { + // Ignore any invalid games advertised. + } + } } catch { @@ -424,9 +434,10 @@ var spawns = currentMap.SpawnPoints; var occupants = server.Clients .Where(c => (c.SpawnPoint - 1 >= 0) && (c.SpawnPoint - 1 < spawns.Length)) - .ToDictionary(c => spawns[c.SpawnPoint - 1], c => new SpawnOccupant(c, server.Mod != modData.Manifest.Id)); + .ToDictionary(c => c.SpawnPoint, c => new SpawnOccupant(c, server.Mod != modData.Manifest.Id)); mapPreview.SpawnOccupants = () => occupants; + mapPreview.DisabledSpawnPoints = () => server.DisabledSpawnPoints; } if (server == null || !server.Clients.Any()) @@ -541,8 +552,7 @@ foreach (var row in rows) serverList.AddChild(row); - if (nextServerRow != null) - nextServerRow.OnClick(); + nextServerRow?.OnClick(); playerCount = games.Sum(g => g.Players); }); @@ -744,8 +754,7 @@ if (disposing && !disposed) { disposed = true; - if (lanGameProbe != null) - lanGameProbe.Dispose(); + lanGameProbe?.Dispose(); } base.Dispose(disposing); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/SettingsLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/SettingsLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/SettingsLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/SettingsLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -44,9 +44,12 @@ SoundDevice soundDevice; PanelType settingsPanel = PanelType.Display; + ScrollPanelWidget hotkeyList; ButtonWidget selectedHotkeyButton; HotkeyEntryWidget hotkeyEntryWidget; HotkeyDefinition duplicateHotkeyDefinition, selectedHotkeyDefinition; + int validHotkeyEntryWidth; + int invalidHotkeyEntryWidth; bool isHotkeyValid; bool isHotkeyDefault; @@ -172,7 +175,7 @@ ss.OnChange += x => field.SetValue(group, (int)x); } - void BindHotkeyPref(HotkeyDefinition hd, Widget template, Widget parent) + void BindHotkeyPref(HotkeyDefinition hd, Widget template) { var key = template.Clone() as Widget; key.Id = hd.Name; @@ -209,7 +212,7 @@ hotkeyEntryWidget.TakeKeyboardFocus(); }; - parent.AddChild(key); + hotkeyList.AddChild(key); } void RegisterSettingsPanel(PanelType type, Func init, Func reset, string panelID, string buttonID) @@ -243,6 +246,8 @@ BindCheckboxPref(panel, "FRAME_LIMIT_CHECKBOX", ds, "CapFramerate"); BindIntSliderPref(panel, "FRAME_LIMIT_SLIDER", ds, "MaxFramerate"); BindCheckboxPref(panel, "PLAYER_STANCE_COLORS_CHECKBOX", gs, "UsePlayerStanceColors"); + if (panel.GetOrNull("PAUSE_SHELLMAP_CHECKBOX") != null) + BindCheckboxPref(panel, "PAUSE_SHELLMAP_CHECKBOX", gs, "PauseShellmap"); var languageDropDownButton = panel.GetOrNull("LANGUAGE_DROPDOWNBUTTON"); if (languageDropDownButton != null) @@ -264,9 +269,10 @@ var glProfileLabel = new CachedTransform(p => p.ToString()); var glProfileDropdown = panel.Get("GL_PROFILE_DROPDOWN"); + var disableProfile = Game.Renderer.SupportedGLProfiles.Length < 2 && ds.GLProfile == GLProfile.Automatic; glProfileDropdown.OnMouseDown = _ => ShowGLProfileDropdown(glProfileDropdown, ds); glProfileDropdown.GetText = () => glProfileLabel.Update(ds.GLProfile); - glProfileDropdown.IsDisabled = () => Game.Renderer.SupportedGLProfiles.Length < 2; + glProfileDropdown.IsDisabled = () => disableProfile; var statusBarsDropDown = panel.Get("STATUS_BAR_DROPDOWN"); statusBarsDropDown.OnMouseDown = _ => ShowStatusBarsDropdown(statusBarsDropDown, gs); @@ -367,9 +373,8 @@ return () => { - int x, y; - Exts.TryParseIntegerInvariant(windowWidth.Text, out x); - Exts.TryParseIntegerInvariant(windowHeight.Text, out y); + Exts.TryParseIntegerInvariant(windowWidth.Text, out var x); + Exts.TryParseIntegerInvariant(windowHeight.Text, out var y); ds.WindowedSize = new int2(x, y); nameTextfield.YieldKeyboardFocus(); }; @@ -578,7 +583,7 @@ Action InitHotkeysPanel(Widget panel) { var hotkeyDialogRoot = panel.Get("HOTKEY_DIALOG_ROOT"); - var hotkeyList = panel.Get("HOTKEY_LIST"); + hotkeyList = panel.Get("HOTKEY_LIST"); hotkeyList.Layout = new GridLayout(hotkeyList); var hotkeyHeader = hotkeyList.Get("HEADER"); var templates = hotkeyList.Get("TEMPLATES"); @@ -587,8 +592,7 @@ Func returnTrue = () => true; Action doNothing = () => { }; - MiniYaml hotkeyGroups; - if (logicArgs.TryGetValue("HotkeyGroups", out hotkeyGroups)) + if (logicArgs.TryGetValue("HotkeyGroups", out var hotkeyGroups)) { InitHotkeyRemapDialog(panel); @@ -616,7 +620,7 @@ if (selectedHotkeyDefinition == null) selectedHotkeyDefinition = hd; - BindHotkeyPref(hd, template, hotkeyList); + BindHotkeyPref(hd, template); } } } @@ -892,7 +896,8 @@ return item; }; - dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, Game.Renderer.SupportedGLProfiles, setupItem); + var profiles = new[] { GLProfile.Automatic }.Concat(Game.Renderer.SupportedGLProfiles); + dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, profiles, setupItem); } static void ShowTargetLinesDropdown(DropDownButtonWidget dropdown, GameSettings s) @@ -940,7 +945,7 @@ if (farRange.X < windowHeight) validSizes.Add(WorldViewport.Far); - if (farRange.Y < windowHeight) + if (viewportSizes.AllowNativeZoom && farRange.Y < windowHeight) validSizes.Add(WorldViewport.Native); dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, validSizes, setupItem); @@ -1057,9 +1062,21 @@ clearButton.IsDisabled = () => !hotkeyEntryWidget.Key.IsValid(); clearButton.OnClick = ClearHotkey; + var overrideButton = panel.Get("OVERRIDE_HOTKEY_BUTTON"); + overrideButton.IsDisabled = () => isHotkeyValid; + overrideButton.IsVisible = () => !isHotkeyValid; + overrideButton.OnClick = OverrideHotkey; + hotkeyEntryWidget = panel.Get("HOTKEY_ENTRY"); hotkeyEntryWidget.IsValid = () => isHotkeyValid; hotkeyEntryWidget.OnLoseFocus = ValidateHotkey; + hotkeyEntryWidget.OnEscKey = () => + { + hotkeyEntryWidget.Key = modData.Hotkeys[selectedHotkeyDefinition.Name].GetValue(); + }; + + validHotkeyEntryWidth = hotkeyEntryWidget.Bounds.Width; + invalidHotkeyEntryWidth = validHotkeyEntryWidth - (clearButton.Bounds.X - overrideButton.Bounds.X); } void ValidateHotkey() @@ -1069,7 +1086,15 @@ isHotkeyDefault = hotkeyEntryWidget.Key == selectedHotkeyDefinition.Default || (!hotkeyEntryWidget.Key.IsValid() && !selectedHotkeyDefinition.Default.IsValid()); if (isHotkeyValid) + { + hotkeyEntryWidget.Bounds.Width = validHotkeyEntryWidth; SaveHotkey(); + } + else + { + hotkeyEntryWidget.Bounds.Width = invalidHotkeyEntryWidth; + hotkeyEntryWidget.TakeKeyboardFocus(); + } } void SaveHotkey() @@ -1090,5 +1115,14 @@ hotkeyEntryWidget.Key = Hotkey.Invalid; hotkeyEntryWidget.YieldKeyboardFocus(); } + + void OverrideHotkey() + { + var duplicateHotkeyButton = hotkeyList.Get(duplicateHotkeyDefinition.Name).Get("HOTKEY"); + WidgetUtils.TruncateButtonToTooltip(duplicateHotkeyButton, Hotkey.Invalid.DisplayString()); + modData.Hotkeys.Set(duplicateHotkeyDefinition.Name, Hotkey.Invalid); + Game.Settings.Save(); + hotkeyEntryWidget.YieldKeyboardFocus(); + } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/SingleHotkeyBaseLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/SingleHotkeyBaseLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/SingleHotkeyBaseLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/SingleHotkeyBaseLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,10 +18,8 @@ { protected SingleHotkeyBaseLogic(Widget widget, ModData modData, string argName, string parentName, Dictionary logicArgs) { - MiniYaml yaml; - var namedKey = new HotkeyReference(); - if (logicArgs.TryGetValue(argName, out yaml)) + if (logicArgs.TryGetValue(argName, out var yaml)) namedKey = modData.Hotkeys[yaml.Value]; var keyhandler = widget.Get(parentName); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/Logic/SystemInfoPromptLogic.cs openra-20210321/OpenRA.Mods.Common/Widgets/Logic/SystemInfoPromptLogic.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/Logic/SystemInfoPromptLogic.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/Logic/SystemInfoPromptLogic.cs 2021-03-21 11:10:05.000000000 +0000 @@ -11,13 +11,9 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.IO; using System.Linq; -using System.Net; -using OpenRA.Primitives; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic @@ -29,22 +25,22 @@ // Increment the version number when adding new stats const int SystemInformationVersion = 4; - static Dictionary> GetSystemInformation() + static Dictionary GetSystemInformation() { var lang = CultureInfo.InstalledUICulture.TwoLetterISOLanguageName; - return new Dictionary>() + return new Dictionary() { - { "id", Pair.New("Anonymous ID", Game.Settings.Debug.UUID) }, - { "platform", Pair.New("OS Type", Platform.CurrentPlatform.ToString()) }, - { "os", Pair.New("OS Version", Environment.OSVersion.ToString()) }, - { "x64", Pair.New("OS is 64 bit", Environment.Is64BitOperatingSystem.ToString()) }, - { "x64process", Pair.New("Process is 64 bit", Environment.Is64BitProcess.ToString()) }, - { "runtime", Pair.New(".NET Runtime", Platform.RuntimeVersion) }, - { "gl", Pair.New("OpenGL Version", Game.Renderer.GLVersion) }, - { "windowsize", Pair.New("Window Size", "{0}x{1}".F(Game.Renderer.NativeResolution.Width, Game.Renderer.NativeResolution.Height)) }, - { "windowscale", Pair.New("Window Scale", Game.Renderer.NativeWindowScale.ToString("F2", CultureInfo.InvariantCulture)) }, - { "uiscale", Pair.New("UI Scale", Game.Settings.Graphics.UIScale.ToString("F2", CultureInfo.InvariantCulture)) }, - { "lang", Pair.New("System Language", lang) } + { "id", ("Anonymous ID", Game.Settings.Debug.UUID) }, + { "platform", ("OS Type", Platform.CurrentPlatform.ToString()) }, + { "os", ("OS Version", Environment.OSVersion.ToString()) }, + { "x64", ("OS is 64 bit", Environment.Is64BitOperatingSystem.ToString()) }, + { "x64process", ("Process is 64 bit", Environment.Is64BitProcess.ToString()) }, + { "runtime", (".NET Runtime", Platform.RuntimeVersion) }, + { "gl", ("OpenGL Version", Game.Renderer.GLVersion) }, + { "windowsize", ("Window Size", "{0}x{1}".F(Game.Renderer.NativeResolution.Width, Game.Renderer.NativeResolution.Height)) }, + { "windowscale", ("Window Scale", Game.Renderer.NativeWindowScale.ToString("F2", CultureInfo.InvariantCulture)) }, + { "uiscale", ("UI Scale", Game.Settings.Graphics.UIScale.ToString("F2", CultureInfo.InvariantCulture)) }, + { "lang", ("System Language", lang) } }; } @@ -60,7 +56,7 @@ return "&sysinfoversion={0}&".F(SystemInformationVersion) + GetSystemInformation() - .Select(kv => kv.Key + "=" + Uri.EscapeUriString(kv.Value.Second)) + .Select(kv => kv.Key + "=" + Uri.EscapeUriString(kv.Value.Value)) .JoinWith("&"); } @@ -78,7 +74,7 @@ foreach (var info in GetSystemInformation().Values) { var label = template.Clone() as LabelWidget; - var text = info.First + ": " + info.Second; + var text = info.Label + ": " + info.Value; label.GetText = () => text; sysInfoData.AddChild(label); } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/MapPreviewWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/MapPreviewWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/MapPreviewWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/MapPreviewWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -57,6 +57,8 @@ public class MapPreviewWidget : Widget { + static readonly int[] NoDisabledSpawnPoints = Array.Empty(); + public readonly bool IgnoreMouseInput = false; public readonly bool ShowSpawnPoints = true; @@ -64,13 +66,14 @@ public readonly string TooltipTemplate = "SPAWN_TOOLTIP"; readonly Lazy tooltipContainer; - readonly Sprite spawnClaimed, spawnUnclaimed; + readonly Sprite spawnClaimed, spawnUnclaimed, spawnDisabled; readonly SpriteFont spawnFont; readonly Color spawnColor, spawnContrastColor; readonly int2 spawnLabelOffset; public Func Preview = () => null; - public Func> SpawnOccupants = () => new Dictionary(); + public Func> SpawnOccupants = () => new Dictionary(); + public Func> DisabledSpawnPoints = () => NoDisabledSpawnPoints; public Action OnMouseDown = _ => { }; public int TooltipSpawnIndex = -1; public bool ShowUnoccupiedSpawnpoints = true; @@ -85,6 +88,7 @@ spawnClaimed = ChromeProvider.GetImage("lobby-bits", "spawn-claimed"); spawnUnclaimed = ChromeProvider.GetImage("lobby-bits", "spawn-unclaimed"); + spawnDisabled = ChromeProvider.GetImage("lobby-bits", "spawn-disabled") ?? spawnUnclaimed; spawnFont = Game.Renderer.Fonts[ChromeMetrics.Get("SpawnFont")]; spawnColor = ChromeMetrics.Get("SpawnColor"); spawnContrastColor = ChromeMetrics.Get("SpawnContrastColor"); @@ -182,28 +186,40 @@ TooltipSpawnIndex = -1; if (ShowSpawnPoints) { - var colors = SpawnOccupants().ToDictionary(c => c.Key, c => c.Value.Color); - var spawnPoints = preview.SpawnPoints; + var occupants = SpawnOccupants(); + var disabledSpawnPoints = DisabledSpawnPoints(); var gridType = preview.GridType; - foreach (var p in spawnPoints) + for (var i = 0; i < spawnPoints.Length; i++) { - var owned = colors.ContainsKey(p); + var p = spawnPoints[i]; + + // Spawn numbers are 1 indexed with 0 meaning "random spawn". + var occupied = occupants.TryGetValue(i + 1, out var occupant); + var disabled = disabledSpawnPoints.Contains(i + 1); var pos = ConvertToPreview(p, gridType); - var sprite = owned ? spawnClaimed : spawnUnclaimed; + + var sprite = disabled ? spawnDisabled : occupied ? spawnClaimed : spawnUnclaimed; var offset = sprite.Size.XY.ToInt2() / 2; - if (owned) - WidgetUtils.FillEllipseWithColor(new Rectangle(pos.X - offset.X + 1, pos.Y - offset.Y + 1, (int)sprite.Size.X - 2, (int)sprite.Size.Y - 2), colors[p]); + if (((pos - Viewport.LastMousePos).ToFloat2() / offset.ToFloat2()).LengthSquared <= 1) + TooltipSpawnIndex = spawnPoints.IndexOf(p) + 1; + + if (disabled) + { + Game.Renderer.RgbaSpriteRenderer.DrawSprite(spawnDisabled, pos - offset); + continue; + } + + if (occupied) + WidgetUtils.FillEllipseWithColor(new Rectangle(pos.X - offset.X + 1, pos.Y - offset.Y + 1, (int)sprite.Size.X - 2, (int)sprite.Size.Y - 2), occupant.Color); Game.Renderer.RgbaSpriteRenderer.DrawSprite(sprite, pos - offset); + var number = Convert.ToChar('A' + spawnPoints.IndexOf(p)).ToString(); var textOffset = spawnFont.Measure(number) / 2 + spawnLabelOffset; spawnFont.DrawTextWithContrast(number, pos - textOffset, spawnColor, spawnContrastColor, 1); - - if (((pos - Viewport.LastMousePos).ToFloat2() / offset.ToFloat2()).LengthSquared <= 1) - TooltipSpawnIndex = spawnPoints.IndexOf(p) + 1; } } } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ObserverArmyIconsWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ObserverArmyIconsWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ObserverArmyIconsWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ObserverArmyIconsWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -107,7 +107,8 @@ var iconTopLeft = RenderOrigin + topLeftOffset; var centerPosition = iconTopLeft; - WidgetUtils.DrawSHPCentered(icon.Image, centerPosition + 0.5f * iconSize, worldRenderer.Palette(unit.IconPalette), 0.5f); + var palette = unit.IconPaletteIsPlayerPalette ? unit.IconPalette + player.InternalName : unit.IconPalette; + WidgetUtils.DrawSHPCentered(icon.Image, centerPosition + 0.5f * iconSize, worldRenderer.Palette(palette), 0.5f); armyIcons.Add(new ArmyIcon { diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ObserverProductionIconsWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ObserverProductionIconsWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ObserverProductionIconsWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ObserverProductionIconsWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -146,7 +146,8 @@ var iconTopLeft = RenderOrigin + topLeftOffset; var centerPosition = iconTopLeft + 0.5f * iconSize; - WidgetUtils.DrawSHPCentered(icon.Image, centerPosition, worldRenderer.Palette(bi.IconPalette), 0.5f); + var palette = bi.IconPaletteIsPlayerPalette ? bi.IconPalette + player.InternalName : bi.IconPalette; + WidgetUtils.DrawSHPCentered(icon.Image, centerPosition, worldRenderer.Palette(palette), 0.5f); var rect = new Rectangle((int)iconTopLeft.X, (int)iconTopLeft.Y, (int)iconSize.X, (int)iconSize.Y); productionIcons.Add(new ProductionIcon diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ObserverSupportPowerIconsWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ObserverSupportPowerIconsWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ObserverSupportPowerIconsWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ObserverSupportPowerIconsWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,7 +23,6 @@ { public readonly string TooltipTemplate = "SUPPORT_POWER_TOOLTIP"; public readonly string TooltipContainer; - readonly Animation icon; readonly World world; readonly WorldRenderer worldRenderer; readonly Dictionary clocks; @@ -45,6 +44,7 @@ readonly List supportPowerIconsIcons = new List(); readonly List supportPowerIconsBounds = new List(); + Animation icon; int lastIconIdx; int currentTooltipToken; @@ -54,7 +54,6 @@ this.world = world; this.worldRenderer = worldRenderer; clocks = new Dictionary(); - icon = new Animation(world, "icon"); // Timers in replays should be synced to the effective game time, not the playback time. timestep = world.Timestep; @@ -125,6 +124,7 @@ if (item == null || item.Info == null || item.Info.Icon == null) continue; + icon = new Animation(worldRenderer.World, item.Info.IconImage); icon.Play(item.Info.Icon); var location = new float2(RenderBounds.Location) + new float2(power.i * (IconWidth + IconSpacing), 0); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -65,6 +65,9 @@ public readonly string NotBuildableSequence = "idle"; public readonly string NotBuildablePalette = "chrome"; + public readonly string OverlayFont = "TinyBold"; + public readonly string SymbolsFont = "Symbols"; + public readonly bool DrawTime = true; [Translate] @@ -98,8 +101,18 @@ public ProductionQueue CurrentQueue { - get { return currentQueue; } - set { currentQueue = value; RefreshIcons(); } + get + { + return currentQueue; + } + set + { + currentQueue = value; + if (currentQueue != null) + UpdateCachedProductionIconOverlays(); + + RefreshIcons(); + } } public override Rectangle EventBounds { get { return eventBounds; } } @@ -110,7 +123,10 @@ readonly WorldRenderer worldRenderer; SpriteFont overlayFont, symbolFont; - float2 holdOffset, readyOffset, timeOffset, queuedOffset, infiniteOffset; + float2 iconOffset, holdOffset, readyOffset, timeOffset, queuedOffset, infiniteOffset; + + Player cachedQueueOwner; + IProductionIconOverlay[] pios; [CustomLintableHotkeyNames] public static IEnumerable LinterHotkeyNames(MiniYamlNode widgetNode, Action emitError, Action emitWarning) @@ -148,9 +164,6 @@ cantBuild = new Animation(world, NotBuildableAnimation); cantBuild.PlayFetchIndex(NotBuildableSequence, () => 0); clock = new Animation(world, ClockAnimation); - - overlayFont = Game.Renderer.Fonts["TinyBold"]; - Game.Renderer.Fonts.TryGetValue("Symbols", out symbolFont); } public override void Initialize(WidgetArgs args) @@ -159,6 +172,19 @@ hotkeys = Exts.MakeArray(HotkeyCount, i => modData.Hotkeys[HotkeyPrefix + (i + 1).ToString("D2")]); + + overlayFont = Game.Renderer.Fonts[OverlayFont]; + Game.Renderer.Fonts.TryGetValue(SymbolsFont, out symbolFont); + + iconOffset = 0.5f * IconSize.ToFloat2() + IconSpriteOffset; + queuedOffset = new float2(4, 2); + holdOffset = iconOffset - overlayFont.Measure(HoldText) / 2; + readyOffset = iconOffset - overlayFont.Measure(ReadyText) / 2; + + if (ChromeMetrics.TryGet("InfiniteOffset", out infiniteOffset)) + infiniteOffset += queuedOffset; + else + infiniteOffset = queuedOffset; } public void ScrollDown() @@ -212,7 +238,12 @@ CurrentQueue = null; if (CurrentQueue != null) + { + if (CurrentQueue.Actor.Owner != cachedQueueOwner) + UpdateCachedProductionIconOverlays(); + RefreshIcons(); + } } public override void MouseEntered() @@ -292,8 +323,7 @@ { // Queue a new item Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Sounds", ClickSound, null); - string notification; - var canQueue = CurrentQueue.CanQueue(buildable, out notification); + var canQueue = CurrentQueue.CanQueue(buildable, out var notification); if (!CurrentQueue.AllQueued().Any()) Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", notification, World.LocalPlayer.Faction.InternalName); @@ -401,6 +431,12 @@ return true; } + void UpdateCachedProductionIconOverlays() + { + cachedQueueOwner = CurrentQueue.Actor.Owner; + pios = cachedQueueOwner.PlayerActor.TraitsImplementing().ToArray(); + } + public void RefreshIcons() { icons = new Dictionary(); @@ -433,13 +469,15 @@ var bi = item.TraitInfo(); icon.Play(bi.Icon); + var palette = bi.IconPaletteIsPlayerPalette ? bi.IconPalette + producer.Actor.Owner.InternalName : bi.IconPalette; + var pi = new ProductionIcon() { Actor = item, Name = item.Name, Hotkey = DisplayedIconCount < HotkeyCount ? hotkeys[DisplayedIconCount] : null, Sprite = icon.Image, - Palette = worldRenderer.Palette(bi.IconPalette), + Palette = worldRenderer.Palette(palette), IconClockPalette = worldRenderer.Palette(ClockPalette), IconDarkenPalette = worldRenderer.Palette(NotBuildablePalette), Pos = new float2(rect.Location), @@ -459,25 +497,13 @@ public override void Draw() { - var iconOffset = 0.5f * IconSize.ToFloat2() + IconSpriteOffset; - timeOffset = iconOffset - overlayFont.Measure(WidgetUtils.FormatTime(0, World.Timestep)) / 2; - queuedOffset = new float2(4, 2); - holdOffset = iconOffset - overlayFont.Measure(HoldText) / 2; - readyOffset = iconOffset - overlayFont.Measure(ReadyText) / 2; - - if (ChromeMetrics.TryGet("InfiniteOffset", out infiniteOffset)) - infiniteOffset += queuedOffset; - else - infiniteOffset = queuedOffset; if (CurrentQueue == null) return; var buildableItems = CurrentQueue.BuildableItems(); - var pios = currentQueue.Actor.Owner.PlayerActor.TraitsImplementing(); - // Icons Game.Renderer.EnableAntialiasingFilter(); foreach (var icon in icons.Values) @@ -530,7 +556,7 @@ icon.Pos + timeOffset, Color.White, Color.Black, 1); - if (first.Infinite) + if (first.Infinite && symbolFont != null) symbolFont.DrawTextWithContrast(InfiniteSymbol, icon.Pos + infiniteOffset, Color.White, Color.Black, 1); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ProductionTabsWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ProductionTabsWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ProductionTabsWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ProductionTabsWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -83,11 +83,15 @@ public string Button = "button"; public string Background = "panel-black"; + public readonly string Decorations = "scrollpanel-decorations"; + public readonly string DecorationScrollLeft = "left"; + public readonly string DecorationScrollRight = "right"; int contentWidth = 0; float listOffset = 0; bool leftPressed = false; bool rightPressed = false; + SpriteFont font; Rectangle leftButtonRect; Rectangle rightButtonRect; Lazy paletteWidget; @@ -107,6 +111,16 @@ paletteWidget = Exts.Lazy(() => Ui.Root.Get(PaletteWidget)); } + public override void Initialize(WidgetArgs args) + { + base.Initialize(args); + + var rb = RenderBounds; + leftButtonRect = new Rectangle(rb.X, rb.Y, ArrowWidth, rb.Height); + rightButtonRect = new Rectangle(rb.Right - ArrowWidth, rb.Y, ArrowWidth, rb.Height); + font = Game.Renderer.Fonts["TinyBold"]; + } + public bool SelectNextTab(bool reverse) { if (queueGroup == null) @@ -170,8 +184,6 @@ return; var rb = RenderBounds; - leftButtonRect = new Rectangle(rb.X, rb.Y, ArrowWidth, rb.Height); - rightButtonRect = new Rectangle(rb.Right - ArrowWidth, rb.Y, ArrowWidth, rb.Height); var leftDisabled = listOffset >= 0; var leftHover = Ui.MouseOverWidget == this && leftButtonRect.Contains(Viewport.LastMousePos); @@ -182,15 +194,19 @@ ButtonWidget.DrawBackground(Button, leftButtonRect, leftDisabled, leftPressed, leftHover, false); ButtonWidget.DrawBackground(Button, rightButtonRect, rightDisabled, rightPressed, rightHover, false); - WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", leftPressed || leftDisabled ? "left_pressed" : "left_arrow"), + var leftArrowImageName = WidgetUtils.GetStatefulImageName(DecorationScrollLeft, leftDisabled, leftPressed, leftHover); + var leftArrowImage = ChromeProvider.GetImage(Decorations, leftArrowImageName) ?? ChromeProvider.GetImage(Decorations, DecorationScrollLeft); + WidgetUtils.DrawRGBA(leftArrowImage, new float2(leftButtonRect.Left + 2, leftButtonRect.Top + 2)); - WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", rightPressed || rightDisabled ? "right_pressed" : "right_arrow"), + + var rightArrowImageName = WidgetUtils.GetStatefulImageName(DecorationScrollRight, rightDisabled, rightPressed, rightHover); + var rightArrowImage = ChromeProvider.GetImage(Decorations, rightArrowImageName) ?? ChromeProvider.GetImage(Decorations, DecorationScrollRight); + WidgetUtils.DrawRGBA(rightArrowImage, new float2(rightButtonRect.Left + 2, rightButtonRect.Top + 2)); // Draw tab buttons Game.Renderer.EnableScissor(new Rectangle(leftButtonRect.Right, rb.Y + 1, rightButtonRect.Left - leftButtonRect.Right - 1, rb.Height)); var origin = new int2(leftButtonRect.Right - 1 + (int)listOffset, leftButtonRect.Y); - var font = Game.Renderer.Fonts["TinyBold"]; contentWidth = 0; foreach (var tab in tabs) diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/RadarWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/RadarWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/RadarWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/RadarWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -134,7 +134,7 @@ if (newShroud != null) { newShroud.OnShroudChanged += UpdateShroudCell; - foreach (var puv in world.Map.ProjectedCellBounds) + foreach (var puv in world.Map.ProjectedCells) UpdateShroudCell(puv); } @@ -206,8 +206,8 @@ void UpdateTerrainColor(MPos uv) { var colorPair = playerRadarTerrain != null && playerRadarTerrain.IsInitialized ? playerRadarTerrain[uv] : PlayerRadarTerrain.GetColor(world.Map, uv); - var leftColor = colorPair.First; - var rightColor = colorPair.Second; + var leftColor = colorPair.Left; + var rightColor = colorPair.Right; var stride = radarSheet.Size.Width; @@ -386,7 +386,7 @@ var stride = radarSheet.Size.Width; Array.Clear(radarData, 4 * actorSprite.Bounds.Top * stride, 4 * actorSprite.Bounds.Height * stride); - var cells = new List>(); + var cells = new List<(CPos Cell, Color Color)>(); unsafe { @@ -403,11 +403,11 @@ t.Trait.PopulateRadarSignatureCells(t.Actor, cells); foreach (var cell in cells) { - if (!world.Map.Contains(cell.First)) + if (!world.Map.Contains(cell.Cell)) continue; - var uv = cell.First.ToMPos(world.Map.Grid.Type); - var color = cell.Second.ToArgb(); + var uv = cell.Cell.ToMPos(world.Map.Grid.Type); + var color = cell.Color.ToArgb(); if (isRectangularIsometric) { // Odd rows are shifted right by 1px diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ResourceBarWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ResourceBarWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ResourceBarWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ResourceBarWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -34,6 +34,7 @@ EWMA providedLerp = new EWMA(0.3f); EWMA usedLerp = new EWMA(0.3f); readonly World world; + Sprite indicator; [ObjectCreator.UseCtor] public ResourceBarWidget(World world) @@ -43,6 +44,13 @@ Ui.Root.Get(TooltipContainer)); } + public override void Initialize(WidgetArgs args) + { + base.Initialize(args); + + indicator = ChromeProvider.GetImage(IndicatorCollection, IndicatorImage); + } + public override void MouseEntered() { if (TooltipContainer == null) @@ -72,7 +80,6 @@ var usedFrac = usedLerp.Update(used / scaleBy); var b = RenderBounds; - var indicator = ChromeProvider.GetImage(IndicatorCollection, IndicatorImage); var color = GetBarColor(); if (Orientation == ResourceBarOrientation.Vertical) diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ScrollPanelWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ScrollPanelWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ScrollPanelWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ScrollPanelWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -48,6 +48,9 @@ public string Background = "scrollpanel-bg"; public string ScrollBarBackground = "scrollpanel-bg"; public string Button = "scrollpanel-button"; + public readonly string Decorations = "scrollpanel-decorations"; + public readonly string DecorationScrollUp = "up"; + public readonly string DecorationScrollDown = "down"; public int ContentHeight; public ILayout Layout; public int MinimumThumbSize = 10; @@ -201,9 +204,14 @@ var upOffset = !upPressed || upDisabled ? 4 : 4 + ButtonDepth; var downOffset = !downPressed || downDisabled ? 4 : 4 + ButtonDepth; - WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", upPressed || upDisabled ? "up_pressed" : "up_arrow"), + var upArrowImageName = WidgetUtils.GetStatefulImageName(DecorationScrollUp, upDisabled, upPressed, upHover); + var upArrowImage = ChromeProvider.GetImage(Decorations, upArrowImageName) ?? ChromeProvider.GetImage(Decorations, DecorationScrollUp); + WidgetUtils.DrawRGBA(upArrowImage, new float2(upButtonRect.Left + upOffset, upButtonRect.Top + upOffset)); - WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", downPressed || downDisabled ? "down_pressed" : "down_arrow"), + + var downArrowImageName = WidgetUtils.GetStatefulImageName(DecorationScrollDown, downDisabled, downPressed, downHover); + var downArrowImage = ChromeProvider.GetImage(Decorations, downArrowImageName) ?? ChromeProvider.GetImage(Decorations, DecorationScrollDown); + WidgetUtils.DrawRGBA(downArrowImage, new float2(downButtonRect.Left + downOffset, downButtonRect.Top + downOffset)); } @@ -230,9 +238,9 @@ } } - public override Rectangle GetEventBounds() + public override bool EventBoundsContains(int2 location) { - return EventBounds; + return EventBounds.Contains(location); } void Scroll(int amount, bool smooth = false) diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/SliderWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/SliderWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/SliderWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/SliderWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -48,10 +48,12 @@ GetValue = other.GetValue; } - void UpdateValue(float newValue) + public void UpdateValue(float newValue) { + var oldValue = Value; Value = newValue.Clamp(MinimumValue, MaximumValue); - OnChange(Value); + if (oldValue != Value) + OnChange(Value); } public override bool HandleMouseInput(MouseInput mi) @@ -114,7 +116,7 @@ if (!IsVisible()) return; - Value = GetValue(); + UpdateValue(GetValue()); var tr = ThumbRect; var rb = RenderBounds; diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/StrategicProgressWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/StrategicProgressWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/StrategicProgressWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/StrategicProgressWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,6 +13,7 @@ using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; +using OpenRA.Traits; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets @@ -48,7 +49,7 @@ { WidgetUtils.DrawRGBA(ChromeProvider.GetImage("strategic", "critical_unowned"), offset + new float2(rb.Left + curX, rb.Top)); - if (world.LocalPlayer != null && WorldUtils.AreMutualAllies(a.Owner, world.LocalPlayer)) + if (world.LocalPlayer != null && a.Owner.RelationshipWith(world.LocalPlayer) == PlayerRelationship.Ally) WidgetUtils.DrawRGBA(ChromeProvider.GetImage("strategic", "player_owned"), offset + new float2(rb.Left + curX, rb.Top)); else if (!a.Owner.NonCombatant) WidgetUtils.DrawRGBA(ChromeProvider.GetImage("strategic", "enemy_owned"), offset + new float2(rb.Left + curX, rb.Top)); @@ -63,7 +64,7 @@ if (pendingWinner == null) return; var winnerSvc = pendingWinner.PlayerActor.Trait(); - var isVictory = pendingWinner == world.LocalPlayer || !WorldUtils.AreMutualAllies(pendingWinner, world.LocalPlayer); + var isVictory = pendingWinner.RelationshipWith(world.LocalPlayer) == PlayerRelationship.Ally; var tc = "Strategic {0} in {1}".F( isVictory ? "victory" : "defeat", WidgetUtils.FormatTime(winnerSvc.TicksLeft, world.Timestep)); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/SupportPowersWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/SupportPowersWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/SupportPowersWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/SupportPowersWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,6 +28,8 @@ [Translate] public readonly string HoldText = ""; + public readonly string OverlayFont = "TinyBold"; + public readonly int2 IconSize = new int2(64, 48); public readonly int IconMargin = 10; public readonly int2 IconSpriteOffset = int2.Zero; @@ -64,7 +66,7 @@ Rectangle eventBounds; public override Rectangle EventBounds { get { return eventBounds; } } SpriteFont overlayFont; - float2 holdOffset, readyOffset, timeOffset; + float2 iconOffset, holdOffset, readyOffset, timeOffset; [CustomLintableHotkeyNames] public static IEnumerable LinterHotkeyNames(MiniYamlNode widgetNode, Action emitError, Action emitWarning) @@ -98,7 +100,6 @@ tooltipContainer = Exts.Lazy(() => Ui.Root.Get(TooltipContainer)); - icon = new Animation(world, "icon"); clock = new Animation(world, ClockAnimation); } @@ -108,6 +109,12 @@ hotkeys = Exts.MakeArray(HotkeyCount, i => modData.Hotkeys[HotkeyPrefix + (i + 1).ToString("D2")]); + + overlayFont = Game.Renderer.Fonts[OverlayFont]; + + iconOffset = 0.5f * IconSize.ToFloat2() + IconSpriteOffset; + holdOffset = iconOffset - overlayFont.Measure(HoldText) / 2; + readyOffset = iconOffset - overlayFont.Measure(ReadyText) / 2; } public class SupportPowerIcon @@ -138,6 +145,7 @@ else rect = new Rectangle(rb.X, rb.Y + IconCount * (IconSize.Y + IconMargin), IconSize.X, IconSize.Y); + icon = new Animation(worldRenderer.World, p.Info.IconImage); icon.Play(p.Info.Icon); var power = new SupportPowerIcon() @@ -190,11 +198,6 @@ public override void Draw() { - var iconOffset = 0.5f * IconSize.ToFloat2() + IconSpriteOffset; - overlayFont = Game.Renderer.Fonts["TinyBold"]; - - holdOffset = iconOffset - overlayFont.Measure(HoldText) / 2; - readyOffset = iconOffset - overlayFont.Measure(ReadyText) / 2; timeOffset = iconOffset - overlayFont.Measure(WidgetUtils.FormatTime(0, worldRenderer.World.Timestep)) / 2; // Icons diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/SupportPowerTimerWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/SupportPowerTimerWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/SupportPowerTimerWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/SupportPowerTimerWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -22,12 +22,13 @@ { public readonly string Font = "Bold"; public readonly string Format = "{0}: {1}"; + public readonly TextAlign Align = TextAlign.Left; public readonly TimerOrder Order = TimerOrder.Descending; readonly int timestep; readonly IEnumerable powers; readonly Color bgDark, bgLight; - Pair[] texts; + (string Text, Color Color)[] texts; [ObjectCreator.UseCtor] public SupportPowerTimerWidget(World world) @@ -35,7 +36,7 @@ powers = world.ActorsWithTrait() .Where(p => !p.Actor.IsDead && !p.Actor.Owner.NonCombatant) .SelectMany(s => s.Trait.Powers.Values) - .Where(p => p.Instances.Any() && p.Info.DisplayTimerStances != Stance.None && !p.Disabled); + .Where(p => p.Instances.Any() && p.Info.DisplayTimerRelationships != PlayerRelationship.None && !p.Disabled); // Timers in replays should be synced to the effective game time, not the playback time. timestep = world.Timestep; @@ -52,7 +53,7 @@ { var owner = p.Instances[0].Self.Owner; var viewer = owner.World.RenderPlayer ?? owner.World.LocalPlayer; - return viewer == null || p.Info.DisplayTimerStances.HasStance(owner.Stances[viewer]); + return viewer == null || p.Info.DisplayTimerRelationships.HasStance(owner.RelationshipWith(viewer)); }); texts = displayedPowers.Select(p => @@ -67,7 +68,7 @@ var color = !p.Ready || Game.LocalTick % 50 < 25 ? playerColor : Color.White; - return Pair.New(text, color); + return (text, color); }).ToArray(); } @@ -80,8 +81,17 @@ foreach (var t in texts) { var font = Game.Renderer.Fonts[Font]; - font.DrawTextWithShadow(t.First, new float2(Bounds.Location) + new float2(0, y), t.Second, bgDark, bgLight, 1); - y += (font.Measure(t.First).Y + 5) * (int)Order; + var textSize = font.Measure(t.Text); + var location = new float2(Bounds.Location) + new float2(0, y); + + if (Align == TextAlign.Center) + location += new int2((Bounds.Width - textSize.X) / 2, 0); + + if (Align == TextAlign.Right) + location += new int2(Bounds.Width - textSize.X, 0); + + font.DrawTextWithShadow(t.Text, location, t.Color, bgDark, bgLight, 1); + y += (font.Measure(t.Text).Y + 5) * (int)Order; } } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/TextFieldWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/TextFieldWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/TextFieldWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/TextFieldWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -365,7 +365,6 @@ Game.Renderer.SetClipboardText(Text.Substring(lowestIndex, highestIndex - lowestIndex)); RemoveSelectedText(); - OnTextEdited(); } break; @@ -531,6 +530,7 @@ ClearSelection(); CursorPosition = lowestIndex; + OnTextEdited(); } } @@ -566,10 +566,8 @@ var cursorPosition = font.Measure(apparentText.Substring(0, CursorPosition)); var disabled = IsDisabled(); - var state = disabled ? "textfield-disabled" : - HasKeyboardFocus ? "textfield-focused" : - Ui.MouseOverWidget == this || Children.Any(c => c == Ui.MouseOverWidget) ? "textfield-hover" : - "textfield"; + var hover = Ui.MouseOverWidget == this || Children.Any(c => c == Ui.MouseOverWidget); + var state = WidgetUtils.GetStatefulImageName("textfield", disabled, false, hover, HasKeyboardFocus); WidgetUtils.DrawPanel(state, new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height)); diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/TooltipContainerWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/TooltipContainerWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/TooltipContainerWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/TooltipContainerWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -62,7 +62,7 @@ public override void Draw() { BeforeRender(); } - public override Rectangle GetEventBounds() { return Rectangle.Empty; } + public override bool EventBoundsContains(int2 location) { return false; } public override int2 ChildOrigin { diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,7 +25,7 @@ public class ViewportControllerWidget : Widget { readonly ModData modData; - readonly ResourceRenderer resourceRenderer; + readonly IEnumerable resourceRenderers; public readonly HotkeyReference ZoomInKey = new HotkeyReference(); public readonly HotkeyReference ZoomOutKey = new HotkeyReference(); @@ -86,15 +86,16 @@ { ScrollDirection.Right, new float2(1, 0) }, }; - Lazy tooltipContainer; + readonly Lazy tooltipContainer; + readonly World world; + readonly WorldRenderer worldRenderer; + int2? joystickScrollStart, joystickScrollEnd; int2? standardScrollStart; bool isStandardScrolling; ScrollDirection keyboardDirections; ScrollDirection edgeDirections; - World world; - WorldRenderer worldRenderer; HotkeyReference[] saveBookmarkHotkeys; HotkeyReference[] restoreBookmarkHotkeys; @@ -144,7 +145,7 @@ tooltipContainer = Exts.Lazy(() => Ui.Root.Get(TooltipContainer)); - resourceRenderer = world.WorldActor.TraitOrDefault(); + resourceRenderers = world.WorldActor.TraitsImplementing().ToArray(); } public override void Initialize(WidgetArgs args) @@ -191,7 +192,7 @@ else if (!isStandardScrolling) { edgeDirections = ScrollDirection.None; - if (Game.Settings.Game.ViewportEdgeScroll && Game.HasInputFocus) + if (Game.Settings.Game.ViewportEdgeScroll && Game.Renderer.WindowHasInputFocus) edgeDirections = CheckForDirections(); if (keyboardDirections != ScrollDirection.None || edgeDirections != ScrollDirection.None) @@ -266,13 +267,14 @@ return; } - if (resourceRenderer != null) + foreach (var resourceRenderer in resourceRenderers) { var resource = resourceRenderer.GetRenderedResourceType(cell); if (resource != null) { TooltipType = WorldTooltipType.Resource; ResourceTooltip = resource; + break; } } } @@ -313,7 +315,7 @@ { if (mi.Event == MouseInputEvent.Scroll && mi.Modifiers.HasModifier(Game.Settings.Game.ZoomModifier)) { - worldRenderer.Viewport.AdjustZoom(mi.Delta.Y * Game.Settings.Game.ZoomSpeed); + worldRenderer.Viewport.AdjustZoom(mi.Delta.Y * Game.Settings.Game.ZoomSpeed, mi.Location); return true; } diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/VqaPlayerWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/VqaPlayerWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/VqaPlayerWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/VqaPlayerWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,11 +28,13 @@ public VqaReader Video { get { return video; } } Sprite videoSprite, overlaySprite; + Sheet overlaySheet; VqaReader video = null; string cachedVideo; float invLength; float2 videoOrigin, videoSize; - uint[,] overlay; + float2 overlayOrigin, overlaySize; + float overlayScale; bool stopped; bool paused; @@ -74,26 +76,13 @@ video.Height), TextureChannel.RGBA); - var scale = Math.Min((float)RenderBounds.Width / video.Width, (float)RenderBounds.Height / video.Height * AspectRatio); + var scale = Math.Min((float)RenderBounds.Width / video.Width, RenderBounds.Height / (video.Height * AspectRatio)); videoOrigin = new float2( RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * video.Height * AspectRatio) / 2); // Round size to integer pixels. Round up to be consistent with the scale calculation. videoSize = new float2((int)Math.Ceiling(video.Width * scale), (int)Math.Ceiling(video.Height * AspectRatio * scale)); - - if (!DrawOverlay) - return; - - var scaledHeight = (int)videoSize.Y; - overlay = new uint[Exts.NextPowerOf2(scaledHeight), 1]; - var black = 255U << 24; - for (var y = 0; y < scaledHeight; y += 2) - overlay[y, 0] = black; - - var overlaySheet = new Sheet(SheetType.BGRA, new Size(1, Exts.NextPowerOf2(scaledHeight))); - overlaySheet.GetTexture().SetData(overlay); - overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, scaledHeight), TextureChannel.RGBA); } public override void Draw() @@ -134,7 +123,45 @@ videoSize); if (DrawOverlay) - Game.Renderer.RgbaSpriteRenderer.DrawSprite(overlaySprite, videoOrigin, videoSize); + { + // Create the scan line grid to render over the video + // To avoid aliasing, this must be an integer number of screen pixels. + // A few complications to be aware of: + // - The video may have a different aspect ratio to the widget RenderBounds + // - The RenderBounds coordinates may be a non-integer scale of the screen pixel size + // - The screen pixel size may change while the video is playing back + // (user moves a window between displays with different DPI on macOS) + var scale = Game.Renderer.WindowScale; + if (overlaySheet == null || overlayScale != scale) + { + overlaySheet?.Dispose(); + + // Calculate the scan line height by converting the video scale (copied from Open()) to screen + // pixels, halving it (scan lines cover half the pixel height), and rounding to the nearest integer. + var videoScale = Math.Min((float)RenderBounds.Width / video.Width, RenderBounds.Height / (video.Height * AspectRatio)); + var halfRowHeight = (int)(videoScale * scale / 2 + 0.5f); + + // The overlay can be minimally stored in a 1px column which is stretched to cover the full screen + var overlayHeight = (int)(RenderBounds.Height * scale / halfRowHeight); + var overlaySheetSize = new Size(1, Exts.NextPowerOf2(overlayHeight)); + var overlay = new byte[4 * Exts.NextPowerOf2(overlayHeight)]; + overlaySheet = new Sheet(SheetType.BGRA, overlaySheetSize); + + // Every second pixel is the scan line - set alpha to 128 to make the lines less harsh + for (var i = 3; i < 4 * overlayHeight; i += 8) + overlay[i] = 128; + + overlaySheet.GetTexture().SetData(overlay, overlaySheetSize.Width, overlaySheetSize.Height); + overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, overlayHeight), TextureChannel.RGBA); + + // Overlay origin must be rounded to the nearest screen pixel to prevent aliasing + overlayOrigin = new float2((int)(RenderBounds.X * scale + 0.5f), (int)(RenderBounds.Y * scale + 0.5f)) / scale; + overlaySize = new float2(RenderBounds.Width, overlayHeight * halfRowHeight / scale); + overlayScale = scale; + } + + Game.Renderer.RgbaSpriteRenderer.DrawSprite(overlaySprite, overlayOrigin, overlaySize); + } } public override bool HandleKeyPress(KeyInput e) diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/WidgetUtils.cs openra-20210321/OpenRA.Mods.Common/Widgets/WidgetUtils.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/WidgetUtils.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/WidgetUtils.cs 2021-03-21 11:10:05.000000000 +0000 @@ -12,7 +12,9 @@ using System; using System.Linq; using OpenRA.Graphics; +using OpenRA.Network; using OpenRA.Primitives; +using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets { @@ -23,6 +25,17 @@ return ChromeProvider.GetImage("chrome-" + world.LocalPlayer.Faction.InternalName, name); } + public static string GetStatefulImageName(string baseName, bool disabled = false, bool pressed = false, bool hover = false, bool focused = false) + { + var suffix = disabled ? "-disabled" : + focused ? "-focused" : + pressed ? "-pressed" : + hover ? "-hover" : + ""; + + return baseName + suffix; + } + public static void DrawRGBA(Sprite s, float2 pos) { Game.Renderer.RgbaSpriteRenderer.DrawSprite(s, pos); @@ -270,6 +283,75 @@ else button.GetTooltipText = null; } + + public static void BindButtonIcon(ButtonWidget button) + { + var icon = button.Get("ICON"); + + var hasActiveImage = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-active") != null; + var hasActiveDisabledImage = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-active-disabled") != null; + var hasActivePressedImage = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-active-pressed") != null; + var hasActiveHoverImage = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-active-hover") != null; + + var hasImage = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName) != null; + var hasDisabledImage = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-disabled") != null; + var hasPressedImage = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-pressed") != null; + var hasHoverImage = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-hover") != null; + + icon.GetImageName = () => + { + var isActive = button.IsHighlighted(); + var isDisabled = button.IsDisabled(); + var isPressed = button.Depressed; + var isHovered = Ui.MouseOverWidget == button; + + var baseName = button.IsHighlighted() ? icon.ImageName + "-active" : icon.ImageName; + var stateName = WidgetUtils.GetStatefulImageName(baseName, isDisabled, isPressed, isHovered); + + if (isActive) + { + if (isDisabled) + return hasActiveDisabledImage ? stateName : hasActiveImage ? baseName : icon.ImageName; + else if (isPressed) + return hasActivePressedImage ? stateName : hasActiveImage ? baseName : icon.ImageName; + else if (isHovered) + return hasActiveHoverImage ? stateName : hasActiveImage ? baseName : icon.ImageName; + else + return hasActiveImage ? baseName : icon.ImageName; + } + else + { + if (isDisabled) + return hasDisabledImage ? stateName : baseName; + else if (isPressed) + return hasPressedImage ? stateName : baseName; + else if (isHovered) + return hasHoverImage ? stateName : baseName; + else + return baseName; + } + }; + } + + public static void BindPlayerNameAndStatus(LabelWidget label, Player p) + { + var client = p.World.LobbyInfo.ClientWithIndex(p.ClientIndex); + var nameFont = Game.Renderer.Fonts[label.Font]; + var name = new CachedTransform<(string Name, WinState WinState, Session.ClientState ClientState), string>(c => + { + var suffix = c.WinState == WinState.Undefined ? "" : " (" + c.Item2 + ")"; + if (c.ClientState == Session.ClientState.Disconnected) + suffix = " (Gone)"; + + return TruncateText(c.Name, label.Bounds.Width - nameFont.Measure(suffix).X, nameFont) + suffix; + }); + + label.GetText = () => + { + var clientState = client != null ? client.State : Session.ClientState.Ready; + return name.Update((p.PlayerName, p.WinState, clientState)); + }; + } } public class CachedTransform diff -Nru openra-20200503/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs openra-20210321/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs --- openra-20200503/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs 2021-03-21 11:10:05.000000000 +0000 @@ -13,6 +13,7 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Effects; +using OpenRA.Mods.Common.Traits; using OpenRA.Orders; using OpenRA.Primitives; using OpenRA.Traits; @@ -57,18 +58,10 @@ normalSelectionColor = Color.White; } - void DrawRollover(Actor unit) - { - var selectionDecorations = unit.TraitOrDefault(); - if (selectionDecorations == null) - return; - - selectionDecorations.DrawRollover(unit, worldRenderer); - } - public override void Draw() { var modifiers = Game.GetModifierKeys(); + IEnumerable rollover; if (IsValidDragbox) { var a = worldRenderer.Viewport.WorldToViewPx(dragStart); @@ -83,15 +76,15 @@ Game.Renderer.RgbaColorRenderer.DrawRect(a, b, 1, color); // Render actors in the dragbox - foreach (var u in SelectActorsInBoxWithDeadzone(World, dragStart, mousePos, modifiers)) - DrawRollover(u); + rollover = SelectActorsInBoxWithDeadzone(World, dragStart, mousePos, modifiers); } else { // Render actors under the mouse pointer - foreach (var u in SelectActorsInBoxWithDeadzone(World, mousePos, mousePos, modifiers)) - DrawRollover(u); + rollover = SelectActorsInBoxWithDeadzone(World, mousePos, mousePos, modifiers); } + + worldRenderer.World.Selection.SetRollover(rollover); } public override bool HandleMouseInput(MouseInput mi) @@ -147,7 +140,7 @@ if (unit != null && eligiblePlayers.Contains(unit.Owner)) { - var s = unit.TraitOrDefault(); + var s = unit.TraitOrDefault(); if (s != null) { // Select actors on the screen that have the same selection class as the actor under the mouse cursor @@ -299,7 +292,7 @@ // Get all the selected actors' selection classes var selectedClasses = ownedActors - .Select(a => a.Trait().Class) + .Select(a => a.Trait().Class) .ToHashSet(); // Select actors on the screen that have the same selection class as one of the already selected actors @@ -340,7 +333,7 @@ if (!owners.Contains(a.Owner)) return false; - var s = a.TraitOrDefault(); + var s = a.TraitOrDefault(); // selectionClasses == null means that units, that meet all other criteria, get selected return s != null && (selectionClasses == null || selectionClasses.Contains(s.Class)); @@ -350,7 +343,7 @@ static IEnumerable SelectHighestPriorityActorAtPoint(World world, int2 a, Modifiers modifiers) { var selected = world.ScreenMap.ActorsAtMouse(a) - .Where(x => x.Actor.Info.HasTraitInfo() && (x.Actor.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x.Actor))) + .Where(x => x.Actor.Info.HasTraitInfo() && (x.Actor.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x.Actor))) .WithHighestSelectionPriority(a, modifiers); if (selected != null) @@ -368,7 +361,7 @@ return world.ScreenMap.ActorsInMouseBox(a, b) .Select(x => x.Actor) - .Where(x => x.Info.HasTraitInfo() && (x.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x))) + .Where(x => x.Info.HasTraitInfo() && (x.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x))) .SubsetWithHighestSelectionPriority(modifiers); } } diff -Nru openra-20200503/OpenRA.Mods.D2k/Activities/SwallowActor.cs openra-20210321/OpenRA.Mods.D2k/Activities/SwallowActor.cs --- openra-20200503/OpenRA.Mods.D2k/Activities/SwallowActor.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Activities/SwallowActor.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,7 +29,6 @@ readonly Target target; readonly Sandworm sandworm; - readonly ConditionManager conditionManager; readonly WeaponInfo weapon; readonly Armament armament; readonly AttackSwallow swallow; @@ -39,9 +38,9 @@ int countdown; CPos burrowLocation; AttackState stance; - int attackingToken = ConditionManager.InvalidConditionToken; + int attackingToken = Actor.InvalidConditionToken; - public SwallowActor(Actor self, Target target, Armament a, IFacing facing) + public SwallowActor(Actor self, in Target target, Armament a, IFacing facing) { this.target = target; this.facing = facing; @@ -50,7 +49,6 @@ sandworm = self.Trait(); positionable = self.Trait(); swallow = self.Trait(); - conditionManager = self.TraitOrDefault(); } bool AttackTargets(Actor self, IEnumerable targets) @@ -103,9 +101,9 @@ stance = AttackState.Burrowed; countdown = swallow.Info.AttackDelay; burrowLocation = self.Location; - if (conditionManager != null && attackingToken == ConditionManager.InvalidConditionToken && - !string.IsNullOrEmpty(swallow.Info.AttackingCondition)) - attackingToken = conditionManager.GrantCondition(self, swallow.Info.AttackingCondition); + if (attackingToken == Actor.InvalidConditionToken) + attackingToken = self.GrantCondition(swallow.Info.AttackingCondition); + break; case AttackState.Burrowed: if (--countdown > 0) @@ -164,8 +162,8 @@ void RevokeCondition(Actor self) { - if (attackingToken != ConditionManager.InvalidConditionToken) - attackingToken = conditionManager.RevokeCondition(self, attackingToken); + if (attackingToken != Actor.InvalidConditionToken) + attackingToken = self.RevokeCondition(attackingToken); } } } diff -Nru openra-20200503/OpenRA.Mods.D2k/Lint/CheckImportActors.cs openra-20210321/OpenRA.Mods.D2k/Lint/CheckImportActors.cs --- openra-20200503/OpenRA.Mods.D2k/Lint/CheckImportActors.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Lint/CheckImportActors.cs 2021-03-21 11:10:05.000000000 +0000 @@ -17,12 +17,12 @@ { public class CheckImportActors : ILintRulesPass { - public void Run(Action emitError, Action emitWarning, Ruleset rules) + public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules) { foreach (var actorData in D2kMapImporter.ActorDataByActorCode.Values) { - if (!rules.Actors.ContainsKey(actorData.First)) - emitError("Undefined actor {0} in map import code.".F(actorData.First)); + if (!rules.Actors.ContainsKey(actorData.Actor)) + emitError("Undefined actor {0} in map import code.".F(actorData.Actor)); } } } diff -Nru openra-20200503/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj openra-20210321/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj --- openra-20200503/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj 2021-03-21 11:10:05.000000000 +0000 @@ -1,12 +1,12 @@  - net461 + net472 true true - 5 + 7.3 true true - ../mods/d2k + ../bin false AnyCPU false @@ -21,12 +21,6 @@ false - - ..\thirdparty\download\Eluant.dll - False - - - False @@ -34,6 +28,7 @@ False + diff -Nru openra-20200503/OpenRA.Mods.D2k/PackageLoaders/D2kSoundResources.cs openra-20210321/OpenRA.Mods.D2k/PackageLoaders/D2kSoundResources.cs --- openra-20200503/OpenRA.Mods.D2k/PackageLoaders/D2kSoundResources.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/PackageLoaders/D2kSoundResources.cs 2021-03-21 11:10:05.000000000 +0000 @@ -64,8 +64,7 @@ public Stream GetStream(string filename) { - Entry e; - if (!index.TryGetValue(filename, out e)) + if (!index.TryGetValue(filename, out var e)) return null; return SegmentStream.CreateWithoutOwningStream(s, e.Offset, (int)e.Length); diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/AttackSwallow.cs openra-20210321/OpenRA.Mods.D2k/Traits/AttackSwallow.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/AttackSwallow.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/AttackSwallow.cs 2021-03-21 11:10:05.000000000 +0000 @@ -51,7 +51,7 @@ Info = info; } - public override void DoAttack(Actor self, Target target) + public override void DoAttack(Actor self, in Target target) { // This is so that the worm does not launch an attack against a target that has reached solid rock if (target.Type != TargetType.Actor || !CanAttack(self, target)) @@ -70,14 +70,14 @@ self.QueueActivity(false, new SwallowActor(self, target, a, facing)); } - public override Activity GetAttackActivity(Actor self, AttackSource source, Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor) + public override Activity GetAttackActivity(Actor self, AttackSource source, in Target newTarget, bool allowMove, bool forceAttack, Color? targetLineColor) { return new SwallowTarget(self, newTarget, allowMove, forceAttack); } public class SwallowTarget : Attack { - public SwallowTarget(Actor self, Target target, bool allowMovement, bool forceAttack) + public SwallowTarget(Actor self, in Target target, bool allowMovement, bool forceAttack) : base(self, target, allowMovement, forceAttack) { } protected override Target RecalculateTarget(Actor self, out bool targetIsHiddenActor) diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/Buildings/D2kActorPreviewPlaceBuildingPreview.cs openra-20210321/OpenRA.Mods.D2k/Traits/Buildings/D2kActorPreviewPlaceBuildingPreview.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/Buildings/D2kActorPreviewPlaceBuildingPreview.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/Buildings/D2kActorPreviewPlaceBuildingPreview.cs 2021-03-21 11:10:05.000000000 +0000 @@ -25,6 +25,9 @@ [Desc("Terrain types that should show the 'unsafe' footprint tile.")] public readonly HashSet UnsafeTerrainTypes = new HashSet { "Rock" }; + [Desc("Only check for 'unsafe' footprint tiles when you have these prerequisites.")] + public readonly string[] RequiresPrerequisites = { }; + protected override IPlaceBuildingPreview CreatePreview(WorldRenderer wr, ActorInfo ai, TypeDictionary init) { return new D2kActorPreviewPlaceBuildingPreviewPreview(wr, ai, this, init); @@ -41,6 +44,7 @@ class D2kActorPreviewPlaceBuildingPreviewPreview : ActorPreviewPlaceBuildingPreviewPreview { readonly D2kActorPreviewPlaceBuildingPreviewInfo info; + readonly bool checkUnsafeTiles; readonly Sprite buildOk; readonly Sprite buildUnsafe; readonly Sprite buildBlocked; @@ -54,6 +58,9 @@ var world = wr.World; var sequences = world.Map.Rules.Sequences; + var techTree = init.Get().Value(world).PlayerActor.Trait(); + checkUnsafeTiles = info.RequiresPrerequisites.Any() && techTree.HasPrerequisites(info.RequiresPrerequisites); + buildOk = sequences.GetSequence("overlay", "build-valid").GetSprite(0); buildUnsafe = sequences.GetSequence("overlay", "build-unsafe").GetSprite(0); buildBlocked = sequences.GetSequence("overlay", "build-invalid").GetSprite(0); @@ -76,13 +83,13 @@ continue; var tile = HasFlag(c.Value, PlaceBuildingCellType.Invalid) ? buildBlocked : - candidateSafeTiles.Contains(c.Key) && info.UnsafeTerrainTypes.Contains(wr.World.Map.GetTerrainInfo(c.Key).Type) + (checkUnsafeTiles && candidateSafeTiles.Contains(c.Key) && info.UnsafeTerrainTypes.Contains(wr.World.Map.GetTerrainInfo(c.Key).Type)) ? buildUnsafe : buildOk; var pal = HasFlag(c.Value, PlaceBuildingCellType.LineBuild) ? linePalette : cellPalette; var pos = wr.World.Map.CenterOfCell(c.Key); var offset = new WVec(0, 0, topLeftPos.Z - pos.Z); - yield return new SpriteRenderable(tile, pos, offset, -511, pal, 1f, true); + yield return new SpriteRenderable(tile, pos, offset, -511, pal, 1f, true, true); } } } diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs openra-20210321/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,154 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.Common.Traits; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.D2k.Traits.Buildings +{ + public class D2kBuildingInfo : BuildingInfo + { + [Desc("Amount of damage received per DamageInterval ticks.")] + public readonly int Damage = 500; + + [Desc("Delay between receiving damage.")] + public readonly int DamageInterval = 100; + + [Desc("Apply the damage using these damagetypes.")] + public readonly BitSet DamageTypes = default(BitSet); + + [Desc("Terrain types where the actor will take damage.")] + public readonly string[] DamageTerrainTypes = { "Rock" }; + + [Desc("Percentage health below which the actor will not receive further damage.")] + public readonly int DamageThreshold = 50; + + [Desc("Inflict damage down to the DamageThreshold when the actor gets created on damaging terrain.")] + public readonly bool StartOnThreshold = true; + + [Desc("The terrain template to place when adding a concrete foundation. " + + "If the template is PickAny, then the actor footprint will be filled with this tile.")] + public readonly ushort ConcreteTemplate = 88; + + [Desc("List of required prerequisites to place a terrain template.")] + public readonly string[] ConcretePrerequisites = { }; + + public override object Create(ActorInitializer init) { return new D2kBuilding(init, this); } + } + + public class D2kBuilding : Building, ITick, INotifyCreated + { + readonly D2kBuildingInfo info; + + BuildableTerrainLayer layer; + IHealth health; + int safeTiles; + int totalTiles; + int damageThreshold; + int damageTicks; + TechTree techTree; + BuildingInfluence bi; + + public D2kBuilding(ActorInitializer init, D2kBuildingInfo info) + : base(init, info) + { + this.info = info; + } + + void INotifyCreated.Created(Actor self) + { + health = self.TraitOrDefault(); + layer = self.World.WorldActor.TraitOrDefault(); + bi = self.World.WorldActor.Trait(); + techTree = self.Owner.PlayerActor.TraitOrDefault(); + } + + protected override void AddedToWorld(Actor self) + { + base.AddedToWorld(self); + + if (layer != null && (!info.ConcretePrerequisites.Any() || techTree == null || techTree.HasPrerequisites(info.ConcretePrerequisites))) + { + var map = self.World.Map; + var template = map.Rules.TileSet.Templates[info.ConcreteTemplate]; + if (template.PickAny) + { + // Fill the footprint with random variants + foreach (var c in info.Tiles(self.Location)) + { + // Only place on allowed terrain types + if (!map.Contains(c) || map.CustomTerrain[c] != byte.MaxValue || !info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type)) + continue; + + // Don't place under other buildings (or their bib) + if (bi.GetBuildingAt(c) != self) + continue; + + var index = Game.CosmeticRandom.Next(template.TilesCount); + layer.AddTile(c, new TerrainTile(template.Id, (byte)index)); + } + } + else + { + for (var i = 0; i < template.TilesCount; i++) + { + var c = self.Location + new CVec(i % template.Size.X, i / template.Size.X); + + // Only place on allowed terrain types + if (!map.Contains(c) || map.CustomTerrain[c] != byte.MaxValue || !info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type)) + continue; + + // Don't place under other buildings (or their bib) + if (bi.GetBuildingAt(c) != self) + continue; + + layer.AddTile(c, new TerrainTile(template.Id, (byte)i)); + } + } + } + + if (health == null) + return; + + foreach (var kv in self.OccupiesSpace.OccupiedCells()) + { + totalTiles++; + if (!info.DamageTerrainTypes.Contains(self.World.Map.GetTerrainInfo(kv.Cell).Type)) + safeTiles++; + } + + if (totalTiles == 0 || totalTiles == safeTiles) + return; + + // Cast to long to avoid overflow when multiplying by the health + damageThreshold = (int)((info.DamageThreshold * (long)health.MaxHP + (100 - info.DamageThreshold) * safeTiles * (long)health.MaxHP / totalTiles) / 100); + + if (!info.StartOnThreshold) + return; + + // Start with maximum damage applied + var delta = health.HP - damageThreshold; + if (delta > 0) + self.InflictDamage(self.World.WorldActor, new Damage(delta, info.DamageTypes)); + } + + void ITick.Tick(Actor self) + { + if (totalTiles == safeTiles || health.HP <= damageThreshold || --damageTicks > 0) + return; + + self.InflictDamage(self.World.WorldActor, new Damage(info.Damage, info.DamageTypes)); + damageTicks = info.DamageInterval; + } + } +} diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/Buildings/LaysTerrain.cs openra-20210321/OpenRA.Mods.D2k/Traits/Buildings/LaysTerrain.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/Buildings/LaysTerrain.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/Buildings/LaysTerrain.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Mods.Common.Traits; -using OpenRA.Traits; - -namespace OpenRA.Mods.D2k.Traits -{ - public class LaysTerrainInfo : ITraitInfo, Requires - { - [Desc("The terrain template to place. If the template is PickAny, then " + - "the actor footprint will be filled with this tile.")] - public readonly ushort Template = 0; - - [FieldLoader.Require] - [Desc("The terrain types that this template will be placed on.")] - public readonly HashSet TerrainTypes = new HashSet(); - - [Desc("Offset relative to the actor TopLeft. Not used if the template is PickAny.", - "Tiles being offset out of the actor's footprint will not be placed.")] - public readonly CVec Offset = CVec.Zero; - - public object Create(ActorInitializer init) { return new LaysTerrain(init.Self, this); } - } - - public class LaysTerrain : INotifyAddedToWorld - { - readonly LaysTerrainInfo info; - readonly BuildableTerrainLayer layer; - readonly BuildingInfluence bi; - readonly TerrainTemplateInfo template; - readonly BuildingInfo buildingInfo; - - public LaysTerrain(Actor self, LaysTerrainInfo info) - { - this.info = info; - layer = self.World.WorldActor.Trait(); - bi = self.World.WorldActor.Trait(); - template = self.World.Map.Rules.TileSet.Templates[info.Template]; - buildingInfo = self.Info.TraitInfo(); - } - - void INotifyAddedToWorld.AddedToWorld(Actor self) - { - var map = self.World.Map; - - if (template.PickAny) - { - // Fill the footprint with random variants - foreach (var c in buildingInfo.Tiles(self.Location)) - { - // Only place on allowed terrain types - if (!map.Contains(c) || !info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type)) - continue; - - // Don't place under other buildings or custom terrain - if (bi.GetBuildingAt(c) != self || map.CustomTerrain[c] != byte.MaxValue) - continue; - - var index = Game.CosmeticRandom.Next(template.TilesCount); - layer.AddTile(c, new TerrainTile(template.Id, (byte)index)); - } - - return; - } - - var origin = self.Location + info.Offset; - for (var i = 0; i < template.TilesCount; i++) - { - var c = origin + new CVec(i % template.Size.X, i / template.Size.X); - - // Only place on allowed terrain types - if (!info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type)) - continue; - - // Don't place under other buildings or custom terrain - if (bi.GetBuildingAt(c) != self || map.CustomTerrain[c] != byte.MaxValue) - continue; - - layer.AddTile(c, new TerrainTile(template.Id, (byte)i)); - } - } - } -} diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/Player/HarvesterInsurance.cs openra-20210321/OpenRA.Mods.D2k/Traits/Player/HarvesterInsurance.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/Player/HarvesterInsurance.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/Player/HarvesterInsurance.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,9 +16,9 @@ namespace OpenRA.Mods.D2k.Traits { [Desc("A player with this trait will receive a free harvester when his last one gets eaten by a sandworm, provided he has at least one refinery.")] - public class HarvesterInsuranceInfo : ITraitInfo + public class HarvesterInsuranceInfo : TraitInfo { - public object Create(ActorInitializer init) { return new HarvesterInsurance(init.Self); } + public override object Create(ActorInitializer init) { return new HarvesterInsurance(init.Self); } } public class HarvesterInsurance diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/Render/WithCrumbleOverlay.cs openra-20210321/OpenRA.Mods.D2k/Traits/Render/WithCrumbleOverlay.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/Render/WithCrumbleOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/Render/WithCrumbleOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -23,7 +23,7 @@ [Desc("Sequence name to use")] public readonly string Sequence = "crumble-overlay"; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; @@ -35,21 +35,34 @@ public class WithCrumbleOverlay : ConditionalTrait { + readonly WithCrumbleOverlayInfo info; + readonly RenderSprites renderSprites; + readonly Animation overlay; + readonly AnimationWithOffset animation; + public WithCrumbleOverlay(ActorInitializer init, WithCrumbleOverlayInfo info) : base(info) { - if (init.Contains()) + this.info = info; + + if (init.Contains(info)) return; - var rs = init.Self.Trait(); + renderSprites = init.Self.Trait(); - var overlay = new Animation(init.World, rs.GetImage(init.Self)); - var anim = new AnimationWithOffset(overlay, null, () => IsTraitDisabled); + overlay = new Animation(init.World, renderSprites.GetImage(init.Self)); + animation = new AnimationWithOffset(overlay, null, () => IsTraitDisabled); + } - // Remove the animation once it is complete - overlay.PlayThen(info.Sequence, () => init.World.AddFrameEndTask(w => rs.Remove(anim))); + protected override void TraitEnabled(Actor self) + { + if (overlay == null) + return; - rs.Add(anim, info.Palette, info.IsPlayerPalette); + renderSprites.Add(animation, info.Palette, info.IsPlayerPalette); + + // Remove the animation once it is complete + overlay.PlayThen(info.Sequence, () => self.World.AddFrameEndTask(w => renderSprites.Remove(animation))); } } } diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/Render/WithDeliveryOverlay.cs openra-20210321/OpenRA.Mods.D2k/Traits/Render/WithDeliveryOverlay.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/Render/WithDeliveryOverlay.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/Render/WithDeliveryOverlay.cs 2021-03-21 11:10:05.000000000 +0000 @@ -26,7 +26,7 @@ [Desc("Position relative to body")] public readonly WVec Offset = WVec.Zero; - [PaletteReference("IsPlayerPalette")] + [PaletteReference(nameof(IsPlayerPalette))] [Desc("Custom palette name")] public readonly string Palette = null; diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/SpiceBloom.cs openra-20210321/OpenRA.Mods.D2k/Traits/SpiceBloom.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/SpiceBloom.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/SpiceBloom.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,7 +21,7 @@ namespace OpenRA.Mods.D2k.Traits { [Desc("Seeds resources by explosive eruptions after accumulation times.")] - public class SpiceBloomInfo : ITraitInfo, IRenderActorPreviewSpritesInfo, Requires + public class SpiceBloomInfo : TraitInfo, IRenderActorPreviewSpritesInfo, Requires { [SequenceReference] public readonly string[] GrowthSequences = { "grow1", "grow2", "grow3" }; @@ -47,7 +47,7 @@ [Desc("The maximum distance in cells that spice may be expelled.")] public readonly int Range = 5; - public object Create(ActorInitializer init) { return new SpiceBloom(init.Self, this); } + public override object Create(ActorInitializer init) { return new SpiceBloom(init.Self, this); } public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { @@ -133,8 +133,8 @@ var args = new ProjectileArgs { Weapon = self.World.Map.Rules.Weapons[info.Weapon.ToLowerInvariant()], - Facing = 0, - CurrentMuzzleFacing = () => 0, + Facing = WAngle.Zero, + CurrentMuzzleFacing = () => WAngle.Zero, DamageModifiers = self.TraitsImplementing() .Select(a => a.GetFirepowerModifier()).ToArray(), @@ -142,6 +142,9 @@ InaccuracyModifiers = self.TraitsImplementing() .Select(a => a.GetInaccuracyModifier()).ToArray(), + RangeModifiers = self.TraitsImplementing() + .Select(a => a.GetRangeModifier()).ToArray(), + Source = self.CenterPosition, CurrentSource = () => self.CenterPosition, SourceActor = self, diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs openra-20210321/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,6 +10,7 @@ #endregion using System.Collections.Generic; +using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Traits; @@ -17,7 +18,7 @@ namespace OpenRA.Mods.D2k.Traits { [Desc("Attach this to the world actor. Required for LaysTerrain to work.")] - public class BuildableTerrainLayerInfo : ITraitInfo + public class BuildableTerrainLayerInfo : TraitInfo { [Desc("Palette to render the layer sprites in.")] public readonly string Palette = TileSet.TerrainPaletteInternalName; @@ -25,17 +26,16 @@ [Desc("The hitpoints, which can be reduced by the DamagesConcreteWarhead.")] public readonly int MaxStrength = 9000; - public object Create(ActorInitializer init) { return new BuildableTerrainLayer(init.Self, this); } + public override object Create(ActorInitializer init) { return new BuildableTerrainLayer(init.Self, this); } } public class BuildableTerrainLayer : IRenderOverlay, IWorldLoaded, ITickRender, INotifyActorDisposing { readonly BuildableTerrainLayerInfo info; - readonly Dictionary dirty = new Dictionary(); - readonly Map map; + readonly Dictionary dirty = new Dictionary(); + readonly World world; readonly CellLayer strength; - BuildingInfluence bi; TerrainSpriteLayer render; Theater theater; bool disposed; @@ -43,14 +43,13 @@ public BuildableTerrainLayer(Actor self, BuildableTerrainLayerInfo info) { this.info = info; - map = self.World.Map; - strength = new CellLayer(self.World.Map); + world = self.World; + strength = new CellLayer(world.Map); } public void WorldLoaded(World w, WorldRenderer wr) { theater = wr.Theater; - bi = w.WorldActor.Trait(); render = new TerrainSpriteLayer(w, wr, theater.Sheet, BlendMode.Alpha, wr.Palette(info.Palette), wr.World.Type != WorldType.Editor); } @@ -59,17 +58,18 @@ if (!strength.Contains(cell)) return; - map.CustomTerrain[cell] = map.Rules.TileSet.GetTerrainIndex(tile); + world.Map.CustomTerrain[cell] = world.Map.Rules.TileSet.GetTerrainIndex(tile); strength[cell] = info.MaxStrength; - - // Terrain tiles define their origin at the topleft - var s = theater.TileSprite(tile); - dirty[cell] = new Sprite(s.Sheet, s.Bounds, s.ZRamp, float2.Zero, s.Channel, s.BlendMode); + dirty[cell] = tile; } public void HitTile(CPos cell, int damage) { - if (!strength.Contains(cell) || strength[cell] == 0 || bi.GetBuildingAt(cell) != null) + if (!strength.Contains(cell) || strength[cell] == 0) + return; + + // Buildings (but not other actors) block damage to cells under their footprint + if (world.ActorMap.GetActorsAt(cell).Any(a => a.TraitOrDefault() != null)) return; strength[cell] = strength[cell] - damage; @@ -82,7 +82,7 @@ if (!strength.Contains(cell)) return; - map.CustomTerrain[cell] = byte.MaxValue; + world.Map.CustomTerrain[cell] = byte.MaxValue; strength[cell] = 0; dirty[cell] = null; } @@ -94,7 +94,17 @@ { if (!self.World.FogObscures(kv.Key)) { - render.Update(kv.Key, kv.Value); + var tile = kv.Value; + if (tile.HasValue) + { + // Terrain tiles define their origin at the topleft + var s = theater.TileSprite(tile.Value); + var ss = new Sprite(s.Sheet, s.Bounds, s.ZRamp, float2.Zero, s.Channel, s.BlendMode); + render.Update(kv.Key, ss, false); + } + else + render.Clear(kv.Key); + remove.Add(kv.Key); } } diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs openra-20210321/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Linq; -using OpenRA.Mods.Common.Traits; -using OpenRA.Traits; - -namespace OpenRA.Mods.D2k.Traits -{ - using ClearSides = D2kResourceRenderer.ClearSides; - - [Desc("Used to render spice with round borders.")] - public class D2kEditorResourceLayerInfo : EditorResourceLayerInfo - { - public override object Create(ActorInitializer init) { return new D2kEditorResourceLayer(init.Self); } - } - - public class D2kEditorResourceLayer : EditorResourceLayer - { - public D2kEditorResourceLayer(Actor self) - : base(self) { } - - public override EditorCellContents UpdateDirtyTile(CPos c) - { - var t = Tiles[c]; - - // Empty tile - if (t.Type == null) - { - t.Sprite = null; - return t; - } - - NetWorth -= t.Density * t.Type.Info.ValuePerUnit; - - t.Density = ResourceDensityAt(c); - - NetWorth += t.Density * t.Type.Info.ValuePerUnit; - - int index; - var clear = FindClearSides(t.Type, c); - if (clear == ClearSides.None) - { - var sprites = D2kResourceRenderer.Variants[t.Variant]; - var frame = t.Density > t.Type.Info.MaxDensity / 2 ? 1 : 0; - t.Sprite = t.Type.Variants.First().Value[sprites[frame]]; - } - else if (D2kResourceRenderer.SpriteMap.TryGetValue(clear, out index)) - t.Sprite = t.Type.Variants.First().Value[index]; - else - t.Sprite = null; - - return t; - } - - protected override string ChooseRandomVariant(ResourceType t) - { - return D2kResourceRenderer.Variants.Keys.Random(Game.CosmeticRandom); - } - - bool CellContains(CPos c, ResourceType t) - { - return Tiles.Contains(c) && Tiles[c].Type == t; - } - - ClearSides FindClearSides(ResourceType t, CPos p) - { - var ret = ClearSides.None; - if (!CellContains(p + new CVec(0, -1), t)) - ret |= ClearSides.Top | ClearSides.TopLeft | ClearSides.TopRight; - - if (!CellContains(p + new CVec(-1, 0), t)) - ret |= ClearSides.Left | ClearSides.TopLeft | ClearSides.BottomLeft; - - if (!CellContains(p + new CVec(1, 0), t)) - ret |= ClearSides.Right | ClearSides.TopRight | ClearSides.BottomRight; - - if (!CellContains(p + new CVec(0, 1), t)) - ret |= ClearSides.Bottom | ClearSides.BottomLeft | ClearSides.BottomRight; - - if (!CellContains(p + new CVec(-1, -1), t)) - ret |= ClearSides.TopLeft; - - if (!CellContains(p + new CVec(1, -1), t)) - ret |= ClearSides.TopRight; - - if (!CellContains(p + new CVec(-1, 1), t)) - ret |= ClearSides.BottomLeft; - - if (!CellContains(p + new CVec(1, 1), t)) - ret |= ClearSides.BottomRight; - - return ret; - } - } -} diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/World/D2kFogPalette.cs openra-20210321/OpenRA.Mods.D2k/Traits/World/D2kFogPalette.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/World/D2kFogPalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/World/D2kFogPalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,7 +16,7 @@ namespace OpenRA.Mods.D2k.Traits { - class D2kFogPaletteInfo : ITraitInfo + class D2kFogPaletteInfo : TraitInfo { [PaletteDefinition] [FieldLoader.Require] @@ -31,7 +31,7 @@ [Desc("Allow palette modifiers to change the palette.")] public readonly bool AllowModifiers = true; - public object Create(ActorInitializer init) { return new D2kFogPalette(this); } + public override object Create(ActorInitializer init) { return new D2kFogPalette(this); } } class D2kFogPalette : ILoadsPalettes, IProvidesAssetBrowserPalettes diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/World/D2kResourceRenderer.cs openra-20210321/OpenRA.Mods.D2k/Traits/World/D2kResourceRenderer.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/World/D2kResourceRenderer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/World/D2kResourceRenderer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -166,24 +166,23 @@ return; var clear = FindClearSides(renderType, cell); - int index; if (clear == ClearSides.None) { var sprites = Variants[content.Variant]; - var frame = density > ResourceLayer.GetMaxResourceDensity(cell) / 2 ? 1 : 0; + var frame = density > renderType.Info.MaxDensity / 2 ? 1 : 0; - UpdateSpriteLayers(cell, renderType.Variants.First().Value[sprites[frame]], renderType.Palette); + UpdateSpriteLayers(cell, renderType.Variants.First().Value, sprites[frame], renderType.Palette); } - else if (SpriteMap.TryGetValue(clear, out index)) + else if (SpriteMap.TryGetValue(clear, out var index)) { - UpdateSpriteLayers(cell, renderType.Variants.First().Value[index], renderType.Palette); + UpdateSpriteLayers(cell, renderType.Variants.First().Value, index, renderType.Palette); } else throw new InvalidOperationException("SpriteMap does not contain an index for ClearSides type '{0}'".F(clear)); } else - UpdateSpriteLayers(cell, null, null); + UpdateSpriteLayers(cell, null, 0, null); } protected override string ChooseRandomVariant(ResourceType t) diff -Nru openra-20200503/OpenRA.Mods.D2k/Traits/World/PaletteFromScaledPalette.cs openra-20210321/OpenRA.Mods.D2k/Traits/World/PaletteFromScaledPalette.cs --- openra-20200503/OpenRA.Mods.D2k/Traits/World/PaletteFromScaledPalette.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Traits/World/PaletteFromScaledPalette.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,7 +18,7 @@ namespace OpenRA.Mods.D2k.Traits { [Desc("Create a palette by applying a scale and offset to the colors in another palette.")] - class PaletteFromScaledPaletteInfo : ITraitInfo + class PaletteFromScaledPaletteInfo : TraitInfo { [PaletteDefinition] [FieldLoader.Require] @@ -39,7 +39,7 @@ [Desc("Amount to offset the base palette colors by.")] public readonly int Offset = 0; - public object Create(ActorInitializer init) { return new PaletteFromScaledPalette(this); } + public override object Create(ActorInitializer init) { return new PaletteFromScaledPalette(this); } } class PaletteFromScaledPalette : ILoadsPalettes, IProvidesAssetBrowserPalettes diff -Nru openra-20200503/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs openra-20210321/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs --- openra-20200503/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,236 +21,236 @@ { const int MapCordonWidth = 2; - public static Dictionary> ActorDataByActorCode = new Dictionary> + public static Dictionary ActorDataByActorCode = new Dictionary { - { 20, Pair.New("wormspawner", "Creeps") }, - { 23, Pair.New("mpspawn", "Neutral") }, - { 41, Pair.New("spicebloom.spawnpoint", "Neutral") }, - { 42, Pair.New("spicebloom.spawnpoint", "Neutral") }, - { 43, Pair.New("spicebloom.spawnpoint", "Neutral") }, - { 44, Pair.New("spicebloom.spawnpoint", "Neutral") }, - { 45, Pair.New("spicebloom.spawnpoint", "Neutral") }, + { 20, ("wormspawner", "Creeps") }, + { 23, ("mpspawn", "Neutral") }, + { 41, ("spicebloom.spawnpoint", "Neutral") }, + { 42, ("spicebloom.spawnpoint", "Neutral") }, + { 43, ("spicebloom.spawnpoint", "Neutral") }, + { 44, ("spicebloom.spawnpoint", "Neutral") }, + { 45, ("spicebloom.spawnpoint", "Neutral") }, // Atreides: - { 4, Pair.New("wall", "Atreides") }, - { 5, Pair.New("wind_trap", "Atreides") }, - { 8, Pair.New("construction_yard", "Atreides") }, - { 11, Pair.New("barracks", "Atreides") }, - { 14, Pair.New("refinery", "Atreides") }, - { 17, Pair.New("outpost", "Atreides") }, - { 63, Pair.New("light_factory", "Atreides") }, - { 69, Pair.New("silo", "Atreides") }, - { 72, Pair.New("heavy_factory", "Atreides") }, - { 75, Pair.New("repair_pad", "Atreides") }, - { 78, Pair.New("medium_gun_turret", "Atreides") }, - { 120, Pair.New("high_tech_factory", "Atreides") }, - { 123, Pair.New("large_gun_turret", "Atreides") }, - { 126, Pair.New("research_centre", "Atreides") }, - { 129, Pair.New("starport", "Atreides") }, - { 132, Pair.New("palace", "Atreides") }, - { 180, Pair.New("light_inf", "Atreides") }, - { 181, Pair.New("trooper", "Atreides") }, - { 182, Pair.New("fremen", "Atreides") }, - { 183, Pair.New("sardaukar", "Atreides") }, - { 184, Pair.New("engineer", "Atreides") }, - { 185, Pair.New("harvester", "Atreides") }, - { 186, Pair.New("mcv", "Atreides") }, - { 187, Pair.New("trike", "Atreides") }, - { 188, Pair.New("quad", "Atreides") }, - { 189, Pair.New("combat_tank_a", "Atreides") }, - { 190, Pair.New("missile_tank", "Atreides") }, - { 191, Pair.New("siege_tank", "Atreides") }, - { 192, Pair.New("carryall", "Atreides") }, - { 194, Pair.New("sonic_tank", "Atreides") }, + { 4, ("wall", "Atreides") }, + { 5, ("wind_trap", "Atreides") }, + { 8, ("construction_yard", "Atreides") }, + { 11, ("barracks", "Atreides") }, + { 14, ("refinery", "Atreides") }, + { 17, ("outpost", "Atreides") }, + { 63, ("light_factory", "Atreides") }, + { 69, ("silo", "Atreides") }, + { 72, ("heavy_factory", "Atreides") }, + { 75, ("repair_pad", "Atreides") }, + { 78, ("medium_gun_turret", "Atreides") }, + { 120, ("high_tech_factory", "Atreides") }, + { 123, ("large_gun_turret", "Atreides") }, + { 126, ("research_centre", "Atreides") }, + { 129, ("starport", "Atreides") }, + { 132, ("palace", "Atreides") }, + { 180, ("light_inf", "Atreides") }, + { 181, ("trooper", "Atreides") }, + { 182, ("fremen", "Atreides") }, + { 183, ("sardaukar", "Atreides") }, + { 184, ("engineer", "Atreides") }, + { 185, ("harvester", "Atreides") }, + { 186, ("mcv", "Atreides") }, + { 187, ("trike", "Atreides") }, + { 188, ("quad", "Atreides") }, + { 189, ("combat_tank_a", "Atreides") }, + { 190, ("missile_tank", "Atreides") }, + { 191, ("siege_tank", "Atreides") }, + { 192, ("carryall", "Atreides") }, + { 194, ("sonic_tank", "Atreides") }, // Harkonnen: - { 204, Pair.New("wall", "Harkonnen") }, - { 205, Pair.New("wind_trap", "Harkonnen") }, - { 208, Pair.New("construction_yard", "Harkonnen") }, - { 211, Pair.New("barracks", "Harkonnen") }, - { 214, Pair.New("refinery", "Harkonnen") }, - { 217, Pair.New("outpost", "Harkonnen") }, - { 263, Pair.New("light_factory", "Harkonnen") }, - { 269, Pair.New("silo", "Harkonnen") }, - { 272, Pair.New("heavy_factory", "Harkonnen") }, - { 275, Pair.New("repair_pad", "Harkonnen") }, - { 278, Pair.New("medium_gun_turret", "Harkonnen") }, - { 320, Pair.New("high_tech_factory", "Harkonnen") }, - { 323, Pair.New("large_gun_turret", "Harkonnen") }, - { 326, Pair.New("research_centre", "Harkonnen") }, - { 329, Pair.New("starport", "Harkonnen") }, - { 332, Pair.New("palace", "Harkonnen") }, - { 360, Pair.New("light_inf", "Harkonnen") }, - { 361, Pair.New("trooper", "Harkonnen") }, - { 362, Pair.New("fremen", "Harkonnen") }, - { 363, Pair.New("mpsardaukar", "Harkonnen") }, - { 364, Pair.New("engineer", "Harkonnen") }, - { 365, Pair.New("harvester", "Harkonnen") }, - { 366, Pair.New("mcv", "Harkonnen") }, - { 367, Pair.New("trike", "Harkonnen") }, - { 368, Pair.New("quad", "Harkonnen") }, - { 369, Pair.New("combat_tank_h", "Harkonnen") }, - { 370, Pair.New("missile_tank", "Harkonnen") }, - { 371, Pair.New("siege_tank", "Harkonnen") }, - { 372, Pair.New("carryall", "Harkonnen") }, - { 374, Pair.New("devastator", "Harkonnen") }, + { 204, ("wall", "Harkonnen") }, + { 205, ("wind_trap", "Harkonnen") }, + { 208, ("construction_yard", "Harkonnen") }, + { 211, ("barracks", "Harkonnen") }, + { 214, ("refinery", "Harkonnen") }, + { 217, ("outpost", "Harkonnen") }, + { 263, ("light_factory", "Harkonnen") }, + { 269, ("silo", "Harkonnen") }, + { 272, ("heavy_factory", "Harkonnen") }, + { 275, ("repair_pad", "Harkonnen") }, + { 278, ("medium_gun_turret", "Harkonnen") }, + { 320, ("high_tech_factory", "Harkonnen") }, + { 323, ("large_gun_turret", "Harkonnen") }, + { 326, ("research_centre", "Harkonnen") }, + { 329, ("starport", "Harkonnen") }, + { 332, ("palace", "Harkonnen") }, + { 360, ("light_inf", "Harkonnen") }, + { 361, ("trooper", "Harkonnen") }, + { 362, ("fremen", "Harkonnen") }, + { 363, ("mpsardaukar", "Harkonnen") }, + { 364, ("engineer", "Harkonnen") }, + { 365, ("harvester", "Harkonnen") }, + { 366, ("mcv", "Harkonnen") }, + { 367, ("trike", "Harkonnen") }, + { 368, ("quad", "Harkonnen") }, + { 369, ("combat_tank_h", "Harkonnen") }, + { 370, ("missile_tank", "Harkonnen") }, + { 371, ("siege_tank", "Harkonnen") }, + { 372, ("carryall", "Harkonnen") }, + { 374, ("devastator", "Harkonnen") }, // Ordos: - { 404, Pair.New("wall", "Ordos") }, - { 405, Pair.New("wind_trap", "Ordos") }, - { 408, Pair.New("construction_yard", "Ordos") }, - { 411, Pair.New("barracks", "Ordos") }, - { 414, Pair.New("refinery", "Ordos") }, - { 417, Pair.New("outpost", "Ordos") }, - { 463, Pair.New("light_factory", "Ordos") }, - { 469, Pair.New("silo", "Ordos") }, - { 472, Pair.New("heavy_factory", "Ordos") }, - { 475, Pair.New("repair_pad", "Ordos") }, - { 478, Pair.New("medium_gun_turret", "Ordos") }, - { 520, Pair.New("high_tech_factory", "Ordos") }, - { 523, Pair.New("large_gun_turret", "Ordos") }, - { 526, Pair.New("research_centre", "Ordos") }, - { 529, Pair.New("starport", "Ordos") }, - { 532, Pair.New("palace", "Ordos") }, - { 560, Pair.New("light_inf", "Ordos") }, - { 561, Pair.New("trooper", "Ordos") }, - { 562, Pair.New("saboteur", "Ordos") }, - { 563, Pair.New("sardaukar", "Ordos") }, - { 564, Pair.New("engineer", "Ordos") }, - { 565, Pair.New("harvester", "Ordos") }, - { 566, Pair.New("mcv", "Ordos") }, - { 567, Pair.New("raider", "Ordos") }, - { 568, Pair.New("quad", "Ordos") }, - { 569, Pair.New("combat_tank_o", "Ordos") }, - { 570, Pair.New("missile_tank", "Ordos") }, - { 571, Pair.New("siege_tank", "Ordos") }, - { 572, Pair.New("carryall", "Ordos") }, - { 574, Pair.New("deviator", "Ordos") }, + { 404, ("wall", "Ordos") }, + { 405, ("wind_trap", "Ordos") }, + { 408, ("construction_yard", "Ordos") }, + { 411, ("barracks", "Ordos") }, + { 414, ("refinery", "Ordos") }, + { 417, ("outpost", "Ordos") }, + { 463, ("light_factory", "Ordos") }, + { 469, ("silo", "Ordos") }, + { 472, ("heavy_factory", "Ordos") }, + { 475, ("repair_pad", "Ordos") }, + { 478, ("medium_gun_turret", "Ordos") }, + { 520, ("high_tech_factory", "Ordos") }, + { 523, ("large_gun_turret", "Ordos") }, + { 526, ("research_centre", "Ordos") }, + { 529, ("starport", "Ordos") }, + { 532, ("palace", "Ordos") }, + { 560, ("light_inf", "Ordos") }, + { 561, ("trooper", "Ordos") }, + { 562, ("saboteur", "Ordos") }, + { 563, ("sardaukar", "Ordos") }, + { 564, ("engineer", "Ordos") }, + { 565, ("harvester", "Ordos") }, + { 566, ("mcv", "Ordos") }, + { 567, ("raider", "Ordos") }, + { 568, ("quad", "Ordos") }, + { 569, ("combat_tank_o", "Ordos") }, + { 570, ("missile_tank", "Ordos") }, + { 571, ("siege_tank", "Ordos") }, + { 572, ("carryall", "Ordos") }, + { 574, ("deviator", "Ordos") }, // Corrino: - { 580, Pair.New("wall", "Corrino") }, - { 581, Pair.New("wind_trap", "Corrino") }, - { 582, Pair.New("construction_yard", "Corrino") }, - { 583, Pair.New("barracks", "Corrino") }, - { 584, Pair.New("refinery", "Corrino") }, - { 585, Pair.New("outpost", "Corrino") }, - { 587, Pair.New("light_factory", "Corrino") }, - { 588, Pair.New("palace", "Corrino") }, - { 589, Pair.New("silo", "Corrino") }, - { 590, Pair.New("heavy_factory", "Corrino") }, - { 591, Pair.New("repair_pad", "Corrino") }, - { 592, Pair.New("medium_gun_turret", "Corrino") }, - { 593, Pair.New("high_tech_factory", "Corrino") }, - { 594, Pair.New("large_gun_turret", "Corrino") }, - { 595, Pair.New("research_centre", "Corrino") }, - { 596, Pair.New("starport", "Corrino") }, - { 597, Pair.New("sietch", "Corrino") }, - { 598, Pair.New("light_inf", "Corrino") }, - { 599, Pair.New("trooper", "Corrino") }, - { 600, Pair.New("sardaukar", "Corrino") }, - { 601, Pair.New("fremen", "Corrino") }, - { 602, Pair.New("engineer", "Corrino") }, - { 603, Pair.New("harvester", "Corrino") }, - { 604, Pair.New("mcv", "Corrino") }, - { 605, Pair.New("trike", "Corrino") }, - { 606, Pair.New("quad", "Corrino") }, - { 607, Pair.New("combat_tank_h", "Corrino") }, - { 608, Pair.New("missile_tank", "Corrino") }, - { 609, Pair.New("siege_tank", "Corrino") }, - { 610, Pair.New("carryall", "Corrino") }, + { 580, ("wall", "Corrino") }, + { 581, ("wind_trap", "Corrino") }, + { 582, ("construction_yard", "Corrino") }, + { 583, ("barracks", "Corrino") }, + { 584, ("refinery", "Corrino") }, + { 585, ("outpost", "Corrino") }, + { 587, ("light_factory", "Corrino") }, + { 588, ("palace", "Corrino") }, + { 589, ("silo", "Corrino") }, + { 590, ("heavy_factory", "Corrino") }, + { 591, ("repair_pad", "Corrino") }, + { 592, ("medium_gun_turret", "Corrino") }, + { 593, ("high_tech_factory", "Corrino") }, + { 594, ("large_gun_turret", "Corrino") }, + { 595, ("research_centre", "Corrino") }, + { 596, ("starport", "Corrino") }, + { 597, ("sietch", "Corrino") }, + { 598, ("light_inf", "Corrino") }, + { 599, ("trooper", "Corrino") }, + { 600, ("sardaukar", "Corrino") }, + { 601, ("fremen", "Corrino") }, + { 602, ("engineer", "Corrino") }, + { 603, ("harvester", "Corrino") }, + { 604, ("mcv", "Corrino") }, + { 605, ("trike", "Corrino") }, + { 606, ("quad", "Corrino") }, + { 607, ("combat_tank_h", "Corrino") }, + { 608, ("missile_tank", "Corrino") }, + { 609, ("siege_tank", "Corrino") }, + { 610, ("carryall", "Corrino") }, // Fremen: - { 620, Pair.New("wall", "Fremen") }, - { 621, Pair.New("wind_trap", "Fremen") }, - { 622, Pair.New("construction_yard", "Fremen") }, - { 623, Pair.New("barracks", "Fremen") }, - { 624, Pair.New("refinery", "Fremen") }, - { 625, Pair.New("outpost", "Fremen") }, - { 627, Pair.New("light_factory", "Fremen") }, - { 628, Pair.New("palace", "Fremen") }, - { 629, Pair.New("silo", "Fremen") }, - { 630, Pair.New("heavy_factory", "Fremen") }, - { 631, Pair.New("repair_pad", "Fremen") }, - { 632, Pair.New("medium_gun_turret", "Fremen") }, - { 633, Pair.New("high_tech_factory", "Fremen") }, - { 634, Pair.New("large_gun_turret", "Fremen") }, - { 635, Pair.New("research_centre", "Fremen") }, - { 636, Pair.New("starport", "Fremen") }, - { 637, Pair.New("sietch", "Fremen") }, - { 638, Pair.New("light_inf", "Fremen") }, - { 639, Pair.New("trooper", "Fremen") }, - { 640, Pair.New("fremen", "Fremen") }, - { 641, Pair.New("nsfremen", "Fremen") }, - { 642, Pair.New("engineer", "Fremen") }, - { 643, Pair.New("harvester", "Fremen") }, - { 644, Pair.New("mcv", "Fremen") }, - { 645, Pair.New("trike", "Fremen") }, - { 646, Pair.New("quad", "Fremen") }, - { 647, Pair.New("combat_tank_a", "Fremen") }, - { 648, Pair.New("missile_tank", "Fremen") }, - { 649, Pair.New("siege_tank", "Fremen") }, - { 650, Pair.New("carryall", "Fremen") }, - { 652, Pair.New("sonic_tank", "Fremen") }, + { 620, ("wall", "Fremen") }, + { 621, ("wind_trap", "Fremen") }, + { 622, ("construction_yard", "Fremen") }, + { 623, ("barracks", "Fremen") }, + { 624, ("refinery", "Fremen") }, + { 625, ("outpost", "Fremen") }, + { 627, ("light_factory", "Fremen") }, + { 628, ("palace", "Fremen") }, + { 629, ("silo", "Fremen") }, + { 630, ("heavy_factory", "Fremen") }, + { 631, ("repair_pad", "Fremen") }, + { 632, ("medium_gun_turret", "Fremen") }, + { 633, ("high_tech_factory", "Fremen") }, + { 634, ("large_gun_turret", "Fremen") }, + { 635, ("research_centre", "Fremen") }, + { 636, ("starport", "Fremen") }, + { 637, ("sietch", "Fremen") }, + { 638, ("light_inf", "Fremen") }, + { 639, ("trooper", "Fremen") }, + { 640, ("fremen", "Fremen") }, + { 641, ("nsfremen", "Fremen") }, + { 642, ("engineer", "Fremen") }, + { 643, ("harvester", "Fremen") }, + { 644, ("mcv", "Fremen") }, + { 645, ("trike", "Fremen") }, + { 646, ("quad", "Fremen") }, + { 647, ("combat_tank_a", "Fremen") }, + { 648, ("missile_tank", "Fremen") }, + { 649, ("siege_tank", "Fremen") }, + { 650, ("carryall", "Fremen") }, + { 652, ("sonic_tank", "Fremen") }, // Smugglers: - { 660, Pair.New("wall", "Smugglers") }, - { 661, Pair.New("wind_trap", "Smugglers") }, - { 662, Pair.New("construction_yard", "Smugglers") }, - { 663, Pair.New("barracks", "Smugglers") }, - { 664, Pair.New("refinery", "Smugglers") }, - { 666, Pair.New("outpost", "Smugglers") }, - { 667, Pair.New("light_factory", "Smugglers") }, - { 668, Pair.New("silo", "Smugglers") }, - { 669, Pair.New("heavy_factory", "Smugglers") }, - { 670, Pair.New("repair_pad", "Smugglers") }, - { 671, Pair.New("medium_gun_turret", "Smugglers") }, - { 672, Pair.New("high_tech_factory", "Smugglers") }, - { 673, Pair.New("large_gun_turret", "Smugglers") }, - { 674, Pair.New("research_centre", "Smugglers") }, - { 675, Pair.New("starport", "Smugglers") }, - { 676, Pair.New("palace", "Smugglers") }, - { 677, Pair.New("light_inf", "Smugglers") }, - { 678, Pair.New("trooper", "Smugglers") }, - { 679, Pair.New("saboteur", "Smugglers") }, - { 680, Pair.New("engineer", "Smugglers") }, - { 681, Pair.New("harvester", "Smugglers") }, - { 682, Pair.New("mcv", "Smugglers") }, - { 683, Pair.New("trike", "Smugglers") }, - { 684, Pair.New("quad", "Smugglers") }, - { 685, Pair.New("combat_tank_o", "Smugglers") }, - { 686, Pair.New("missile_tank", "Smugglers") }, - { 687, Pair.New("siege_tank", "Smugglers") }, - { 688, Pair.New("carryall", "Smugglers") }, + { 660, ("wall", "Smugglers") }, + { 661, ("wind_trap", "Smugglers") }, + { 662, ("construction_yard", "Smugglers") }, + { 663, ("barracks", "Smugglers") }, + { 664, ("refinery", "Smugglers") }, + { 666, ("outpost", "Smugglers") }, + { 667, ("light_factory", "Smugglers") }, + { 668, ("silo", "Smugglers") }, + { 669, ("heavy_factory", "Smugglers") }, + { 670, ("repair_pad", "Smugglers") }, + { 671, ("medium_gun_turret", "Smugglers") }, + { 672, ("high_tech_factory", "Smugglers") }, + { 673, ("large_gun_turret", "Smugglers") }, + { 674, ("research_centre", "Smugglers") }, + { 675, ("starport", "Smugglers") }, + { 676, ("palace", "Smugglers") }, + { 677, ("light_inf", "Smugglers") }, + { 678, ("trooper", "Smugglers") }, + { 679, ("saboteur", "Smugglers") }, + { 680, ("engineer", "Smugglers") }, + { 681, ("harvester", "Smugglers") }, + { 682, ("mcv", "Smugglers") }, + { 683, ("trike", "Smugglers") }, + { 684, ("quad", "Smugglers") }, + { 685, ("combat_tank_o", "Smugglers") }, + { 686, ("missile_tank", "Smugglers") }, + { 687, ("siege_tank", "Smugglers") }, + { 688, ("carryall", "Smugglers") }, // Mercenaries: - { 700, Pair.New("wall", "Mercenaries") }, - { 701, Pair.New("wind_trap", "Mercenaries") }, - { 702, Pair.New("construction_yard", "Mercenaries") }, - { 703, Pair.New("barracks", "Mercenaries") }, - { 704, Pair.New("refinery", "Mercenaries") }, - { 705, Pair.New("outpost", "Mercenaries") }, - { 707, Pair.New("light_factory", "Mercenaries") }, - { 708, Pair.New("silo", "Mercenaries") }, - { 709, Pair.New("heavy_factory", "Mercenaries") }, - { 710, Pair.New("repair_pad", "Mercenaries") }, - { 711, Pair.New("medium_gun_turret", "Mercenaries") }, - { 712, Pair.New("high_tech_factory", "Mercenaries") }, - { 713, Pair.New("large_gun_turret", "Mercenaries") }, - { 714, Pair.New("research_centre", "Mercenaries") }, - { 715, Pair.New("starport", "Mercenaries") }, - { 716, Pair.New("palace", "Mercenaries") }, - { 717, Pair.New("light_inf", "Mercenaries") }, - { 718, Pair.New("trooper", "Mercenaries") }, - { 719, Pair.New("saboteur", "Mercenaries") }, - { 720, Pair.New("harvester", "Mercenaries") }, - { 721, Pair.New("harvester", "Mercenaries") }, - { 722, Pair.New("mcv", "Mercenaries") }, - { 723, Pair.New("trike", "Mercenaries") }, - { 724, Pair.New("quad", "Mercenaries") }, - { 725, Pair.New("combat_tank_o", "Mercenaries") }, - { 726, Pair.New("missile_tank", "Mercenaries") }, - { 727, Pair.New("siege_tank", "Mercenaries") }, - { 728, Pair.New("carryall", "Mercenaries") }, + { 700, ("wall", "Mercenaries") }, + { 701, ("wind_trap", "Mercenaries") }, + { 702, ("construction_yard", "Mercenaries") }, + { 703, ("barracks", "Mercenaries") }, + { 704, ("refinery", "Mercenaries") }, + { 705, ("outpost", "Mercenaries") }, + { 707, ("light_factory", "Mercenaries") }, + { 708, ("silo", "Mercenaries") }, + { 709, ("heavy_factory", "Mercenaries") }, + { 710, ("repair_pad", "Mercenaries") }, + { 711, ("medium_gun_turret", "Mercenaries") }, + { 712, ("high_tech_factory", "Mercenaries") }, + { 713, ("large_gun_turret", "Mercenaries") }, + { 714, ("research_centre", "Mercenaries") }, + { 715, ("starport", "Mercenaries") }, + { 716, ("palace", "Mercenaries") }, + { 717, ("light_inf", "Mercenaries") }, + { 718, ("trooper", "Mercenaries") }, + { 719, ("saboteur", "Mercenaries") }, + { 720, ("harvester", "Mercenaries") }, + { 721, ("harvester", "Mercenaries") }, + { 722, ("mcv", "Mercenaries") }, + { 723, ("trike", "Mercenaries") }, + { 724, ("quad", "Mercenaries") }, + { 725, ("combat_tank_o", "Mercenaries") }, + { 726, ("missile_tank", "Mercenaries") }, + { 727, ("siege_tank", "Mercenaries") }, + { 728, ("carryall", "Mercenaries") }, }; readonly Ruleset rules; @@ -322,7 +322,7 @@ // Get all templates from the tileset YAML file that have at least one frame and an Image property corresponding to the requested tileset // Each frame is a tile from the Dune 2000 tileset files, with the Frame ID being the index of the tile in the original file tileSetsFromYaml = tileSet.Templates.Where(t => t.Value.Frames != null - && t.Value.Images[0].ToLower() == tilesetName.ToLower()).Select(ts => ts.Value).ToList(); + && t.Value.Images[0].ToLowerInvariant() == tilesetName.ToLowerInvariant()).Select(ts => ts.Value).ToList(); var players = new MapPlayers(map.Rules, playerCount); map.PlayerDefinitions = players.ToMiniYaml(); @@ -350,18 +350,18 @@ if (ActorDataByActorCode.ContainsKey(tileSpecialInfo)) { var kvp = ActorDataByActorCode[tileSpecialInfo]; - if (!rules.Actors.ContainsKey(kvp.First.ToLower())) - throw new InvalidOperationException("Actor with name {0} could not be found in the rules YAML file!".F(kvp.First)); + if (!rules.Actors.ContainsKey(kvp.Actor.ToLowerInvariant())) + throw new InvalidOperationException("Actor with name {0} could not be found in the rules YAML file!".F(kvp.Actor)); - var a = new ActorReference(kvp.First) + var a = new ActorReference(kvp.Actor) { new LocationInit(locationOnMap), - new OwnerInit(kvp.Second) + new OwnerInit(kvp.Owner) }; map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, a.Save())); - if (kvp.First == "mpspawn") + if (kvp.Actor == "mpspawn") playerCount++; } } @@ -380,7 +380,7 @@ TerrainTile GetTile(int tileIndex) { // Some tiles are duplicates of other tiles, just on a different tileset - if (tilesetName.ToLower() == "bloxbgbs.r8") + if (tilesetName.ToLowerInvariant() == "bloxbgbs.r8") { if (tileIndex == 355) return new TerrainTile(441, 0); @@ -389,7 +389,7 @@ return new TerrainTile(442, 0); } - if (tilesetName.ToLower() == "bloxtree.r8") + if (tilesetName.ToLowerInvariant() == "bloxtree.r8") { var indices = new[] { 683, 684, 685, 706, 703, 704, 705, 726, 723, 724, 725, 746, 743, 744, 745, 747 }; for (var i = 0; i < 16; i++) @@ -410,7 +410,7 @@ return new TerrainTile(215, 0); } - if (tilesetName.ToLower() == "bloxwast.r8") + if (tilesetName.ToLowerInvariant() == "bloxwast.r8") { if (tileIndex == 342) return new TerrainTile(250, 0); diff -Nru openra-20200503/OpenRA.Mods.D2k/Warheads/DamagesConcreteWarhead.cs openra-20210321/OpenRA.Mods.D2k/Warheads/DamagesConcreteWarhead.cs --- openra-20200503/OpenRA.Mods.D2k/Warheads/DamagesConcreteWarhead.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Mods.D2k/Warheads/DamagesConcreteWarhead.cs 2021-03-21 11:10:05.000000000 +0000 @@ -9,7 +9,6 @@ */ #endregion -using System.Collections.Generic; using OpenRA.GameRules; using OpenRA.Mods.Common.Warheads; using OpenRA.Mods.D2k.Traits; @@ -24,7 +23,7 @@ [FieldLoader.Require] public readonly int Damage = 0; - public override void DoImpact(Target target, WarheadArgs args) + public override void DoImpact(in Target target, WarheadArgs args) { if (target.Type == TargetType.Invalid) return; diff -Nru openra-20200503/OpenRA.Platforms.Default/DefaultPlatform.cs openra-20210321/OpenRA.Platforms.Default/DefaultPlatform.cs --- openra-20200503/OpenRA.Platforms.Default/DefaultPlatform.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/DefaultPlatform.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,9 +16,9 @@ { public class DefaultPlatform : IPlatform { - public IPlatformWindow CreateWindow(Size size, WindowMode windowMode, float scaleModifier, int batchSize, int videoDisplay, GLProfile profile) + public IPlatformWindow CreateWindow(Size size, WindowMode windowMode, float scaleModifier, int batchSize, int videoDisplay, GLProfile profile, bool enableLegacyGL) { - return new Sdl2PlatformWindow(size, windowMode, scaleModifier, batchSize, videoDisplay, profile); + return new Sdl2PlatformWindow(size, windowMode, scaleModifier, batchSize, videoDisplay, profile, enableLegacyGL); } public ISoundEngine CreateSound(string device) diff -Nru openra-20200503/OpenRA.Platforms.Default/MultiTapDetection.cs openra-20210321/OpenRA.Platforms.Default/MultiTapDetection.cs --- openra-20200503/OpenRA.Platforms.Default/MultiTapDetection.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/MultiTapDetection.cs 2021-03-21 11:10:05.000000000 +0000 @@ -16,8 +16,8 @@ { static class MultiTapDetection { - static Cache, TapHistory> keyHistoryCache = - new Cache, TapHistory>(_ => new TapHistory(DateTime.Now - TimeSpan.FromSeconds(1))); + static Cache<(Keycode Key, Modifiers Mods), TapHistory> keyHistoryCache = + new Cache<(Keycode, Modifiers), TapHistory>(_ => new TapHistory(DateTime.Now - TimeSpan.FromSeconds(1))); static Cache clickHistoryCache = new Cache(_ => new TapHistory(DateTime.Now - TimeSpan.FromSeconds(1))); @@ -33,35 +33,35 @@ public static int DetectFromKeyboard(Keycode key, Modifiers mods) { - return keyHistoryCache[Pair.New(key, mods)].GetTapCount(int2.Zero); + return keyHistoryCache[(key, mods)].GetTapCount(int2.Zero); } public static int InfoFromKeyboard(Keycode key, Modifiers mods) { - return keyHistoryCache[Pair.New(key, mods)].LastTapCount(); + return keyHistoryCache[(key, mods)].LastTapCount(); } } class TapHistory { - public Pair FirstRelease, SecondRelease, ThirdRelease; + public (DateTime Time, int2 Location) FirstRelease, SecondRelease, ThirdRelease; public TapHistory(DateTime now) { - FirstRelease = SecondRelease = ThirdRelease = Pair.New(now, int2.Zero); + FirstRelease = SecondRelease = ThirdRelease = (now, int2.Zero); } - static bool CloseEnough(Pair a, Pair b) + static bool CloseEnough((DateTime Time, int2 Location) a, (DateTime Time, int2 Location) b) { - return a.First - b.First < TimeSpan.FromMilliseconds(250) - && (a.Second - b.Second).Length < 4; + return a.Time - b.Time < TimeSpan.FromMilliseconds(250) + && (a.Location - b.Location).Length < 4; } public int GetTapCount(int2 xy) { FirstRelease = SecondRelease; SecondRelease = ThirdRelease; - ThirdRelease = Pair.New(DateTime.Now, xy); + ThirdRelease = (DateTime.Now, xy); if (!CloseEnough(ThirdRelease, SecondRelease)) return 1; diff -Nru openra-20200503/OpenRA.Platforms.Default/OpenAlSoundEngine.cs openra-20210321/OpenRA.Platforms.Default/OpenAlSoundEngine.cs --- openra-20200503/OpenRA.Platforms.Default/OpenAlSoundEngine.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/OpenAlSoundEngine.cs 2021-03-21 11:10:05.000000000 +0000 @@ -242,8 +242,7 @@ atten = 0.66f * ((PoolSize - activeCount * 0.5f) / PoolSize); } - uint source; - if (!TryGetSourceFromPool(out source)) + if (!TryGetSourceFromPool(out var source)) return null; var slot = sourcePool[source]; @@ -259,8 +258,7 @@ { var currFrame = Game.LocalTick; - uint source; - if (!TryGetSourceFromPool(out source)) + if (!TryGetSourceFromPool(out var source)) return null; var slot = sourcePool[source]; @@ -295,8 +293,7 @@ void PauseSound(uint source, bool paused) { - int state; - AL10.alGetSourcei(source, AL10.AL_SOURCE_STATE, out state); + AL10.alGetSourcei(source, AL10.AL_SOURCE_STATE, out var state); if (paused) { if (state == AL10.AL_PLAYING) @@ -317,8 +314,7 @@ { var sounds = sourcePool.Keys.Where(key => { - int state; - AL10.alGetSourcei(key, AL10.AL_SOURCE_STATE, out state); + AL10.alGetSourcei(key, AL10.AL_SOURCE_STATE, out var state); return (state == AL10.AL_PLAYING || state == AL10.AL_PAUSED) && (music == null || key != ((OpenAlSound)music).Source) && (video == null || key != ((OpenAlSound)video).Source); @@ -330,17 +326,13 @@ public void StopSound(ISound sound) { - if (sound == null) - return; - - ((OpenAlSound)sound).Stop(); + ((OpenAlSound)sound)?.Stop(); } public void StopAllSounds() { foreach (var slot in sourcePool.Values) - if (slot.Sound != null) - slot.Sound.Stop(); + slot.Sound?.Stop(); } public void SetListenerPosition(WPos position) @@ -449,7 +441,7 @@ public float Volume { - get { float volume; AL10.alGetSourcef(Source, AL10.AL_GAIN, out volume); return volume; } + get { AL10.alGetSourcef(Source, AL10.AL_GAIN, out var volume); return volume; } set { AL10.alSourcef(Source, AL10.AL_GAIN, value); } } @@ -457,8 +449,7 @@ { get { - int sampleOffset; - AL10.alGetSourcei(Source, AL11.AL_SAMPLE_OFFSET, out sampleOffset); + AL10.alGetSourcei(Source, AL11.AL_SAMPLE_OFFSET, out var sampleOffset); return sampleOffset / SampleRate; } } @@ -467,8 +458,7 @@ { get { - int state; - AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out state); + AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out var state); return state == AL10.AL_STOPPED; } } @@ -480,8 +470,7 @@ protected void StopSource() { - int state; - AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out state); + AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out var state); if (state == AL10.AL_PLAYING || state == AL10.AL_PAUSED) AL10.alSourceStop(Source); } @@ -554,8 +543,7 @@ // TODO: A race condition can happen between the state check and playing/rewinding if a // user pauses/resumes at the right moment. The window of opportunity is small and the // consequences are minor, so for now we'll ignore it. - int state; - AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out state); + AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out var state); if (state != AL10.AL_STOPPED) AL10.alSourcePlay(source); else @@ -575,8 +563,7 @@ // has stopped. var currentSeek = SeekPosition; - int state; - AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out state); + AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out var state); if (state == AL10.AL_STOPPED) break; diff -Nru openra-20200503/OpenRA.Platforms.Default/OpenGL.cs openra-20210321/OpenRA.Platforms.Default/OpenGL.cs --- openra-20200503/OpenRA.Platforms.Default/OpenGL.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/OpenGL.cs 2021-03-21 11:10:05.000000000 +0000 @@ -543,6 +543,7 @@ } } + Console.WriteLine("OpenGL renderer: " + glGetString(GL_RENDERER)); Console.WriteLine("OpenGL version: " + glGetString(GL_VERSION)); try @@ -596,15 +597,24 @@ glBindTexture = Bind("glBindTexture"); glActiveTexture = Bind("glActiveTexture"); glTexImage2D = Bind("glTexImage2D"); - glGetTexImage = Bind("glGetTexImage"); glTexParameteri = Bind("glTexParameteri"); glTexParameterf = Bind("glTexParameterf"); if (Profile != GLProfile.Legacy) { + if (Profile != GLProfile.Embedded) + { + glGetTexImage = Bind("glGetTexImage"); + glBindFragDataLocation = Bind("glBindFragDataLocation"); + } + else + { + glGetTexImage = null; + glBindFragDataLocation = null; + } + glGenVertexArrays = Bind("glGenVertexArrays"); glBindVertexArray = Bind("glBindVertexArray"); - glBindFragDataLocation = Bind("glBindFragDataLocation"); glGenFramebuffers = Bind("glGenFramebuffers"); glBindFramebuffer = Bind("glBindFramebuffer"); glFramebufferTexture2D = Bind("glFramebufferTexture2D"); @@ -719,8 +729,7 @@ if (Profile != GLProfile.Legacy) { - int extensionCount; - glGetIntegerv(GL_NUM_EXTENSIONS, out extensionCount); + glGetIntegerv(GL_NUM_EXTENSIONS, out var extensionCount); for (var i = 0; i < extensionCount; i++) Log.Write("graphics", glGetStringi(GL_EXTENSIONS, (uint)i)); } @@ -731,7 +740,7 @@ public static void CheckGLError() { // Let the debug message handler log the errors instead. - if (Features.HasFlag(GLFeatures.DebugMessagesCallback)) + if ((Features & GLFeatures.DebugMessagesCallback) == GLFeatures.DebugMessagesCallback) return; var type = glGetError(); diff -Nru openra-20200503/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj openra-20210321/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj --- openra-20200503/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj 2021-03-21 11:10:05.000000000 +0000 @@ -1,17 +1,22 @@  - net461 + net472 true true - 5 + 7.3 true true - .. + ../bin false AnyCPU false ..\OpenRA.ruleset + + win-x64 + linux-x64 + osx-x64 + @@ -21,19 +26,12 @@ false - - ..\thirdparty\download\Eluant.dll - - - ..\thirdparty\download\SDL2-CS.dll - - - ..\thirdparty\download\OpenAL-CS.dll - - - + + + + @@ -43,8 +41,8 @@ - + PreserveNewest - \ No newline at end of file + diff -Nru openra-20200503/OpenRA.Platforms.Default/OpenRA.Platforms.Default.dll.config openra-20210321/OpenRA.Platforms.Default/OpenRA.Platforms.Default.dll.config --- openra-20200503/OpenRA.Platforms.Default/OpenRA.Platforms.Default.dll.config 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/OpenRA.Platforms.Default.dll.config 2021-03-21 11:10:05.000000000 +0000 @@ -1,6 +1,5 @@ - - - + + diff -Nru openra-20200503/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs openra-20210321/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs --- openra-20200503/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs 2021-03-21 11:10:05.000000000 +0000 @@ -40,8 +40,7 @@ if (OpenGL.Profile != GLProfile.Legacy) { - uint vao; - OpenGL.glGenVertexArrays(1, out vao); + OpenGL.glGenVertexArrays(1, out var vao); OpenGL.CheckGLError(); OpenGL.glBindVertexArray(vao); OpenGL.CheckGLError(); @@ -53,6 +52,8 @@ OpenGL.CheckGLError(); OpenGL.glEnableVertexAttribArray(Shader.TexMetadataAttributeIndex); OpenGL.CheckGLError(); + OpenGL.glEnableVertexAttribArray(Shader.TintAttributeIndex); + OpenGL.CheckGLError(); } public IVertexBuffer CreateVertexBuffer(int size) @@ -229,6 +230,21 @@ OpenGL.CheckGLError(); OpenGL.glBlendFunc(OpenGL.GL_DST_COLOR, OpenGL.GL_SRC_COLOR); break; + case BlendMode.LowAdditive: + OpenGL.glEnable(OpenGL.GL_BLEND); + OpenGL.CheckGLError(); + OpenGL.glBlendFunc(OpenGL.GL_DST_COLOR, OpenGL.GL_ONE); + break; + case BlendMode.Screen: + OpenGL.glEnable(OpenGL.GL_BLEND); + OpenGL.CheckGLError(); + OpenGL.glBlendFunc(OpenGL.GL_SRC_COLOR, OpenGL.GL_ONE_MINUS_SRC_COLOR); + break; + case BlendMode.Translucent: + OpenGL.glEnable(OpenGL.GL_BLEND); + OpenGL.CheckGLError(); + OpenGL.glBlendFunc(OpenGL.GL_DST_COLOR, OpenGL.GL_ONE_MINUS_DST_COLOR); + break; } OpenGL.CheckGLError(); diff -Nru openra-20200503/OpenRA.Platforms.Default/Sdl2Input.cs openra-20210321/OpenRA.Platforms.Default/Sdl2Input.cs --- openra-20200503/OpenRA.Platforms.Default/Sdl2Input.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/Sdl2Input.cs 2021-03-21 11:10:05.000000000 +0000 @@ -67,13 +67,15 @@ inputHandler.ModifierKeys(mods); MouseInput? pendingMotion = null; - SDL.SDL_Event e; - while (SDL.SDL_PollEvent(out e) != 0) + while (SDL.SDL_PollEvent(out var e) != 0) { switch (e.type) { case SDL.SDL_EventType.SDL_QUIT: - Game.Exit(); + // On macOS, we'd like to restrict Cmd + Q from suddenly exiting the game. + if (Platform.CurrentPlatform != PlatformType.OSX || !mods.HasModifier(Modifiers.Meta)) + Game.Exit(); + break; case SDL.SDL_EventType.SDL_WINDOWEVENT: @@ -81,11 +83,11 @@ switch (e.window.windowEvent) { case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST: - Game.HasInputFocus = false; + device.HasInputFocus = false; break; case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED: - Game.HasInputFocus = true; + device.HasInputFocus = true; break; // Triggered when moving between displays with different DPI settings @@ -157,8 +159,7 @@ case SDL.SDL_EventType.SDL_MOUSEWHEEL: { - int x, y; - SDL.SDL_GetMouseState(out x, out y); + SDL.SDL_GetMouseState(out var x, out var y); var pos = EventPosition(device, x, y); inputHandler.OnMouseInput(new MouseInput(MouseInputEvent.Scroll, MouseButton.None, pos, new int2(0, e.wheel.y), mods, 0)); diff -Nru openra-20200503/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs openra-20210321/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs --- openra-20200503/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,6 +10,7 @@ #endregion using System; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; @@ -108,6 +109,8 @@ } } + public bool HasInputFocus { get; internal set; } + public GLProfile GLProfile { get @@ -132,7 +135,7 @@ static extern bool SetProcessDPIAware(); public Sdl2PlatformWindow(Size requestEffectiveWindowSize, WindowMode windowMode, - float scaleModifier, int batchSize, int videoDisplay, GLProfile requestProfile) + float scaleModifier, int batchSize, int videoDisplay, GLProfile requestProfile, bool enableLegacyGL) { // Lock the Window/Surface properties until initialization is complete lock (syncObject) @@ -143,46 +146,50 @@ if (Platform.CurrentPlatform == PlatformType.Windows) SetProcessDPIAware(); - SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO); - // Decide which OpenGL profile to use. - // We first need to query the available profiles on Windows/Linux. - // On macOS, known/consistent OpenGL support is provided by the OS. - if (Platform.CurrentPlatform == PlatformType.OSX) - supportedProfiles = new[] { GLProfile.Modern, GLProfile.Legacy }; - else - supportedProfiles = new[] { GLProfile.Modern, GLProfile.Embedded, GLProfile.Legacy } - .Where(CanCreateGLWindow) - .ToArray(); + // Prefer standard GL over GLES provided by the native driver + var testProfiles = new List { GLProfile.ANGLE, GLProfile.Modern, GLProfile.Embedded }; + if (enableLegacyGL) + testProfiles.Add(GLProfile.Legacy); + + supportedProfiles = testProfiles + .Where(CanCreateGLWindow) + .ToArray(); if (!supportedProfiles.Any()) throw new InvalidOperationException("No supported OpenGL profiles were found."); profile = supportedProfiles.Contains(requestProfile) ? requestProfile : supportedProfiles.First(); + + // Note: This must be called after the CanCreateGLWindow checks above, + // which needs to create and destroy its own SDL contexts as a workaround for specific buggy drivers + SDL.SDL_Init(SDL.SDL_INIT_VIDEO); SetSDLAttributes(profile); Console.WriteLine("Using SDL 2 with OpenGL ({0}) renderer", profile); if (videoDisplay < 0 || videoDisplay >= DisplayCount) videoDisplay = 0; - SDL.SDL_DisplayMode display; - SDL.SDL_GetCurrentDisplayMode(videoDisplay, out display); + SDL.SDL_GetCurrentDisplayMode(videoDisplay, out var display); // Windows and Linux define window sizes in native pixel units. // Query the display/dpi scale so we can convert our requested effective size to pixels. // This is not necessary on macOS, which defines window sizes in effective units ("points"). if (Platform.CurrentPlatform == PlatformType.Windows) { - float ddpi, hdpi, vdpi; - if (SDL.SDL_GetDisplayDPI(videoDisplay, out ddpi, out hdpi, out vdpi) == 0) - windowScale = ddpi / 96; + // Launch the game with OPENRA_DISPLAY_SCALE to force a specific scaling factor + // Otherwise fall back to Windows's DPI configuration + var scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE"); + if (scaleVariable == null || !float.TryParse(scaleVariable, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out windowScale) || windowScale <= 0) + if (SDL.SDL_GetDisplayDPI(videoDisplay, out var ddpi, out _, out _) == 0) + windowScale = ddpi / 96; } - else if (Platform.CurrentPlatform != PlatformType.OSX) + else if (Platform.CurrentPlatform == PlatformType.Linux) { // Launch the game with OPENRA_DISPLAY_SCALE to force a specific scaling factor // Otherwise fall back to GDK_SCALE or parsing the x11 DPI configuration var scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE") ?? Environment.GetEnvironmentVariable("GDK_SCALE"); - if (scaleVariable == null || !float.TryParse(scaleVariable, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out windowScale)) + if (scaleVariable == null || !float.TryParse(scaleVariable, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out windowScale) || windowScale <= 0) { // Attempt to automatically detect DPI try @@ -193,9 +200,8 @@ var p = Process.Start(psi); var lines = p.StandardOutput.ReadToEnd().Split('\n'); - int dpi; foreach (var line in lines) - if (line.StartsWith("Xft.dpi") && int.TryParse(line.Substring(8), out dpi)) + if (line.StartsWith("Xft.dpi") && int.TryParse(line.Substring(8), out var dpi)) windowScale = dpi / 96f; } catch { } @@ -226,8 +232,7 @@ // (if dark mode is enabled) unless we drain the event queue before initializing GL if (Platform.CurrentPlatform == PlatformType.OSX) { - SDL.SDL_Event e; - while (SDL.SDL_PollEvent(out e) != 0) + while (SDL.SDL_PollEvent(out var e) != 0) { // We can safely ignore all mouse/keyboard events and window size changes // (these will be caught in the window setup below), but do need to process focus @@ -236,11 +241,11 @@ switch (e.window.windowEvent) { case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST: - Game.HasInputFocus = false; + HasInputFocus = false; break; case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED: - Game.HasInputFocus = true; + HasInputFocus = true; break; } } @@ -252,9 +257,7 @@ { // OSX defines the window size in "points", with a device-dependent number of pixels per point. // The window scale is simply the ratio of GL pixels / window points. - int width, height; - - SDL.SDL_GL_GetDrawableSize(Window, out width, out height); + SDL.SDL_GL_GetDrawableSize(Window, out var width, out var height); surfaceSize = new Size(width, height); windowScale = width * 1f / windowSize.Width; } @@ -280,8 +283,7 @@ // This is usually not what the player wants, but is the best we can consistently do. if (Platform.CurrentPlatform == PlatformType.OSX) { - int width, height; - SDL.SDL_GetWindowSize(Window, out width, out height); + SDL.SDL_GetWindowSize(Window, out var width, out var height); windowSize = surfaceSize = new Size(width, height); windowScale = 1; } @@ -378,8 +380,7 @@ { if (mode) { - int x, y; - SDL.SDL_GetMouseState(out x, out y); + SDL.SDL_GetMouseState(out var x, out var y); lockedMousePosition = new int2(x, y); } else @@ -397,8 +398,7 @@ // We need to recalculate our scale to account for the potential change in the actual rendered area if (Platform.CurrentPlatform == PlatformType.OSX) { - int width, height; - SDL.SDL_GL_GetDrawableSize(Window, out width, out height); + SDL.SDL_GL_GetDrawableSize(Window, out var width, out var height); if (width != SurfaceSize.Width || height != SurfaceSize.Height) { @@ -422,8 +422,7 @@ disposed = true; - if (context != null) - context.Dispose(); + context?.Dispose(); if (Window != IntPtr.Zero) SDL.SDL_DestroyWindow(Window); @@ -473,6 +472,9 @@ SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0); + var useAngle = profile == GLProfile.ANGLE ? "1" : "0"; + SDL.SDL_SetHint("SDL_OPENGL_ES_DRIVER", useAngle); + switch (profile) { case GLProfile.Modern: @@ -480,6 +482,7 @@ SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, (int)SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE); break; + case GLProfile.ANGLE: case GLProfile.Embedded: SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 0); @@ -495,6 +498,9 @@ static bool CanCreateGLWindow(GLProfile profile) { // Implementation inspired by TestIndividualGLVersion from Veldrid + + // Need to create and destroy its own SDL contexts as a workaround for specific buggy drivers + SDL.SDL_Init(SDL.SDL_INIT_VIDEO); SetSDLAttributes(profile); var flags = SDL.SDL_WindowFlags.SDL_WINDOW_HIDDEN | SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL; @@ -502,6 +508,7 @@ if (window == IntPtr.Zero || !string.IsNullOrEmpty(SDL.SDL_GetError())) { SDL.SDL_ClearError(); + SDL.SDL_Quit(); return false; } @@ -510,12 +517,22 @@ { SDL.SDL_ClearError(); SDL.SDL_DestroyWindow(window); + SDL.SDL_Quit(); return false; } + // Distinguish between ANGLE and native GLES + var success = true; + if (profile == GLProfile.ANGLE || profile == GLProfile.Embedded) + { + var isAngle = SDL.SDL_GL_ExtensionSupported("GL_ANGLE_texture_usage") == SDL.SDL_bool.SDL_TRUE; + success = isAngle ^ (profile != GLProfile.ANGLE); + } + SDL.SDL_GL_DeleteContext(context); SDL.SDL_DestroyWindow(window); - return true; + SDL.SDL_Quit(); + return success; } public void SetScaleModifier(float scale) diff -Nru openra-20200503/OpenRA.Platforms.Default/Shader.cs openra-20210321/OpenRA.Platforms.Default/Shader.cs --- openra-20200503/OpenRA.Platforms.Default/Shader.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/Shader.cs 2021-03-21 11:10:05.000000000 +0000 @@ -21,6 +21,7 @@ public const int VertexPosAttributeIndex = 0; public const int TexCoordAttributeIndex = 1; public const int TexMetadataAttributeIndex = 2; + public const int TintAttributeIndex = 3; readonly Dictionary samplers = new Dictionary(); readonly Dictionary legacySizeUniforms = new Dictionary(); @@ -31,7 +32,7 @@ protected uint CompileShaderObject(int type, string name) { var ext = type == OpenGL.GL_VERTEX_SHADER ? "vert" : "frag"; - var filename = Path.Combine(Platform.GameDir, "glsl", name + "." + ext); + var filename = Path.Combine(Platform.EngineDir, "glsl", name + "." + ext); var code = File.ReadAllText(filename); var version = OpenGL.Profile == GLProfile.Embedded ? "300 es" : @@ -50,16 +51,13 @@ OpenGL.CheckGLError(); OpenGL.glCompileShader(shader); OpenGL.CheckGLError(); - int success; - OpenGL.glGetShaderiv(shader, OpenGL.GL_COMPILE_STATUS, out success); + OpenGL.glGetShaderiv(shader, OpenGL.GL_COMPILE_STATUS, out var success); OpenGL.CheckGLError(); if (success == OpenGL.GL_FALSE) { - int len; - OpenGL.glGetShaderiv(shader, OpenGL.GL_INFO_LOG_LENGTH, out len); + OpenGL.glGetShaderiv(shader, OpenGL.GL_INFO_LOG_LENGTH, out var len); var log = new StringBuilder(len); - int length; - OpenGL.glGetShaderInfoLog(shader, len, out length, log); + OpenGL.glGetShaderInfoLog(shader, len, out _, log); Log.Write("graphics", "GL Info Log:\n{0}", log.ToString()); throw new InvalidProgramException("Compile error in shader object '{0}'".F(filename)); @@ -83,8 +81,10 @@ OpenGL.CheckGLError(); OpenGL.glBindAttribLocation(program, TexMetadataAttributeIndex, "aVertexTexMetadata"); OpenGL.CheckGLError(); + OpenGL.glBindAttribLocation(program, TintAttributeIndex, "aVertexTint"); + OpenGL.CheckGLError(); - if (OpenGL.Profile != GLProfile.Legacy) + if (OpenGL.Profile == GLProfile.Modern) { OpenGL.glBindFragDataLocation(program, 0, "fragColor"); OpenGL.CheckGLError(); @@ -97,17 +97,14 @@ OpenGL.glLinkProgram(program); OpenGL.CheckGLError(); - int success; - OpenGL.glGetProgramiv(program, OpenGL.GL_LINK_STATUS, out success); + OpenGL.glGetProgramiv(program, OpenGL.GL_LINK_STATUS, out var success); OpenGL.CheckGLError(); if (success == OpenGL.GL_FALSE) { - int len; - OpenGL.glGetProgramiv(program, OpenGL.GL_INFO_LOG_LENGTH, out len); + OpenGL.glGetProgramiv(program, OpenGL.GL_INFO_LOG_LENGTH, out var len); var log = new StringBuilder(len); - int length; - OpenGL.glGetProgramInfoLog(program, len, out length, log); + OpenGL.glGetProgramInfoLog(program, len, out _, log); Log.Write("graphics", "GL Info Log:\n{0}", log.ToString()); throw new InvalidProgramException("Link error in shader program '{0}'".F(name)); } @@ -115,18 +112,15 @@ OpenGL.glUseProgram(program); OpenGL.CheckGLError(); - int numUniforms; - OpenGL.glGetProgramiv(program, OpenGL.GL_ACTIVE_UNIFORMS, out numUniforms); + OpenGL.glGetProgramiv(program, OpenGL.GL_ACTIVE_UNIFORMS, out var numUniforms); OpenGL.CheckGLError(); var nextTexUnit = 0; for (var i = 0; i < numUniforms; i++) { - int length, size; - int type; var sb = new StringBuilder(128); - OpenGL.glGetActiveUniform(program, i, 128, out length, out size, out type, sb); + OpenGL.glGetActiveUniform(program, i, 128, out _, out _, out var type, sb); var sampler = sb.ToString(); OpenGL.CheckGLError(); @@ -169,8 +163,7 @@ OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, texture.ID); // Work around missing textureSize GLSL function by explicitly tracking sizes in a uniform - int param; - if (OpenGL.Profile == GLProfile.Legacy && legacySizeUniforms.TryGetValue(kv.Key, out param)) + if (OpenGL.Profile == GLProfile.Legacy && legacySizeUniforms.TryGetValue(kv.Key, out var param)) { OpenGL.glUniform2f(param, texture.Size.Width, texture.Size.Height); OpenGL.CheckGLError(); @@ -192,8 +185,7 @@ if (t == null) return; - int texUnit; - if (samplers.TryGetValue(name, out texUnit)) + if (samplers.TryGetValue(name, out var texUnit)) textures[texUnit] = t; } diff -Nru openra-20200503/OpenRA.Platforms.Default/Texture.cs openra-20210321/OpenRA.Platforms.Default/Texture.cs --- openra-20200503/OpenRA.Platforms.Default/Texture.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/Texture.cs 2021-03-21 11:10:05.000000000 +0000 @@ -122,11 +122,9 @@ if (OpenGL.Profile == GLProfile.Embedded) { // Query the active framebuffer so we can restore it afterwards - int lastFramebuffer; - OpenGL.glGetIntegerv(OpenGL.GL_FRAMEBUFFER_BINDING, out lastFramebuffer); + OpenGL.glGetIntegerv(OpenGL.GL_FRAMEBUFFER_BINDING, out var lastFramebuffer); - uint framebuffer; - OpenGL.glGenFramebuffers(1, out framebuffer); + OpenGL.glGenFramebuffers(1, out var framebuffer); OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, framebuffer); OpenGL.CheckGLError(); diff -Nru openra-20200503/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs openra-20210321/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs --- openra-20200503/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs 2021-03-21 11:10:05.000000000 +0000 @@ -29,9 +29,9 @@ readonly Stack messagePool = new Stack(); readonly Queue messages = new Queue(); + public readonly int BatchSize; readonly object syncObject = new object(); readonly Thread renderThread; - readonly int batchSize; volatile ExceptionDispatchInfo messageException; // Delegates that perform actions on the real device. @@ -53,7 +53,7 @@ public ThreadedGraphicsContext(Sdl2GraphicsContext context, int batchSize) { - this.batchSize = batchSize; + BatchSize = batchSize; renderThread = new Thread(RenderThread) { Name = "ThreadedGraphicsContext RenderThread", @@ -89,7 +89,7 @@ getCreateFrameBuffer = tuple => { - var t = (Tuple)tuple; + var t = (ValueTuple)tuple; return new ThreadedFrameBuffer(this, context.CreateFrameBuffer(t.Item1, (ITextureInternal)CreateTexture(), t.Item2)); }; @@ -98,13 +98,13 @@ doDrawPrimitives = tuple => { - var t = (Tuple)tuple; + var t = (ValueTuple)tuple; context.DrawPrimitives(t.Item1, t.Item2, t.Item3); }; doEnableScissor = tuple => { - var t = (Tuple)tuple; + var t = (ValueTuple)tuple; context.EnableScissor(t.Item1, t.Item2, t.Item3, t.Item4); }; doSetBlendMode = mode => { context.SetBlendMode((BlendMode)mode); }; @@ -143,15 +143,15 @@ internal Vertex[] GetVertices(int size) { lock (verticesPool) - if (size <= batchSize && verticesPool.Count > 0) + if (size <= BatchSize && verticesPool.Count > 0) return verticesPool.Pop(); - return new Vertex[size < batchSize ? batchSize : size]; + return new Vertex[size < BatchSize ? BatchSize : size]; } internal void ReturnVertices(Vertex[] vertices) { - if (vertices.Length == batchSize) + if (vertices.Length == BatchSize) lock (verticesPool) verticesPool.Push(vertices); } @@ -260,8 +260,7 @@ var localResult = result; result = null; - if (localEdi != null) - localEdi.Throw(); + localEdi?.Throw(); return localResult; } } @@ -278,8 +277,7 @@ void QueueMessage(Message message) { var exception = messageException; - if (exception != null) - exception.Throw(); + exception?.Throw(); lock (messages) { @@ -390,12 +388,12 @@ public IFrameBuffer CreateFrameBuffer(Size s) { - return Send(getCreateFrameBuffer, Tuple.Create(s, Color.FromArgb(0))); + return Send(getCreateFrameBuffer, (s, Color.FromArgb(0))); } public IFrameBuffer CreateFrameBuffer(Size s, Color clearColor) { - return Send(getCreateFrameBuffer, Tuple.Create(s, clearColor)); + return Send(getCreateFrameBuffer, (s, clearColor)); } public IShader CreateShader(string name) @@ -425,7 +423,7 @@ public void DrawPrimitives(PrimitiveType type, int firstVertex, int numVertices) { - Post(doDrawPrimitives, Tuple.Create(type, firstVertex, numVertices)); + Post(doDrawPrimitives, (type, firstVertex, numVertices)); } public void EnableDepthBuffer() @@ -435,7 +433,7 @@ public void EnableScissor(int left, int top, int width, int height) { - Post(doEnableScissor, Tuple.Create(left, top, width, height)); + Post(doEnableScissor, (left, top, width, height)); } public void Present() @@ -515,15 +513,17 @@ readonly ThreadedGraphicsContext device; readonly Action bind; readonly Action setData1; - readonly Func setData2; + readonly Action setData2; + readonly Func setData3; readonly Action dispose; public ThreadedVertexBuffer(ThreadedGraphicsContext device, IVertexBuffer vertexBuffer) { this.device = device; bind = vertexBuffer.Bind; - setData1 = tuple => { var t = (Tuple)tuple; vertexBuffer.SetData(t.Item1, t.Item2); device.ReturnVertices(t.Item1); }; - setData2 = tuple => { var t = (Tuple)tuple; vertexBuffer.SetData(t.Item1, t.Item2, t.Item3); return null; }; + setData1 = tuple => { var t = (ValueTuple)tuple; vertexBuffer.SetData(t.Item1, t.Item2); device.ReturnVertices(t.Item1); }; + setData2 = tuple => { var t = (ValueTuple)tuple; vertexBuffer.SetData(t.Item1, t.Item2, t.Item3, t.Item4); device.ReturnVertices(t.Item1); }; + setData3 = tuple => { setData2(tuple); return null; }; dispose = vertexBuffer.Dispose; } @@ -536,20 +536,23 @@ { var buffer = device.GetVertices(length); Array.Copy(vertices, buffer, length); - device.Post(setData1, Tuple.Create(buffer, length)); - } - - public void SetData(IntPtr data, int start, int length) - { - // We can't return until we are finished with the data, so we must Send here. - device.Send(setData2, Tuple.Create(data, start, length)); + device.Post(setData1, (buffer, length)); } - public void SetData(Vertex[] vertices, int start, int length) + public void SetData(Vertex[] vertices, int offset, int start, int length) { - var buffer = device.GetVertices(length); - Array.Copy(vertices, start, buffer, 0, length); - device.Post(setData1, Tuple.Create(buffer, length)); + if (length <= device.BatchSize) + { + // If we are able to use a buffer without allocation, post a message to avoid blocking. + var buffer = device.GetVertices(length); + Array.Copy(vertices, offset, buffer, 0, length); + device.Post(setData2, (buffer, 0, start, length)); + } + else + { + // If the length is too large for a buffer, send a message and block to avoid allocations. + device.Send(setData3, (vertices, offset, start, length)); + } } public void Dispose() @@ -569,6 +572,7 @@ readonly Func getData; readonly Func setData1; readonly Action setData2; + readonly Func setData3; readonly Action dispose; public ThreadedTexture(ThreadedGraphicsContext device, ITextureInternal texture) @@ -578,10 +582,11 @@ getScaleFilter = () => texture.ScaleFilter; setScaleFilter = value => texture.ScaleFilter = (TextureScaleFilter)value; getSize = () => texture.Size; - setEmpty = tuple => { var t = (Tuple)tuple; texture.SetEmpty(t.Item1, t.Item2); }; + setEmpty = tuple => { var t = (ValueTuple)tuple; texture.SetEmpty(t.Item1, t.Item2); }; getData = () => texture.GetData(); setData1 = colors => { texture.SetData((uint[,])colors); return null; }; - setData2 = tuple => { var t = (Tuple)tuple; texture.SetData(t.Item1, t.Item2, t.Item3); }; + setData2 = tuple => { var t = (ValueTuple)tuple; texture.SetData(t.Item1, t.Item2, t.Item3); }; + setData3 = tuple => { setData2(tuple); return null; }; dispose = texture.Dispose; } @@ -616,7 +621,7 @@ public void SetEmpty(int width, int height) { - device.Post(setEmpty, Tuple.Create(width, height)); + device.Post(setEmpty, (width, height)); } public byte[] GetData() @@ -632,11 +637,21 @@ public void SetData(byte[] colors, int width, int height) { - // This creates some garbage for the GC to clean up, - // but allows us post a message instead of blocking the message queue by sending it. - var temp = new byte[colors.Length]; - Array.Copy(colors, temp, temp.Length); - device.Post(setData2, Tuple.Create(temp, width, height)); + // Objects 85000 bytes or more will be directly allocated in the Large Object Heap (LOH). + // https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/large-object-heap + if (colors.Length < 85000) + { + // If we are able to create a small array the GC can collect easily, post a message to avoid blocking. + var temp = new byte[colors.Length]; + Array.Copy(colors, temp, temp.Length); + device.Post(setData2, (temp, width, height)); + } + else + { + // If the length is large and would result in an array on the Large Object Heap (LOH), + // send a message and block to avoid LOH allocation as this requires a Gen2 collection. + device.Send(setData3, (colors, width, height)); + } } public void Dispose() @@ -661,13 +676,13 @@ { this.device = device; prepareRender = shader.PrepareRender; - setBool = tuple => { var t = (Tuple)tuple; shader.SetBool(t.Item1, t.Item2); }; - setMatrix = tuple => { var t = (Tuple)tuple; shader.SetMatrix(t.Item1, t.Item2); }; - setTexture = tuple => { var t = (Tuple)tuple; shader.SetTexture(t.Item1, t.Item2); }; - setVec1 = tuple => { var t = (Tuple)tuple; shader.SetVec(t.Item1, t.Item2); }; - setVec2 = tuple => { var t = (Tuple)tuple; shader.SetVec(t.Item1, t.Item2, t.Item3); }; - setVec3 = tuple => { var t = (Tuple)tuple; shader.SetVec(t.Item1, t.Item2, t.Item3); }; - setVec4 = tuple => { var t = (Tuple)tuple; shader.SetVec(t.Item1, t.Item2, t.Item3, t.Item4); }; + setBool = tuple => { var t = (ValueTuple)tuple; shader.SetBool(t.Item1, t.Item2); }; + setMatrix = tuple => { var t = (ValueTuple)tuple; shader.SetMatrix(t.Item1, t.Item2); }; + setTexture = tuple => { var t = (ValueTuple)tuple; shader.SetTexture(t.Item1, t.Item2); }; + setVec1 = tuple => { var t = (ValueTuple)tuple; shader.SetVec(t.Item1, t.Item2); }; + setVec2 = tuple => { var t = (ValueTuple)tuple; shader.SetVec(t.Item1, t.Item2, t.Item3); }; + setVec3 = tuple => { var t = (ValueTuple)tuple; shader.SetVec(t.Item1, t.Item2, t.Item3); }; + setVec4 = tuple => { var t = (ValueTuple)tuple; shader.SetVec(t.Item1, t.Item2, t.Item3, t.Item4); }; } public void PrepareRender() @@ -677,37 +692,37 @@ public void SetBool(string name, bool value) { - device.Post(setBool, Tuple.Create(name, value)); + device.Post(setBool, (name, value)); } public void SetMatrix(string param, float[] mtx) { - device.Post(setMatrix, Tuple.Create(param, mtx)); + device.Post(setMatrix, (param, mtx)); } public void SetTexture(string param, ITexture texture) { - device.Post(setTexture, Tuple.Create(param, texture)); + device.Post(setTexture, (param, texture)); } public void SetVec(string name, float x) { - device.Post(setVec1, Tuple.Create(name, x)); + device.Post(setVec1, (name, x)); } public void SetVec(string name, float[] vec, int length) { - device.Post(setVec2, Tuple.Create(name, vec, length)); + device.Post(setVec2, (name, vec, length)); } public void SetVec(string name, float x, float y) { - device.Post(setVec3, Tuple.Create(name, x, y)); + device.Post(setVec3, (name, x, y)); } public void SetVec(string name, float x, float y, float z) { - device.Post(setVec4, Tuple.Create(name, x, y, z)); + device.Post(setVec4, (name, x, y, z)); } } } diff -Nru openra-20200503/OpenRA.Platforms.Default/VertexBuffer.cs openra-20210321/OpenRA.Platforms.Default/VertexBuffer.cs --- openra-20200503/OpenRA.Platforms.Default/VertexBuffer.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Platforms.Default/VertexBuffer.cs 2021-03-21 11:10:05.000000000 +0000 @@ -57,10 +57,10 @@ public void SetData(T[] data, int length) { - SetData(data, 0, length); + SetData(data, 0, 0, length); } - public void SetData(T[] data, int start, int length) + public void SetData(T[] data, int offset, int start, int length) { Bind(); @@ -70,7 +70,7 @@ OpenGL.glBufferSubData(OpenGL.GL_ARRAY_BUFFER, new IntPtr(VertexSize * start), new IntPtr(VertexSize * length), - ptr.AddrOfPinnedObject()); + ptr.AddrOfPinnedObject() + VertexSize * offset); } finally { @@ -80,16 +80,6 @@ OpenGL.CheckGLError(); } - public void SetData(IntPtr data, int start, int length) - { - Bind(); - OpenGL.glBufferSubData(OpenGL.GL_ARRAY_BUFFER, - new IntPtr(VertexSize * start), - new IntPtr(VertexSize * length), - data); - OpenGL.CheckGLError(); - } - public void Bind() { VerifyThreadAffinity(); @@ -101,6 +91,8 @@ OpenGL.CheckGLError(); OpenGL.glVertexAttribPointer(Shader.TexMetadataAttributeIndex, 2, OpenGL.GL_FLOAT, false, VertexSize, new IntPtr(28)); OpenGL.CheckGLError(); + OpenGL.glVertexAttribPointer(Shader.TintAttributeIndex, 3, OpenGL.GL_FLOAT, false, VertexSize, new IntPtr(36)); + OpenGL.CheckGLError(); } public void Dispose() diff -Nru openra-20200503/OpenRA.PostProcess/OpenRA.PostProcess.csproj openra-20210321/OpenRA.PostProcess/OpenRA.PostProcess.csproj --- openra-20200503/OpenRA.PostProcess/OpenRA.PostProcess.csproj 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.PostProcess/OpenRA.PostProcess.csproj 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ - - - Exe - net461 - true - true - false - .. - false - 5 - true - true - AnyCPU - false - false - ..\OpenRA.ruleset - Debug;Release;Release-x86 - - - - - - - DEBUG;TRACE - false - - - true - - - - - - - - - - - - diff -Nru openra-20200503/OpenRA.PostProcess/Program.cs openra-20210321/OpenRA.PostProcess/Program.cs --- openra-20200503/OpenRA.PostProcess/Program.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.PostProcess/Program.cs 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.IO; -using System.Linq; - -namespace OpenRA.PostProcess -{ - class Program - { - static void Main(string[] args) - { - var assembly = args.First(); - var flags = args.Skip(1).ToArray(); - - Console.WriteLine("Post-processing {0}", assembly); - var data = File.ReadAllBytes(assembly); - var peOffset = BitConverter.ToInt32(data, 0x3c); - - foreach (var flag in flags) - { - if (flag == "-LAA") - { - // Set /LARGEADDRESSAWARE Flag (Application can handle large (>2GB) addresses) - Console.WriteLine(" - Enabling /LARGEADDRESSAWARE"); - data[peOffset + 4 + 18] |= 0x20; - } - else - Console.WriteLine("error: Unknown flag '{0}'", flag); - } - - if (flags.Length == 0) - Console.WriteLine("error: No flags were specified"); - - File.WriteAllBytes(args[0], data); - } - } -} diff -Nru openra-20200503/OpenRA.Server/OpenRA.Server.csproj openra-20210321/OpenRA.Server/OpenRA.Server.csproj --- openra-20200503/OpenRA.Server/OpenRA.Server.csproj 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Server/OpenRA.Server.csproj 2021-03-21 11:10:05.000000000 +0000 @@ -1,21 +1,20 @@  Exe - net461 + net472 true true false - .. + ../bin false - 5 + 7.3 true true AnyCPU false false ..\OpenRA.ruleset - Release;Debug;Release-x86 - mono + Release;Debug @@ -25,15 +24,13 @@ DEBUG;TRACE false - + true - - false - + @@ -42,8 +39,4 @@ - - - - - \ No newline at end of file + diff -Nru openra-20200503/OpenRA.Server/Program.cs openra-20210321/OpenRA.Server/Program.cs --- openra-20200503/OpenRA.Server/Program.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Server/Program.cs 2021-03-21 11:10:05.000000000 +0000 @@ -10,6 +10,7 @@ #endregion using System; +using System.Collections.Generic; using System.IO; using System.Net; using System.Threading; @@ -22,6 +23,11 @@ static void Main(string[] args) { var arguments = new Arguments(args); + + var engineDirArg = arguments.GetValue("Engine.EngineDir", null); + if (!string.IsNullOrEmpty(engineDirArg)) + Platform.OverrideEngineDir(engineDirArg); + var supportDirArg = arguments.GetValue("Engine.SupportDir", null); if (!string.IsNullOrEmpty(supportDirArg)) Platform.OverrideSupportDir(supportDirArg); @@ -53,7 +59,7 @@ var envModSearchPaths = Environment.GetEnvironmentVariable("MOD_SEARCH_PATHS"); var modSearchPaths = !string.IsNullOrWhiteSpace(envModSearchPaths) ? FieldLoader.GetValue("MOD_SEARCH_PATHS", envModSearchPaths) : - new[] { Path.Combine(".", "mods") }; + new[] { Path.Combine(Platform.EngineDir, "mods") }; var mods = new InstalledMods(modSearchPaths, explicitModPaths); @@ -66,7 +72,9 @@ settings.Map = modData.MapCache.ChooseInitialMap(settings.Map, new MersenneTwister()); - var server = new Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, modData, ServerType.Dedicated); + var endpoints = new List { new IPEndPoint(IPAddress.IPv6Any, settings.ListenPort), new IPEndPoint(IPAddress.Any, settings.ListenPort) }; + var server = new Server(endpoints, settings, modData, ServerType.Dedicated); + GC.Collect(); while (true) { diff -Nru openra-20200503/OpenRA.sln openra-20210321/OpenRA.sln --- openra-20200503/OpenRA.sln 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.sln 2021-03-21 11:10:05.000000000 +0000 @@ -19,69 +19,54 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRA.Test", "OpenRA.Test\OpenRA.Test.csproj", "{6CB8E1B7-6B36-4D93-8633-7C573E194AC4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRA.PostProcess", "OpenRA.PostProcess\OpenRA.PostProcess.csproj", "{EE63AF7E-92EA-48FB-81E2-53D7D92F8050}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRA.Launcher", "OpenRA.Launcher\OpenRA.Launcher.csproj", "{54DAE0E0-3125-49D3-992E-A0E931EB5FC8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRA.WindowsLauncher", "OpenRA.WindowsLauncher\OpenRA.WindowsLauncher.csproj", "{912B578E-0BC0-4987-807B-1E294A87DA37}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU - Release-x86|Any CPU = Release-x86|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug|Any CPU.Build.0 = Debug|Any CPU {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release|Any CPU.ActiveCfg = Release|Any CPU {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release|Any CPU.Build.0 = Release|Any CPU - {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release-x86|Any CPU.ActiveCfg = Release-x86|Any CPU - {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release-x86|Any CPU.Build.0 = Release-x86|Any CPU {2881135D-4D62-493E-8F83-5EEE92CCC6BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2881135D-4D62-493E-8F83-5EEE92CCC6BE}.Debug|Any CPU.Build.0 = Debug|Any CPU {2881135D-4D62-493E-8F83-5EEE92CCC6BE}.Release|Any CPU.ActiveCfg = Release|Any CPU {2881135D-4D62-493E-8F83-5EEE92CCC6BE}.Release|Any CPU.Build.0 = Release|Any CPU - {2881135D-4D62-493E-8F83-5EEE92CCC6BE}.Release-x86|Any CPU.ActiveCfg = Release|Any CPU - {2881135D-4D62-493E-8F83-5EEE92CCC6BE}.Release-x86|Any CPU.Build.0 = Release|Any CPU {F33337BE-CB69-4B24-850F-07D23E408DDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F33337BE-CB69-4B24-850F-07D23E408DDF}.Debug|Any CPU.Build.0 = Debug|Any CPU {F33337BE-CB69-4B24-850F-07D23E408DDF}.Release|Any CPU.ActiveCfg = Release|Any CPU {F33337BE-CB69-4B24-850F-07D23E408DDF}.Release|Any CPU.Build.0 = Release|Any CPU - {F33337BE-CB69-4B24-850F-07D23E408DDF}.Release-x86|Any CPU.ActiveCfg = Release-x86|Any CPU - {F33337BE-CB69-4B24-850F-07D23E408DDF}.Release-x86|Any CPU.Build.0 = Release-x86|Any CPU {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Debug|Any CPU.Build.0 = Debug|Any CPU {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Release|Any CPU.ActiveCfg = Release|Any CPU {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Release|Any CPU.Build.0 = Release|Any CPU - {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Release-x86|Any CPU.ActiveCfg = Release-x86|Any CPU - {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Release-x86|Any CPU.Build.0 = Release-x86|Any CPU {C0B0465C-6BE2-409C-8770-3A9BF64C4344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C0B0465C-6BE2-409C-8770-3A9BF64C4344}.Debug|Any CPU.Build.0 = Debug|Any CPU {C0B0465C-6BE2-409C-8770-3A9BF64C4344}.Release|Any CPU.ActiveCfg = Release|Any CPU {C0B0465C-6BE2-409C-8770-3A9BF64C4344}.Release|Any CPU.Build.0 = Release|Any CPU - {C0B0465C-6BE2-409C-8770-3A9BF64C4344}.Release-x86|Any CPU.ActiveCfg = Release|Any CPU - {C0B0465C-6BE2-409C-8770-3A9BF64C4344}.Release-x86|Any CPU.Build.0 = Release|Any CPU {33D03738-C154-4028-8EA8-63A3C488A651}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {33D03738-C154-4028-8EA8-63A3C488A651}.Debug|Any CPU.Build.0 = Debug|Any CPU {33D03738-C154-4028-8EA8-63A3C488A651}.Release|Any CPU.ActiveCfg = Release|Any CPU {33D03738-C154-4028-8EA8-63A3C488A651}.Release|Any CPU.Build.0 = Release|Any CPU - {33D03738-C154-4028-8EA8-63A3C488A651}.Release-x86|Any CPU.ActiveCfg = Release|Any CPU - {33D03738-C154-4028-8EA8-63A3C488A651}.Release-x86|Any CPU.Build.0 = Release|Any CPU {FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}.Debug|Any CPU.Build.0 = Debug|Any CPU {FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}.Release|Any CPU.ActiveCfg = Release|Any CPU {FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}.Release|Any CPU.Build.0 = Release|Any CPU - {FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}.Release-x86|Any CPU.ActiveCfg = Release|Any CPU - {FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}.Release-x86|Any CPU.Build.0 = Release|Any CPU {6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Debug|Any CPU.Build.0 = Debug|Any CPU {6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Release|Any CPU.ActiveCfg = Release|Any CPU {6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Release|Any CPU.Build.0 = Release|Any CPU - {6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Release-x86|Any CPU.ActiveCfg = Release|Any CPU - {6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Release-x86|Any CPU.Build.0 = Release|Any CPU - {EE63AF7E-92EA-48FB-81E2-53D7D92F8050}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EE63AF7E-92EA-48FB-81E2-53D7D92F8050}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EE63AF7E-92EA-48FB-81E2-53D7D92F8050}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EE63AF7E-92EA-48FB-81E2-53D7D92F8050}.Release|Any CPU.Build.0 = Release|Any CPU - {EE63AF7E-92EA-48FB-81E2-53D7D92F8050}.Release-x86|Any CPU.ActiveCfg = Release-x86|Any CPU - {EE63AF7E-92EA-48FB-81E2-53D7D92F8050}.Release-x86|Any CPU.Build.0 = Release-x86|Any CPU + {54DAE0E0-3125-49D3-992E-A0E931EB5FC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54DAE0E0-3125-49D3-992E-A0E931EB5FC8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54DAE0E0-3125-49D3-992E-A0E931EB5FC8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54DAE0E0-3125-49D3-992E-A0E931EB5FC8}.Release|Any CPU.Build.0 = Release|Any CPU + {912B578E-0BC0-4987-807B-1E294A87DA37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {912B578E-0BC0-4987-807B-1E294A87DA37}.Release|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff -Nru openra-20200503/OpenRA.Test/OpenRA.Game/ActorInfoTest.cs openra-20210321/OpenRA.Test/OpenRA.Game/ActorInfoTest.cs --- openra-20200503/OpenRA.Test/OpenRA.Game/ActorInfoTest.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Test/OpenRA.Game/ActorInfoTest.cs 2021-03-21 11:10:05.000000000 +0000 @@ -15,8 +15,8 @@ namespace OpenRA.Test { - interface IMock : ITraitInfo { } - class MockTraitInfo : ITraitInfo { public object Create(ActorInitializer init) { return null; } } + interface IMock : ITraitInfoInterface { } + class MockTraitInfo : TraitInfo { public override object Create(ActorInitializer init) { return null; } } class MockInheritInfo : MockTraitInfo { } class MockAInfo : MockInheritInfo, IMock { } class MockBInfo : MockTraitInfo, Requires, Requires, Requires { } @@ -31,7 +31,7 @@ [TestCase(TestName = "Trait ordering sorts in dependency order correctly")] public void TraitOrderingSortsCorrectly() { - var unorderedTraits = new ITraitInfo[] { new MockBInfo(), new MockCInfo(), new MockAInfo(), new MockBInfo() }; + var unorderedTraits = new TraitInfo[] { new MockBInfo(), new MockCInfo(), new MockAInfo(), new MockBInfo() }; var actorInfo = new ActorInfo("test", unorderedTraits); var orderedTraits = actorInfo.TraitsInConstructOrder().ToArray(); diff -Nru openra-20200503/OpenRA.Test/OpenRA.Game/CoordinateTest.cs openra-20210321/OpenRA.Test/OpenRA.Game/CoordinateTest.cs --- openra-20200503/OpenRA.Test/OpenRA.Game/CoordinateTest.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Test/OpenRA.Game/CoordinateTest.cs 2021-03-21 11:10:05.000000000 +0000 @@ -28,19 +28,12 @@ for (var y = 0; y < 12; y++) { var cell = new CPos(x, y); - try - { - Assert.That(cell, Is.EqualTo(cell.ToMPos(gridType).ToCPos(gridType))); - } - catch - { - // Known problem on isometric mods that shouldn't be visible to players as these are outside the map. - if (gridType == MapGridType.RectangularIsometric && y > x) - continue; - Console.WriteLine("Coordinate {0} on grid type {1} failed to convert back.".F(cell, gridType)); - throw; - } + // Known problem on isometric mods that shouldn't be visible to players as these are outside the map. + if (gridType == MapGridType.RectangularIsometric && y > x) + continue; + + Assert.That(cell, Is.EqualTo(cell.ToMPos(gridType).ToCPos(gridType))); } } } diff -Nru openra-20200503/OpenRA.Test/OpenRA.Game/PlatformTest.cs openra-20210321/OpenRA.Test/OpenRA.Game/PlatformTest.cs --- openra-20200503/OpenRA.Test/OpenRA.Game/PlatformTest.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Test/OpenRA.Game/PlatformTest.cs 2021-03-21 11:10:05.000000000 +0000 @@ -18,45 +18,26 @@ public class PlatformTest { string supportDir; - string gameDir; + string engineDir; [SetUp] public void SetUp() { supportDir = Platform.SupportDir; - gameDir = Platform.GameDir; + engineDir = Platform.EngineDir; } [TestCase(TestName = "Returns literal paths")] public void ResolvePath() { - Assert.That(Platform.ResolvePath("^testpath"), + Assert.That(Platform.ResolvePath("^SupportDir|testpath"), Is.EqualTo(Path.Combine(supportDir, "testpath"))); - Assert.That(Platform.ResolvePath(".\\testpath"), - Is.EqualTo(Path.Combine(gameDir, "testpath"))); - - Assert.That(Platform.ResolvePath("./testpath"), - Is.EqualTo(Path.Combine(gameDir, "testpath"))); - - Assert.That(Platform.ResolvePath(Path.Combine(".", "Foo.dll")), - Is.EqualTo(Path.Combine(gameDir, "Foo.dll"))); + Assert.That(Platform.ResolvePath("^EngineDir|Foo.dll"), + Is.EqualTo(Path.Combine(engineDir, "Foo.dll"))); Assert.That(Platform.ResolvePath("testpath"), Is.EqualTo("testpath")); } - - [TestCase(TestName = "Returns encoded paths")] - public void UnresolvePath() - { - Assert.That(Platform.UnresolvePath(Path.Combine(supportDir, "testpath")), - Is.EqualTo("^testpath")); - - Assert.That(Platform.UnresolvePath(Path.Combine(gameDir, "testpath")), - Is.EqualTo("./testpath")); - - Assert.That(Platform.UnresolvePath("testpath"), - Is.EqualTo("testpath")); - } } } diff -Nru openra-20200503/OpenRA.Test/OpenRA.Test.csproj openra-20210321/OpenRA.Test/OpenRA.Test.csproj --- openra-20200503/OpenRA.Test/OpenRA.Test.csproj 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Test/OpenRA.Test.csproj 2021-03-21 11:10:05.000000000 +0000 @@ -1,11 +1,11 @@  - net461 + net472 true - 5 + 7.3 true true - .. + ../bin false AnyCPU false @@ -20,23 +20,18 @@ false - - ..\thirdparty\download\Eluant.dll - False - False - - - ..\thirdparty\download\nunit.framework.dll - False - False - - - False + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff -Nru openra-20200503/OpenRA.Test.nunit openra-20210321/OpenRA.Test.nunit --- openra-20200503/OpenRA.Test.nunit 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Test.nunit 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ - - - - - - diff -Nru openra-20200503/OpenRA.Utility/OpenRA.Utility.csproj openra-20210321/OpenRA.Utility/OpenRA.Utility.csproj --- openra-20200503/OpenRA.Utility/OpenRA.Utility.csproj 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Utility/OpenRA.Utility.csproj 2021-03-21 11:10:05.000000000 +0000 @@ -1,21 +1,20 @@  Exe - net461 + net472 true true false - .. + ../bin false - 5 + 7.3 true true AnyCPU false false ..\OpenRA.ruleset - Release;Debug;Release-x86 - mono + Release;Debug @@ -25,15 +24,13 @@ DEBUG;TRACE false - + true - - false - + @@ -42,8 +39,4 @@ - - - - - \ No newline at end of file + diff -Nru openra-20200503/OpenRA.Utility/Program.cs openra-20210321/OpenRA.Utility/Program.cs --- openra-20200503/OpenRA.Utility/Program.cs 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/OpenRA.Utility/Program.cs 2021-03-21 11:10:05.000000000 +0000 @@ -40,6 +40,10 @@ { static void Main(string[] args) { + var engineDir = Environment.GetEnvironmentVariable("ENGINE_DIR"); + if (!string.IsNullOrEmpty(engineDir)) + Platform.OverrideEngineDir(engineDir); + Log.AddChannel("perf", null); Log.AddChannel("debug", null); @@ -48,7 +52,7 @@ var envModSearchPaths = Environment.GetEnvironmentVariable("MOD_SEARCH_PATHS"); var modSearchPaths = !string.IsNullOrWhiteSpace(envModSearchPaths) ? FieldLoader.GetValue("MOD_SEARCH_PATHS", envModSearchPaths) : - new[] { Path.Combine(".", "mods") }; + new[] { Path.Combine(Platform.EngineDir, "mods") }; if (args.Length == 0) { diff -Nru openra-20200503/OpenRA.WindowsLauncher/App.config openra-20210321/OpenRA.WindowsLauncher/App.config --- openra-20200503/OpenRA.WindowsLauncher/App.config 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.WindowsLauncher/App.config 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff -Nru openra-20200503/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj openra-20210321/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj --- openra-20200503/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,61 @@ + + + winexe + net472 + true + true + false + 7.3 + true + true + false + ../bin + false + AnyCPU + false + false + ..\OpenRA.ruleset + Release;Debug + $(LauncherName) + $(LauncherIcon) + + + + + + + DEBUG;TRACE + false + + + true + + + + + + <_Parameter1>ModID + <_Parameter2>$(ModID) + + + <_Parameter1>DisplayName + <_Parameter2>$(DisplayName) + + + <_Parameter1>FaqUrl + <_Parameter2>$(FaqUrl) + + + + + + + + + + + + + + + diff -Nru openra-20200503/OpenRA.WindowsLauncher/Program.cs openra-20210321/OpenRA.WindowsLauncher/Program.cs --- openra-20200503/OpenRA.WindowsLauncher/Program.cs 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/OpenRA.WindowsLauncher/Program.cs 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,197 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using SDL2; + +namespace OpenRA.WindowsLauncher +{ + class WindowsLauncher + { + [DllImport("user32.dll")] + static extern bool SetForegroundWindow(IntPtr hWnd); + + [DllImport("user32.dll")] + static extern bool AllowSetForegroundWindow(int dwProcessId); + + static Process gameProcess; + static string modID; + static string displayName; + static string faqUrl; + + static int Main(string[] args) + { + // The modID, displayName, and faqUrl variables are embedded in the assembly metadata by defining + // -p:ModID="mymod", -p:DisplayName="My Mod", -p:FaqUrl="https://my.tld/faq" when compiling the project + var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(); + foreach (var a in attributes) + { + if (a is AssemblyMetadataAttribute metadata) + { + switch (metadata.Key) + { + case "ModID": modID = metadata.Value; break; + case "DisplayName": displayName = metadata.Value; break; + case "FaqUrl": faqUrl = metadata.Value; break; + } + } + } + + if (args.Any(x => x.StartsWith("Engine.LaunchPath=", StringComparison.Ordinal))) + return RunGame(args); + + return RunInnerLauncher(args); + } + + static int RunGame(string[] args) + { + var launcherPath = Assembly.GetExecutingAssembly().Location; + var directory = Path.GetDirectoryName(launcherPath); + Directory.SetCurrentDirectory(directory); + + AppDomain.CurrentDomain.UnhandledException += (_, e) => ExceptionHandler.HandleFatalError((Exception)e.ExceptionObject); + + try + { + return (int)Game.InitializeAndRun(args); + } + catch (Exception e) + { + // We must grant permission for the launcher process to bring the error dialog to the foreground. + // Finding the parent process id is unreasonably difficult on Windows, so instead pass -1 to enable for all processes. + AllowSetForegroundWindow(-1); + ExceptionHandler.HandleFatalError(e); + return (int)RunStatus.Error; + } + } + + static int RunInnerLauncher(string[] args) + { + var launcherPath = Process.GetCurrentProcess().MainModule.FileName; + var launcherArgs = args.ToList(); + + if (!launcherArgs.Any(x => x.StartsWith("Engine.LaunchPath=", StringComparison.Ordinal))) + launcherArgs.Add("Engine.LaunchPath=\"" + launcherPath + "\""); + + if (!launcherArgs.Any(x => x.StartsWith("Game.Mod=", StringComparison.Ordinal))) + launcherArgs.Add("Game.Mod=" + modID); + + var psi = new ProcessStartInfo(launcherPath, string.Join(" ", launcherArgs)); + + try + { + gameProcess = Process.Start(psi); + } + catch + { + return 1; + } + + if (gameProcess == null) + return 1; + + gameProcess.EnableRaisingEvents = true; + gameProcess.Exited += GameProcessExited; + gameProcess.WaitForExit(); + + return 0; + } + + static void ShowErrorDialog() + { + var viewLogs = new SDL.SDL_MessageBoxButtonData + { + buttonid = 2, + text = "View Logs", + flags = SDL.SDL_MessageBoxButtonFlags.SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT + }; + + var viewFaq = new SDL.SDL_MessageBoxButtonData + { + buttonid = 1, + text = "View FAQ" + }; + + var quit = new SDL.SDL_MessageBoxButtonData + { + buttonid = 0, + text = "Quit", + flags = SDL.SDL_MessageBoxButtonFlags.SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT + }; + + var dialog = new SDL.SDL_MessageBoxData + { + flags = SDL.SDL_MessageBoxFlags.SDL_MESSAGEBOX_ERROR, + title = "Fatal Error", + message = displayName + " has encountered a fatal error and must close.\nRefer to the crash logs and FAQ for more information.", + buttons = new[] { quit, viewFaq, viewLogs }, + numbuttons = 3 + }; + + // SDL_ShowMessageBox may create the error dialog behind other windows. + // We want to bring it to the foreground, but can't do it from the main thread + // because SDL_ShowMessageBox blocks until the user presses a button. + // HACK: Spawn a thread to raise it to the foreground after a short delay. + Task.Run(() => + { + Thread.Sleep(1000); + SetForegroundWindow(Process.GetCurrentProcess().MainWindowHandle); + }); + + if (SDL.SDL_ShowMessageBox(ref dialog, out var buttonid) < 0) + Exit(); + + switch (buttonid) + { + case 0: Exit(); break; + case 1: + { + try + { + Process.Start(faqUrl); + } + catch { } + break; + } + + case 2: + { + try + { + Process.Start(Path.Combine(Platform.SupportDir, "Logs")); + } + catch { } + break; + } + } + } + + static void GameProcessExited(object sender, EventArgs e) + { + if (gameProcess.ExitCode != (int)RunStatus.Success) + ShowErrorDialog(); + + Exit(); + } + + static void Exit() + { + Environment.Exit(0); + } + } +} Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/cnc_1024x1024.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/cnc_1024x1024.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/cnc_128x128.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/cnc_128x128.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/cnc_16x16.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/cnc_16x16.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/cnc_24x24.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/cnc_24x24.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/cnc_256x256.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/cnc_256x256.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/cnc_32x32.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/cnc_32x32.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/cnc_48x48.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/cnc_48x48.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/cnc_512x512.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/cnc_512x512.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/cnc_64x64.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/cnc_64x64.png differ diff -Nru openra-20200503/packaging/artwork/cnc_scalable.svg openra-20210321/packaging/artwork/cnc_scalable.svg --- openra-20200503/packaging/artwork/cnc_scalable.svg 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/artwork/cnc_scalable.svg 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/d2k_1024x1024.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/d2k_1024x1024.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/d2k_128x128.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/d2k_128x128.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/d2k_16x16.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/d2k_16x16.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/d2k_24x24.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/d2k_24x24.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/d2k_256x256.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/d2k_256x256.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/d2k_32x32.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/d2k_32x32.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/d2k_48x48.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/d2k_48x48.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/d2k_512x512.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/d2k_512x512.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/d2k_64x64.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/d2k_64x64.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/macos-background-2x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/macos-background-2x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/macos-background.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/macos-background.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/ra_1024x1024.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/ra_1024x1024.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/ra_128x128.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/ra_128x128.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/ra_16x16.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/ra_16x16.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/ra_24x24.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/ra_24x24.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/ra_256x256.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/ra_256x256.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/ra_32x32.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/ra_32x32.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/ra_48x48.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/ra_48x48.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/ra_512x512.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/ra_512x512.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/artwork/ra_64x64.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/artwork/ra_64x64.png differ diff -Nru openra-20200503/packaging/artwork/ra_scalable.svg openra-20210321/packaging/artwork/ra_scalable.svg --- openra-20200503/packaging/artwork/ra_scalable.svg 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/artwork/ra_scalable.svg 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,231 @@ + + + +image/svg+xml + + + + + + + + + + + + + \ No newline at end of file diff -Nru openra-20200503/packaging/freebsd/openra openra-20210321/packaging/freebsd/openra --- openra-20200503/packaging/freebsd/openra 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/freebsd/openra 2021-03-21 11:10:05.000000000 +0000 @@ -10,8 +10,8 @@ # openra_user="" (default: openra) # openra_chdir="" # (default: /usr/home/${openra_user}) -# openra_path="" -# (default: ${openra_chdir}/OpenRA/OpenRA.Game.exe) +# openra_path="" +# (default: ${openra_chdir}/OpenRA/OpenRA.exe) # openra_ServerName="" (default: "Dedicated Server") # openra_Mod="" (default: ra) # openra_ListenPort="" (default: 1234) @@ -45,11 +45,9 @@ : ${openra_AdvertiseOnline="True"} openra_Dedicated="True" -openra_DedicatedLoop="True" : ${openra_runflags="Game.Mod=${openra_Mod} \ Server.Dedicated=${openra_Dedicated} \ - Server.DedicatedLoop=${openra_DedicatedLoop} \ Server.Name=\"${openra_ServerName}\" \ Server.ListenPort=${openra_ListenPort} \ Server.AdvertiseOnline=${openra_AdvertiseOnline}\ diff -Nru openra-20200503/packaging/functions.sh openra-20210321/packaging/functions.sh --- openra-20200503/packaging/functions.sh 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/functions.sh 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,335 @@ +#!/bin/sh +# Helper functions for packaging and installing OpenRA + +#### +# This file must stay /bin/sh and POSIX compliant for macOS and BSD portability. +# Copy-paste the entire script into http://shellcheck.net to check. +#### + +# Compile and publish (using Mono) the core engine and specified mod assemblies to the target directory +# Arguments: +# SRC_PATH: Path to the root OpenRA directory +# DEST_PATH: Path to the root of the install destination (will be created if necessary) +# TARGETPLATFORM: Platform type (win-x86, win-x64, osx-x64, linux-x64, unix-generic) +# COPY_GENERIC_LAUNCHER: If set to True the OpenRA.exe will also be copied (True, False) +# COPY_CNC_DLL: If set to True the OpenRA.Mods.Cnc.dll will also be copied (True, False) +# COPY_D2K_DLL: If set to True the OpenRA.Mods.D2k.dll will also be copied (True, False) +# Used by: +# Makefile (install target for local installs and downstream packaging) +# Linux AppImage packaging +# macOS packaging +# Windows packaging +# Mod SDK Linux AppImage packaging +# Mod SDK macOS packaging +# Mod SDK Windows packaging +install_assemblies_mono() { + SRC_PATH="${1}" + DEST_PATH="${2}" + TARGETPLATFORM="${3}" + COPY_GENERIC_LAUNCHER="${4}" + COPY_CNC_DLL="${5}" + COPY_D2K_DLL="${6}" + + echo "Building assemblies" + ORIG_PWD=$(pwd) + cd "${SRC_PATH}" || exit 1 + msbuild -verbosity:m -nologo -t:Clean + rm -rf "${SRC_PATH:?}/bin" + msbuild -verbosity:m -nologo -t:Build -restore -p:Configuration=Release -p:TargetPlatform="${TARGETPLATFORM}" + if [ "${TARGETPLATFORM}" = "unix-generic" ]; then + ./configure-system-libraries.sh + fi + + ./fetch-geoip.sh + cd "${ORIG_PWD}" || exit 1 + + echo "Installing engine to ${DEST_PATH}" + install -d "${DEST_PATH}" + + # Core engine + install -m755 "${SRC_PATH}/bin/OpenRA.Server.exe" "${DEST_PATH}" + install -m755 "${SRC_PATH}/bin/OpenRA.Utility.exe" "${DEST_PATH}" + install -m644 "${SRC_PATH}/bin/OpenRA.Game.dll" "${DEST_PATH}" + install -m644 "${SRC_PATH}/bin/OpenRA.Platforms.Default.dll" "${DEST_PATH}" + if [ "${COPY_GENERIC_LAUNCHER}" = "True" ]; then + install -m755 "${SRC_PATH}/bin/OpenRA.exe" "${DEST_PATH}" + fi + + # Mod dlls + install -m644 "${SRC_PATH}/bin/OpenRA.Mods.Common.dll" "${DEST_PATH}" + if [ "${COPY_CNC_DLL}" = "True" ]; then + install -m644 "${SRC_PATH}/bin/OpenRA.Mods.Cnc.dll" "${DEST_PATH}" + fi + + if [ "${COPY_D2K_DLL}" = "True" ]; then + install -m644 "${SRC_PATH}/bin/OpenRA.Mods.D2k.dll" "${DEST_PATH}" + fi + + # Managed Dependencies + for LIB in ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll Open.Nat.dll BeaconLib.dll DiscordRPC.dll Newtonsoft.Json.dll SDL2-CS.dll OpenAL-CS.Core.dll Eluant.dll; do + install -m644 "${SRC_PATH}/bin/${LIB}" "${DEST_PATH}" + done + + # Native dependencies + if [ "${TARGETPLATFORM}" = "win-x86" ] || [ "${TARGETPLATFORM}" = "win-x64" ]; then + echo "Installing dependencies for ${TARGETPLATFORM} to ${DEST_PATH}" + for LIB in soft_oal.dll SDL2.dll freetype6.dll lua51.dll libEGL.dll libGLESv2.dll; do + install -m644 "${SRC_PATH}/bin/${LIB}" "${DEST_PATH}" + done + else + for LIB in OpenRA.Platforms.Default.dll.config SDL2-CS.dll.config OpenAL-CS.Core.dll.config Eluant.dll.config; do + install -m644 "${SRC_PATH}/bin/${LIB}" "${DEST_PATH}" + done + fi + + if [ "${TARGETPLATFORM}" = "linux-x64" ]; then + echo "Installing dependencies for ${TARGETPLATFORM} to ${DEST_PATH}" + for LIB in soft_oal.so SDL2.so freetype6.so lua51.so; do + install -m755 "${SRC_PATH}/bin/${LIB}" "${DEST_PATH}" + done + fi + + if [ "${TARGETPLATFORM}" = "osx-x64" ]; then + echo "Installing dependencies for ${TARGETPLATFORM} to ${DEST_PATH}" + for LIB in soft_oal.dylib SDL2.dylib freetype6.dylib lua51.dylib; do + install -m755 "${SRC_PATH}/bin/${LIB}" "${DEST_PATH}" + done + fi +} + +# Copy the core engine and specified mod data to the target directory +# Arguments: +# SRC_PATH: Path to the root OpenRA directory +# DEST_PATH: Path to the root of the install destination (will be created if necessary) +# MOD [MOD...]: One or more mod ids to copy (cnc, d2k, ra) +# Used by: +# Makefile (install target for local installs and downstream packaging) +# Linux AppImage packaging +# macOS packaging +# Windows packaging +# Mod SDK Linux AppImage packaging +# Mod SDK macOS packaging +# Mod SDK Windows packaging +install_data() { + SRC_PATH="${1}" + DEST_PATH="${2}" + shift 2 + + echo "Installing engine files to ${DEST_PATH}" + for FILE in VERSION AUTHORS COPYING IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP "global mix database.dat"; do + install -m644 "${SRC_PATH}/${FILE}" "${DEST_PATH}" + done + + cp -r "${SRC_PATH}/glsl" "${DEST_PATH}" + cp -r "${SRC_PATH}/lua" "${DEST_PATH}" + + echo "Installing common mod files to ${DEST_PATH}" + install -d "${DEST_PATH}/mods" + cp -r "${SRC_PATH}/mods/common" "${DEST_PATH}/mods/" + + while [ -n "${1}" ]; do + MOD_ID="${1}" + if [ "${MOD_ID}" = "ra" ] || [ "${MOD_ID}" = "cnc" ] || [ "${MOD_ID}" = "d2k" ]; then + echo "Installing mod ${MOD_ID} to ${DEST_PATH}" + cp -r "${SRC_PATH}/mods/${MOD_ID}" "${DEST_PATH}/mods/" + cp -r "${SRC_PATH}/mods/modcontent" "${DEST_PATH}/mods/" + fi + + shift + done +} + +# Compile and publish (using Mono) a windows launcher with the specified mod details to the target directory +# Arguments: +# SRC_PATH: Path to the root OpenRA directory +# DEST_PATH: Path to the root of the install destination (will be created if necessary) +# TARGETPLATFORM: Platform type (win-x86, win-x64) +# MOD_ID: Mod id to launch (e.g. "ra") +# LAUNCHER_NAME: Filename (without the .exe extension) for the launcher +# MOD_NAME: Human-readable mod name to show in the crash dialog (e.g. "Red Alert") +# ICON_PATH: Path to a windows .ico file +# FAQ_URL: URL to load when the "View FAQ" button is pressed in the crash dialog (e.g. https://wiki.openra.net/FAQ) +# Used by: +# Windows packaging +# Mod SDK Windows packaging +install_windows_launcher() +{ + SRC_PATH="${1}" + DEST_PATH="${2}" + TARGETPLATFORM="${3}" + MOD_ID="${4}" + LAUNCHER_NAME="${5}" + MOD_NAME="${6}" + ICON_PATH="${7}" + FAQ_URL="${8}" + + msbuild -verbosity:m -nologo -t:Clean "${SRC_PATH}/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" + rm -rf "${SRC_PATH:?}/bin" + msbuild -t:Build "${SRC_PATH}/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" -restore -p:Configuration=Release -p:TargetPlatform="${TARGETPLATFORM}" -p:LauncherName="${LAUNCHER_NAME}" -p:LauncherIcon="${ICON_PATH}" -p:ModID="${MOD_ID}" -p:DisplayName="${MOD_NAME}" -p:FaqUrl="${FAQ_URL}" + install -m755 "${SRC_PATH}/bin/${LAUNCHER_NAME}.exe" "${DEST_PATH}" + install -m644 "${SRC_PATH}/bin/${LAUNCHER_NAME}.exe.config" "${DEST_PATH}" + + # Enable the full 4GB address space for the 32 bit game executable + # The server and utility do not use enough memory to need this + if [ "${TARGETPLATFORM}" = "win-x86" ]; then + python3 "${SRC_PATH}/packaging/windows/MakeLAA.py" "${DEST_PATH}/${LAUNCHER_NAME}.exe" + fi +} + +# Write a version string to the engine VERSION file +# Arguments: +# VERSION: OpenRA version string +# DEST_PATH: Path to the root of the install destination +# Used by: +# Makefile (install target for local installs and downstream packaging) +# Linux AppImage packaging +# macOS packaging +# Windows packaging +# Mod SDK Linux AppImage packaging +# Mod SDK macOS packaging +# Mod SDK Windows packaging +set_engine_version() { + VERSION="${1}" + DEST_PATH="${2}" + echo "${VERSION}" > "${DEST_PATH}/VERSION" +} + +# Write a version string to a list of specified mod.yamls +# Arguments: +# VERSION: OpenRA version string +# MOD_YAML_PATH [MOD_YAML_PATH...]: One or more mod.yaml files to update +# Used by: +# Makefile (install target for local installs and downstream packaging) +# Linux AppImage packaging +# macOS packaging +# Windows packaging +# Mod SDK Linux AppImage packaging +# Mod SDK macOS packaging +# Mod SDK Windows packaging +set_mod_version() { + VERSION="${1}" + shift + while [ -n "${1}" ]; do + MOD_YAML_PATH="${1}" + awk -v v="${VERSION}" '{sub("Version:.*$", "Version: " v); print $0}' "${MOD_YAML_PATH}" > "${MOD_YAML_PATH}.tmp" + awk -v v="${VERSION}" '{sub("/[^/]*: User$", "/"v ": User"); print $0}' "${MOD_YAML_PATH}.tmp" > "${MOD_YAML_PATH}" + rm "${MOD_YAML_PATH}.tmp" + shift + done +} + +# Copy launch wrappers, application icons, desktop, and MIME files to the target directory +# Arguments: +# SRC_PATH: Path to the root OpenRA directory +# BUILD_PATH: Path to packaging filesystem root (e.g. /tmp/openra-build/ or "" for a local install) +# OPENRA_PATH: Path to the OpenRA installation (e.g. /usr/local/lib/openra) +# BIN_PATH: Path to install wrapper scripts (e.g. /usr/local/bin) +# SHARE_PATH: Parent path to the icons and applications directory (e.g. /usr/local/share) +# VERSION: OpenRA version string +# MOD [MOD...]: One or more mod ids to copy (cnc, d2k, ra) +# Used by: +# Makefile (install-linux-shortcuts target for local installs and downstream packaging) +install_linux_shortcuts() { + SRC_PATH="${1}" + BUILD_PATH="${2}" + OPENRA_PATH="${3}" + BIN_PATH="${4}" + SHARE_PATH="${5}" + VERSION="${6}" + shift 6 + + while [ -n "${1}" ]; do + MOD_ID="${1}" + if [ "${MOD_ID}" = "ra" ] || [ "${MOD_ID}" = "cnc" ] || [ "${MOD_ID}" = "d2k" ]; then + if [ "${MOD_ID}" = "cnc" ]; then + MOD_NAME="Tiberian Dawn" + fi + + if [ "${MOD_ID}" = "d2k" ]; then + MOD_NAME="Dune 2000" + fi + + if [ "${MOD_ID}" = "ra" ]; then + MOD_NAME="Red Alert" + fi + + # wrapper scripts + install -d "${BUILD_PATH}/${BIN_PATH}" + sed 's/{DEBUG}/--debug/' "${SRC_PATH}/packaging/linux/openra.in" | sed "s|{GAME_INSTALL_DIR}|${OPENRA_PATH}|" | sed "s|{BIN_DIR}|${BIN_PATH}|" | sed "s/{MODID}/${MOD_ID}/g" | sed "s/{TAG}/${VERSION}/g" | sed "s/{MODNAME}/${MOD_NAME}/g" > "${SRC_PATH}/packaging/linux/openra-${MOD_ID}" + sed 's/{DEBUG}/--debug/' "${SRC_PATH}/packaging/linux/openra-server.in" | sed "s|{GAME_INSTALL_DIR}|${OPENRA_PATH}|" | sed "s/{MODID}/${MOD_ID}/g" > "${SRC_PATH}/packaging/linux/openra-${MOD_ID}-server" + install -m755 "${SRC_PATH}/packaging/linux/openra-${MOD_ID}" "${BUILD_PATH}/${BIN_PATH}" + install -m755 "${SRC_PATH}/packaging/linux/openra-${MOD_ID}-server" "${BUILD_PATH}/${BIN_PATH}" + rm "${SRC_PATH}/packaging/linux/openra-${MOD_ID}" "${SRC_PATH}/packaging/linux/openra-${MOD_ID}-server" + + # desktop files + install -d "${BUILD_PATH}${SHARE_PATH}/applications" + sed "s/{MODID}/${MOD_ID}/g" "${SRC_PATH}/packaging/linux/openra.desktop.in" | sed "s/{MODNAME}/${MOD_NAME}/g" | sed "s/{TAG}/${VERSION}/g" > "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.desktop" + install -m644 "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.desktop" "${BUILD_PATH}${SHARE_PATH}/applications" + rm "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.desktop" + + # icons + for SIZE in 16x16 32x32 48x48 64x64 128x128; do + install -d "${BUILD_PATH}${SHARE_PATH}/icons/hicolor/${SIZE}/apps" + install -m644 "${SRC_PATH}/packaging/artwork/${MOD_ID}_${SIZE}.png" "${BUILD_PATH}${SHARE_PATH}/icons/hicolor/${SIZE}/apps/openra-${MOD_ID}.png" + done + + if [ "${MOD_ID}" = "ra" ] || [ "${MOD_ID}" = "cnc" ]; then + install -d "${BUILD_PATH}${SHARE_PATH}/icons/hicolor/scalable/apps" + install -m644 "${SRC_PATH}/packaging/artwork/${MOD_ID}_scalable.svg" "${BUILD_PATH}${SHARE_PATH}/icons/hicolor/scalable/apps/openra-${MOD_ID}.svg" + fi + + # MIME info + install -d "${BUILD_PATH}${SHARE_PATH}/mime/packages" + sed "s/{MODID}/${MOD_ID}/g" "${SRC_PATH}/packaging/linux/openra-mimeinfo.xml.in" | sed "s/{TAG}/${VERSION}/g" > "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.xml" + install -m644 "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.xml" "${BUILD_PATH}${SHARE_PATH}/mime/packages/openra-${MOD_ID}.xml" + rm "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.xml" + fi + + shift + done +} + +# Copy AppStream metadata to the target directory +# Arguments: +# SRC_PATH: Path to the root OpenRA directory +# BUILD_PATH: Path to packaging filesystem root (e.g. /tmp/openra-build/ or "" for a local install) +# SHARE_PATH: Parent path to the appdata directory (e.g. /usr/local/share) +# MOD [MOD...]: One or more mod ids to copy (cnc, d2k, ra) +# Used by: +# Makefile (install-linux-appdata target for local installs and downstream packaging) +install_linux_appdata() { + SRC_PATH="${1}" + BUILD_PATH="${2}" + SHARE_PATH="${3}" + shift 3 + while [ -n "${1}" ]; do + MOD_ID="${1}" + SCREENSHOT_CNC= + SCREENSHOT_D2K= + SCREENSHOT_RA= + if [ "${MOD_ID}" = "ra" ] || [ "${MOD_ID}" = "cnc" ] || [ "${MOD_ID}" = "d2k" ]; then + if [ "${MOD_ID}" = "cnc" ]; then + MOD_NAME="Tiberian Dawn" + SCREENSHOT_CNC=" type=\"default\"" + fi + + if [ "${MOD_ID}" = "d2k" ]; then + MOD_NAME="Dune 2000" + SCREENSHOT_D2K=" type=\"default\"" + fi + + if [ "${MOD_ID}" = "ra" ]; then + MOD_NAME="Red Alert" + SCREENSHOT_RA=" type=\"default\"" + fi + fi + + install -d "${BUILD_PATH}${SHARE_PATH}/metainfo" + + sed "s/{MODID}/${MOD_ID}/g" "${SRC_PATH}/packaging/linux/openra.metainfo.xml.in" | sed "s/{MOD_NAME}/${MOD_NAME}/g" | sed "s/{SCREENSHOT_RA}/${SCREENSHOT_RA}/g" | sed "s/{SCREENSHOT_CNC}/${SCREENSHOT_CNC}/g" | sed "s/{SCREENSHOT_D2K}/${SCREENSHOT_D2K}/g"> "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.metainfo.xml" + install -m644 "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.metainfo.xml" "${BUILD_PATH}${SHARE_PATH}/metainfo" + rm "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.metainfo.xml" + + shift + done +} diff -Nru openra-20200503/packaging/.itch.toml openra-20210321/packaging/.itch.toml --- openra-20200503/packaging/.itch.toml 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/.itch.toml 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,17 @@ +[[prereqs]] +name = "net-4.7.2" + +[[actions]] +os = "windows" +name = "Red Alert" +path = "RedAlert.exe" + +[[actions]] +os = "windows" +name = "Dune 2000" +path = "Dune2000.exe" + +[[actions]] +os = "windows" +name = "Tiberian Dawn" +path = "TiberianDawn.exe" diff -Nru openra-20200503/packaging/linux/AppRun.in openra-20210321/packaging/linux/AppRun.in --- openra-20200503/packaging/linux/AppRun.in 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/linux/AppRun.in 2021-03-21 11:10:05.000000000 +0000 @@ -23,22 +23,22 @@ # Update/create the mono certificate store to enable https web queries if [ -f "/etc/pki/tls/certs/ca-bundle.crt" ]; then - mono "${HERE}/usr/lib/mono/4.5/cert-sync.exe" --quiet --user /etc/pki/tls/certs/ca-bundle.crt + mono "${HERE}/usr/lib/mono/4.5/cert-sync.exe" --quiet --user /etc/pki/tls/certs/ca-bundle.crt elif [ -f "/etc/ssl/certs/ca-certificates.crt" ]; then - mono "${HERE}/usr/lib/mono/4.5/cert-sync.exe" --quiet --user /etc/ssl/certs/ca-certificates.crt + mono "${HERE}/usr/lib/mono/4.5/cert-sync.exe" --quiet --user /etc/ssl/certs/ca-certificates.crt else - echo "WARNING: Unable to sync system certificate store - https requests will fail" + echo "WARNING: Unable to sync system certificate store - https requests will fail" fi # Run the game or server if [ -n "$1" ] && [ "$1" = "--server" ]; then - # Drop the --server argument - shift - exec "openra-{MODID}-server" "$@" + # Drop the --server argument + shift + exec "openra-{MODID}-server" "$@" elif [ -n "$1" ] && [ "$1" = "--utility" ]; then - # Drop the --utility argument - shift - exec "openra-{MODID}-utility" "$@" + # Drop the --utility argument + shift + exec "openra-{MODID}-utility" "$@" else - exec "openra-{MODID}" "$@" + exec "openra-{MODID}" "$@" fi diff -Nru openra-20200503/packaging/linux/buildpackage.sh openra-20210321/packaging/linux/buildpackage.sh --- openra-20200503/packaging/linux/buildpackage.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/linux/buildpackage.sh 2021-03-21 11:10:05.000000000 +0000 @@ -3,11 +3,10 @@ set -e command -v make >/dev/null 2>&1 || { echo >&2 "Linux packaging requires make."; exit 1; } -command -v python >/dev/null 2>&1 || { echo >&2 "Linux packaging requires python."; exit 1; } command -v tar >/dev/null 2>&1 || { echo >&2 "Linux packaging requires tar."; exit 1; } command -v curl >/dev/null 2>&1 || command -v wget > /dev/null 2>&1 || { echo >&2 "Linux packaging requires curl or wget."; exit 1; } -DEPENDENCIES_TAG="20200222" +DEPENDENCIES_TAG="20200328" if [ $# -eq "0" ]; then echo "Usage: $(basename "$0") version [outputdir]" @@ -16,11 +15,13 @@ # Set the working dir to the location of this script cd "$(dirname "$0")" || exit 1 +. ../functions.sh TAG="$1" OUTPUTDIR="$2" SRCDIR="$(pwd)/../.." BUILTDIR="$(pwd)/build" +ARTWORK_DIR="$(pwd)/../artwork/" UPDATE_CHANNEL="" SUFFIX="-devel" @@ -42,113 +43,93 @@ exit 1 fi -echo "Building core files" - -pushd "${SRCDIR}" > /dev/null || exit 1 - -make clean - -# linux-dependencies target will trigger the lua detection script, which we don't want during packaging -make cli-dependencies -sed "s/@LIBLUA51@/liblua5.1.so.0/" thirdparty/Eluant.dll.config.in > Eluant.dll.config - -make core -make version VERSION="${TAG}" -make install-engine prefix="usr" DESTDIR="${BUILTDIR}/" -make install-common-mod-files prefix="usr" DESTDIR="${BUILTDIR}/" - -popd > /dev/null || exit 1 - # Add native libraries echo "Downloading dependencies" if command -v curl >/dev/null 2>&1; then - curl -s -L -O https://github.com/OpenRA/AppImageSupport/releases/download/${DEPENDENCIES_TAG}/libs.tar.bz2 || exit 3 + curl -s -L -O https://github.com/OpenRA/AppImageSupport/releases/download/${DEPENDENCIES_TAG}/mono.tar.bz2 || exit 3 curl -s -L -O https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage || exit 3 else - wget -cq https://github.com/OpenRA/AppImageSupport/releases/download/${DEPENDENCIES_TAG}/libs.tar.bz2 || exit 3 + wget -cq https://github.com/OpenRA/AppImageSupport/releases/download/${DEPENDENCIES_TAG}/mono.tar.bz2 || exit 3 wget -cq https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage || exit 3 fi +# travis-ci doesn't support mounting FUSE filesystems so extract and run the contents manually chmod a+x appimagetool-x86_64.AppImage +./appimagetool-x86_64.AppImage --appimage-extract echo "Building AppImage" -mkdir libs -pushd libs -tar xf ../libs.tar.bz2 - -install -d "${BUILTDIR}/usr/bin" -install -d "${BUILTDIR}/etc/mono/4.5" -install -d "${BUILTDIR}/usr/lib/mono/4.5" - -install -Dm 0755 usr/bin/mono "${BUILTDIR}/usr/bin/" +mkdir "${BUILTDIR}" +tar xf mono.tar.bz2 -C "${BUILTDIR}" +chmod 0755 "${BUILTDIR}/usr/bin/mono" +chmod 0644 "${BUILTDIR}/etc/mono/config" +chmod 0644 "${BUILTDIR}/etc/mono/4.5/machine.config" +chmod 0644 "${BUILTDIR}/usr/lib/mono/4.5/Facades/"*.dll +chmod 0644 "${BUILTDIR}/usr/lib/mono/4.5/"*.dll "${BUILTDIR}/usr/lib/mono/4.5/"*.exe +chmod 0755 "${BUILTDIR}/usr/lib/"*.so -install -Dm 0644 /etc/mono/config "${BUILTDIR}/etc/mono/" -install -Dm 0644 /etc/mono/4.5/machine.config "${BUILTDIR}/etc/mono/4.5" - -for f in $(ls usr/lib/mono/4.5/*.dll usr/lib/mono/4.5/*.exe); do install -Dm 0644 "$f" "${BUILTDIR}/usr/lib/mono/4.5/"; done -for f in $(ls usr/lib/*.so usr/lib/*.so.*); do install -Dm 0755 "$f" "${BUILTDIR}/usr/lib/"; done - -popd - -rm -rf libs libs.tar.bz2 +rm -rf mono.tar.bz2 build_appimage() { MOD_ID=${1} DISPLAY_NAME=${2} + DISCORD_ID=${3} APPDIR="$(pwd)/${MOD_ID}.appdir" APPIMAGE="OpenRA-$(echo "${DISPLAY_NAME}" | sed 's/ /-/g')${SUFFIX}-x86_64.AppImage" cp -r "${BUILTDIR}" "${APPDIR}" - # Add mod files - pushd "${SRCDIR}" > /dev/null || exit 1 - cp -r "mods/${MOD_ID}" mods/modcontent "${APPDIR}/usr/lib/openra/mods" - popd > /dev/null || exit 1 - - # Add launcher and icons - sed "s/{MODID}/${MOD_ID}/g" AppRun.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" > AppRun.temp - install -m 0755 AppRun.temp "${APPDIR}/AppRun" + IS_D2K="False" + if [ "${MOD_ID}" = "d2k" ]; then + IS_D2K="True" + fi - sed "s/{MODID}/${MOD_ID}/g" openra.desktop.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" | sed "s/{TAG}/${TAG}/g" > temp.desktop - echo "StartupWMClass=openra-${MOD_ID}-${TAG}" >> temp.desktop + install_assemblies_mono "${SRCDIR}" "${APPDIR}/usr/lib/openra" "linux-x64" "True" "True" "${IS_D2K}" + install_data "${SRCDIR}" "${APPDIR}/usr/lib/openra" "${MOD_ID}" + set_engine_version "${TAG}" "${APPDIR}/usr/lib/openra" + set_mod_version "${TAG}" "${APPDIR}/usr/lib/openra/mods/${MOD_ID}/mod.yaml" "${APPDIR}/usr/lib/openra/mods/modcontent/mod.yaml" - install -Dm 0755 temp.desktop "${APPDIR}/usr/share/applications/openra-${MOD_ID}.desktop" - install -m 0755 temp.desktop "${APPDIR}/openra-${MOD_ID}.desktop" + # Add launcher and icons + sed "s/{MODID}/${MOD_ID}/g" AppRun.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" > "${APPDIR}/AppRun" + chmod 0755 "${APPDIR}/AppRun" - sed "s/{MODID}/${MOD_ID}/g" openra-mimeinfo.xml.in | sed "s/{TAG}/${TAG}/g" > temp.xml - install -Dm 0755 temp.xml "${APPDIR}/usr/share/mime/packages/openra-${MOD_ID}.xml" + mkdir -p "${APPDIR}/usr/share/applications" + # Note that the non-discord version of the desktop file is used by the Mod SDK and must be maintained in parallel with the discord version! + sed "s/{MODID}/${MOD_ID}/g" openra.desktop.discord.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" | sed "s/{TAG}/${TAG}/g" | sed "s/{DISCORDAPPID}/${DISCORD_ID}/g" > "${APPDIR}/usr/share/applications/openra-${MOD_ID}.desktop" + chmod 0755 "${APPDIR}/usr/share/applications/openra-${MOD_ID}.desktop" + cp "${APPDIR}/usr/share/applications/openra-${MOD_ID}.desktop" "${APPDIR}/openra-${MOD_ID}.desktop" + + mkdir -p "${APPDIR}/usr/share/mime/packages" + # Note that the non-discord version of the mimeinfo file is used by the Mod SDK and must be maintained in parallel with the discord version! + sed "s/{MODID}/${MOD_ID}/g" openra-mimeinfo.xml.discord.in | sed "s/{TAG}/${TAG}/g" | sed "s/{DISCORDAPPID}/${DISCORD_ID}/g" > "${APPDIR}/usr/share/mime/packages/openra-${MOD_ID}.xml" + chmod 0755 "${APPDIR}/usr/share/mime/packages/openra-${MOD_ID}.xml" - if [ -f "icons/${MOD_ID}_scalable.svg" ]; then - install -Dm644 "icons/${MOD_ID}_scalable.svg" "${APPDIR}/usr/share/icons/hicolor/scalable/apps/openra-${MOD_ID}.svg" + if [ -f "${ARTWORK_DIR}/${MOD_ID}_scalable.svg" ]; then + install -Dm644 "${ARTWORK_DIR}/${MOD_ID}_scalable.svg" "${APPDIR}/usr/share/icons/hicolor/scalable/apps/openra-${MOD_ID}.svg" fi for i in 16x16 32x32 48x48 64x64 128x128 256x256 512x512 1024x1024; do - if [ -f "icons/${MOD_ID}_${i}.png" ]; then - install -Dm644 "icons/${MOD_ID}_${i}.png" "${APPDIR}/usr/share/icons/hicolor/${i}/apps/openra-${MOD_ID}.png" - install -m644 "icons/${MOD_ID}_${i}.png" "${APPDIR}/openra-${MOD_ID}.png" + if [ -f "${ARTWORK_DIR}/${MOD_ID}_${i}.png" ]; then + install -Dm644 "${ARTWORK_DIR}/${MOD_ID}_${i}.png" "${APPDIR}/usr/share/icons/hicolor/${i}/apps/openra-${MOD_ID}.png" + install -m644 "${ARTWORK_DIR}/${MOD_ID}_${i}.png" "${APPDIR}/openra-${MOD_ID}.png" fi done - sed "s/{MODID}/${MOD_ID}/g" openra.appimage.in | sed "s/{TAG}/${TAG}/g" | sed "s/{MODNAME}/${DISPLAY_NAME}/g" > openra-mod.temp - install -m 0755 openra-mod.temp "${APPDIR}/usr/bin/openra-${MOD_ID}" + sed "s/{MODID}/${MOD_ID}/g" openra.appimage.in | sed "s/{TAG}/${TAG}/g" | sed "s/{MODNAME}/${DISPLAY_NAME}/g" > "${APPDIR}/usr/bin/openra-${MOD_ID}" + chmod 0755 "${APPDIR}/usr/bin/openra-${MOD_ID}" - sed "s/{MODID}/${MOD_ID}/g" openra-server.appimage.in > openra-mod-server.temp - install -m 0755 openra-mod-server.temp "${APPDIR}/usr/bin/openra-${MOD_ID}-server" + sed "s/{MODID}/${MOD_ID}/g" openra-server.appimage.in > "${APPDIR}/usr/bin/openra-${MOD_ID}-server" + chmod 0755 "${APPDIR}/usr/bin/openra-${MOD_ID}-server" - sed "s/{MODID}/${MOD_ID}/g" openra-utility.appimage.in > openra-mod-utility.temp - install -m 0755 openra-mod-utility.temp "${APPDIR}/usr/bin/openra-${MOD_ID}-utility" + sed "s/{MODID}/${MOD_ID}/g" openra-utility.appimage.in > "${APPDIR}/usr/bin/openra-${MOD_ID}-utility" + chmod 0755 "${APPDIR}/usr/bin/openra-${MOD_ID}-utility" install -m 0755 gtk-dialog.py "${APPDIR}/usr/bin/gtk-dialog.py" - install -m 0755 restore-environment.sh "${APPDIR}/usr/bin/restore-environment.sh" - # travis-ci doesn't support mounting FUSE filesystems so extract and run the contents manually - ./appimagetool-x86_64.AppImage --appimage-extract - - # Embed update metadata if (and only if) compiled on travis - if [ ! -z "${TRAVIS_REPO_SLUG}" ]; then + # Embed update metadata if (and only if) compiled on GitHub Actions + if [ -n "${GITHUB_REPOSITORY}" ]; then ARCH=x86_64 ./squashfs-root/AppRun --no-appstream -u "zsync|https://master.openra.net/appimagecheck?mod=${MOD_ID}&channel=${UPDATE_CHANNEL}" "${APPDIR}" "${OUTPUTDIR}/${APPIMAGE}" - zsyncmake -u "https://github.com/${TRAVIS_REPO_SLUG}/releases/download/${TAG}/${APPIMAGE}" -o "${OUTPUTDIR}/${APPIMAGE}.zsync" "${OUTPUTDIR}/${APPIMAGE}" + zsyncmake -u "https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${APPIMAGE}" -o "${OUTPUTDIR}/${APPIMAGE}.zsync" "${OUTPUTDIR}/${APPIMAGE}" else ARCH=x86_64 ./squashfs-root/AppRun --no-appstream "${APPDIR}" "${OUTPUTDIR}/${APPIMAGE}" fi @@ -156,9 +137,9 @@ rm -rf "${APPDIR}" } -build_appimage "ra" "Red Alert" -build_appimage "cnc" "Tiberian Dawn" -build_appimage "d2k" "Dune 2000" +build_appimage "ra" "Red Alert" "699222659766026240" +build_appimage "cnc" "Tiberian Dawn" "699223250181292033" +build_appimage "d2k" "Dune 2000" "712711732770111550" # Clean up -rm -rf openra-mod.temp openra-mod-server.temp openra-mod-utility.temp temp.desktop temp.xml AppRun.temp appimagetool-x86_64.AppImage squashfs-root "${BUILTDIR}" +rm -rf appimagetool-x86_64.AppImage squashfs-root "${BUILTDIR}" Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/cnc_128x128.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/cnc_128x128.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/cnc_16x16.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/cnc_16x16.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/cnc_32x32.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/cnc_32x32.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/cnc_48x48.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/cnc_48x48.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/cnc_64x64.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/cnc_64x64.png differ diff -Nru openra-20200503/packaging/linux/icons/cnc_scalable.svg openra-20210321/packaging/linux/icons/cnc_scalable.svg --- openra-20200503/packaging/linux/icons/cnc_scalable.svg 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/linux/icons/cnc_scalable.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,226 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/d2k_128x128.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/d2k_128x128.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/d2k_16x16.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/d2k_16x16.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/d2k_32x32.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/d2k_32x32.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/d2k_48x48.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/d2k_48x48.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/d2k_64x64.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/d2k_64x64.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/ra_128x128.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/ra_128x128.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/ra_16x16.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/ra_16x16.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/ra_32x32.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/ra_32x32.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/ra_48x48.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/ra_48x48.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/linux/icons/ra_64x64.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/linux/icons/ra_64x64.png differ diff -Nru openra-20200503/packaging/linux/icons/ra_scalable.svg openra-20210321/packaging/linux/icons/ra_scalable.svg --- openra-20200503/packaging/linux/icons/ra_scalable.svg 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/linux/icons/ra_scalable.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,231 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - \ No newline at end of file diff -Nru openra-20200503/packaging/linux/openra.appdata.xml.in openra-20210321/packaging/linux/openra.appdata.xml.in --- openra-20200503/packaging/linux/openra.appdata.xml.in 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/linux/openra.appdata.xml.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ - - - openra-{MODID}.desktop - CC0-1.0 - GPL-3.0 - OpenRA - {MOD_NAME} - Reimagining of early Westwood real-time strategy games - -

- OpenRA is a project that recreates and modernizes the classic Command & Conquer real time strategy games. We have developed a flexible open source game engine (the OpenRA engine) that provides a common platform for rebuilding and reimagining classic 2D and 2.5D RTS games (the OpenRA mods). -

-

- The OpenRA mods include new features and gameplay improvements that bring them into the modern era: -

-
    -
  • A choice between “right click” and classic “left click” control schemes
  • -
  • Overhauled sidebar interfaces for managing production
  • -
  • Support for game replays and an observer interface designed for streaming games online
  • -
  • The “fog of war” that obscures the battlefield outside your units' line of sight
  • -
  • Civilian structures that can be captured to provide benefits
  • -
  • Units gain experience as they fight and improve when they earn new ranks
  • -
-

- OpenRA is 100% free, and comes bundled with three distinct mods. When you run a mod for the first time the game can automatically download the original game assets, or you can use the original game disks. -

-
- - - http://www.openra.net/images/appdata/ingame-ra.png - Red Alert mod - - - http://www.openra.net/images/appdata/ingame-cnc.png - Tiberian Dawn mod - - - http://www.openra.net/images/appdata/ingame-d2k.png - Dune 2000 Mod - - - http://www.openra.net/images/appdata/multiplayer.png - Multiplayer lobby in the Tiberian Dawn mod - - - http://www.openra.net - paul_at_chote.net - - none - none - moderate - moderate - none - none - none - moderate - none - none - mild - mild - none - intense - none - none - none - none - none - none - -
diff -Nru openra-20200503/packaging/linux/openra.appimage.in openra-20210321/packaging/linux/openra.appimage.in --- openra-20200503/packaging/linux/openra.appimage.in 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/linux/openra.appimage.in 2021-03-21 11:10:05.000000000 +0000 @@ -6,48 +6,54 @@ # APPIMAGE is an environment variable set by the runtime # defining the absolute path to the .AppImage file if [ -n "${APPIMAGE}" ]; then - LAUNCHER=${APPIMAGE} + LAUNCHER=${APPIMAGE} - # appimaged doesn't update the mime or icon caches when registering AppImages. - # Run update-desktop-database and gtk-update-icon-cache ourselves if we detect - # that the desktop file has been installed but the handler is not cached - if command -v update-desktop-database > /dev/null; then - APPIMAGEID=$(printf "file://%s" "${APPIMAGE}" | md5sum | cut -d' ' -f1) - LAUNCHER_NAME="appimagekit_${APPIMAGEID}-openra-{MODID}.desktop" - LAUNCHER_PATH="${HOME}/.local/share/applications/${LAUNCHER_NAME}" - MIMECACHE_PATH="${HOME}/.local/share/applications/mimeinfo.cache" - SCHEME="x-scheme-handler/openra-{MODID}-{TAG}" - if [ -f "${LAUNCHER_PATH}" ] && ! grep -qs "${SCHEME}=" "${MIMECACHE_PATH}"; then - update-desktop-database "${HOME}/.local/share/applications" - if command -v gtk-update-icon-cache > /dev/null; then - gtk-update-icon-cache ~/.local/share/icons/hicolor/ -t - fi - fi - fi + # appimaged doesn't update the mime or icon caches when registering AppImages. + # Run update-desktop-database and gtk-update-icon-cache ourselves if we detect + # that the desktop file has been installed but the handler is not cached + if command -v update-desktop-database > /dev/null; then + APPIMAGEID=$(printf "file://%s" "${APPIMAGE}" | md5sum | cut -d' ' -f1) + LAUNCHER_NAME="appimagekit_${APPIMAGEID}-openra-{MODID}.desktop" + LAUNCHER_PATH="${HOME}/.local/share/applications/${LAUNCHER_NAME}" + MIMECACHE_PATH="${HOME}/.local/share/applications/mimeinfo.cache" + SCHEME="x-scheme-handler/openra-{MODID}-{TAG}" + if [ -f "${LAUNCHER_PATH}" ] && ! grep -qs "${SCHEME}=" "${MIMECACHE_PATH}"; then + update-desktop-database "${HOME}/.local/share/applications" + if command -v gtk-update-icon-cache > /dev/null; then + gtk-update-icon-cache ~/.local/share/icons/hicolor/ -t + fi + fi + fi fi # Search for server connection PROTOCOL_PREFIX="openra-{MODID}-{TAG}://" JOIN_SERVER="" if [ "${1#${PROTOCOL_PREFIX}}" != "${1}" ]; then - JOIN_SERVER="Launch.Connect=${1#${PROTOCOL_PREFIX}}" + JOIN_SERVER="Launch.Connect=${1#${PROTOCOL_PREFIX}}" fi # Run the game export SDL_VIDEO_X11_WMCLASS="openra-{MODID}-{TAG}" -mono --debug OpenRA.Game.exe Game.Mod={MODID} Engine.LaunchPath="${LAUNCHER}" Engine.LaunchWrapper="${HERE}/restore-environment.sh" "${JOIN_SERVER}" "$@" +mono --debug OpenRA.exe Game.Mod={MODID} Engine.LaunchPath="${LAUNCHER}" Engine.LaunchWrapper="${HERE}/restore-environment.sh" "${JOIN_SERVER}" "$@" # Show a crash dialog if something went wrong if [ $? != 0 ] && [ $? != 1 ]; then - ERROR_MESSAGE="{MODNAME} has encountered a fatal error.\nPlease refer to the crash logs and FAQ for more information.\n\nLog files are located in ~/.openra/Logs\nThe FAQ is available at http://wiki.openra.net/FAQ" - if command -v zenity > /dev/null; then - zenity --no-wrap --error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null - elif command -v kdialog > /dev/null; then - kdialog --title "{MODNAME}" --error "${ERROR_MESSAGE}" - elif "${HERE}/gtk-dialog.py" test > /dev/null; then - "${HERE}/gtk-dialog.py" error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null - else - printf "${ERROR_MESSAGE}\n" - fi - exit 1 + LOGS="${XDG_CONFIG_HOME:-${HOME}/.config}/openra/Logs" + if [ ! -d "${LOGS}" ] && [ -d "${HOME}/.openra/Logs" ]; then + LOGS="${HOME}/.openra/Logs" + fi + + test -d Support/Logs && LOGS="${PWD}/Support/Logs" + ERROR_MESSAGE="{MODNAME} has encountered a fatal error.\nPlease refer to the crash logs and FAQ for more information.\n\nLog files are located in ${LOGS}\nThe FAQ is available at http://wiki.openra.net/FAQ" + if command -v zenity > /dev/null; then + zenity --no-wrap --error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null + elif command -v kdialog > /dev/null; then + kdialog --title "{MODNAME}" --error "${ERROR_MESSAGE}" + elif "${HERE}/gtk-dialog.py" test > /dev/null; then + "${HERE}/gtk-dialog.py" error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null + else + printf "${ERROR_MESSAGE}\n" + fi + exit 1 fi diff -Nru openra-20200503/packaging/linux/openra.desktop.discord.in openra-20210321/packaging/linux/openra.desktop.discord.in --- openra-20200503/packaging/linux/openra.desktop.discord.in 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/linux/openra.desktop.discord.in 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,12 @@ +[Desktop Entry] +Type=Application +Version=1.0 +Name=OpenRA - {MODNAME} +GenericName=Real Time Strategy Game +GenericName[de]=Echtzeit-Strategiespiel +Icon=openra-{MODID} +Exec=openra-{MODID} %U +Terminal=false +Categories=Game;StrategyGame; +StartupWMClass=openra-{MODID}-{TAG} +MimeType=x-scheme-handler/openra-{MODID}-{TAG};x-scheme-handler/discord-{DISCORDAPPID}; diff -Nru openra-20200503/packaging/linux/openra.desktop.in openra-20210321/packaging/linux/openra.desktop.in --- openra-20200503/packaging/linux/openra.desktop.in 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/linux/openra.desktop.in 2021-03-21 11:10:05.000000000 +0000 @@ -4,9 +4,9 @@ Name=OpenRA - {MODNAME} GenericName=Real Time Strategy Game GenericName[de]=Echtzeit-Strategiespiel -Comment=Reimagining of early Westwood Games Icon=openra-{MODID} Exec=openra-{MODID} %U Terminal=false Categories=Game;StrategyGame; +StartupWMClass=openra-{MODID}-{TAG} MimeType=x-scheme-handler/openra-{MODID}-{TAG}; diff -Nru openra-20200503/packaging/linux/openra.in openra-20210321/packaging/linux/openra.in --- openra-20200503/packaging/linux/openra.in 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/linux/openra.in 2021-03-21 11:10:05.000000000 +0000 @@ -5,21 +5,27 @@ PROTOCOL_PREFIX="openra-{MODID}-{TAG}://" JOIN_SERVER="" if [ "${1#${PROTOCOL_PREFIX}}" != "${1}" ]; then - JOIN_SERVER="Launch.Connect=${1#${PROTOCOL_PREFIX}}" + JOIN_SERVER="Launch.Connect=${1#${PROTOCOL_PREFIX}}" fi # Run the game -mono {DEBUG} OpenRA.Game.exe Game.Mod={MODID} Engine.LaunchPath="{BIN_DIR}/openra-{MODID}" "${JOIN_SERVER}" "$@" +mono {DEBUG} OpenRA.exe Game.Mod={MODID} Engine.LaunchPath="{BIN_DIR}/openra-{MODID}" "${JOIN_SERVER}" "$@" # Show a crash dialog if something went wrong if [ $? != 0 ] && [ $? != 1 ]; then - ERROR_MESSAGE="{MODNAME} has encountered a fatal error.\nPlease refer to the crash logs and FAQ for more information.\n\nLog files are located in ~/.openra/Logs\nThe FAQ is available at http://wiki.openra.net/FAQ" - if command -v zenity > /dev/null; then - zenity --no-wrap --error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null - elif command -v kdialog > /dev/null; then - kdialog --title "{MODNAME}" --error "${ERROR_MESSAGE}" - else - printf "${ERROR_MESSAGE}\n" - fi - exit 1 + LOGS="${XDG_CONFIG_HOME:-${HOME}/.config}/openra/Logs" + if [ ! -d "${LOGS}" ] && [ -d "${HOME}/.openra/Logs" ]; then + LOGS="${HOME}/.openra/Logs" + fi + + test -d Support/Logs && LOGS="${PWD}/Support/Logs" + ERROR_MESSAGE="{MODNAME} has encountered a fatal error.\nPlease refer to the crash logs and FAQ for more information.\n\nLog files are located in ${LOGS}\nThe FAQ is available at http://wiki.openra.net/FAQ" + if command -v zenity > /dev/null; then + zenity --no-wrap --error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null + elif command -v kdialog > /dev/null; then + kdialog --title "{MODNAME}" --error "${ERROR_MESSAGE}" + else + printf "${ERROR_MESSAGE}\n" + fi + exit 1 fi diff -Nru openra-20200503/packaging/linux/openra.metainfo.xml.in openra-20210321/packaging/linux/openra.metainfo.xml.in --- openra-20200503/packaging/linux/openra.metainfo.xml.in 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/linux/openra.metainfo.xml.in 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,58 @@ + + + openra-{MODID}.desktop + CC0-1.0 + GPL-3.0 + OpenRA - {MOD_NAME} + Reimagining of early Westwood real-time strategy games + +

+ OpenRA is a project that recreates and modernizes the classic Command & Conquer real time strategy games. We have developed a flexible open source game engine (the OpenRA engine) that provides a common platform for rebuilding and reimagining classic 2D and 2.5D RTS games (the OpenRA mods). +

+

+ The OpenRA mods include new features and gameplay improvements that bring them into the modern era: +

+
    +
  • A choice between “right click” and classic “left click” control schemes
  • +
  • Overhauled sidebar interfaces for managing production
  • +
  • Support for game replays and an observer interface designed for streaming games online
  • +
  • The “fog of war” that obscures the battlefield outside your units' line of sight
  • +
  • Civilian structures that can be captured to provide benefits
  • +
  • Units gain experience as they fight and improve when they earn new ranks
  • +
+

+ OpenRA is 100% free, and comes bundled with three distinct mods. When you run a mod for the first time the game can automatically download the original game assets, or you can use the original game disks. +

+
+ openra-{MODID}.desktop + + + http://www.openra.net/images/appdata/ingame-ra.png + Red Alert mod + + + http://www.openra.net/images/appdata/ingame-cnc.png + Tiberian Dawn mod + + + http://www.openra.net/images/appdata/ingame-d2k.png + Dune 2000 Mod + + + http://www.openra.net/images/appdata/multiplayer.png + Multiplayer lobby in the Tiberian Dawn mod + + + https://www.openra.net + https://github.com/OpenRA/OpenRA/issues + paul_at_chote.net + + moderate + moderate + moderate + moderate + mild + mild + intense + +
diff -Nru openra-20200503/packaging/linux/openra-mimeinfo.xml.discord.in openra-20210321/packaging/linux/openra-mimeinfo.xml.discord.in --- openra-20200503/packaging/linux/openra-mimeinfo.xml.discord.in 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/linux/openra-mimeinfo.xml.discord.in 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,14 @@ + + + + + + Join OpenRA server + + + + + Launch OpenRA from Discord + + + diff -Nru openra-20200503/packaging/linux/openra-server.appimage.in openra-20210321/packaging/linux/openra-server.appimage.in --- openra-20200503/packaging/linux/openra-server.appimage.in 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/linux/openra-server.appimage.in 2021-03-21 11:10:05.000000000 +0000 @@ -2,4 +2,4 @@ HERE="$(dirname "$(readlink -f "${0}")")" cd "${HERE}/../lib/openra" || exit 1 -mono --debug OpenRA.Server.exe Game.Mod={MODID} "$@" +mono --debug OpenRA.Server.exe Game.Mod="{MODID}" "$@" diff -Nru openra-20200503/packaging/linux/restore-environment.sh openra-20210321/packaging/linux/restore-environment.sh --- openra-20200503/packaging/linux/restore-environment.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/linux/restore-environment.sh 2021-03-21 11:10:05.000000000 +0000 @@ -9,15 +9,15 @@ unset MONO_PATH MONO_CFG_DIR MONO_CONFIG if [ -n "${OPENRA_ORIG_MONO_PATH}" ]; then - export MONO_PATH="${OPENRA_ORIG_MONO_PATH}" + export MONO_PATH="${OPENRA_ORIG_MONO_PATH}" fi if [ -n "${OPENRA_ORIG_MONO_CFG_DIR}" ]; then - export MONO_CFG_DIR="${OPENRA_ORIG_MONO_CFG_DIR}" + export MONO_CFG_DIR="${OPENRA_ORIG_MONO_CFG_DIR}" fi if [ -n "${OPENRA_ORIG_MONO_CONFIG}" ]; then - export MONO_CONFIG="${OPENRA_ORIG_MONO_CONFIG}" + export MONO_CONFIG="${OPENRA_ORIG_MONO_CONFIG}" fi unset SDL_VIDEO_X11_WMCLASS OPENRA_ORIG_MONO_PATH OPENRA_ORIG_MONO_CFG_DIR OPENRA_ORIG_MONO_CONFIG Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/background-2x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/background-2x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/background.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/background.png differ diff -Nru openra-20200503/packaging/macos/buildpackage.sh openra-20210321/packaging/macos/buildpackage.sh --- openra-20200503/packaging/macos/buildpackage.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/macos/buildpackage.sh 2021-03-21 11:10:05.000000000 +0000 @@ -1,8 +1,9 @@ #!/bin/bash # OpenRA packaging script for macOS # -# The application bundles will be signed if the following environment variable is defined: -# MACOS_DEVELOPER_IDENTITY: Certificate name, of the form `Developer\ ID\ Application:\ ` +# The application bundles will be signed if the following environment variables are defined: +# MACOS_DEVELOPER_IDENTITY: The alphanumeric identifier listed in the certificate name ("Developer ID Application: ()") +# or as Team ID in your Apple Developer account Membership Details. # If the identity is not already in the default keychain, specify the following environment variables to import it: # MACOS_DEVELOPER_CERTIFICATE_BASE64: base64 content of the exported .p12 developer ID certificate. # Generate using `base64 certificate.p12 | pbcopy` @@ -12,21 +13,23 @@ # MACOS_DEVELOPER_USERNAME: Email address for the developer account # MACOS_DEVELOPER_PASSWORD: App-specific password for the developer account # +set -e -LAUNCHER_TAG="osx-launcher-20200316" +MONO_TAG="osx-launcher-20200830" if [ $# -ne "2" ]; then echo "Usage: $(basename "$0") tag outputdir" exit 1 fi -if [[ "$OSTYPE" != "darwin"* ]]; then +if [[ "${OSTYPE}" != "darwin"* ]]; then echo >&2 "macOS packaging requires a macOS host" exit 1 fi # Set the working dir to the location of this script -cd "$(dirname "$0")" || exit 1 +cd "$(dirname "${0}")" || exit 1 +. ../functions.sh # Import code signing certificate if [ -n "${MACOS_DEVELOPER_CERTIFICATE_BASE64}" ] && [ -n "${MACOS_DEVELOPER_CERTIFICATE_PASSWORD}" ] && [ -n "${MACOS_DEVELOPER_IDENTITY}" ]; then @@ -40,165 +43,189 @@ rm -fr build.p12 fi -TAG="$1" -OUTPUTDIR="$2" +TAG="${1}" +OUTPUTDIR="${2}" SRCDIR="$(pwd)/../.." BUILTDIR="$(pwd)/build" +ARTWORK_DIR="$(pwd)/../artwork/" modify_plist() { - sed "s|$1|$2|g" "$3" > "$3.tmp" && mv "$3.tmp" "$3" + sed "s|${1}|${2}|g" "${3}" > "${3}.tmp" && mv "${3}.tmp" "${3}" } # Copies the game files and sets metadata -populate_bundle() { - TEMPLATE_DIR="${BUILTDIR}/${1}" - MOD_ID=${2} - MOD_NAME=${3} - cp -r "${BUILTDIR}/OpenRA.app" "${TEMPLATE_DIR}" - - # Assemble multi-resolution icon - iconutil --convert icns ${MOD_ID}.iconset -o "${TEMPLATE_DIR}/Contents/Resources/${MOD_ID}.icns" +build_app() { + TEMPLATE_DIR="${1}" + LAUNCHER_DIR="${2}" + MOD_ID="${3}" + MOD_NAME="${4}" + DISCORD_APPID="${5}" + + LAUNCHER_CONTENTS_DIR="${LAUNCHER_DIR}/Contents" + LAUNCHER_RESOURCES_DIR="${LAUNCHER_CONTENTS_DIR}/Resources" + + cp -r "${TEMPLATE_DIR}" "${LAUNCHER_DIR}" + + IS_D2K="False" + if [ "${MOD_ID}" = "d2k" ]; then + IS_D2K="True" + fi - # Copy macOS specific files - modify_plist "{MOD_ID}" "${MOD_ID}" "${TEMPLATE_DIR}/Contents/Info.plist" - modify_plist "{MOD_NAME}" "${MOD_NAME}" "${TEMPLATE_DIR}/Contents/Info.plist" - modify_plist "{JOIN_SERVER_URL_SCHEME}" "openra-${MOD_ID}-${TAG}" "${TEMPLATE_DIR}/Contents/Info.plist" -} + # Install engine and mod files + install_assemblies_mono "${SRCDIR}" "${LAUNCHER_RESOURCES_DIR}" "osx-x64" "True" "True" "${IS_D2K}" + install_data "${SRCDIR}" "${LAUNCHER_RESOURCES_DIR}" "${MOD_ID}" + set_engine_version "${TAG}" "${LAUNCHER_RESOURCES_DIR}" + set_mod_version "${TAG}" "${LAUNCHER_RESOURCES_DIR}/mods/${MOD_ID}/mod.yaml" "${LAUNCHER_RESOURCES_DIR}/mods/modcontent/mod.yaml" -# Deletes from the first argument's mod dirs all the later arguments -delete_mods() { - pushd "${BUILTDIR}/${1}/Contents/Resources/mods" > /dev/null || exit 1 - shift - rm -rf "$@" - pushd > /dev/null || exit 1 -} + # Assemble multi-resolution icon + mkdir "${MOD_ID}.iconset" + cp "${ARTWORK_DIR}/${MOD_ID}_16x16.png" "${MOD_ID}.iconset/icon_16x16.png" + cp "${ARTWORK_DIR}/${MOD_ID}_32x32.png" "${MOD_ID}.iconset/icon_16x16@2.png" + cp "${ARTWORK_DIR}/${MOD_ID}_32x32.png" "${MOD_ID}.iconset/icon_32x32.png" + cp "${ARTWORK_DIR}/${MOD_ID}_64x64.png" "${MOD_ID}.iconset/icon_32x32@2x.png" + cp "${ARTWORK_DIR}/${MOD_ID}_128x128.png" "${MOD_ID}.iconset/icon_128x128.png" + cp "${ARTWORK_DIR}/${MOD_ID}_256x256.png" "${MOD_ID}.iconset/icon_128x128@2x.png" + cp "${ARTWORK_DIR}/${MOD_ID}_256x256.png" "${MOD_ID}.iconset/icon_256x256.png" + cp "${ARTWORK_DIR}/${MOD_ID}_512x512.png" "${MOD_ID}.iconset/icon_256x256@2x.png" + cp "${ARTWORK_DIR}/${MOD_ID}_1024x1024.png" "${MOD_ID}.iconset/icon_512x512@2x.png" + iconutil --convert icns "${MOD_ID}.iconset" -o "${LAUNCHER_RESOURCES_DIR}/${MOD_ID}.icns" + rm -rf "${MOD_ID}.iconset" + + # Set launcher metadata + modify_plist "{MOD_ID}" "${MOD_ID}" "${LAUNCHER_CONTENTS_DIR}/Info.plist" + modify_plist "{MOD_NAME}" "${MOD_NAME}" "${LAUNCHER_CONTENTS_DIR}/Info.plist" + modify_plist "{JOIN_SERVER_URL_SCHEME}" "openra-${MOD_ID}-${TAG}" "${LAUNCHER_CONTENTS_DIR}/Info.plist" + modify_plist "{DISCORD_URL_SCHEME}" "discord-${DISCORD_APPID}" "${LAUNCHER_CONTENTS_DIR}/Info.plist" -# Sign binaries with developer certificate -sign_bundle() { + # Sign binaries with developer certificate if [ -n "${MACOS_DEVELOPER_IDENTITY}" ]; then - codesign -s "${MACOS_DEVELOPER_IDENTITY}" --timestamp --options runtime -f --entitlements entitlements.plist "${BUILTDIR}/${1}/Contents/Resources/"*.dylib - codesign -s "${MACOS_DEVELOPER_IDENTITY}" --timestamp --options runtime -f --entitlements entitlements.plist --deep "${BUILTDIR}/${1}" + codesign -s "${MACOS_DEVELOPER_IDENTITY}" --timestamp --options runtime -f --entitlements entitlements.plist "${LAUNCHER_RESOURCES_DIR}/"*.dylib + codesign -s "${MACOS_DEVELOPER_IDENTITY}" --timestamp --options runtime -f --entitlements entitlements.plist --deep "${LAUNCHER_DIR}" fi } -echo "Building launchers" -curl -s -L -O https://github.com/OpenRA/OpenRALauncherOSX/releases/download/${LAUNCHER_TAG}/launcher.zip || exit 3 -unzip -qq -d "${BUILTDIR}" launcher.zip -rm launcher.zip - -modify_plist "{DEV_VERSION}" "${TAG}" "${BUILTDIR}/OpenRA.app/Contents/Info.plist" -modify_plist "{FAQ_URL}" "http://wiki.openra.net/FAQ" "${BUILTDIR}/OpenRA.app/Contents/Info.plist" -echo "Building core files" - -pushd "${SRCDIR}" > /dev/null || exit 1 -make clean -make osx-dependencies -make core -make version VERSION="${TAG}" -make install-core gameinstalldir="/Contents/Resources/" DESTDIR="${BUILTDIR}/OpenRA.app" -popd > /dev/null || exit 1 - -populate_bundle "OpenRA - Red Alert.app" "ra" "Red Alert" -delete_mods "OpenRA - Red Alert.app" "cnc" "d2k" -sign_bundle "OpenRA - Red Alert.app" - -populate_bundle "OpenRA - Tiberian Dawn.app" "cnc" "Tiberian Dawn" -delete_mods "OpenRA - Tiberian Dawn.app" "ra" "d2k" -sign_bundle "OpenRA - Tiberian Dawn.app" - -populate_bundle "OpenRA - Dune 2000.app" "d2k" "Dune 2000" -delete_mods "OpenRA - Dune 2000.app" "ra" "cnc" -sign_bundle "OpenRA - Dune 2000.app" - -rm -rf "${BUILTDIR}/OpenRA.app" - -if [ -n "${MACOS_DEVELOPER_CERTIFICATE_BASE64}" ] && [ -n "${MACOS_DEVELOPER_CERTIFICATE_PASSWORD}" ] && [ -n "${MACOS_DEVELOPER_IDENTITY}" ]; then - security delete-keychain build.keychain -fi +build_platform() { + PLATFORM="${1}" + DMG_PATH="${2}" + echo "Building launchers (${PLATFORM})" + + # Prepare generic template for the mods to duplicate and customize + TEMPLATE_DIR="${BUILTDIR}/template.app" + mkdir -p "${TEMPLATE_DIR}/Contents/Resources" + mkdir -p "${TEMPLATE_DIR}/Contents/MacOS" + echo "APPL????" > "${TEMPLATE_DIR}/Contents/PkgInfo" + cp Info.plist.in "${TEMPLATE_DIR}/Contents/Info.plist" + modify_plist "{DEV_VERSION}" "${TAG}" "${TEMPLATE_DIR}/Contents/Info.plist" + modify_plist "{FAQ_URL}" "http://wiki.openra.net/FAQ" "${TEMPLATE_DIR}/Contents/Info.plist" + + if [ "${PLATFORM}" = "compat" ]; then + modify_plist "{MINIMUM_SYSTEM_VERSION}" "10.9" "${TEMPLATE_DIR}/Contents/Info.plist" + clang -m64 launcher-mono.m -o "${TEMPLATE_DIR}/Contents/MacOS/OpenRA" -framework AppKit -mmacosx-version-min=10.9 + else + modify_plist "{MINIMUM_SYSTEM_VERSION}" "10.13" "${TEMPLATE_DIR}/Contents/Info.plist" + clang -m64 launcher.m -o "${TEMPLATE_DIR}/Contents/MacOS/OpenRA" -framework AppKit -mmacosx-version-min=10.13 + + curl -s -L -O https://github.com/OpenRA/OpenRALauncherOSX/releases/download/${MONO_TAG}/mono.zip || exit 3 + unzip -qq -d "${BUILTDIR}/mono" mono.zip + mv "${BUILTDIR}/mono/mono" "${TEMPLATE_DIR}/Contents/MacOS/" + mv "${BUILTDIR}/mono/etc" "${TEMPLATE_DIR}/Contents/Resources" + mv "${BUILTDIR}/mono/lib" "${TEMPLATE_DIR}/Contents/Resources" + rm mono.zip + rmdir "${BUILTDIR}/mono" + fi -echo "Packaging disk image" -hdiutil create build.dmg -format UDRW -volname "OpenRA" -fs HFS+ -srcfolder build -DMG_DEVICE=$(hdiutil attach -readwrite -noverify -noautoopen "build.dmg" | egrep '^/dev/' | sed 1q | awk '{print $1}') -sleep 2 - -# Background image is created from source svg in artsrc repository -mkdir "/Volumes/OpenRA/.background/" -tiffutil -cathidpicheck background.png background-2x.png -out "/Volumes/OpenRA/.background/background.tiff" - -cp "${BUILTDIR}/OpenRA - Red Alert.app/Contents/Resources/ra.icns" "/Volumes/OpenRA/.VolumeIcon.icns" - -echo ' - tell application "Finder" - tell disk "'OpenRA'" - open - set current view of container window to icon view - set toolbar visible of container window to false - set statusbar visible of container window to false - set the bounds of container window to {400, 100, 1040, 580} - set theViewOptions to the icon view options of container window - set arrangement of theViewOptions to not arranged - set icon size of theViewOptions to 72 - set background picture of theViewOptions to file ".background:background.tiff" - make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} - set position of item "'OpenRA - Tiberian Dawn.app'" of container window to {160, 106} - set position of item "'OpenRA - Red Alert.app'" of container window to {320, 106} - set position of item "'OpenRA - Dune 2000.app'" of container window to {480, 106} - set position of item "Applications" of container window to {320, 298} - set position of item ".background" of container window to {160, 298} - set position of item ".fseventsd" of container window to {160, 298} - set position of item ".VolumeIcon.icns" of container window to {160, 298} - update without registering applications - delay 5 - close - end tell - end tell -' | osascript - -# HACK: Copy the volume icon again - something in the previous step seems to delete it...? -cp "${BUILTDIR}/OpenRA - Red Alert.app/Contents/Resources/ra.icns" "/Volumes/OpenRA/.VolumeIcon.icns" -SetFile -c icnC "/Volumes/OpenRA/.VolumeIcon.icns" -SetFile -a C "/Volumes/OpenRA" - -chmod -Rf go-w /Volumes/OpenRA -sync -sync + build_app "${TEMPLATE_DIR}" "${BUILTDIR}/OpenRA - Red Alert.app" "ra" "Red Alert" "699222659766026240" + build_app "${TEMPLATE_DIR}" "${BUILTDIR}/OpenRA - Tiberian Dawn.app" "cnc" "Tiberian Dawn" "699223250181292033" + build_app "${TEMPLATE_DIR}" "${BUILTDIR}/OpenRA - Dune 2000.app" "d2k" "Dune 2000" "712711732770111550" + + rm -rf "${TEMPLATE_DIR}" + + echo "Packaging disk image" + hdiutil create "${DMG_PATH}" -format UDRW -volname "OpenRA" -fs HFS+ -srcfolder build + DMG_DEVICE=$(hdiutil attach -readwrite -noverify -noautoopen "${DMG_PATH}" | egrep '^/dev/' | sed 1q | awk '{print $1}') + sleep 2 + + # Background image is created from source svg in artsrc repository + mkdir "/Volumes/OpenRA/.background/" + tiffutil -cathidpicheck "${ARTWORK_DIR}/macos-background.png" "${ARTWORK_DIR}/macos-background-2x.png" -out "/Volumes/OpenRA/.background/background.tiff" + + cp "${BUILTDIR}/OpenRA - Red Alert.app/Contents/Resources/ra.icns" "/Volumes/OpenRA/.VolumeIcon.icns" + + echo ' + tell application "Finder" + tell disk "'OpenRA'" + open + set current view of container window to icon view + set toolbar visible of container window to false + set statusbar visible of container window to false + set the bounds of container window to {400, 100, 1040, 580} + set theViewOptions to the icon view options of container window + set arrangement of theViewOptions to not arranged + set icon size of theViewOptions to 72 + set background picture of theViewOptions to file ".background:background.tiff" + make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} + set position of item "'OpenRA - Tiberian Dawn.app'" of container window to {160, 106} + set position of item "'OpenRA - Red Alert.app'" of container window to {320, 106} + set position of item "'OpenRA - Dune 2000.app'" of container window to {480, 106} + set position of item "Applications" of container window to {320, 298} + set position of item ".background" of container window to {160, 298} + set position of item ".fseventsd" of container window to {160, 298} + set position of item ".VolumeIcon.icns" of container window to {160, 298} + update without registering applications + delay 5 + close + end tell + end tell + ' | osascript + + # HACK: Copy the volume icon again - something in the previous step seems to delete it...? + cp "${BUILTDIR}/OpenRA - Red Alert.app/Contents/Resources/ra.icns" "/Volumes/OpenRA/.VolumeIcon.icns" + SetFile -c icnC "/Volumes/OpenRA/.VolumeIcon.icns" + SetFile -a C "/Volumes/OpenRA" + + chmod -Rf go-w /Volumes/OpenRA + sync + sync -hdiutil detach "${DMG_DEVICE}" + hdiutil detach "${DMG_DEVICE}" + rm -rf "${BUILTDIR}" +} -# Submit for notarization -if [ -n "${MACOS_DEVELOPER_USERNAME}" ] && [ -n "${MACOS_DEVELOPER_PASSWORD}" ]; then - echo "Submitting disk image for notarization" +notarize_package() { + DMG_PATH="${1}" + NOTARIZE_DMG_PATH="${DMG_PATH%.*}"-notarization.dmg + echo "Submitting ${DMG_PATH} for notarization" # Reset xcode search path to fix xcrun not finding altool sudo xcode-select -r # Create a temporary read-only dmg for submission (notarization service rejects read/write images) - hdiutil convert build.dmg -format UDZO -imagekey zlib-level=9 -ov -o notarization.dmg + hdiutil convert "${DMG_PATH}" -format UDZO -imagekey zlib-level=9 -ov -o "${NOTARIZE_DMG_PATH}" - NOTARIZATION_UUID=$(xcrun altool --notarize-app --primary-bundle-id "net.openra.packaging" -u "${MACOS_DEVELOPER_USERNAME}" -p "${MACOS_DEVELOPER_PASSWORD}" --file notarization.dmg 2>&1 | awk -F' = ' '/RequestUUID/ { print $2; exit }') + NOTARIZATION_UUID=$(xcrun altool --notarize-app --primary-bundle-id "net.openra.packaging" -u "${MACOS_DEVELOPER_USERNAME}" -p "${MACOS_DEVELOPER_PASSWORD}" --file "${NOTARIZE_DMG_PATH}" 2>&1 | awk -F' = ' '/RequestUUID/ { print $2; exit }') if [ -z "${NOTARIZATION_UUID}" ]; then echo "Submission failed" exit 1 fi - echo "Submission UUID is ${NOTARIZATION_UUID}" - rm notarization.dmg + echo "${DMG_PATH} submission UUID is ${NOTARIZATION_UUID}" + rm "${NOTARIZE_DMG_PATH}" while :; do sleep 30 NOTARIZATION_RESULT=$(xcrun altool --notarization-info "${NOTARIZATION_UUID}" -u "${MACOS_DEVELOPER_USERNAME}" -p "${MACOS_DEVELOPER_PASSWORD}" 2>&1 | awk -F': ' '/Status/ { print $2; exit }') - echo "Submission status: ${NOTARIZATION_RESULT}" + echo "${DMG_PATH}: ${NOTARIZATION_RESULT}" if [ "${NOTARIZATION_RESULT}" == "invalid" ]; then NOTARIZATION_LOG_URL=$(xcrun altool --notarization-info "${NOTARIZATION_UUID}" -u "${MACOS_DEVELOPER_USERNAME}" -p "${MACOS_DEVELOPER_PASSWORD}" 2>&1 | awk -F': ' '/LogFileURL/ { print $2; exit }') - echo "Notarization failed with error:" + echo "${NOTARIZATION_UUID} failed notarization with error:" curl -s "${NOTARIZATION_LOG_URL}" -w "\n" exit 1 fi if [ "${NOTARIZATION_RESULT}" == "success" ]; then - echo "Stapling notarization tickets" - DMG_DEVICE=$(hdiutil attach -readwrite -noverify -noautoopen "build.dmg" | egrep '^/dev/' | sed 1q | awk '{print $1}') + echo "${DMG_PATH}: Stapling tickets" + DMG_DEVICE=$(hdiutil attach -readwrite -noverify -noautoopen "${DMG_PATH}" | egrep '^/dev/' | sed 1q | awk '{print $1}') sleep 2 xcrun stapler staple "/Volumes/OpenRA/OpenRA - Red Alert.app" @@ -212,9 +239,29 @@ break fi done +} + +finalize_package() { + INPUT_PATH="${1}" + OUTPUT_PATH="${2}" + + hdiutil convert "${INPUT_PATH}" -format UDZO -imagekey zlib-level=9 -ov -o "${OUTPUT_PATH}" + rm "${INPUT_PATH}" +} + +build_platform "standard" "build.dmg" +build_platform "compat" "build-compat.dmg" + +if [ -n "${MACOS_DEVELOPER_CERTIFICATE_BASE64}" ] && [ -n "${MACOS_DEVELOPER_CERTIFICATE_PASSWORD}" ] && [ -n "${MACOS_DEVELOPER_IDENTITY}" ]; then + security delete-keychain build.keychain fi -hdiutil convert build.dmg -format UDZO -imagekey zlib-level=9 -ov -o "${OUTPUTDIR}/OpenRA-${TAG}.dmg" +if [ -n "${MACOS_DEVELOPER_USERNAME}" ] && [ -n "${MACOS_DEVELOPER_PASSWORD}" ]; then + # Parallelize processing + (notarize_package "build.dmg") & + (notarize_package "build-compat.dmg") & + wait +fi -# Clean up -rm -rf "${BUILTDIR}" build.dmg +finalize_package "build.dmg" "${OUTPUTDIR}/OpenRA-${TAG}.dmg" +finalize_package "build-compat.dmg" "${OUTPUTDIR}/OpenRA-${TAG}-compat.dmg" Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/cnc.iconset/icon_128x128.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/cnc.iconset/icon_128x128.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/cnc.iconset/icon_16x16.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/cnc.iconset/icon_16x16.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/cnc.iconset/icon_256x256.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/cnc.iconset/icon_256x256.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/cnc.iconset/icon_32x32.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/cnc.iconset/icon_32x32.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/cnc.iconset/icon_512x512@2x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/cnc.iconset/icon_512x512@2x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/cnc.iconset/icon_512x512.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/cnc.iconset/icon_512x512.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/d2k.iconset/icon_128x128.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/d2k.iconset/icon_128x128.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/d2k.iconset/icon_16x16.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/d2k.iconset/icon_16x16.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/d2k.iconset/icon_256x256.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/d2k.iconset/icon_256x256.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/d2k.iconset/icon_32x32.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/d2k.iconset/icon_32x32.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/d2k.iconset/icon_512x512@2x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/d2k.iconset/icon_512x512@2x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/d2k.iconset/icon_512x512.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/d2k.iconset/icon_512x512.png differ diff -Nru openra-20200503/packaging/macos/Info.plist.in openra-20210321/packaging/macos/Info.plist.in --- openra-20200503/packaging/macos/Info.plist.in 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/macos/Info.plist.in 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,52 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDisplayName + {MOD_NAME} + CFBundleExecutable + OpenRA + CFBundleIconFile + {MOD_ID}.icns + CFBundleIdentifier + net.openra.mod.{MOD_ID} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + {MOD_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + {DEV_VERSION} + CFBundleSignature + ???? + CFBundleVersion + {DEV_VERSION} + LSMinimumSystemVersion + {MINIMUM_SYSTEM_VERSION} + NSPrincipalClass + NSApplication + CFBundleURLTypes + + + CFBundleURLName + OpenRA Server + CFBundleURLSchemes + + {JOIN_SERVER_URL_SCHEME} + {DISCORD_URL_SCHEME} + + + + ModId + {MOD_ID} + FaqUrl + {FAQ_URL} + JoinServerUrlScheme + {JOIN_SERVER_URL_SCHEME} + NSRequiresAquaSystemAppearance + + + diff -Nru openra-20200503/packaging/macos/launcher.m openra-20210321/packaging/macos/launcher.m --- openra-20200503/packaging/macos/launcher.m 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/macos/launcher.m 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,277 @@ +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ + +#import +#include + +@interface OpenRALauncher : NSObject +- (void)launchGameWithArgs: (NSArray *)gameArgs; +@end + +@implementation OpenRALauncher + +BOOL launched = NO; +NSTask *gameTask; + +- (NSString *)modName +{ + NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; + if (plist) + { + NSString *title = [plist objectForKey:@"CFBundleDisplayName"]; + if (title && [title length] > 0) + return title; + } + + return @"OpenRA"; +} + +- (void)showCrashPrompt +{ + NSString *modName = [self modName]; + NSString *message = [NSString stringWithFormat: @"%@ has encountered a fatal error and must close.\nPlease refer to the crash logs and FAQ for more information.", modName]; + + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Fatal Error"]; + [alert setInformativeText:message]; + [alert addButtonWithTitle:@"View Logs"]; + [alert addButtonWithTitle:@"View FAQ"]; + [alert addButtonWithTitle:@"Quit"]; + + NSInteger answer = [alert runModal]; + [alert release]; + + if (answer == NSAlertFirstButtonReturn) + { + NSString *logDir = [@"~/Library/Application Support/OpenRA/Logs/" stringByExpandingTildeInPath]; + [[NSWorkspace sharedWorkspace] openFile: logDir withApplication:@"Finder"]; + } + else if (answer == NSAlertSecondButtonReturn) + { + NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; + if (plist) + { + NSString *faqUrl = [plist objectForKey:@"FaqUrl"]; + if (faqUrl && [faqUrl length] > 0) + [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:faqUrl]]; + } + } +} + +// Application was launched via a URL handler +- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent +{ + NSMutableArray *gameArgs = [[[NSProcessInfo processInfo] arguments] mutableCopy]; + NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; + NSString *url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + + if (plist) + { + NSString *joinServerUrl = [plist objectForKey:@"JoinServerUrlScheme"]; + if (joinServerUrl && [joinServerUrl length] > 0) + { + NSString *prefix = [joinServerUrl stringByAppendingString: @"://"]; + if ([url hasPrefix: prefix]) + { + NSString *trimmed = [url substringFromIndex:[prefix length]]; + NSArray *parts = [trimmed componentsSeparatedByString:@":"]; + NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; + + if ([parts count] == 2 && [formatter numberFromString: [parts objectAtIndex:1]] != nil) + [gameArgs addObject: [NSString stringWithFormat: @"Launch.Connect=%@", trimmed]]; + + [formatter release]; + } + } + } + + [self launchGameWithArgs: gameArgs]; + [gameArgs release]; +} + +- (void)applicationWillFinishLaunching:(NSNotification *)aNotification +{ + // Register for url events + NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; + if (plist) + { + NSString *joinServerUrl = [plist objectForKey:@"JoinServerUrlScheme"]; + NSString *bundleIdentifier = [plist objectForKey:@"CFBundleIdentifier"]; + if (joinServerUrl && [joinServerUrl length] > 0 && bundleIdentifier) + { + LSSetDefaultHandlerForURLScheme((CFStringRef)joinServerUrl, (CFStringRef)bundleIdentifier); + [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(getUrl:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; + } + } +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + [self launchGameWithArgs: [[NSProcessInfo processInfo] arguments]]; +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed: (NSApplication *)theApplication +{ + return YES; +} + +- (void)launchGameWithArgs: (NSArray *)gameArgs +{ + if (launched) + { + NSLog(@"launchgame is already running... ignoring request."); + return; + } + + launched = YES; + + // Default values - can be overriden by setting certain keys Info.plist + NSString *gameName = @"OpenRA.exe"; + NSString *modId = nil; + + NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; + if (plist) + { + NSString *exeValue = [plist objectForKey:@"MonoGameExe"]; + if (exeValue && [exeValue length] > 0) + gameName = exeValue; + + NSString *modIdValue = [plist objectForKey:@"ModId"]; + if (modIdValue && [modIdValue length] > 0) + modId = modIdValue; + } + + NSString *exePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: @"Contents/MacOS/"]; + NSString *gamePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: @"Contents/Resources/"]; + + NSString *launchPath = [exePath stringByAppendingPathComponent: @"mono"]; + NSString *appPath = [exePath stringByAppendingPathComponent: @"OpenRA"]; + NSString *engineLaunchPath = [self resolveTranslocatedPath: appPath]; + + NSMutableArray *launchArgs = [NSMutableArray arrayWithCapacity: [gameArgs count] + 2]; + [launchArgs addObject: @"--debug"]; + [launchArgs addObject: [gamePath stringByAppendingPathComponent: gameName]]; + [launchArgs addObject: [NSString stringWithFormat:@"Engine.LaunchPath=\"%@\"", engineLaunchPath]]; + + if (modId) + [launchArgs addObject: [NSString stringWithFormat:@"Game.Mod=%@", modId]]; + + [launchArgs addObjectsFromArray: gameArgs]; + + NSLog(@"Running mono with arguments:"); + for (size_t i = 0; i < [launchArgs count]; i++) + NSLog(@"%@", [launchArgs objectAtIndex: i]); + + gameTask = [[NSTask alloc] init]; + [gameTask setCurrentDirectoryPath: gamePath]; + [gameTask setLaunchPath: launchPath]; + [gameTask setArguments: launchArgs]; + + NSMutableDictionary *environment = [NSMutableDictionary dictionaryWithDictionary: [[NSProcessInfo processInfo] environment]]; + [environment setObject: [gamePath stringByAppendingPathComponent: @"lib/mono/4.5"] forKey: @"MONO_PATH"]; + [environment setObject: [gamePath stringByAppendingPathComponent: @"etc"] forKey: @"MONO_CFG_DIR"]; + [environment setObject: [gamePath stringByAppendingPathComponent: @"etc/mono/config"] forKey: @"MONO_CONFIG"]; + [gameTask setEnvironment: environment]; + + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(taskExited:) + name: NSTaskDidTerminateNotification + object: gameTask + ]; + + [gameTask launch]; +} + +- (NSString *)resolveTranslocatedPath: (NSString *)path +{ + // macOS 10.12 introduced the "App Translocation" feature, which runs quarantined applications + // from a transient read-only disk image. The read-only image isn't a problem, but the transient + // path breaks the mod registration/switching feature. + // This resolves the original path which can then be written into the mod metadata for future + // launches (which will then be re-translocated) + + // Running on macOS < 10.12 + if (floor(NSAppKitVersionNumber) <= 1404) + return path; + + void *handle = dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY); + + // Failed to load security framework + if (handle == NULL) + return path; + + Boolean (*mySecTranslocateIsTranslocatedURL)(CFURLRef path, bool *isTranslocated, CFErrorRef * __nullable error); + mySecTranslocateIsTranslocatedURL = dlsym(handle, "SecTranslocateIsTranslocatedURL"); + + CFURLRef __nullable (*mySecTranslocateCreateOriginalPathForURL)(CFURLRef translocatedPath, CFErrorRef * __nullable error); + mySecTranslocateCreateOriginalPathForURL = dlsym(handle, "SecTranslocateCreateOriginalPathForURL"); + + // Failed to resolve required functions + if (mySecTranslocateIsTranslocatedURL == NULL || mySecTranslocateCreateOriginalPathForURL == NULL) + return path; + + bool isTranslocated = false; + CFURLRef pathURLRef = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)path, kCFURLPOSIXPathStyle, false); + + if (mySecTranslocateIsTranslocatedURL(pathURLRef, &isTranslocated, NULL)) + { + if (isTranslocated) + { + CFURLRef resolvedURL = mySecTranslocateCreateOriginalPathForURL(pathURLRef, NULL); + path = [(NSURL *)(resolvedURL) path]; + } + } + + CFRelease(pathURLRef); + return path; +} + +- (void)taskExited:(NSNotification *)note +{ + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:NSTaskDidTerminateNotification + object:gameTask + ]; + + int ret = [gameTask terminationStatus]; + + NSLog(@"launchgame exited with code %d", ret); + [gameTask release]; + gameTask = nil; + + // We're done here + if (ret == 0) + exit(0); + + // Make the error dialog visible + [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular]; + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; + [self showCrashPrompt]; + + exit(1); +} + +@end + +int main(int argc, char **argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSApplication *application = [NSApplication sharedApplication]; + OpenRALauncher *launcher = [[OpenRALauncher alloc] init]; + [NSApp setActivationPolicy: NSApplicationActivationPolicyProhibited]; + + [application setDelegate:launcher]; + [application run]; + + [launcher release]; + [pool drain]; + + return EXIT_SUCCESS; +} diff -Nru openra-20200503/packaging/macos/launcher-mono.m openra-20210321/packaging/macos/launcher-mono.m --- openra-20200503/packaging/macos/launcher-mono.m 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/macos/launcher-mono.m 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,372 @@ +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ + +#import +#include + +#define SYSTEM_MONO_PATH @"/Library/Frameworks/Mono.framework/Versions/Current/" +#define SYSTEM_MONO_MIN_VERSION @"6.4" + +typedef int (* mono_main)(int argc, char **argv); +typedef void (* mono_free)(void *ptr); +typedef char *(* mono_get_runtime_build_info)(void); + +@interface OpenRALauncher : NSObject +- (void)launchGameWithArgs: (NSArray *)gameArgs; +@end + +@implementation OpenRALauncher + +BOOL launched = NO; +NSTask *gameTask; + +static int check_mono_version(const char *version, const char *req_version) +{ + char *req_end, *end; + long req_val, val; + + while (*req_version) + { + req_val = strtol(req_version, &req_end, 10); + if (req_version == req_end || (*req_end && *req_end != '.')) + { + fprintf(stderr, "Bad version requirement string '%s'\n", req_end); + return FALSE; + } + + req_version = req_end; + if (*req_version) + req_version++; + + val = strtol (version, &end, 10); + if (version == end || val < req_val) + return FALSE; + + if (val > req_val) + return TRUE; + + if (*req_version == '.' && *end != '.') + return FALSE; + + version = end + 1; + } + + return TRUE; +} + +- (int)hasValidMono +{ + void *libmono = dlopen([[SYSTEM_MONO_PATH stringByAppendingPathComponent: @"/lib/libmonosgen-2.0.dylib"] UTF8String], RTLD_LAZY); + + if (libmono == NULL) + { + fprintf (stderr, "Failed to load libmonosgen-2.0.dylib: %s\n", dlerror()); + return FALSE; + } + + mono_main _mono_main = (mono_main)dlsym(libmono, "mono_main"); + if (!_mono_main) + { + fprintf(stderr, "Could not load mono_main(): %s\n", dlerror()); + return FALSE; + } + + mono_free _mono_free = (mono_free)dlsym(libmono, "mono_free"); + if (!_mono_free) + { + fprintf(stderr, "Could not load mono_free(): %s\n", dlerror()); + return FALSE; + } + + mono_get_runtime_build_info _mono_get_runtime_build_info = (mono_get_runtime_build_info)dlsym(libmono, "mono_get_runtime_build_info"); + if (!_mono_get_runtime_build_info) + { + fprintf(stderr, "Could not load mono_get_runtime_build_info(): %s\n", dlerror()); + return FALSE; + } + + char *mono_version = _mono_get_runtime_build_info(); + return check_mono_version(mono_version, [SYSTEM_MONO_MIN_VERSION UTF8String]); +} + +- (NSString *)modName +{ + NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; + if (plist) + { + NSString *title = [plist objectForKey:@"CFBundleDisplayName"]; + if (title && [title length] > 0) + return title; + } + + return @"OpenRA"; +} + +- (void)exitWithMonoPrompt +{ + [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular]; + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; + + NSString *modName = [self modName]; + NSString *title = [NSString stringWithFormat: @"Cannot launch %@", modName]; + NSString *message = [NSString stringWithFormat: @"%@ requires Mono %@ or later. Please install Mono and try again.", modName, SYSTEM_MONO_MIN_VERSION]; + + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:title]; + [alert setInformativeText:message]; + [alert addButtonWithTitle:@"Download Mono"]; + [alert addButtonWithTitle:@"Quit"]; + NSInteger answer = [alert runModal]; + [alert release]; + + if (answer == NSAlertFirstButtonReturn) + [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:@"https://www.mono-project.com/download/"]]; + + exit(1); +} + +- (void)exitWithCrashPrompt +{ + [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular]; + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; + + NSString *modName = [self modName]; + NSString *message = [NSString stringWithFormat: @"%@ has encountered a fatal error and must close.\nPlease refer to the crash logs and FAQ for more information.", modName]; + + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Fatal Error"]; + [alert setInformativeText:message]; + [alert addButtonWithTitle:@"View Logs"]; + [alert addButtonWithTitle:@"View FAQ"]; + [alert addButtonWithTitle:@"Quit"]; + + NSInteger answer = [alert runModal]; + [alert release]; + + if (answer == NSAlertFirstButtonReturn) + { + NSString *logDir = [@"~/Library/Application Support/OpenRA/Logs/" stringByExpandingTildeInPath]; + [[NSWorkspace sharedWorkspace] openFile: logDir withApplication:@"Finder"]; + } + else if (answer == NSAlertSecondButtonReturn) + { + NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; + if (plist) + { + NSString *faqUrl = [plist objectForKey:@"FaqUrl"]; + if (faqUrl && [faqUrl length] > 0) + [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:faqUrl]]; + } + } + + exit(1); +} + +// Application was launched via a URL handler +- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent +{ + NSMutableArray *gameArgs = [[[NSProcessInfo processInfo] arguments] mutableCopy]; + NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; + NSString *url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + + if (plist) + { + NSString *joinServerUrl = [plist objectForKey:@"JoinServerUrlScheme"]; + if (joinServerUrl && [joinServerUrl length] > 0) + { + NSString *prefix = [joinServerUrl stringByAppendingString: @"://"]; + if ([url hasPrefix: prefix]) + { + NSString *trimmed = [url substringFromIndex:[prefix length]]; + NSArray *parts = [trimmed componentsSeparatedByString:@":"]; + NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; + + if ([parts count] == 2 && [formatter numberFromString: [parts objectAtIndex:1]] != nil) + [gameArgs addObject: [NSString stringWithFormat: @"Launch.Connect=%@", trimmed]]; + + [formatter release]; + } + } + } + + [self launchGameWithArgs: gameArgs]; + [gameArgs release]; +} + +- (void)applicationWillFinishLaunching:(NSNotification *)aNotification +{ + // Register for url events + NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; + if (plist) + { + NSString *joinServerUrl = [plist objectForKey:@"JoinServerUrlScheme"]; + NSString *bundleIdentifier = [plist objectForKey:@"CFBundleIdentifier"]; + if (joinServerUrl && [joinServerUrl length] > 0 && bundleIdentifier) + { + LSSetDefaultHandlerForURLScheme((CFStringRef)joinServerUrl, (CFStringRef)bundleIdentifier); + [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(getUrl:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; + } + } +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + [self launchGameWithArgs: [[NSProcessInfo processInfo] arguments]]; +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed: (NSApplication *)theApplication +{ + return YES; +} + +- (void)launchGameWithArgs: (NSArray *)gameArgs +{ + if (launched) + { + NSLog(@"launchgame is already running... ignoring request."); + return; + } + + launched = YES; + + if (![self hasValidMono]) + [self exitWithMonoPrompt]; + + // Default values - can be overriden by setting certain keys Info.plist + NSString *gameName = @"OpenRA.exe"; + NSString *modId = nil; + + NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; + if (plist) + { + NSString *exeValue = [plist objectForKey:@"MonoGameExe"]; + if (exeValue && [exeValue length] > 0) + gameName = exeValue; + + NSString *modIdValue = [plist objectForKey:@"ModId"]; + if (modIdValue && [modIdValue length] > 0) + modId = modIdValue; + } + + NSString *exePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: @"Contents/MacOS/"]; + NSString *gamePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: @"Contents/Resources/"]; + + NSString *launchPath = [SYSTEM_MONO_PATH stringByAppendingPathComponent: @"Commands/mono"]; + NSString *appPath = [exePath stringByAppendingPathComponent: @"OpenRA"]; + NSString *engineLaunchPath = [self resolveTranslocatedPath: appPath]; + + NSMutableArray *launchArgs = [NSMutableArray arrayWithCapacity: [gameArgs count] + 2]; + [launchArgs addObject: @"--debug"]; + [launchArgs addObject: [gamePath stringByAppendingPathComponent: gameName]]; + [launchArgs addObject: [NSString stringWithFormat:@"Engine.LaunchPath=\"%@\"", engineLaunchPath]]; + + if (modId) + [launchArgs addObject: [NSString stringWithFormat:@"Game.Mod=%@", modId]]; + + [launchArgs addObjectsFromArray: gameArgs]; + + NSLog(@"Running launchgame with arguments:"); + for (size_t i = 0; i < [launchArgs count]; i++) + NSLog(@"%@", [launchArgs objectAtIndex: i]); + + gameTask = [[NSTask alloc] init]; + [gameTask setCurrentDirectoryPath: gamePath]; + [gameTask setLaunchPath: launchPath]; + [gameTask setArguments: launchArgs]; + + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(taskExited:) + name: NSTaskDidTerminateNotification + object: gameTask + ]; + + [gameTask launch]; +} + +- (NSString *)resolveTranslocatedPath: (NSString *)path +{ + // macOS 10.12 introduced the "App Translocation" feature, which runs quarantined applications + // from a transient read-only disk image. The read-only image isn't a problem, but the transient + // path breaks the mod registration/switching feature. + // This resolves the original path which can then be written into the mod metadata for future + // launches (which will then be re-translocated) + + // Running on macOS < 10.12 + if (floor(NSAppKitVersionNumber) <= 1404) + return path; + + void *handle = dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY); + + // Failed to load security framework + if (handle == NULL) + return path; + + Boolean (*mySecTranslocateIsTranslocatedURL)(CFURLRef path, bool *isTranslocated, CFErrorRef * __nullable error); + mySecTranslocateIsTranslocatedURL = dlsym(handle, "SecTranslocateIsTranslocatedURL"); + + CFURLRef __nullable (*mySecTranslocateCreateOriginalPathForURL)(CFURLRef translocatedPath, CFErrorRef * __nullable error); + mySecTranslocateCreateOriginalPathForURL = dlsym(handle, "SecTranslocateCreateOriginalPathForURL"); + + // Failed to resolve required functions + if (mySecTranslocateIsTranslocatedURL == NULL || mySecTranslocateCreateOriginalPathForURL == NULL) + return path; + + bool isTranslocated = false; + CFURLRef pathURLRef = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)path, kCFURLPOSIXPathStyle, false); + + if (mySecTranslocateIsTranslocatedURL(pathURLRef, &isTranslocated, NULL)) + { + if (isTranslocated) + { + CFURLRef resolvedURL = mySecTranslocateCreateOriginalPathForURL(pathURLRef, NULL); + path = [(NSURL *)(resolvedURL) path]; + } + } + + CFRelease(pathURLRef); + return path; +} + +- (void)taskExited:(NSNotification *)note +{ + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:NSTaskDidTerminateNotification + object:gameTask + ]; + + int ret = [gameTask terminationStatus]; + NSLog(@"launchgame exited with code %d", ret); + [gameTask release]; + gameTask = nil; + + // We're done here + if (ret != 0) + [self exitWithCrashPrompt]; + + exit(0); +} + +@end + +int main(int argc, char **argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSApplication *application = [NSApplication sharedApplication]; + OpenRALauncher *launcher = [[OpenRALauncher alloc] init]; + [NSApp setActivationPolicy: NSApplicationActivationPolicyProhibited]; + + [application setDelegate:launcher]; + [application run]; + + [launcher release]; + [pool drain]; + + return EXIT_SUCCESS; +} Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/ra.iconset/icon_128x128.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/ra.iconset/icon_128x128.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/ra.iconset/icon_16x16.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/ra.iconset/icon_16x16.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/ra.iconset/icon_256x256.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/ra.iconset/icon_256x256.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/ra.iconset/icon_32x32.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/ra.iconset/icon_32x32.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/ra.iconset/icon_512x512@2x.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/ra.iconset/icon_512x512@2x.png differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/macos/ra.iconset/icon_512x512.png and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/macos/ra.iconset/icon_512x512.png differ diff -Nru openra-20200503/packaging/package-all.sh openra-20210321/packaging/package-all.sh --- openra-20200503/packaging/package-all.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/package-all.sh 2021-03-21 11:10:05.000000000 +0000 @@ -2,8 +2,8 @@ # OpenRA master packaging script if [ $# -ne "2" ]; then - echo "Usage: ${0##*/} version outputdir." - exit 1 + echo "Usage: ${0##*/} version outputdir." + exit 1 fi export GIT_TAG="$1" @@ -14,15 +14,15 @@ #build packages using a subshell so directory changes do not persist beyond the function function build_package() ( - function on_build() { - echo "$1 package build failed." 1>&2 - } - #trap function executes on any error in the following commands - trap "on_build $1" ERR - set -e - echo "Building $1 package(s)." - cd "$1" - ./buildpackage.sh "${GIT_TAG}" "${BUILD_OUTPUT_DIR}" + function on_build() { + echo "$1 package build failed." 1>&2 + } + #trap function executes on any error in the following commands + trap "on_build $1" ERR + set -e + echo "Building $1 package(s)." + cd "$1" + ./buildpackage.sh "${GIT_TAG}" "${BUILD_OUTPUT_DIR}" ) #exit on any non-zero exited (failed) command diff -Nru openra-20200503/packaging/source/buildpackage.sh openra-20210321/packaging/source/buildpackage.sh --- openra-20200503/packaging/source/buildpackage.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/source/buildpackage.sh 2021-03-21 11:10:05.000000000 +0000 @@ -2,8 +2,8 @@ # OpenRA packaging script for versioned source tarball if [ $# -ne "2" ]; then - echo "Usage: $(basename "$0") tag outputdir" - exit 1 + echo "Usage: $(basename "$0") tag outputdir" + exit 1 fi # Set the working dir to the location of this script Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/ssh.enc and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/ssh.enc differ diff -Nru openra-20200503/packaging/update-wiki.sh openra-20210321/packaging/update-wiki.sh --- openra-20200503/packaging/update-wiki.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/update-wiki.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -#!/bin/bash - -case "$1" in - bleed) - exit - ;; - next | playtest-*) - TAG=" (playtest)" - ;; - master | release-*) - TAG="" - ;; - *) - echo "Unknown branch: $1" - exit - ;; -esac - -echo "Updating https://github.com/OpenRA/OpenRA/wiki/" - -SSH_KEY="$HOME"/.ssh/id_rsa - -mkdir -p "$(dirname "$SSH_KEY")" -openssl aes-256-cbc -k "$KEY" -in ssh.enc -d -out "$SSH_KEY" -chmod 0600 "$SSH_KEY" - -rm -rf "$HOME/openra-wiki" -git clone git@github.com:OpenRA/OpenRA.wiki.git "$HOME/openra-wiki" - -mono --debug ../OpenRA.Utility.exe all --docs "$1" > "${HOME}/openra-wiki/Traits${TAG}.md" -mono --debug ../OpenRA.Utility.exe all --weapon-docs "$1" > "${HOME}/openra-wiki/Weapons${TAG}.md" -mono --debug ../OpenRA.Utility.exe all --lua-docs "$1" > "${HOME}/openra-wiki/Lua API${TAG}.md" -mono --debug ../OpenRA.Utility.exe all --settings-docs "$1" > "${HOME}/openra-wiki/Settings${TAG}.md" - -pushd "$HOME/openra-wiki" || exit 1 -git config --local user.email "orabot@users.noreply.github.com" -git config --local user.name "orabot" -git add "Traits${TAG}.md" -git add "Lua API${TAG}.md" -git add "Weapons${TAG}.md" -git add "Settings${TAG}.md" -git commit -m "Update trait and scripting documentation for branch $1" && -git push origin master -popd || exit - -shred -u "$SSH_KEY" diff -Nru openra-20200503/packaging/windows/buildpackage.sh openra-20210321/packaging/windows/buildpackage.sh --- openra-20200503/packaging/windows/buildpackage.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/windows/buildpackage.sh 2021-03-21 11:10:05.000000000 +0000 @@ -1,8 +1,12 @@ #!/bin/bash +# OpenRA packaging script for Windows + +set -e command -v curl >/dev/null 2>&1 || { echo >&2 "Windows packaging requires curl."; exit 1; } -command -v markdown >/dev/null 2>&1 || { echo >&2 "Windows packaging requires markdown."; exit 1; } command -v makensis >/dev/null 2>&1 || { echo >&2 "Windows packaging requires makensis."; exit 1; } +command -v convert >/dev/null 2>&1 || { echo >&2 "Windows packaging requires ImageMagick."; exit 1; } +command -v python3 >/dev/null 2>&1 || { echo >&2 "Windows packaging requires python 3."; exit 1; } if [ $# -ne "2" ]; then echo "Usage: $(basename "$0") tag outputdir" @@ -11,14 +15,15 @@ # Set the working dir to the location of this script cd "$(dirname "$0")" || exit 1 +. ../functions.sh TAG="$1" OUTPUTDIR="$2" SRCDIR="$(pwd)/../.." BUILTDIR="$(pwd)/build" +ARTWORK_DIR="$(pwd)/../artwork/" -LAUNCHER_LIBS="-r:System.dll -r:System.Drawing.dll -r:System.Windows.Forms.dll -r:${BUILTDIR}/OpenRA.Game.exe" -FAQ_URL="http://wiki.openra.net/FAQ" +FAQ_URL="https://wiki.openra.net/FAQ" SUFFIX=" (dev)" if [[ ${TAG} == release* ]]; then @@ -29,54 +34,44 @@ function makelauncher() { - sed "s|DISPLAY_NAME|$2|" WindowsLauncher.cs.in | sed "s|MOD_ID|$3|" | sed "s|FAQ_URL|${FAQ_URL}|" > WindowsLauncher.cs - csc WindowsLauncher.cs -warn:4 -warnaserror -platform:"$5" -out:"$1" -t:winexe ${LAUNCHER_LIBS} -win32icon:"$4" - rm WindowsLauncher.cs - mono "${SRCDIR}/OpenRA.PostProcess.exe" "$1" -LAA > /dev/null + LAUNCHER_NAME="${1}" + DISPLAY_NAME="${2}" + MOD_ID="${3}" + PLATFORM="${4}" + + convert "${ARTWORK_DIR}/${MOD_ID}_16x16.png" "${ARTWORK_DIR}/${MOD_ID}_24x24.png" "${ARTWORK_DIR}/${MOD_ID}_32x32.png" "${ARTWORK_DIR}/${MOD_ID}_48x48.png" "${ARTWORK_DIR}/${MOD_ID}_256x256.png" "${BUILTDIR}/${MOD_ID}.ico" + install_windows_launcher "${SRCDIR}" "${BUILTDIR}" "win-${PLATFORM}" "${MOD_ID}" "${LAUNCHER_NAME}" "${DISPLAY_NAME}" "${BUILTDIR}/${MOD_ID}.ico" "${FAQ_URL}" } function build_platform() { - echo "Building core files ($1)" - if [ "$1" = "x86" ]; then - IS_WIN32="WIN32=true" + PLATFORM="${1}" + + echo "Building core files (${PLATFORM})" + if [ "${PLATFORM}" = "x86" ]; then USE_PROGRAMFILES32="-DUSE_PROGRAMFILES32=true" else - IS_WIN32="WIN32=false" USE_PROGRAMFILES32="" fi - pushd "${SRCDIR}" > /dev/null || exit 1 - make clean - make windows-dependencies "${IS_WIN32}" - make core "${IS_WIN32}" - make version VERSION="${TAG}" - make install-core gameinstalldir="" DESTDIR="${BUILTDIR}" - popd > /dev/null || exit 1 - - echo "Compiling Windows launchers ($1)" - makelauncher "${BUILTDIR}/RedAlert.exe" "Red Alert" "ra" RedAlert.ico $1 - makelauncher "${BUILTDIR}/TiberianDawn.exe" "Tiberian Dawn" "cnc" TiberianDawn.ico $1 - makelauncher "${BUILTDIR}/Dune2000.exe" "Dune 2000" "d2k" Dune2000.ico $1 - - # Windows specific files - cp OpenRA.ico RedAlert.ico TiberianDawn.ico Dune2000.ico "${BUILTDIR}" - cp "${SRCDIR}/OpenRA.Game.exe.config" "${BUILTDIR}" - - curl -s -L -O https://raw.githubusercontent.com/wiki/OpenRA/OpenRA/Changelog.md - markdown Changelog.md > "${BUILTDIR}/CHANGELOG.html" - rm Changelog.md - - markdown "${SRCDIR}/README.md" > "${BUILTDIR}/README.html" - markdown "${SRCDIR}/CONTRIBUTING.md" > "${BUILTDIR}/CONTRIBUTING.html" + install_assemblies_mono "${SRCDIR}" "${BUILTDIR}" "win-${PLATFORM}" "False" "True" "True" + install_data "${SRCDIR}" "${BUILTDIR}" "cnc" "d2k" "ra" + set_engine_version "${TAG}" "${BUILTDIR}" + set_mod_version "${TAG}" "${BUILTDIR}/mods/cnc/mod.yaml" "${BUILTDIR}/mods/d2k/mod.yaml" "${BUILTDIR}/mods/ra/mod.yaml" "${BUILTDIR}/mods/modcontent/mod.yaml" + + echo "Compiling Windows launchers (${PLATFORM})" + makelauncher "RedAlert" "Red Alert" "ra" "${PLATFORM}" + makelauncher "TiberianDawn" "Tiberian Dawn" "cnc" "${PLATFORM}" + makelauncher "Dune2000" "Dune 2000" "d2k" "${PLATFORM}" echo "Building Windows setup.exe ($1)" - makensis -V2 -DSRCDIR="${BUILTDIR}" -DDEPSDIR="${SRCDIR}/thirdparty/download/windows" -DTAG="${TAG}" -DSUFFIX="${SUFFIX}" ${USE_PROGRAMFILES32} OpenRA.nsi - if [ $? -eq 0 ]; then - mv OpenRA.Setup.exe "${OUTPUTDIR}/OpenRA-$TAG-$1.exe" - else - exit 1 - fi + makensis -V2 -DSRCDIR="${BUILTDIR}" -DTAG="${TAG}" -DSUFFIX="${SUFFIX}" -DOUTFILE="${OUTPUTDIR}/OpenRA-${TAG}-${PLATFORM}.exe" ${USE_PROGRAMFILES32} OpenRA.nsi || exit 1 + + echo "Packaging zip archive ($1)" + pushd "${BUILTDIR}" > /dev/null + zip "OpenRA-${TAG}-${PLATFORM}-winportable.zip" -r -9 * --quiet + mv "OpenRA-${TAG}-${PLATFORM}-winportable.zip" "${OUTPUTDIR}" + popd > /dev/null rm -rf "${BUILTDIR}" } Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/windows/Dune2000.ico and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/windows/Dune2000.ico differ diff -Nru openra-20200503/packaging/windows/MakeLAA.py openra-20210321/packaging/windows/MakeLAA.py --- openra-20200503/packaging/windows/MakeLAA.py 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/packaging/windows/MakeLAA.py 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,19 @@ +# Copyright 2007-2020 The OpenRA Developers (see AUTHORS) +# This file is part of OpenRA, which is free software. It is made +# available to you under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. For more +# information, see COPYING. + +import struct +import sys + +if __name__ == "__main__": + print(sys.argv[1] + ': Enabling /LARGEADDRESSAWARE') + with open(sys.argv[1], 'r+b') as assembly: + assembly.seek(0x3c) + peOffset = struct.unpack('i', assembly.read(4))[0] + assembly.seek(peOffset + 4 + 18) + flags = struct.unpack('B', assembly.read(1))[0] | 0x20 + assembly.seek(peOffset + 4 + 18) + assembly.write(struct.pack('B', flags)) Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/windows/OpenRA.ico and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/windows/OpenRA.ico differ diff -Nru openra-20200503/packaging/windows/OpenRA.nsi openra-20210321/packaging/windows/OpenRA.nsi --- openra-20200503/packaging/windows/OpenRA.nsi 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/windows/OpenRA.nsi 2021-03-21 11:10:05.000000000 +0000 @@ -19,10 +19,12 @@ !include "WordFunc.nsh" Name "OpenRA" -OutFile "OpenRA.Setup.exe" +OutFile "${OUTFILE}" ManifestDPIAware true +Unicode True + Function .onInit !ifndef USE_PROGRAMFILES32 SetRegView 64 @@ -62,6 +64,10 @@ !insertmacro MUI_LANGUAGE "English" +!define RA_DISCORDID 699222659766026240 +!define CNC_DISCORDID 699223250181292033 +!define D2K_DISCORDID 712711732770111550 + ;*************************** ;Section Definitions ;*************************** @@ -73,19 +79,34 @@ ; Join server URL Scheme WriteRegStr HKLM "Software\Classes\openra-ra-${TAG}" "" "URL:Join OpenRA server" WriteRegStr HKLM "Software\Classes\openra-ra-${TAG}" "URL Protocol" "" - WriteRegStr HKLM "Software\Classes\openra-ra-${TAG}\DefaultIcon" "" "$INSTDIR\RedAlert.ico,0" + WriteRegStr HKLM "Software\Classes\openra-ra-${TAG}\DefaultIcon" "" "$INSTDIR\ra.ico,0" WriteRegStr HKLM "Software\Classes\openra-ra-${TAG}\Shell\Open\Command" "" "$INSTDIR\RedAlert.exe Launch.URI=%1" + WriteRegStr HKLM "Software\Classes\discord-${RA_DISCORDID}" "" "URL:Run game ${RA_DISCORDID} protocol" + WriteRegStr HKLM "Software\Classes\discord-${RA_DISCORDID}" "URL Protocol" "" + WriteRegStr HKLM "Software\Classes\discord-${RA_DISCORDID}\DefaultIcon" "" "$INSTDIR\ra.ico,0" + WriteRegStr HKLM "Software\Classes\discord-${RA_DISCORDID}\Shell\Open\Command" "" "$INSTDIR\RedAlert.exe" + WriteRegStr HKLM "Software\Classes\openra-cnc-${TAG}" "" "URL:Join OpenRA server" WriteRegStr HKLM "Software\Classes\openra-cnc-${TAG}" "URL Protocol" "" - WriteRegStr HKLM "Software\Classes\openra-cnc-${TAG}\DefaultIcon" "" "$INSTDIR\TiberianDawn.ico,0" + WriteRegStr HKLM "Software\Classes\openra-cnc-${TAG}\DefaultIcon" "" "$INSTDIR\cnc.ico,0" WriteRegStr HKLM "Software\Classes\openra-cnc-${TAG}\Shell\Open\Command" "" "$INSTDIR\TiberianDawn.exe Launch.URI=%1" + WriteRegStr HKLM "Software\Classes\discord-${CNC_DISCORDID}" "" "URL:Run game ${CNC_DISCORDID} protocol" + WriteRegStr HKLM "Software\Classes\discord-${CNC_DISCORDID}" "URL Protocol" "" + WriteRegStr HKLM "Software\Classes\discord-${CNC_DISCORDID}\DefaultIcon" "" "$INSTDIR\cnc.ico,0" + WriteRegStr HKLM "Software\Classes\discord-${CNC_DISCORDID}\Shell\Open\Command" "" "$INSTDIR\TiberianDawn.exe" + WriteRegStr HKLM "Software\Classes\openra-d2k-${TAG}" "" "URL:Join OpenRA server" WriteRegStr HKLM "Software\Classes\openra-d2k-${TAG}" "URL Protocol" "" - WriteRegStr HKLM "Software\Classes\openra-d2k-${TAG}\DefaultIcon" "" "$INSTDIR\Dune2000.ico,0" + WriteRegStr HKLM "Software\Classes\openra-d2k-${TAG}\DefaultIcon" "" "$INSTDIR\d2k.ico,0" WriteRegStr HKLM "Software\Classes\openra-d2k-${TAG}\Shell\Open\Command" "" "$INSTDIR\Dune2000.exe Launch.URI=%1" + WriteRegStr HKLM "Software\Classes\discord-${D2K_DISCORDID}" "" "URL:Run game ${D2K_DISCORDID} protocol" + WriteRegStr HKLM "Software\Classes\discord-${D2K_DISCORDID}" "URL Protocol" "" + WriteRegStr HKLM "Software\Classes\discord-${D2K_DISCORDID}\DefaultIcon" "" "$INSTDIR\d2k.ico,0" + WriteRegStr HKLM "Software\Classes\discord-${D2K_DISCORDID}\Shell\Open\Command" "" "$INSTDIR\Dune2000.exe" + ; Remove obsolete file associations DeleteRegKey HKLM "Software\Classes\.orarep" DeleteRegKey HKLM "Software\Classes\OpenRA_replay" @@ -107,37 +128,15 @@ File /r "${SRCDIR}\mods\modcontent" SetOutPath "$INSTDIR" - File "${SRCDIR}\RedAlert.exe" - File "${SRCDIR}\TiberianDawn.exe" - File "${SRCDIR}\Dune2000.exe" - File "${SRCDIR}\OpenRA.Game.exe" - File "${SRCDIR}\OpenRA.Game.exe.config" - File "${SRCDIR}\OpenRA.Utility.exe" - File "${SRCDIR}\OpenRA.Server.exe" - File "${SRCDIR}\OpenRA.Platforms.Default.dll" - File "${SRCDIR}\ICSharpCode.SharpZipLib.dll" - File "${SRCDIR}\FuzzyLogicLibrary.dll" - File "${SRCDIR}\Open.Nat.dll" + File "${SRCDIR}\*.exe" + File "${SRCDIR}\*.exe.config" + File "${SRCDIR}\*.dll" + File "${SRCDIR}\*.ico" File "${SRCDIR}\VERSION" File "${SRCDIR}\AUTHORS" File "${SRCDIR}\COPYING" - File "${SRCDIR}\README.html" - File "${SRCDIR}\CHANGELOG.html" - File "${SRCDIR}\CONTRIBUTING.html" - File "${SRCDIR}\OpenRA.ico" - File "${SRCDIR}\RedAlert.ico" - File "${SRCDIR}\TiberianDawn.ico" - File "${SRCDIR}\Dune2000.ico" - File "${SRCDIR}\SDL2-CS.dll" - File "${SRCDIR}\OpenAL-CS.dll" File "${SRCDIR}\global mix database.dat" File "${SRCDIR}\IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP" - File "${SRCDIR}\eluant.dll" - File "${SRCDIR}\rix0rrr.BeaconLib.dll" - File "${DEPSDIR}\soft_oal.dll" - File "${DEPSDIR}\SDL2.dll" - File "${DEPSDIR}\freetype6.dll" - File "${DEPSDIR}\lua51.dll" !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory "$SMPROGRAMS\$StartMenuFolder" @@ -191,9 +190,9 @@ ; https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" "Release" IfErrors error 0 - IntCmp $0 394254 done error done + IntCmp $0 461808 done error done error: - MessageBox MB_OK ".NET Framework v4.6.1 or later is required to run OpenRA." + MessageBox MB_OK ".NET Framework v4.7.2 or later is required to run OpenRA." Abort done: SectionEnd @@ -205,12 +204,11 @@ WriteUninstaller $INSTDIR\uninstaller.exe WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "DisplayName" "OpenRA${SUFFIX}" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "UninstallString" "$INSTDIR\uninstaller.exe" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "QuietUninstallString" "$\"$INSTDIR\uninstaller.exe$\" /S" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "InstallLocation" "$INSTDIR" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "DisplayIcon" "$INSTDIR\OpenRA.ico" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "DisplayIcon" "$INSTDIR\ra.ico" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "Publisher" "OpenRA developers" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "URLInfoAbout" "http://openra.net" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "Readme" "$INSTDIR\README.html" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "DisplayVersion" "${TAG}" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "NoModify" "1" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" "NoRepair" "1" @@ -226,37 +224,15 @@ RMDir /r $INSTDIR\maps RMDir /r $INSTDIR\glsl RMDir /r $INSTDIR\lua - Delete $INSTDIR\RedAlert.exe - Delete $INSTDIR\TiberianDawn.exe - Delete $INSTDIR\Dune2000.exe - Delete $INSTDIR\OpenRA.Game.exe - Delete $INSTDIR\OpenRA.Game.exe.config - Delete $INSTDIR\OpenRA.Utility.exe - Delete $INSTDIR\OpenRA.Server.exe - Delete $INSTDIR\OpenRA.Platforms.Default.dll - Delete $INSTDIR\ICSharpCode.SharpZipLib.dll - Delete $INSTDIR\FuzzyLogicLibrary.dll - Delete $INSTDIR\Open.Nat.dll + Delete $INSTDIR\*.exe + Delete $INSTDIR\*.exe.config + Delete $INSTDIR\*.dll + Delete $INSTDIR\*.ico Delete $INSTDIR\VERSION Delete $INSTDIR\AUTHORS Delete $INSTDIR\COPYING - Delete $INSTDIR\README.html - Delete $INSTDIR\CHANGELOG.html - Delete $INSTDIR\CONTRIBUTING.html - Delete $INSTDIR\OpenRA.ico - Delete $INSTDIR\RedAlert.ico - Delete $INSTDIR\TiberianDawn.ico - Delete $INSTDIR\Dune2000.ico Delete "$INSTDIR\global mix database.dat" Delete $INSTDIR\IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP - Delete $INSTDIR\soft_oal.dll - Delete $INSTDIR\SDL2.dll - Delete $INSTDIR\lua51.dll - Delete $INSTDIR\eluant.dll - Delete $INSTDIR\freetype6.dll - Delete $INSTDIR\SDL2-CS.dll - Delete $INSTDIR\OpenAL-CS.dll - Delete $INSTDIR\rix0rrr.BeaconLib.dll RMDir /r $INSTDIR\Support DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" @@ -264,6 +240,10 @@ DeleteRegKey HKLM "Software\Classes\openra-cnc-${TAG}" DeleteRegKey HKLM "Software\Classes\openra-d2k-${TAG}" + DeleteRegKey HKLM "Software\Classes\discord-${RA_DISCORDID}" + DeleteRegKey HKLM "Software\Classes\discord-${CNC_DISCORDID}" + DeleteRegKey HKLM "Software\Classes\discord-${D2K_DISCORDID}" + Delete $INSTDIR\uninstaller.exe RMDir $INSTDIR Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/windows/RedAlert.ico and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/windows/RedAlert.ico differ Binary files /tmp/tmp7x7d2E/9u463ImENm/openra-20200503/packaging/windows/TiberianDawn.ico and /tmp/tmp7x7d2E/ZXWBnqKl2n/openra-20210321/packaging/windows/TiberianDawn.ico differ diff -Nru openra-20200503/packaging/windows/WindowsLauncher.cs.in openra-20210321/packaging/windows/WindowsLauncher.cs.in --- openra-20200503/packaging/windows/WindowsLauncher.cs.in 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/packaging/windows/WindowsLauncher.cs.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,205 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Media; -using System.Reflection; -using System.Windows.Forms; - -namespace OpenRA -{ - class WindowsLauncher - { - static Process gameProcess; - - // Constants to be replaced by the wrapper / compilation script - const string ModID = "MOD_ID"; - const string DisplayName = "DISPLAY_NAME"; - const string FaqUrl = "FAQ_URL"; - - [STAThread] - static int Main(string[] args) - { - if (args.Any(x => x.StartsWith("Engine.LaunchPath=", StringComparison.Ordinal))) - return RunGame(args); - - return RunInnerLauncher(args); - } - - static int RunGame(string[] args) - { - var launcherPath = Assembly.GetExecutingAssembly().Location; - var directory = Path.GetDirectoryName(launcherPath); - Directory.SetCurrentDirectory(directory); - - AppDomain.CurrentDomain.UnhandledException += (_, e) => ExceptionHandler.HandleFatalError((Exception)e.ExceptionObject); - - try - { - return (int)Game.InitializeAndRun(args); - } - catch (Exception e) - { - ExceptionHandler.HandleFatalError(e); - return (int)RunStatus.Error; - } - } - - static int RunInnerLauncher(string[] args) - { - var launcherPath = Assembly.GetExecutingAssembly().Location; - var launcherArgs = args.ToList(); - - if (!launcherArgs.Any(x => x.StartsWith("Engine.LaunchPath=", StringComparison.Ordinal))) - launcherArgs.Add("Engine.LaunchPath=\"" + launcherPath + "\""); - - if (!launcherArgs.Any(x => x.StartsWith("Game.Mod=", StringComparison.Ordinal))) - launcherArgs.Add("Game.Mod=" + ModID); - - var psi = new ProcessStartInfo(launcherPath, string.Join(" ", launcherArgs)); - - try - { - gameProcess = Process.Start(psi); - } - catch - { - return 1; - } - - if (gameProcess == null) - return 1; - - gameProcess.EnableRaisingEvents = true; - gameProcess.Exited += GameProcessExited; - - Application.Run(); - - return 0; - } - - static void ShowErrorDialog() - { - var headerLabel = new Label - { - Location = new Point(0, 10), - Height = 15, - Text = DisplayName + " has encountered a fatal error and must close.", - TextAlign = ContentAlignment.TopCenter - }; - - var docsLabel = new Label - { - Location = new Point(0, 25), - Height = 15, - Text = "Refer to the crash logs and FAQ for more information.", - TextAlign = ContentAlignment.TopCenter - }; - - int formWidth; - using (var g = headerLabel.CreateGraphics()) - { - var headerWidth = (int)g.MeasureString(headerLabel.Text, headerLabel.Font).Width + 60; - var docsWidth = (int)g.MeasureString(docsLabel.Text, docsLabel.Font).Width + 60; - formWidth = Math.Max(headerWidth, docsWidth); - headerLabel.Width = formWidth; - docsLabel.Width = formWidth; - } - - var form = new Form - { - Size = new Size(formWidth, 110), - Text = "Fatal Error", - MinimizeBox = false, - MaximizeBox = false, - FormBorderStyle = FormBorderStyle.FixedDialog, - StartPosition = FormStartPosition.CenterScreen, - TopLevel = true, - Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location) - }; - - var viewLogs = new Button - { - Location = new Point(10, 50), - Size = new Size(75, 23), - Text = "View Logs" - }; - - var viewFaq = new Button - { - Location = new Point(90, 50), - Size = new Size(75, 23), - Text = "View FAQ" - }; - - var quit = new Button - { - Location = new Point(formWidth - 90, 50), - Size = new Size(75, 23), - Text = "Quit", - DialogResult = DialogResult.Cancel - }; - - form.Controls.Add(headerLabel); - form.Controls.Add(docsLabel); - form.Controls.Add(viewLogs); - form.Controls.Add(viewFaq); - form.Controls.Add(quit); - - viewLogs.Click += ViewLogsClicked; - viewFaq.Click += ViewFaqClicked; - form.FormClosed += FormClosed; - - SystemSounds.Exclamation.Play(); - form.ShowDialog(); - } - - static void GameProcessExited(object sender, EventArgs e) - { - if (gameProcess.ExitCode != (int)RunStatus.Success) - ShowErrorDialog(); - - Exit(); - } - - static void ViewLogsClicked(object sender, EventArgs e) - { - try - { - Process.Start(Platform.ResolvePath("^", "Logs")); - } - catch { } - } - - static void ViewFaqClicked(object sender, EventArgs e) - { - try - { - Process.Start(FaqUrl); - } - catch { } - } - - static void FormClosed(object sender, EventArgs e) - { - Exit(); - } - - static void Exit() - { - Environment.Exit(0); - } - } -} diff -Nru openra-20200503/README.md openra-20210321/README.md --- openra-20200503/README.md 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/README.md 2021-03-21 11:10:05.000000000 +0000 @@ -4,7 +4,7 @@ * Website: [http://www.openra.net](http://www.openra.net) * IRC: \#openra on irc.freenode.net -* Repository: [https://github.com/OpenRA/OpenRA](https://github.com/OpenRA/OpenRA) [![Travis CI build status](https://travis-ci.org/OpenRA/OpenRA.svg?branch=bleed)](https://travis-ci.org/OpenRA/OpenRA) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/axc9k6jd25ej2o4w?svg=true)](https://ci.appveyor.com/project/OpenRA/openra) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3650/badge.svg)](https://scan.coverity.com/projects/3650) +* Repository: [https://github.com/OpenRA/OpenRA](https://github.com/OpenRA/OpenRA) ![Continuous Integration](https://github.com/OpenRA/OpenRA/workflows/Continuous%20Integration/badge.svg) Please read the [FAQ](http://wiki.openra.net/FAQ) in our [Wiki](http://wiki.openra.net) and report problems at [http://bugs.openra.net](http://bugs.openra.net). @@ -18,6 +18,8 @@ * Command & Conquer: Tiberian Dawn * Dune 2000 +EA has not endorsed and does not support this product. + Check our [Playing the Game](https://github.com/OpenRA/OpenRA/wiki/Playing-the-game) Guide to win multiplayer matches. ## Contribute @@ -37,7 +39,7 @@ * Download a copy of the [OpenRA Mod SDK](https://github.com/OpenRA/OpenRAModSDK/) to start your own mod. * Check the [Modding Guide](http://wiki.openra.net/Modding-Guide) to create your own classic RTS. -* There exists an auto-generated [Trait documentation](http://wiki.openra.net/Traits) to get started with yaml files. +* There exists an auto-generated [Trait documentation](https://docs.openra.net/en/latest/release/traits/) to get started with yaml files. * Some hints on how to create new OpenRA compatible [Pixelart](http://wiki.openra.net/Pixelart). * Upload total conversions at [our ModDB profile](http://www.moddb.com/games/openra/mods). @@ -48,7 +50,7 @@ ## License Copyright 2007-2020 The OpenRA Developers (see [AUTHORS](https://github.com/OpenRA/OpenRA/blob/bleed/AUTHORS)) -This file is part of OpenRA, which is free software. It is made +This file is part of OpenRA, which is free software. It is made available to you under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. For more diff -Nru openra-20200503/thirdparty/configure-native-deps.sh openra-20210321/thirdparty/configure-native-deps.sh --- openra-20200503/thirdparty/configure-native-deps.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/thirdparty/configure-native-deps.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -#!/bin/sh -# Use BSD/Linux system dependencies where possible, but take into account different .so names. - -#### -# This file must stay /bin/sh and POSIX compliant for BSD portability. -# Copy-paste the entire script into http://shellcheck.net to check. -#### - -locations="/lib /lib64 /usr/lib /usr/lib64 /usr/lib/i386-linux-gnu /usr/lib/x86_64-linux-gnu /usr/lib/arm-linux-gnueabihf /usr/lib/aarch64-linux-gnu /usr/lib/powerpc64le-linux-gnu /usr/lib/mipsel-linux-gnu /usr/local/lib /opt/lib /opt/local/lib /app/lib" -sonames="liblua.so.5.1.5 liblua5.1.so.5.1 liblua5.1.so.0 liblua.so.5.1 liblua-5.1.so liblua5.1.so" - -if [ -f Eluant.dll.config ]; then - exit 0 -fi - -for location in $locations ; do - for soname in $sonames ; do - if [ -f "$location/$soname" ]; then - liblua51=$soname - echo "Detected Lua 5.1 library at $location/$soname" - break 2 - fi - done -done - -if [ -z "$liblua51" ]; then - echo "Lua 5.1 library detection failed." - exit 1 -else - sed "s/@LIBLUA51@/${liblua51}/" thirdparty/Eluant.dll.config.in > Eluant.dll.config - echo "Eluant.dll.config has been created successfully." -fi diff -Nru openra-20200503/thirdparty/Eluant.dll.config.in openra-20210321/thirdparty/Eluant.dll.config.in --- openra-20200503/thirdparty/Eluant.dll.config.in 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/thirdparty/Eluant.dll.config.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ - - - diff -Nru openra-20200503/thirdparty/fetch-thirdparty-deps-osx.sh openra-20210321/thirdparty/fetch-thirdparty-deps-osx.sh --- openra-20200503/thirdparty/fetch-thirdparty-deps-osx.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/thirdparty/fetch-thirdparty-deps-osx.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -#!/bin/bash - -LAUNCHER_TAG="osx-launcher-20200316" - -download_dir="${0%/*}/download/osx" -mkdir -p "$download_dir" -cd "$download_dir" || exit 1 - -if [ ! -f libSDL2.dylib ]; then - echo "Fetching OS X SDL2 library from GitHub." - curl -LOs https://github.com/OpenRA/OpenRALauncherOSX/releases/download/${LAUNCHER_TAG}/libSDL2.dylib -fi - -if [ ! -f liblua.5.1.dylib ]; then - echo "Fetching OS X Lua 5.1 library from GitHub." - curl -LOs https://github.com/OpenRA/OpenRALauncherOSX/releases/download/${LAUNCHER_TAG}/liblua.5.1.dylib -fi - -if [ ! -f Eluant.dll.config ]; then - echo "Fetching OS X Lua configuration file from GitHub." - curl -LOs https://raw.githubusercontent.com/OpenRA/OpenRALauncherOSX/${LAUNCHER_TAG}/Eluant.dll.config -fi - -if [ ! -f libfreetype.6.dylib ]; then - echo "Fetching OS X FreeType library from GitHub." - curl -LOs https://github.com/OpenRA/OpenRALauncherOSX/releases/download/${LAUNCHER_TAG}/libfreetype.6.dylib -fi - -if [ ! -f libopenal.1.dylib ]; then - echo "Fetching OS X OpenAL Soft library from GitHub." - curl -LOs https://github.com/OpenRA/OpenRALauncherOSX/releases/download/${LAUNCHER_TAG}/libopenal.1.dylib -fi diff -Nru openra-20200503/thirdparty/fetch-thirdparty-deps.ps1 openra-20210321/thirdparty/fetch-thirdparty-deps.ps1 --- openra-20200503/thirdparty/fetch-thirdparty-deps.ps1 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/thirdparty/fetch-thirdparty-deps.ps1 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -mkdir download/windows -Force >$null - -cd download - -if (!(Test-Path "nuget.exe")) -{ - echo "Fetching NuGet." - # Work around PowerShell's Invoke-WebRequest not being available on some versions of PowerShell by using the BCL. - # To do that we need to work around further and use absolute paths because DownloadFile is not aware of PowerShell's current directory. - $target = Join-Path $pwd.ToString() "nuget.exe" - (New-Object System.Net.WebClient).DownloadFile("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", $target) -} - -if (!(Test-Path "ICSharpCode.SharpZipLib.dll")) -{ - echo "Fetching ICSharpCode.SharpZipLib from NuGet." - ./nuget.exe install SharpZipLib -Version 1.1.0 -ExcludeVersion -Verbosity quiet -Source nuget.org - cp SharpZipLib/lib/net45/ICSharpCode.SharpZipLib.dll . - rmdir SharpZipLib -Recurse -} - -if (!(Test-Path "nunit.framework.dll")) -{ - echo "Fetching NUnit from NuGet." - ./nuget.exe install NUnit -Version 3.0.1 -ExcludeVersion -Verbosity quiet -Source nuget.org - cp NUnit/lib/net40/nunit.framework* . - rmdir NUnit -Recurse -} - -if (!(Test-Path "windows/SDL2.dll")) -{ - echo "Fetching SDL2 from libsdl.org" - - # Download zip: - $zipFileName = "SDL2-2.0.10-win32-x64.zip" - $target = Join-Path $pwd.ToString() $zipFileName - (New-Object System.Net.WebClient).DownloadFile("https://www.libsdl.org/release/" + $zipFileName, $target) - - # Extract zip: - $shell_app=new-object -com shell.application - $currentPath = (Get-Location).Path - $zipFile = $shell_app.namespace($currentPath + "\$zipFileName") - $destination = $shell_app.namespace($currentPath + "\windows") - $destination.Copyhere($zipFile.items()) - - # Remove junk files: - rm "$zipFileName" - rm -path "$currentPath\windows\README-SDL.txt" -} - -if (!(Test-Path "Open.Nat.dll")) -{ - echo "Fetching Open.Nat from NuGet." - ./nuget.exe install Open.Nat -Version 2.1.0 -ExcludeVersion -Verbosity quiet -Source nuget.org - cp Open.Nat/lib/net45/Open.Nat.dll . - rmdir Open.Nat -Recurse -} - -if (!(Test-Path "windows/lua51.dll")) -{ - echo "Fetching Lua 5.1 from NuGet." - ./nuget.exe install lua.binaries -Version 5.1.5 -ExcludeVersion -Verbosity quiet -Source nuget.org - cp lua.binaries/bin/win64/dll8/lua5.1.dll ./windows/lua51.dll - rmdir lua.binaries -Recurse -} - -if (!(Test-Path "windows/freetype6.dll")) -{ - echo "Fetching FreeType2 from NuGet." - ./nuget.exe install SharpFont.Dependencies -Version 2.6.0 -ExcludeVersion -Verbosity quiet -Source nuget.org - cp SharpFont.Dependencies/bin/msvc9/x64/freetype6.dll ./windows/freetype6.dll - rmdir SharpFont.Dependencies -Recurse -} - -if (!(Test-Path "windows/soft_oal.dll")) -{ - echo "Fetching OpenAL Soft from NuGet." - ./nuget.exe install OpenAL-Soft -Version 1.16.0 -ExcludeVersion -Verbosity quiet -Source nuget.org - cp OpenAL-Soft/bin/Win64/soft_oal.dll windows/soft_oal.dll - rmdir OpenAL-Soft -Recurse -} - -if (!(Test-Path "FuzzyLogicLibrary.dll")) -{ - echo "Fetching FuzzyLogicLibrary from NuGet." - ./nuget.exe install FuzzyLogicLibrary -Version 1.2.0 -ExcludeVersion -Verbosity quiet -Source nuget.org - cp FuzzyLogicLibrary/bin/Release/FuzzyLogicLibrary.dll . - rmdir FuzzyLogicLibrary -Recurse -} - -if (!(Test-Path "rix0rrr.BeaconLib.dll")) -{ - echo "Fetching rix0rrr.BeaconLib from NuGet." - ./nuget.exe install rix0rrr.BeaconLib -Version 1.0.1 -ExcludeVersion -Verbosity quiet -Source nuget.org - cp rix0rrr.BeaconLib/lib/net40/rix0rrr.BeaconLib.dll . - rmdir rix0rrr.BeaconLib -Recurse -} - -[Net.ServicePointManager]::SecurityProtocol = 'Tls12' - -if (!(Test-Path "SDL2-CS.dll")) -{ - echo "Fetching SDL2-CS from GitHub." - $target = Join-Path $pwd.ToString() "SDL2-CS.dll" - (New-Object System.Net.WebClient).DownloadFile("https://github.com/OpenRA/SDL2-CS/releases/download/20190907/SDL2-CS.dll", $target) -} - -if (!(Test-Path "OpenAL-CS.dll")) -{ - echo "Fetching OpenAL-CS from GitHub." - $target = Join-Path $pwd.ToString() "OpenAL-CS.dll" - (New-Object System.Net.WebClient).DownloadFile("https://github.com/OpenRA/OpenAL-CS/releases/download/20190907/OpenAL-CS.dll", $target) -} - -if (!(Test-Path "Eluant.dll")) -{ - echo "Fetching Eluant from GitHub." - $target = Join-Path $pwd.ToString() "Eluant.dll" - (New-Object System.Net.WebClient).DownloadFile("https://github.com/OpenRA/Eluant/releases/download/20160124/Eluant.dll", $target) -} - -cd .. diff -Nru openra-20200503/thirdparty/fetch-thirdparty-deps.sh openra-20210321/thirdparty/fetch-thirdparty-deps.sh --- openra-20200503/thirdparty/fetch-thirdparty-deps.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/thirdparty/fetch-thirdparty-deps.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -#!/bin/sh - -#### -# This file must stay /bin/sh and POSIX compliant for BSD portability. -# Copy-paste the entire script into http://shellcheck.net to check. -#### - -# Die on any error for Travis CI to automatically retry: -set -e - -download_dir="${0%/*}/download" - -mkdir -p "${download_dir}" -cd "${download_dir}" || exit 1 - -if [ ! -f ICSharpCode.SharpZipLib.dll ]; then - echo "Fetching ICSharpCode.SharpZipLib from NuGet" - ../noget.sh SharpZipLib 1.1.0 - cp ./SharpZipLib/lib/net45/ICSharpCode.SharpZipLib.dll . - rm -rf SharpZipLib -fi - -if [ ! -f nunit.framework.dll ]; then - echo "Fetching NUnit from NuGet" - ../noget.sh NUnit 3.0.1 - cp ./NUnit/lib/net40/nunit.framework* . - rm -rf NUnit -fi - -if [ ! -f nunit3-console.exe ]; then - echo "Fetching NUnit.Console from NuGet" - ../noget.sh NUnit.Console 3.0.1 - cp -R ./NUnit.Console/tools/* . - chmod +x nunit3-console.exe - rm -rf NUnit.Console -fi - -if [ ! -f Open.Nat.dll ]; then - echo "Fetching Open.Nat from NuGet" - ../noget.sh Open.Nat 2.1.0 - if [ -d ./Open.NAT ]; then mv Open.NAT Open.Nat; fi - cp ./Open.Nat/lib/net45/Open.Nat.dll . - rm -rf Open.Nat -fi - -if [ ! -f FuzzyLogicLibrary.dll ]; then - echo "Fetching FuzzyLogicLibrary from NuGet." - ../noget.sh FuzzyLogicLibrary 1.2.0 - cp ./FuzzyLogicLibrary/bin/Release/FuzzyLogicLibrary.dll . - rm -rf FuzzyLogicLibrary -fi - -if [ ! -f SDL2-CS.dll ] || [ ! -f SDL2-CS.dll.config ]; then - echo "Fetching SDL2-CS from GitHub." - if command -v curl >/dev/null 2>&1; then - curl -s -L -O https://github.com/OpenRA/SDL2-CS/releases/download/20190907/SDL2-CS.dll - curl -s -L -O https://github.com/OpenRA/SDL2-CS/releases/download/20190907/SDL2-CS.dll.config - else - wget -cq https://github.com/OpenRA/SDL2-CS/releases/download/20190907/SDL2-CS.dll - wget -cq https://github.com/OpenRA/SDL2-CS/releases/download/20190907/SDL2-CS.dll.config - fi -fi - -if [ ! -f OpenAL-CS.dll ] || [ ! -f OpenAL-CS.dll.config ]; then - echo "Fetching OpenAL-CS from GitHub." - if command -v curl >/dev/null 2>&1; then - curl -s -L -O https://github.com/OpenRA/OpenAL-CS/releases/download/20200316/OpenAL-CS.dll - curl -s -L -O https://github.com/OpenRA/OpenAL-CS/releases/download/20200316/OpenAL-CS.dll.config - else - wget -cq https://github.com/OpenRA/OpenAL-CS/releases/download/20200316/OpenAL-CS.dll - wget -cq https://github.com/OpenRA/OpenAL-CS/releases/download/20200316/OpenAL-CS.dll.config - fi -fi - -if [ ! -f Eluant.dll ]; then - echo "Fetching Eluant from GitHub." - if command -v curl >/dev/null 2>&1; then - curl -s -L -O https://github.com/OpenRA/Eluant/releases/download/20160124/Eluant.dll - else - wget -cq https://github.com/OpenRA/Eluant/releases/download/20160124/Eluant.dll - fi -fi - -if [ ! -f rix0rrr.BeaconLib.dll ]; then - echo "Fetching rix0rrr.BeaconLib from NuGet." - ../noget.sh rix0rrr.BeaconLib 1.0.1 - cp ./rix0rrr.BeaconLib/lib/net40/rix0rrr.BeaconLib.dll . - rm -rf rix0rrr.BeaconLib -fi diff -Nru openra-20200503/thirdparty/fetch-thirdparty-deps-windows.sh openra-20210321/thirdparty/fetch-thirdparty-deps-windows.sh --- openra-20200503/thirdparty/fetch-thirdparty-deps-windows.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/thirdparty/fetch-thirdparty-deps-windows.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -#!/bin/bash - -# Die on any error for Travis CI to automatically retry: -set -e - -if [ $# -ne "1" ]; then - echo "Usage: $(basename "$0") (32|64)" - exit 1 -fi - -if [ "$1" != "x86" ] && [ "$1" != "x64" ]; then - echo "Usage: $(basename "$0") (32|64)" - exit 1 -fi - -download_dir="${0%/*}/download/windows" - -mkdir -p "${download_dir}" -cd "${download_dir}" || exit 1 - -if [ ! -f SDL2.dll ]; then - echo "Fetching SDL2 from libsdl.org" - if [ "$1" = "x86" ]; then - curl -LOs https://www.libsdl.org/release/SDL2-2.0.10-win32-x86.zip - unzip SDL2-2.0.10-win32-x86.zip SDL2.dll - rm SDL2-2.0.10-win32-x86.zip - else - curl -LOs https://www.libsdl.org/release/SDL2-2.0.10-win32-x64.zip - unzip SDL2-2.0.10-win32-x64.zip SDL2.dll - rm SDL2-2.0.10-win32-x64.zip - fi -fi - -if [ ! -f freetype6.dll ]; then - echo "Fetching FreeType2 from NuGet" - ../../noget.sh SharpFont.Dependencies 2.6.0 - if [ "$1" = "x86" ]; then - cp ./SharpFont.Dependencies/bin/msvc9/x86/freetype6.dll . - else - cp ./SharpFont.Dependencies/bin/msvc9/x64/freetype6.dll . - fi - rm -rf SharpFont.Dependencies -fi - -if [ ! -f lua51.dll ]; then - echo "Fetching Lua 5.1 from NuGet" - ../../noget.sh lua.binaries 5.1.5 - if [ "$1" = "x86" ]; then - cp ./lua.binaries/bin/win32/dll8/lua5.1.dll ./lua51.dll - else - cp ./lua.binaries/bin/win64/dll8/lua5.1.dll ./lua51.dll - fi - rm -rf lua.binaries -fi - -if [ ! -f soft_oal.dll ]; then - echo "Fetching OpenAL Soft from NuGet" - ../../noget.sh OpenAL-Soft 1.16.0 - if [ "$1" = "x86" ]; then - cp ./OpenAL-Soft/bin/Win32/soft_oal.dll ./soft_oal.dll - else - cp ./OpenAL-Soft/bin/Win64/soft_oal.dll ./soft_oal.dll - fi - rm -rf OpenAL-Soft -fi diff -Nru openra-20200503/thirdparty/noget.sh openra-20210321/thirdparty/noget.sh --- openra-20200503/thirdparty/noget.sh 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/thirdparty/noget.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -#!/bin/sh -# fallback without dependency resolution if nuget is not present on the system - -#### -# This file must stay /bin/sh and POSIX compliant for BSD portability. -# Copy-paste the entire script into http://shellcheck.net to check. -#### - -command -v curl >/dev/null 2>&1 || command -v wget > /dev/null 2>&1 || { echo >&2 "Obtaining thirdparty dependencies requires curl or wget."; exit 1; } - -archive="$1" -version="$2" -if command -v curl >/dev/null 2>&1; then - curl -o "$archive.zip" -Ls https://nuget.org/api/v2/package/"$archive"/"$version" -else - wget -cq https://nuget.org/api/v2/package/"$archive"/"$version" -O "$archive.zip" -fi -mkdir -p "$archive" -unzip -o -qq "$archive.zip" -d "$archive" && rm "$archive.zip" diff -Nru openra-20200503/.travis.yml openra-20210321/.travis.yml --- openra-20200503/.travis.yml 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/.travis.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -# Travis-CI Build for OpenRA -# see travis-ci.org for details - -language: csharp -mono: 6.4.0 - -jobs: - include: - - os: linux - dist: xenial - - os: osx - if: tag IS present - osx_image: xcode10 - -cache: - directories: - - thirdparty/download - -addons: - apt: - packages: - - lua5.1 - - dpkg - - zsync - - markdown - -# Environment variables -env: - secure: "C0+Hlfa0YGErxUuWV00Tj6p45otC/D3YwYFuLpi2mj1rDFn/4dgh5WRngjvdDBVbXJ3duaZ78jPHWm1jr7vn2jqj9yETsCIK9psWd38ep/FEBM0SDr6MUD89OuXk/YyvxJAE+UXF6bXg7giey09g/CwBigjMW7ynET3wNAWPHPs=" - -# Fetch dependencies -# Run the build script -# Check source code with StyleCop -# call OpenRA to check for YAML errors -# Run the NUnit tests -script: - - travis_retry make all-dependencies - - make all - - test "$TRAVIS_OS_NAME" == "linux" && make check || echo "Skipping check" - - test "$TRAVIS_OS_NAME" == "linux" && make check-scripts || echo "Skipping scripts check" - - test "$TRAVIS_OS_NAME" == "linux" && make test || echo "Skipping tests" - - test "$TRAVIS_OS_NAME" == "linux" && make nunit || echo "Skipping nunit tests" - -# Only watch the development branch and tagged release. -branches: - only: - - /^release-.*$/ - - /^playtest-.*$/ - - /^pkgtest-.*$/ - - /^prep-.*$/ - - bleed - -# Notify developers when build passed/failed. -notifications: - irc: - template: - - "%{repository}#%{build_number} %{commit} %{author}: %{message} %{build_url}" - channels: - - "irc.freenode.net#openra" - use_notice: true - skip_join: true - -before_deploy: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - wget https://mirrors.edge.kernel.org/ubuntu/pool/universe/n/nsis/nsis-common_3.04-1_all.deb; - wget https://mirrors.edge.kernel.org/ubuntu/pool/universe/n/nsis/nsis_3.04-1_amd64.deb; - sudo dpkg -i nsis-common_3.04-1_all.deb; - sudo dpkg -i nsis_3.04-1_amd64.deb; - cd packaging && ./update-wiki.sh ${TRAVIS_TAG} && cd ..; - fi; - - export PATH=$PATH:$HOME/usr/bin - - DOTVERSION=`echo ${TRAVIS_TAG} | sed "s/-/\\./g"` - - cd packaging - - mkdir build - - ./package-all.sh ${TRAVIS_TAG} ${PWD}/build/ -deploy: - provider: releases - api_key: - secure: "g/LU11f+mjqv+lj0sR1UliHwogXL4ofJUwoG5Dbqlvdf5UTLWytw/OWSCv8RGyuh10miyWeaoqHh1cn2C1IFhUEqN1sSeKKKOWOTvJ2FR5mzi9uH3d/MOBzG5icQ7Qh0fZ1YPz5RaJJhYu6bmfvA/1gD49GoaX2kxQL4J5cEBgg=" - file_glob: true - file: build/* - skip_cleanup: true - on: - all_branches: true - tags: true - repo: OpenRA/OpenRA diff -Nru openra-20200503/utility.cmd openra-20210321/utility.cmd --- openra-20200503/utility.cmd 2020-04-26 11:38:42.000000000 +0000 +++ openra-20210321/utility.cmd 2021-03-21 11:10:05.000000000 +0000 @@ -1,11 +1,12 @@ @echo off title OpenRA.Utility.exe +set ENGINE_DIR=.. :choosemod echo ---------------------------------------- echo. -call OpenRA.Utility.exe +call bin\OpenRA.Utility.exe echo Enter --exit to exit -set /P mod=Please enter a modname: OpenRA.Utility.exe +set /P mod="Please enter a modname: OpenRA.Utility.exe " if /I "%mod%" EQU "--exit" (exit /b) if /I "%mod%" EQU "ra" (goto help) if /I "%mod%" EQU "cnc" (goto help) @@ -20,7 +21,7 @@ echo ---------------------------------------- echo. echo OpenRA.Utility.exe %mod% -call OpenRA.Utility.exe %mod% +call bin\OpenRA.Utility.exe %mod% :start echo. echo ---------------------------------------- @@ -30,7 +31,7 @@ echo --help to view the help echo --mod to choose a new mod echo. -set /P command=Please enter a command: OpenRA.Utility.exe %mod% +set /P command="Please enter a command: OpenRA.Utility.exe %mod% " if /I "%command%" EQU "--exit" (exit /b) if /I "%command%" EQU "--help" (goto help) if /I "%command%" EQU "--mod" (goto choosemod) @@ -38,5 +39,5 @@ echo ---------------------------------------- echo. echo OpenRA.Utility.exe %mod% %command% -call OpenRA.Utility.exe %mod% %command% -goto start \ No newline at end of file +call bin\OpenRA.Utility.exe %mod% %command% +goto start diff -Nru openra-20200503/utility.sh openra-20210321/utility.sh --- openra-20200503/utility.sh 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/utility.sh 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,2 @@ +#!/bin/sh +ENGINE_DIR=.. mono --debug bin/OpenRA.Utility.exe $@ diff -Nru openra-20200503/.vscode/extensions.json openra-20210321/.vscode/extensions.json --- openra-20200503/.vscode/extensions.json 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/.vscode/extensions.json 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "ms-dotnettools.csharp", + "EditorConfig.EditorConfig", + "ms-vscode.mono-debug" + ] +} diff -Nru openra-20200503/.vscode/launch.json openra-20210321/.vscode/launch.json --- openra-20200503/.vscode/launch.json 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/.vscode/launch.json 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,61 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch (TD)", + "type": "clr", + "linux": { + "type": "mono" + }, + "osx": { + "type": "mono" + }, + "request": "launch", + "program": "${workspaceRoot}/bin/OpenRA.exe", + "args": ["Game.Mod=cnc", "Engine.EngineDir=.."], + "preLaunchTask": "build", + }, + { + "name": "Launch (RA)", + "type": "clr", + "linux": { + "type": "mono" + }, + "osx": { + "type": "mono" + }, + "request": "launch", + "program": "${workspaceRoot}/bin/OpenRA.exe", + "args": ["Game.Mod=ra", "Engine.EngineDir=.."], + "preLaunchTask": "build", + }, + { + "name": "Launch (D2k)", + "type": "clr", + "linux": { + "type": "mono" + }, + "osx": { + "type": "mono" + }, + "request": "launch", + "program": "${workspaceRoot}/bin/OpenRA.exe", + "args": ["Game.Mod=d2k", "Engine.EngineDir=.."], + "preLaunchTask": "build", + }, + { + "name": "Launch (TS)", + "type": "clr", + "linux": { + "type": "mono" + }, + "osx": { + "type": "mono" + }, + "request": "launch", + "program": "${workspaceRoot}/bin/OpenRA.exe", + "args": ["Game.Mod=ts", "Engine.EngineDir=.."], + "preLaunchTask": "build", + }, + ] +} diff -Nru openra-20200503/.vscode/settings.json openra-20210321/.vscode/settings.json --- openra-20200503/.vscode/settings.json 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/.vscode/settings.json 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,3 @@ +{ + "omnisharp.enableRoslynAnalyzers": true +} diff -Nru openra-20200503/.vscode/tasks.json openra-20210321/.vscode/tasks.json --- openra-20200503/.vscode/tasks.json 1970-01-01 00:00:00.000000000 +0000 +++ openra-20210321/.vscode/tasks.json 2021-03-21 11:10:05.000000000 +0000 @@ -0,0 +1,13 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "make", + "args": ["all"], + "windows": { + "command": "make.cmd" + } + } + ] +}