Compare commits

...

630 Commits

Author SHA1 Message Date
abcdefg30
5943ecc943 Correct the support dir location in ExtractSettingsDocsCommand 2020-04-26 12:38:42 +01:00
Paul Chote
c13e078ebd Disable debug callbacks on Intel HD 4000. 2020-04-25 21:03:25 +02:00
Paul Chote
426c3d68a1 Expose GL Profile in settings menu. 2020-04-25 21:03:23 +02:00
Paul Chote
5b6b4ab4ee Restore legacy OpenGL 2.1 support. 2020-04-25 21:03:20 +02:00
Paul Chote
835a9e605a Replace PreferGLES settings flag with GLProfile enum. 2020-04-25 21:03:05 +02:00
Paul Chote
390fbe6718 Split GLProfile from GLFeatures. 2020-04-25 21:00:51 +02:00
abcdefg30
1bf3d090d5 Fix a crash when completing objectives in Allies06 out of order 2020-04-23 21:57:22 +01:00
abcdefg30
9e279b9987 Treat transit-only tiles as invalid locations for minelayers 2020-04-18 13:35:27 +01:00
Adam Mitchell
4b6780bc67 Fix units stuck on transit-only when resupplying 2020-04-17 11:10:10 +02:00
abcdefg30
0a9aa488db Adapt the utility commands to import crates as well 2020-04-17 10:49:53 +02:00
abcdefg30
97ecfa548e Remove a TODO about grey nod colors 2020-04-17 10:49:38 +02:00
abcdefg30
82a98ae6e6 Set the wcrate and scrate sequences up 2020-04-17 10:49:25 +02:00
abcdefg30
32b241eae7 Add missing money crates to TD campaign missions 2020-04-17 10:49:09 +02:00
abcdefg30
e8084ade68 Move money crates to a default in the shared campaign rules 2020-04-17 10:48:58 +02:00
Paul Chote
16c2cbf577 Work around and explain color picker conversion issue. 2020-04-17 10:40:32 +02:00
Paul Chote
b51980a9ea Fix map-specific factions remaining selected when changing map. 2020-04-16 16:49:16 +02:00
Paul Chote
631a61e219 Block profiles with revoked keys from joining auth-only servers. 2020-04-16 16:43:33 +02:00
abcdefg30
5ff2546a5d Add more engineers to the wave in nod07
Otherwise buildings will only be damaged
2020-04-16 13:21:53 +02:00
abcdefg30
bf2640308a Fix APC reinforcements in nod07a and b 2020-04-16 13:21:52 +02:00
abcdefg30
63cee6a0e3 Fix a crash in nod07b 2020-04-16 13:21:50 +02:00
Paul Chote
cab47c4975 Disable IP tooltip in skirmish games. 2020-04-15 23:16:07 +02:00
Paul Chote
6385c24875 Switch GeoIP database from MaxMind to IP2Location.
The IP2Location data is licensed under CC BY-SA, which
allows us to distribute the database with releases.
2020-04-15 23:16:05 +02:00
Paul Chote
1d1bafd836 Fix long player locations overrunning the player tooltip. 2020-04-15 23:16:03 +02:00
netnazgul
5cacce3c93 Modify preset colors to not get flagged by color validator 2020-04-14 18:31:35 +02:00
Paul Chote
798c92abeb Fix mine layer desync.
World.FogObscures depends on the local RenderPlayer and should not
be used from simulation code!
2020-04-12 23:06:25 +02:00
abcdefg30
9236a05d53 Fix a yaml error in GDI08a 2020-04-07 20:59:46 +02:00
netnazgul
fc7b3d83e5 Fix tile errors on the map "Pie of Animosity" 2020-04-07 20:53:59 +02:00
Punsho
00ddf82e85 RA Balance patch 2020-03-29 21:51:52 +02:00
Paul Chote
c10ebb455b Fix actors with no footprint leaving stale data when deleted. 2020-03-29 21:08:25 +02:00
Paul Chote
d999a0534b Move selectableActor check inside InputOverridesSelection. 2020-03-29 13:26:05 +02:00
Ivaylo Draganov
02454fb764 Adjust spacing and width in editor category dropdown 2020-03-28 20:41:31 +00:00
abcdefg30
df81857abe Adjust the map visibility panel height 2020-03-28 20:41:23 +00:00
abcdefg30
ae0745b542 Start with randomized wind strength 2020-03-28 19:47:21 +01:00
Paul Chote
89b5e34320 Fix and simplify WeatherOverlay:
- Fix rendering issues
- Track particles in world pixels instead of screen pixels
- Removed un/underused fade in/out support
- Update wind once per tick instead of once per particle
- Make Particle struct readonly
2020-03-28 19:47:19 +01:00
Paul Chote
47cc6eda7e Make the right edge of the airfield transitable. 2020-03-28 19:14:43 +01:00
Paul Chote
6da23ed3d7 Fix minelayers leaking enemy mine positions through the fog. 2020-03-28 18:49:24 +01:00
Paul Chote
3ee4613a98 Fix SpriteEffect updating twice in the first tick. 2020-03-28 17:18:12 +01:00
Paul Chote
616bfbe553 Fix and simplify ScrollPanelWidget thumb rect calculation. 2020-03-26 16:53:09 +01:00
Ivaylo Draganov
ecbcc9c8bb Align lobby bits in the player tab in TD 2020-03-25 13:02:34 +01:00
Paul Chote
068ce9b215 Restore ability to configure RMB orders + RMB panning. 2020-03-25 12:37:43 +01:00
Paul Chote
170bcd500c Remove text caching from CncLoadScreen.
We have repeatedly failed at invalidating these
cached values when things change, so the small perf
win is not worth the hassle.
2020-03-25 12:21:15 +01:00
Paul Chote
6efb40c9a6 Fix detection circle line rendering. 2020-03-24 20:59:58 +01:00
Ivaylo Draganov
3c92c2d789 Adjust the stroke of the muted indicator glyph 2020-03-24 16:57:48 +01:00
Paul Chote
f823d20a86 Replace deprecated native OpenAL with OpenAL Soft on macOS. 2020-03-23 11:17:46 +01:00
Paul Chote
ca4b97cd03 Remove invalid caching from GCOT. 2020-03-23 11:17:08 +01:00
Matthias Mailänder
8b5e322891 Remove .lua scripts from the .NET solution file. 2020-03-21 21:24:03 +01:00
unknown
70e1c4bb0c Add gdi09ea 2020-03-21 21:11:14 +01:00
abcdefg30
8690ad4e19 Add support for destroying enemy carryalls 2020-03-21 11:00:39 +01:00
abcdefg30
a01233c3df Add support for an announcement function for carryall reinforcements 2020-03-21 11:00:14 +01:00
abcdefg30
d0d55b3fc1 Add Ordos06a 2020-03-21 10:59:59 +01:00
abcdefg30
2a26a07ce6 Let VS2019 remove a duplicate line from the solution 2020-03-21 10:59:45 +01:00
abcdefg30
65e088204f Fix the settings tooltip container being overwritten ingame 2020-03-20 16:06:46 +01:00
Michael Silber
77e38ceea9 Add gdi08a 2020-03-17 19:04:53 +01:00
Paul Chote
989d1475b9 Update macOS launcher to fix "View Logs" button. 2020-03-16 19:17:12 +00:00
Paul Chote
580a96cda4 Cache CandidateMovementCells within the same tick. 2020-03-12 17:07:45 +01:00
Paul Chote
5a8964aabe Fix infantry switching subcells and blocking eachother while moving. 2020-03-11 15:40:58 +01:00
Paul Chote
c9dcf305c9 Fix FreeSubCell ignoring preferred subcell requests. 2020-03-11 15:40:56 +01:00
Paul Chote
5489d6909c Fix pathing across transit-only cells. 2020-03-11 15:40:54 +01:00
Paul Chote
85412a6d98 Fix variable naming in Locomotor. 2020-03-11 15:40:53 +01:00
abcdefg30
b69806123a Fix aircraft not taking off properly 2020-03-08 17:19:56 +01:00
abcdefg30
df4c363e9c Notify blockers upon paradropping 2020-03-03 20:51:39 +00:00
abcdefg30
a909a3e692 Ignore self and actors not at ground level in Parachutable.OnLanded 2020-03-03 20:51:39 +00:00
abcdefg30
dd26253905 Fix the IgnoreActor check in Parachutable 2020-03-03 20:51:39 +00:00
abcdefg30
69b7ba2d22 Fix NREs in ProductionParadrop 2020-03-03 20:51:39 +00:00
Paul Chote
d2f306e488 Fix GetActorsAt(CPos, SubCell) with special-case subcells.
If given FullCell or Any we should be returning actors in
any subcell, not none.
2020-03-03 20:06:51 +01:00
Paul Chote
4a6fefa434 Disable idle scanning on RA planes. 2020-03-02 22:22:56 +01:00
Paul Chote
16e0ea611e Revert "Fix AttackFollow ignoring allowMove flag when auto-targeting."
This reverts commit 3e116060cf.
2020-03-02 22:22:56 +01:00
Paul Chote
05a2e77be2 Add support for uncompressed databases. 2020-03-02 17:29:30 +01:00
Paul Chote
dd2fa36261 Fix invalid channel server crash. 2020-03-02 17:29:30 +01:00
abcdefg30
5fa1dec6d8 Fix a crash in --clear-invalid-mod-registrations 2020-03-02 17:26:34 +01:00
Paul Chote
f86d96794d Add explicitly defined version strings to the lua docs. 2020-03-02 17:24:17 +01:00
Paul Chote
304307df5a Fix wiki script again. 2020-03-01 16:41:19 +00:00
Paul Chote
c8856749f3 Only update the wiki from the Linux host. 2020-03-01 16:10:07 +00:00
Paul Chote
ce91c5a76f Fix WithDisguisingInfantryBody idle animation crash. 2020-03-01 14:43:12 +01:00
Paul Chote
e6314a944c Round dropdown arrow position to an integer pixel. 2020-03-01 14:41:17 +01:00
Paul Chote
93d006e14e Fix incorrect end point rendering in DrawConnectedLine. 2020-02-29 18:13:54 +01:00
Paul Chote
d73ed7670a Port missions to the new Paratroopers API. 2020-02-29 16:07:24 +01:00
Paul Chote
c0587cc568 Introduce ActivateParatroopers Lua API.
SendParatroopers and SendParatroopersFrom are now deprecated.
The paratrooper actors themselves can be accessed using the
Trigger.OnPassengerExited trigger.
2020-02-29 16:07:24 +01:00
Paul Chote
ed415cb637 Remove deprecated *Upgrade Lua API methods. 2020-02-29 16:07:24 +01:00
abcdefg30
a10deddf53 Update the Lua API 2020-02-28 18:48:05 +01:00
abcdefg30
a5bc841355 Ignore the types of an exit when the production type is null or empty 2020-02-28 18:48:05 +01:00
Paul Chote
41657dd291 Allow spectators to be kicked after the game starts. 2020-02-28 00:04:49 +01:00
abcdefg30
a7d5b7b8b0 Fix FreeActorWithDelivery not being properly conditional 2020-02-27 18:50:51 +01:00
reaperrr
eb007fc43c Add Frames support to Combine 2020-02-27 18:44:34 +01:00
Paul Chote
301d09ea8f Remove undefined RequiresForceMove from TransformsIntoTransforms. 2020-02-27 18:42:48 +01:00
Paul Chote
ac46b4b791 Fix transparent pixels in Mobile Flack icon. 2020-02-27 00:11:39 +01:00
Paul Chote
fb7c781a66 Add multi-resolution mod icon support. 2020-02-26 23:47:15 +01:00
Paul Chote
e5309ee586 Remove unused InstalledMods.Icons cache. 2020-02-26 23:47:15 +01:00
Paul Chote
84df61c672 Add multi-resolution badge support. 2020-02-26 23:47:15 +01:00
Paul Chote
de4a7cecf0 Rework multi-resolution sprite handling:
- Sprite.Bounds now refers to rectangles in the source image.
  Use this when copying pixels, etc.
- Sprite.Size now refers to sizes in effective pixel coordinates.
  Use this when rendering.
- Sheet.DPIScale has been removed.
- "Density" term is introduced to refer to the number of artwork
  pixels per effective pixel.
2020-02-26 23:47:15 +01:00
abc013
c0ece00c4b Prevent production cycling when producing actor does not occupy space 2020-02-26 23:25:41 +01:00
Paul Chote
6ba02800ab Add TransformsIntoTransforms to enable queued MCV redeploy. 2020-02-24 12:56:49 +01:00
Paul Chote
84419e4259 Add queued argument to CanIssueDeployOrder. 2020-02-24 12:56:49 +01:00
Paul Chote
2016ab105e Fix Reverses parsing. 2020-02-23 16:41:57 +01:00
Paul Chote
def65b10bd Don't crash with an unhelpful IndexOutOfRangeException. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
31d98cc802 Reduce the electro death loop length. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
ccbaa4f816 Setup the original laser zap death animation. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
2049d1b26a Allow guessing of sprite sequence length from number of frames. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
15f8469272 Use the original elongated tesla zap death animation. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
43cac2f051 Don't complain about shadow frame length when there are none. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
39b7db2703 Allow repetition of frames in sequence setups. 2020-02-23 16:41:57 +01:00
Paul Chote
d3291ea585 Fix script error in ordos05. 2020-02-23 11:03:23 +01:00
Ivaylo Draganov
2e8740d6a8 Change default hotkey bindings for select and cycle production buildings 2020-02-22 20:06:21 +00:00
Ivaylo Draganov
1bcad55c1f Add a hotkey to select the current production facility 2020-02-22 20:06:21 +00:00
Paul Chote
7ffc689037 Fix TD panel-transparent definition. 2020-02-22 12:39:11 -06:00
Paul Chote
7d17916e3f Load badges on the main thread. 2020-02-22 19:19:20 +01:00
abcdefg30
e877bb1206 Fix GrantConditionOnProduction not using ShowSelectionBar 2020-02-22 18:05:40 +00:00
reaperrr
226159d220 AttackBase ResolveOrder optimization
Only check for "Stop" when the other 'if' didn't apply.
2020-02-22 17:56:47 +00:00
reaperrr
da4ed24064 Mobile ResolveOrder optimization
When the order is "Move", the other two 'if' checks
are redundant, so 'else if' makes more sense here.
2020-02-22 17:56:47 +00:00
reaperrr
b524dc9b72 Carryall ResolveOrder optimization
There can be only one OrderString at a time,
so we make 'PickupUnit' an "else if", too.
2020-02-22 17:56:47 +00:00
reaperrr
1e43a8f590 Minor Aircraft ResolveOrder optimization
Streamline RTB if checks.
2020-02-22 17:56:47 +00:00
Matthias Mailänder
805a8fc556 Specify unicode without BOM as standard. 2020-02-22 18:44:10 +01:00
Robert
885931ae74 Run every color validation together
This ensures that color picks that have multiple issues will
have them all checked at the same time, including ensuring that
the fix for one issue doesn't cause another issue.

Handling of the onError action has been changed from being called
at once to collecting the potential errors in a HashSet to deduplicate
them and then calling onError after a valid color has been found.
(Otherwise you would in the worst case get 256 error messages logged!)
2020-02-22 16:31:29 +00:00
Robert
4d4f1d6068 Avoid null vectors when making colors valid
If the picked color and a forbidden color are identical (like
if they both picked the same palette color and in the special case
when a picked color is outside of the allowed range and the method
returns the picked color as the forbidden color),
the vector between them is zero and the maths for adjusting
the color fails by hitting the iteration limit. This changes
the zero vector to the smallest possible vector in order to
avoid the issue.

This can result in some seriously close adjustments in the case of
picking identical palette colors, which might
be undesirable compared to picking a new palette color.
2020-02-22 16:31:29 +00:00
Robert
fafa219d11 Added error message if color could not be adjusted
The failsafe in ColorValidator aborts after 255 iterations of
adjusting the color and picks a random color. This message makes it
clearer to the user. Results in two messages being displayed,
first one about adjusting and the about a random color pick.
2020-02-22 16:31:29 +00:00
Paul Chote
eae287efc3 Fix travis packaging. 2020-02-22 10:28:48 -06:00
Paul Chote
8903577227 Update native libraries shipped in the AppImages:
* SDL2 reverted back to 2.0.8 (2.0.9 and 2.0.10 generate compilation
  errors so are missing from the libs tarball)
* Package Freetype 2.0.10
2020-02-22 10:28:48 -06:00
Matthias Mailänder
103cb61020 Add a new rallypoint established notification. 2020-02-22 17:16:17 +01:00
Ivaylo Draganov
1dd1786469 Reduce duplication of "Battlefield Control" chat line label 2020-02-22 15:58:00 +00:00
Ivaylo Draganov
3e2022a3dd Allow players to mute shellmap background music 2020-02-22 15:50:01 +00:00
Paul Chote
28f7604172 Reset nextScanTime only when actually scanning for targets. 2020-02-22 16:30:07 +01:00
Paul Chote
96463634c7 Add --debug-chrome-regions utility command. 2020-02-22 16:18:45 +01:00
Paul Chote
01f5ecb2f9 Fix save game loading screen stripe bounds. 2020-02-22 16:14:32 +01:00
reaperrr
d835090d0b Move LCWCompression support to Mods.Cnc 2020-02-22 15:40:37 +01:00
reaperrr
c687600d66 Duplicate part of LCWCompression to VqaReader
Duplicates the part needed by the VqaReader,
so we can move LCWCompression to Mods.Cnc
ahead of VQA (which has some additional prerequisites).
2020-02-22 15:40:37 +01:00
reaperrr
ed618c807d Streamline LCWCompression code
Just making it more concise to reduce line count.
No functionality/efficiency changes.
2020-02-22 15:40:37 +01:00
Paul Chote
85faa5edf6 Add visual indicator when the game is muted. 2020-02-22 14:42:11 +01:00
Paul Chote
3f601e1ec1 Update color picker hue slider when the color changes. 2020-02-22 14:00:12 +01:00
teinarss
9d68b815a1 Fix tooltip in Observer widgets 2020-02-22 11:38:53 +01:00
teinarss
cffe5e3d9d Add owner token to TooltipContainer 2020-02-22 11:38:53 +01:00
Paul Chote
7e72cd262c Fix FlyAttack invalid target crash. 2020-02-19 23:35:16 -06:00
Paul Chote
9a6602656b Ignore nearEnough if we think the actor can get closer. 2020-02-18 19:37:17 +01:00
Matthias Mailänder
57da756f2f Set the camera pitch to 30° 2020-02-18 00:49:04 +01:00
abcdefg30
40bb45a02b Deprecate the release-20181215 path 2020-02-17 20:14:56 +00:00
abcdefg30
f73d23661f Update the update paths for release-20200202 2020-02-17 20:14:56 +00:00
Paul Chote
09a019f9c6 Add a lint check for LockFaction on mission players. 2020-02-16 20:51:29 +01:00
Paul Chote
4ec258cbdd Add missing LockFaction definitions to nod09, 10a, 10b. 2020-02-16 20:51:29 +01:00
Paul Chote
41d7a2d429 Fix an integer overflow when calculating selection priorities. 2020-02-16 17:57:04 +01:00
abcdefg30
7cec1b771d Fix Actor.CurrentActivity bogusly pointing to finished activities 2020-02-16 16:58:06 +01:00
abcdefg30
b1b74c13c3 Ensure that we never tick an activity before calling OnFirstRun 2020-02-16 16:58:06 +01:00
abcdefg30
c4a5540bfd Ensure that we never run Done child activities 2020-02-16 16:58:06 +01:00
abcdefg30
abcb2ea512 Directly mark queued activities that are cancelled as Done 2020-02-16 16:58:06 +01:00
Paul Chote
f45dd24781 Update AppImage SDL2 dependency to 2.0.10. 2020-02-16 14:53:42 +01:00
Paul Chote
8d23994a04 Update Windows SDL2 dependency to 2.0.10. 2020-02-16 14:53:42 +01:00
Paul Chote
46e0b3b363 Update macOS SDL2 dependency to 2.0.10. 2020-02-16 14:53:42 +01:00
Paul Chote
689049cc12 Fix NRE in ArmyUnit constructor. 2020-02-16 13:57:19 +01:00
Paul Chote
1485194ef3 Automatically scale DPI under Linux. 2020-02-16 13:44:50 +01:00
Paul Chote
4203a3191f Overhaul macOS packaging:
- Build on Travis-CI macOS VM
- Sign and notarize for distribution
- Create macOS-specific files from generic sources during packaging
- Add volume icon
- Rename osx directory to macos
2020-02-15 18:51:21 +01:00
Paul Chote
7b4019577d Force disable glDebugMessageCallback on Linux+AMD. 2020-02-15 11:38:30 +01:00
Paul Chote
52f4e24e22 Fix spectator minimap not updating when in "Disable Shroud" view. 2020-02-14 23:07:31 +01:00
Paul Chote
ab196a23e6 Fix AttackFollow ignoring allowMove flag when auto-targeting. 2020-02-14 17:30:38 +01:00
Paul Chote
3a688e03f0 Add multiple levels of fallback. 2020-02-12 21:17:39 +00:00
Paul Chote
a43335c7b0 Restore transient blocker check in pathfinding queries. 2020-02-12 21:17:39 +00:00
Paul Chote
585b8dc13c Set default rally point to an empty path. 2020-02-09 16:52:22 +01:00
Paul Chote
b2f0ac15e8 Generalize RallyPointInfo.Offset to support arbitrary length paths. 2020-02-09 16:52:22 +01:00
Paul Chote
9dc4ea8541 Fix production door not closing if the actor stays on the exit cell. 2020-02-09 16:52:22 +01:00
teinarss
817f75c808 Add unique ingame-observer.yaml for D2K 2020-02-09 16:37:21 +01:00
teinarss
7e3830e053 Updated production spec widget to handle overflow 2020-02-09 16:37:21 +01:00
teinarss
b81ede2d64 Added widget showing the army for players in spec 2020-02-09 16:37:21 +01:00
Mustafa Alperen Seki
6ab0ace9e1 Add PlayLaunchSounds() to SupportPowers which are missing it. 2020-02-09 13:34:46 +01:00
Paul Chote
85a5b6cc17 Fix subcell crusher logic. 2020-02-09 13:18:57 +01:00
Ivaylo Draganov
62af58c2e6 Calculate position of dropdown arrow glyph based on image width 2020-02-09 12:53:30 +01:00
abcdefg30
aeacc86028 Remove a loop closure guard variable 2020-02-09 12:18:09 +01:00
abcdefg30
5c4ec1bf0e Fix a crash when a SourceActor does not occupy space 2020-02-09 12:18:09 +01:00
abcdefg30
e3f545cae9 Make WarheadArgs.Source nullable 2020-02-09 12:18:09 +01:00
Paul Chote
71cbfc5968 Change default player color to dark red. 2020-02-08 20:09:02 +01:00
Paul Chote
fdc3a6a32d Change default name from Newbie to Commander. 2020-02-08 20:09:02 +01:00
Paul Chote
e6c1356d59 Add introduction prompt on first run. 2020-02-08 20:09:02 +01:00
Paul Chote
e8df28c518 Extract sysinfo logic to its own class. 2020-02-08 20:09:02 +01:00
Martin Bertsche
98aef70e88 Added display selection option to settings for fullscreen modes. 2020-02-08 18:14:35 +00:00
abcdefg30
de0bb9ee39 Fix a crash in the ReplaceAttackTypeStrafe update rule 2020-02-06 21:52:46 +00:00
tovl
c18857f15d Let immovable actors block individual minefield cells. 2020-02-06 22:26:15 +01:00
Paul Chote
9a0916afbb Add UI Scale dropdown to the settings menu. 2020-02-04 19:56:15 +01:00
Paul Chote
6388a6bff4 Add Graphics.UIScale setting to modify UI size. 2020-02-04 19:56:15 +01:00
Paul Chote
ce445f993c Add SupportDir argument to the launch-dedicated scripts. 2020-02-04 00:21:52 +01:00
Paul Chote
0e39c98989 Ignore empty support directory overrides. 2020-02-04 00:21:52 +01:00
Paul Chote
c2bc313bf0 Fix key repeat events queueing many deploy/scatter/stop orders. 2020-02-01 13:18:04 +01:00
Paul Chote
5c76a6e7a7 Fix key up events queueing duplicate deploy/scatter/stop orders. 2020-02-01 13:18:04 +01:00
Matthias Mailänder
1e8912b4e4 Fix the namespace. 2020-02-01 02:42:25 +01:00
abcdefg30
6cc27eaa76 Fix the description of VeteranProductionIconOverlay 2020-01-31 13:55:56 +01:00
Ivaylo Draganov
1020a7bfab Use common notice colors for UPnP status labels 2020-01-31 00:50:25 +01:00
Ivaylo Draganov
b80928bd95 Display a confirmation prompt on settings panel reset 2020-01-30 23:06:49 +01:00
abcdefg30
a6371f6fa9 Fix mission specific buildings not granting prerequisites 2020-01-29 20:59:45 +00:00
Paul Chote
bf314fdc7b Define window size in effective pixel coordinates. 2020-01-26 20:22:49 +01:00
Paul Chote
f0033c44c7 Use full window resolution on Windows. 2020-01-26 20:22:49 +01:00
Paul Chote
fd64ad7c89 Support rendering at non-integer display scales:
* 2x and 3x DPI artwork can be specified using
  Image2x and Image3x in chrome.yaml.
* Images are rendered using bilinear interpolation.
* For non-integer screen scales, prefer downscaling
  the next biggest resolution image over upscaling.
2020-01-26 20:22:49 +01:00
Paul Chote
809b1507a6 Fix font rendering at non-integer display scales. 2020-01-26 20:22:49 +01:00
Paul Chote
d91495a041 Allocate 1px empty margin between sprites. 2020-01-26 20:22:49 +01:00
Paul Chote
84daf890d3 Use antialiasing filter when rendering world annotations. 2020-01-26 20:22:49 +01:00
Paul Chote
1bc6fb0f46 Use antialiasing filter when rendering UI icons and actors. 2020-01-26 20:22:49 +01:00
Paul Chote
1f849e9f7d Add antialiasing support for paletted sprites. 2020-01-26 20:22:49 +01:00
Paul Chote
bd4724842c Fix software cursor rendering at fractional scales. 2020-01-26 20:22:49 +01:00
Paul Chote
25a7299c67 Fix scroll event position calculation. 2020-01-26 20:22:49 +01:00
Paul Chote
518450cd8a Extract load screen sheet handling into a superclass. 2020-01-26 20:22:49 +01:00
Paul Chote
57a8cf7a59 Rework Display settings tab. 2020-01-26 17:11:45 +01:00
Paul Chote
83732f299b Add DropDownButtonWidget.PanelAlign. 2020-01-26 17:11:45 +01:00
Paul Chote
f730b55255 Move hardware cursor control to hidden DisableHardwareCursors setting. 2020-01-26 17:11:45 +01:00
Paul Chote
370f7a44fa Restore cursor doubling for "default" cursor. 2020-01-26 17:11:45 +01:00
Paul Chote
f7e5111123 Apply cursor doubling setting without requiring a restart. 2020-01-26 17:11:45 +01:00
Paul Chote
847db5e59b Merge HardwareCursor and SoftwareCursor into CursorManager. 2020-01-26 17:11:45 +01:00
Mustafa Alperen Seki
d7f43b33c7 Make GrantConditionOnAttack PausableConditional 2020-01-26 17:05:02 +01:00
Paul Chote
3a6d88cfef Align settings to the standard row height. 2020-01-26 16:52:14 +01:00
Paul Chote
70f899c8d1 Remove unused localization options from settings.yaml. 2020-01-26 16:52:14 +01:00
Paul Chote
e138afc328 Overhaul Input settings. 2020-01-26 16:52:14 +01:00
Paul Chote
a84c914317 Move highlighting logic into a dedicated widget. 2020-01-26 16:52:14 +01:00
Paul Chote
46d59eef5e Update TD cash glyphs. 2020-01-25 22:02:43 +01:00
Paul Chote
79d25b9eca Update RA cash glyphs. 2020-01-25 22:02:43 +01:00
Paul Chote
cc530649c7 Fix horizontal positioning of dropdown arrow glyph. 2020-01-25 21:56:02 +01:00
abcdefg30
aeb623498f Remove old update rules 2020-01-25 21:29:36 +01:00
Mustafa Alperen Seki
d4b08850f3 Fix conditionality of DisguiseTooltipInfo. 2020-01-25 17:28:15 +02:00
Paul Chote
1fada0f2b4 Add KHR suffix as defined by the KHR_debug spec. 2020-01-25 13:44:06 +01:00
Paul Chote
b08f9886be Add Graphics.DisableGLDebugMessageCallback setting. 2020-01-25 13:44:06 +01:00
reaperrr
46384d25f2 Improve Rectangle HitShape debug overlay
Showing vertical sides, too.
2020-01-25 13:38:35 +01:00
reaperrr
9dcba8710b Add turret-linking support to HitShape
Allows to link a HitShape to the
position and facing of a turret.
2020-01-25 13:38:35 +01:00
reaperrr
b839204c7f Minor WithInfantryBody reorganisation
Move PlayStandAnimation to a more suitable position
inside the file.
2020-01-25 13:26:25 +01:00
reaperrr
595b6c8923 Greatly simplified WithInfantryBody TickIdle code
There was a lot of redundancy and unnecessary
complexity in several checks.

This now also prevents infantry from randomly
restarting and potentially switching between stand
sequences if there are no idle sequences.
Old behavior can still be replicated by listing
stand sequences as IdleSequences.
2020-01-25 13:26:25 +01:00
Ivaylo Draganov
9474bdba5c Use proper glyph for in-game chat close button 2020-01-25 13:17:09 +01:00
abcdefg30
f5aa304e09 Add stray update rules to the correct path 2020-01-25 10:48:50 +00:00
Pavel Penev
93bec9e430 Updated the default mods' weapons 2020-01-24 13:09:37 +01:00
Pavel Penev
d33a5bf94e Added an UpgradeRule CreateScreenShakeWarhead 2020-01-24 13:09:37 +01:00
Pavel Penev
b00154e2bc Created ShakeScreenWarhead and removed the hardcoded shaking from NukeLaunch and MadTank 2020-01-24 13:09:37 +01:00
reaperrr
6220d7e62e Introduce WarheadArgs
- Passes additional arguments to warheads on impact
- Uses that to reduce parameter count of DoImpact by 1
2020-01-21 19:31:34 +01:00
Paul Chote
fdc0a6e2b9 Rework TS Chrome in preparation for UI scaling. 2020-01-19 20:36:59 +01:00
Paul Chote
f37d9a7010 Rework D2k Chrome in preparation for UI scaling. 2020-01-19 20:34:18 +01:00
abcdefg30
9f66e3936d Add issue templates for the new issue template chooser 2020-01-19 17:27:43 +01:00
Paul Chote
f1325e12d4 Extract text contrast radius to ChromeMetrics and reduce to 1px. 2020-01-19 17:18:22 +01:00
Paul Chote
7611449d3d Reimplement text contrast using greyscale dilation. 2020-01-19 17:18:22 +01:00
abcdefg30
15b2d6b9e0 Let all Positionable traits notify visual position changes 2020-01-18 23:07:23 +00:00
Paul Chote
d0f44143c2 Fix activity cancellation on FlyAttack RTB.
* AbortOnResupply will now cancel queued activities
  in addition to the current attack.
* Resupply if no ammo is available during a standard attack.
* Don't resupply (move directly to target) if no ammo is available
  during an attack move (C&C3 style).
2020-01-18 16:38:53 +01:00
Paul Chote
51870a471a Add AttackSource enum. 2020-01-18 16:38:53 +01:00
Paul Chote
6f52365f9d Don't run NextActivity if it has been canceled. 2020-01-18 16:38:53 +01:00
Paul Chote
66b8689957 Use 32bit modcontent cursor. 2020-01-17 16:49:58 +01:00
Paul Chote
4fd475f7c2 Add RGBA cursor support. 2020-01-17 16:49:58 +01:00
Paul Chote
522861e484 Support 32 bit png sprites. 2020-01-17 16:49:58 +01:00
Paul Chote
1111ce4754 Add support for 32 bit BGRA sprites. 2020-01-17 16:49:58 +01:00
Paul Chote
cdbee49280 Fix slider ticks in TD. 2020-01-17 13:42:51 +01:00
reaperrr
aa63696933 Update rule for WithPermanentInjury removal 2020-01-16 22:56:39 +01:00
reaperrr
10540839f6 Make crippled TS Cyborgs use permanent TakeCover
This is more in line with original behavior.
Also allows us to remove WithPermanentInjury.
2020-01-16 22:56:39 +01:00
reaperrr
a9eca2cf54 Add support for enabling prone state permanently
Negative ProneTime now activates prone state
permanently as soon as the trait is enabled.
2020-01-16 22:56:39 +01:00
Paul Chote
d6436858a9 Fix IPAddress capitalization. 2020-01-15 12:12:54 +01:00
Paul Chote
38cb818469 Anonymise client IPs and allow server operators to disable sharing. 2020-01-15 12:12:54 +01:00
Paul Chote
422cc2b0d0 Hide location and IP labels if not known. 2020-01-15 12:12:54 +01:00
Paul Chote
d74a5065b9 Require GeoLite2 database path to be specified by the server operator. 2020-01-15 12:12:54 +01:00
Paul Chote
6b2c019caa Evaluate player location on the server. 2020-01-15 12:12:54 +01:00
Paul Chote
c430884c8b Require GeoLite2 database path to be specified by the server operator. 2020-01-15 12:12:54 +01:00
Matthias Mailänder
8dda6d8e3d Remove unnecessary null check. 2020-01-14 22:08:57 +01:00
Matthias Mailänder
c43d581e7f Add cursor palette support to GIMP/Jasc palette definitions. 2020-01-14 22:08:57 +01:00
teinarss
f0b69f8b8d Separated resource rendering into another trait 2020-01-14 19:38:47 +01:00
Matthias Mailänder
0e93d85273 Move the AssetBrowserFileEndingsFilter to IGlobalModData
to avoid mods having to duplicate the whole chrome layout.
2020-01-13 13:46:34 +01:00
Paul Chote
adb3c8e39c Split fixed-wing attack and strafe attack types. 2020-01-12 21:06:35 +01:00
tovl
85bc843554 Fix aircraft failing to engage targets within range. 2020-01-12 21:06:35 +01:00
Matthias Mailänder
c95216cd19 Move the hard-coded shroud palette to the C&C folder. 2020-01-12 19:35:41 +00:00
Paul Chote
cc05621c10 Draw editor terrain/resource preview as part of the world. 2020-01-12 18:30:50 +01:00
Paul Chote
e74033bded Render editor actor previews as part of the world. 2020-01-12 18:30:50 +01:00
Paul Chote
fe25fdf0ff Improve robustness of editor actor cell checks. 2020-01-12 18:30:50 +01:00
Paul Chote
1282650274 Rework RA Chrome in preparation for UI scaling. 2020-01-12 18:16:41 +01:00
Paul Chote
d622015b59 Fix Texture.GetData under GLES. 2020-01-12 17:04:23 +01:00
Paul Chote
524e8875d0 Restore MODIFIER_OVERRIDES handling of unmodified attack move hotkey. 2020-01-12 16:33:35 +01:00
Paul Chote
8c2a2d2cb8 Rework TD/modcontent chrome in preparation for UI scaling. 2020-01-12 15:52:12 +01:00
abcdefg30
a28992aa38 Default LocalClientId in ReplayConnection to -1
We do not have a local client in replays.
This change prevents anything from accidentally using (sometimes there might be clients with ID 0 present).
2020-01-12 14:23:34 +01:00
Paul Chote
0db4085950 Load and save registrations to both the active and legacy support directories. 2020-01-12 14:10:23 +01:00
Paul Chote
f162d90e9f Rework support dir initialization. 2020-01-12 14:10:23 +01:00
abcdefg30
abfb28a4f3 Fix the Build function in gdi04b 2020-01-12 14:04:51 +01:00
abcdefg30
c15a555cff Fix cargo initialisation 2020-01-12 13:58:04 +01:00
abcdefg30
e1c07d32d5 Prevent cell triggers in sarin-gas-2 from firing several times 2020-01-12 13:49:25 +01:00
tovl
fbfef903ac Let movement trigger visibility recalculation. 2020-01-12 04:50:25 +01:00
tovl
695d9a6cb1 Centralize shroud changes in one pass to improve performance. 2020-01-12 04:50:25 +01:00
Paul Chote
0106ed3669 Restore red lines for harvester targets. 2020-01-12 04:08:59 +01:00
abcdefg30
ac42dd79ca Make the command bar directly check if a GuardOrderGenerator is active 2020-01-12 00:54:38 +00:00
abcdefg30
deffc2dd15 Add support for defining the palette of WithResourceLevelOverlay 2020-01-12 00:47:20 +00:00
reaperrr
bb1d5f1d5c Fix ReloadAmmoPool.ResetFire ignoring multipliers 2020-01-11 23:29:37 +00:00
teinarss
43eabdf54a Fix naming in editor 2020-01-11 22:03:26 +00:00
tovl
0e32cbee5e Fix crash in RallyPointIndicator. 2020-01-11 21:26:47 +00:00
reaperrr
308c64c7b1 Fix trait order issues with KillsSelf 2020-01-06 21:47:53 +00:00
reaperrr
16c2062d9d Replace LandOnCondition with landing when paused 2020-01-06 21:47:53 +00:00
reaperrr
ac44367440 Refactor Spin to MaximumSpinSpeed
Additionally, add descriptions to
other FallsToEarth properties.
2020-01-06 21:47:53 +00:00
reaperrr
20beb4abe1 Fix Harpy husk rotor offset 2020-01-06 21:47:53 +00:00
reaperrr
a369634ea8 Display EMP effect on EMP'd aircraft's husks
When EMP'd while airborne.
2020-01-06 21:47:53 +00:00
reaperrr
7a095f30ec Make TS aircraft crash when EMP'd mid-air
And refuse move orders if EMP'd while landed.
Matches original behaviour.
2020-01-06 21:47:53 +00:00
Punsho
59bcac410f Make EMP effect carryall and orca transport 2020-01-06 21:47:53 +00:00
reaperrr
4499343ed2 Make Aircraft actually pausable/disableable
This commit makes aircraft
- ignore any aircraft-specific orders while disabled
- show blocked move cursor while paused
- set speeds to zero while paused or disabled
2020-01-06 21:47:53 +00:00
reaperrr
4b006bc484 Make Aircraft PausableConditional
Note: This commit only does the minimum changes
to implement PausableConditional, there are no
logic changes yet (like disabling movement on PauseOnCondition).
2020-01-06 21:47:53 +00:00
abcdefg30
23b3c237b7 Update the year numbers in all license headers to 2020 2020-01-05 17:00:34 +00:00
Matthias Mailänder
e33cf8a8ae Fix a crash when cursor is null. 2020-01-05 13:27:53 +00:00
Matthias Mailänder
7e9a3d3bc9 Unhardcode transparent index in manual palettes as well. 2020-01-05 13:17:43 +00:00
Matthias Mailänder
6ea85a1a62 Don't hard-code the transparent background color. 2020-01-05 13:17:43 +00:00
Ivaylo Draganov
535144b208 Use system chat line for audio muted/unmuted notifications 2020-01-04 23:05:25 +00:00
Paul Chote
439cd4aded Rework HardwareCursor sprite padding.
All frames in a sequence now use the same bounds
and hotspot, and have a size that is a multiple of 8.
2020-01-04 22:45:51 +01:00
tovl
2094142b7d Include tunnel check in CanStayInCell. 2020-01-04 16:04:27 +00:00
tovl
196d9670d3 Disallow units from idling on bibs in TS. 2020-01-04 16:04:27 +00:00
tovl
434c46058f Disallow units idling on service depot. 2020-01-04 16:04:27 +00:00
tovl
c360d8bcef Make service depot passable. 2020-01-04 16:04:27 +00:00
teinarss
76221471ff Remove unused code from Cargo trait 2020-01-03 19:34:56 +01:00
teinarss
a9d7535915 Remove cargo initialization from Tick 2020-01-03 19:34:56 +01:00
teinarss
20610d05a2 Remove CurrentAdjacentCells update on each tick in Cargo 2020-01-03 19:34:56 +01:00
Ivaylo Draganov
af5d8a3bbe Add a hotkey to cycle harvesters 2020-01-02 23:42:22 +01:00
abcdefg30
ab348336f5 Fix ants teleporting into the map area
Waypoint17 is not at the map edge, waypoint7 is.
Also fixes a path, since waypoint20 -> waypoint10 is going back and makes no sense.
Going directly waypoint20 -> waypoint2 works and as compensation I added waypoint21 -> waypoint10 -> waypoint2.
2020-01-02 16:34:38 +00:00
reaperrr
804d61a6a1 Fix DeliverUnit-related crash 2020-01-01 20:42:36 +01:00
Paul Chote
baa5b3d25e Bypass fingerprint validation for skirmish/mission servers. 2020-01-01 20:33:30 +01:00
Paul Chote
8f2bf27edf Replace Server.Dedicated with Server.Type. 2020-01-01 20:33:30 +01:00
abcdefg30
a9f37bc9f1 Remove a leftover geoip reference from the linux packaging script 2019-12-31 17:03:05 +00:00
unknown
79136a520f Remove dublicate function 2019-12-31 17:32:43 +01:00
Paul Chote
adf1c0b616 Remove GeoIP database from install/packaging scripts. 2019-12-31 17:28:30 +01:00
Paul Chote
e063e13ff4 Remove automatic GeoIP download from the build scripts.
The database file is now locked behind an account login.

https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases/
2019-12-31 17:28:30 +01:00
reaperrr
9d7ecdbc2c Disable SupportPowerInstances when player lost
Fixes bots using player actor powers after defeat.
2019-12-30 22:50:54 +01:00
reaperrr
7a57f0e6ef Expose delay of WithDeathAnimation
Allows to show it a few ticks after death if the modder
wishes so.
2019-12-30 18:01:09 +00:00
reaperrr
c55c65f6d7 Add delay support to SpriteEffect 2019-12-30 18:01:09 +00:00
reaperrr
037ce9ebf3 Rename ProneTime to Duration
More in line with our property naming conventions.

Additionally, added descs to ProneOffset and
ProneSequencePrefix, since at  least the purpose of
the former isn't entirely clear without looking at the code.
2019-12-30 11:34:41 +01:00
reaperrr
cef940fea9 Fix TakeCover to be disabled properly
Speed and Damage modifiers were ignoring IsTraitDisabled.
2019-12-30 11:34:41 +01:00
Paul Chote
a7ae93978a Disable sound controls when no audio device is available. 2019-12-29 17:53:44 +01:00
Paul Chote
4052620f94 Rename dummy sound label to "No Sound Output". 2019-12-29 17:53:44 +01:00
Paul Chote
032c412e09 Fix WithTextDecoration rendering. 2019-12-28 21:44:26 +01:00
Paul Chote
5a686b3289 Fix duplicated/distorted SequencePlaceBuildingPreview annotations. 2019-12-28 20:56:09 +01:00
Paul Chote
2bf16a34d6 Filter invalid actor IDs when restoring selection save data. 2019-12-28 20:48:46 +01:00
Paul Chote
7ccc63b51c Fix incorrect region definitions. 2019-12-28 19:15:36 +01:00
Paul Chote
e7253fd643 Manual chrome.yaml cleanups. 2019-12-28 19:15:36 +01:00
Paul Chote
f3d7bf403e Rework chrome.yaml format and panel rendering. 2019-12-28 19:15:36 +01:00
Paul Chote
0b8a367867 Fix MiniYaml parsing of empty comments 2019-12-28 19:15:36 +01:00
abcdefg30
aabfd91001 Fix an indentation style issue in TransformsIntoAircraft 2019-12-28 19:16:21 +03:00
Ivaylo Draganov
3d1b4c2509 Remove "Surrender" button for single player games 2019-12-28 15:06:26 +00:00
Ivaylo Draganov
14bc7885b3 Always prompt the user to confirm when leaving a game 2019-12-28 15:06:26 +00:00
Ivaylo Draganov
2204e807b8 Add restart button to main menu for single player (missions, skirmish, replays) 2019-12-28 15:06:26 +00:00
abcdefg30
baa50c9c53 Pass DamageTypes in Explodes 2019-12-28 10:54:27 +01:00
Paul Chote
7d887f0332 Fix NV shader compile errors in combined.frag. 2019-12-27 20:20:42 +01:00
Paul Chote
51eaa17b1e Replace frame limit text field with a slider. 2019-12-26 17:25:38 +01:00
Paul Chote
35a36b4cdf Disable frame limiter by default
VSync does a more reliable job of this.
2019-12-26 17:25:38 +01:00
Paul Chote
2231183fe0 Account for game ticks when applying the frame limiter. 2019-12-26 17:25:38 +01:00
Paul Chote
656a260171 Add VSync setting. 2019-12-26 17:25:38 +01:00
abcdefg30
959c750851 Move voice playing for orders into a helper function 2019-12-23 15:01:36 +01:00
abcdefg30
4d407da3e6 Fix a potential crash in PlayVoiceForOrders 2019-12-23 15:01:36 +01:00
abcdefg30
bb1d1f8140 Remove a nowadays unnecessary loop safeguard 2019-12-23 14:57:50 +01:00
abcdefg30
d2db707521 Move unit order resolving into a helper function 2019-12-23 14:53:13 +01:00
Abdurrahmaan Iqbal
a107da0888 Fix for mod credits overriding engine credits 2019-12-23 13:48:47 +00:00
Paul Chote
b1f7c5c4e3 Remove overlapping vision ranges from RA actors.
This brings a significant perf saving by reducing
the number of evaluated tiles.
2019-12-23 13:53:08 +01:00
Paul Chote
04bad1ae66 Add MinRange support to AffectsShroud. 2019-12-23 13:53:08 +01:00
Paul Chote
5830d4de6c Fix ATEK vision ranges. 2019-12-23 13:53:08 +01:00
abcdefg30
bb85146544 Make orcas buildable on nod07c 2019-12-21 00:48:03 +01:00
abcdefg30
c4ab5d4561 Fix/Update the patrols on nod07c 2019-12-21 00:48:03 +01:00
abcdefg30
54e2aad1cd Fix broken reinforcements on gdi04 and limit them to 3 waves 2019-12-21 00:48:03 +01:00
abcdefg30
b1f6c69fce Use a global script in Tiberian Dawn 2019-12-21 00:48:03 +01:00
abcdefg30
dbe73a06ad Remove ISync from RallyPoint 2019-12-15 23:21:27 +01:00
Paul Chote
f36d0cc214 Fix ModContent cursor. 2019-12-15 22:29:26 +01:00
abcdefg30
1e138a9774 Drop invisible invalid targets immediately when changing stance 2019-12-14 17:17:36 +01:00
abcdefg30
905e02b765 Prevent a crash in AutoTarget.HasValidTargetPriority 2019-12-14 17:17:36 +01:00
Paul Chote
3487846636 Restore NukePower support for proxy actors. 2019-12-14 17:07:16 +01:00
tovl
203fff0ab7 Allow queued structure rallypoints. 2019-12-13 23:51:03 +01:00
tovl
3236499fb7 Increase IMove.MoveTo call flexibility. 2019-12-13 23:51:03 +01:00
Paul Chote
28dbda29e3 Add zoom hotkeys. 2019-12-13 21:29:43 +01:00
Paul Chote
1dcb903580 Implement new viewport size/zoom UI. 2019-12-13 21:29:43 +01:00
Paul Chote
860117daf9 Implement optimized pixel-art antialiasing mode for non-integer world zoom. 2019-12-13 21:29:43 +01:00
Paul Chote
cd368b43df Draw GPS dots using the UI renderers. 2019-12-13 21:29:43 +01:00
Torleif West
ae4b2591bf fix for RA2 cloning vats
formatting

minor formatting

passing CI

closing line bracket

use production unit

opening should not be followed by a blank line

revert tab change
2019-12-12 22:08:25 +01:00
Paul Chote
b0c65c5eb9 Overhaul cursor double setting. 2019-12-11 13:38:52 +01:00
Paul Chote
010fafc6d3 Fix hardware cursors on systems with >150% DPI scaling. 2019-12-11 13:38:52 +01:00
Paul Chote
79aac08a48 Fix turret positioning in the map editor. 2019-12-11 11:02:04 +01:00
Paul Chote
630ca0aefb Draw editor selection box using the UI renderers. 2019-12-11 11:02:04 +01:00
abcdefg30
2918ecadaa Fix team chat messages not always being displayed 2019-12-10 13:05:38 +01:00
reaperrr
82be8d9990 Move AUD support to Mods.Cnc 2019-12-09 22:06:53 +01:00
reaperrr
4d92fde5f7 Remove VqaReader dependency on AudReader
Use ImaAdpcmReader directly, since VQAs only contain
header-less raw IMA  ADPCM audio.
2019-12-09 22:06:53 +01:00
reaperrr
5afc1c1443 Remove duplication between IMA and AUD readers
These parts were identical duplicates, so I removed them
and made AudReader depend on ImaAdpcmReader instead.

Applied some style fixes while I was at it.
2019-12-09 22:06:53 +01:00
abcdefg30
22374ed732 Remove the bogus 'GameSaved' speech notification definition 2019-12-08 21:56:24 +01:00
abcdefg30
bc484a9858 Add 'AirstrikeReady' to 'DisablePrefixes' 2019-12-08 21:56:24 +01:00
abcdefg30
9a57980952 Remove 'AbilityInsufficientPower' from cnc's notifications 2019-12-08 21:56:24 +01:00
Ivaylo Draganov
0900ac2b2f Remove stray "Hotkeys" label in the Input Settings panel in TD 2019-12-08 21:38:28 +01:00
reaperrr
4751b1a176 Move ShpTDLoader, LZO and XORDelta formats to Mods.Cnc
They're pretty much RA/TD-specific formats.
2019-12-08 19:43:51 +00:00
reaperrr
cd123830c3 Move VocLoader from D2k to Cnc
My assumption that the D2 mod would want,
let alone need Mods.D2k was wrong.
Meanwhile, it does need Mods.Cnc for at least
the Pak format as well, so this is a good enough
compromise.
2019-12-08 18:14:17 +00:00
Ivaylo Draganov
93e42b0b27 Add selection tiers as inheritable templates 2019-12-08 18:39:21 +01:00
tovl
088919fecc Change color of selection box based on selection mode. 2019-12-08 17:34:10 +01:00
reaperrr
efc06a020b Move WithDeliveryAnimation to Mods.Common 2019-12-08 16:03:14 +00:00
reaperrr
fe1d3b3821 Move ProductionAirdrop to Mods.Common 2019-12-08 16:03:14 +00:00
reaperrr
948a9c9b19 Add ProductionAirdrop.ActorType update rule 2019-12-08 16:03:14 +00:00
Paul Chote
2603a495e6 Add render_world perf sampler. 2019-12-08 04:36:31 +01:00
Paul Chote
8c41e6a3f7 Remove redundant zoom parameter. 2019-12-08 04:36:31 +01:00
Paul Chote
327866ffc3 Render world via an intermediate FrameBuffer. 2019-12-08 04:36:31 +01:00
Paul Chote
0c8a47b5af Add scissor support to IFrameBuffer. 2019-12-08 04:36:31 +01:00
Paul Chote
e7de7b4c05 Introduce World and UI rendering phases. 2019-12-08 04:36:31 +01:00
Paul Chote
ebd1557523 Draw voxel debug annotations using the UI renderers. 2019-12-08 04:36:31 +01:00
abcdefg30
9a5eaa7cb7 Don't throw an exception when a field is missing 2019-12-07 09:15:38 +01:00
Curtis Shmyr
f037436536 Added TooltipName as an actor Lua property 2019-12-06 09:33:23 +01:00
abcdefg30
b1571ad17a Make Parachutable public 2019-12-05 23:13:35 +01:00
Paul Chote
494a7870d6 Add fallback exits to RA Kennel. 2019-12-05 18:01:09 +01:00
Paul Chote
dbe1d2d928 Add fallback exits to TS barracks. 2019-12-05 18:01:09 +01:00
Paul Chote
2146dd29bb Add priority levels to Exit. 2019-12-05 18:01:09 +01:00
matjaeck
5ac9d2c2f1 Fix botmodules querying the Player actor before it is assigned. 2019-12-05 01:48:56 +01:00
reaperrr
a74235bdbc Move ShpD2 and TmpRA/TD loaders to Mods.Cnc
Reducing the count of proprietary formats in Mods.Common.

Note: Moving ShpD2 to Mods.Cnc is intentional. RA/TD
use it for their original mouse shp files, and any D2(k) mod
will normally need Mods.Cnc anyway, while we can avoid
adding a Mods.D2k dependency to RA/TD this way.
2019-12-01 16:23:54 +01:00
reaperrr
a98a96b05d Update update rule paths 2019-11-30 20:08:27 +01:00
abc013
b4c116cb31 Fix ExtractLanguageStrings utility command 2019-11-29 16:40:00 +01:00
reaperrr
074ebefee1 Fix FCOM still providing space while being captured 2019-11-27 23:04:28 +01:00
tovl
6fb3dc050b Let CreateGroup use ExtraActors field. 2019-11-26 22:06:37 +01:00
tovl
00ce1d7ee6 Allow additional actor IDs to be send with orders. 2019-11-26 22:06:37 +01:00
reaperrr
b8e15fbe40 Move FastByteReader from LCW to own file
And make it public.
Making it easier to move formats that depend on it
to Mods.Cnc independently later.
2019-11-23 19:04:27 +01:00
reaperrr
3f06541b2b Move Shp conversion/remap commands to Mods.Cnc 2019-11-23 19:04:27 +01:00
reaperrr
65728bc032 Move VocLoader to Mods.D2k
While this is strictly speaking a D2 format, any
D2 mod is pretty much guaranteed to use Mods.D2k,
so this should be a good enough place to move it to.
2019-11-23 19:04:27 +01:00
reaperrr
c4597b5c6b Fix RA desert tree fire palette
By default WithDamageOverlay uses the actors'
palette, but RA's desert terrain uses the TD desert.pal
which isn't compatible with RA's fire animation shps.
2019-11-23 18:40:27 +01:00
abcdefg30
142f823e6f Explain that CanEnterCell ignores 'subCell' if there is a free subcell 2019-11-21 14:13:17 +01:00
abcdefg30
25b7386f0d Let Mobile's CanEnterCell consider ToSubCell 2019-11-21 14:13:17 +01:00
abcdefg30
4717e98c48 Add a subCell parameter to IPositionableInfo.CanEnterCell 2019-11-21 14:13:17 +01:00
abcdefg30
980c1e1b6a Fix McvManagerBotModule spamming deploy orders
Removes the 'activeMCVs' list since it was not useful.
The real bugfix is not iterating over 'activeMCVs' when issueing new orders
(this was previously needed for already discovered mcvs that stopped)
but over 'newMCVs' instead.
2019-11-20 16:44:39 +01:00
teinarss
a47f60d3a6 Add a trait PlayerRadarTerrain to track explored terrain 2019-11-20 16:24:56 +01:00
reaperrr
ee00954f2e Replace AmmoPool lookup methods with properties
And gave the more suitable names while at it.
This is more in line with how we do things in
other places.
2019-11-20 15:45:41 +01:00
teinarss
c77aa4c8f9 Add IsDead check to FerryUnit OnFirstRun 2019-11-19 15:59:27 +01:00
reaperrr
8181a452cb Fix some header dates
Seems these were overlooked or merged after
the dates of the other files were updated.
2019-11-17 22:32:51 +01:00
Paul Chote
f39b688c39 Add GrantPrerequisiteChargeDrainPower and DrainPrerequisitePowerOnDamage.
These traits implement the Firestorm defense charge/drain logic.
2019-11-17 17:06:29 +01:00
Paul Chote
1fa90c0474 Allow support powers to override the icon overlay/tooltip labels. 2019-11-17 17:06:29 +01:00
Paul Chote
70b020205d Rename *Time to *Ticks and increase internal resolution. 2019-11-17 17:06:29 +01:00
Paul Chote
e03abdc0da Add support for custom SupportPowerInstances. 2019-11-17 17:06:29 +01:00
Paul Chote
61c56dcb00 Fix DamageModifier crashes when an actor is demolished.
Demolish calls GetDamageModifier with a null Damage.
2019-11-17 17:06:29 +01:00
Paul Chote
6b1e81a7b5 Spawn ejected pilots inside a FrameEndTask. 2019-11-16 23:07:58 +01:00
RoosterDragon
04912ea996 Expose a setting for Weighted A*
Replace Constants.CellCost and Constants.DiagonalCellCost with a dynamically calculated value based on the lowest cost terrain to traverse. Using a fixed value meant the pathfinder heuristics would be incorrect.

In the four default mods, the minimum cost is in fact 100, not 125. This increase would essentially allow the pathfinder to return suboptimal paths up to 25% longer in the worst case, but it would be quicker to do so.

This is exactly what Weighted A* does - overestimate the heuristic by some factor in order to speed up the search by checking fewer routes. This makes the heuristic inadmissible and it may now return suboptimal paths, but their worst case length is bounded by the weight. A weight of 125% will never produce paths more than 25% longer than the shortest, optimal, path.

We set the default weight to 25% to effectively maintain the existing, suboptimal, behaviour due to the choice of the old constant - in future it may prove a useful tuning knob for performance.
2019-11-15 13:05:41 +01:00
Abdurrahmaan Iqbal
72eb4e1749 Fix #17230: Dummy audio output class 2019-11-14 23:46:14 +01:00
blackhand1001
70b1df6ce7 Fix squadmanager adding naval units to ground attack forces.
Fix squadmanager adding naval units to ground attack forces. This was breaking the behavior of both naval and ground squads.
2019-11-09 11:19:09 +01:00
abcdefg30
a586f10875 Don't allow movement for actors without IMove
However, this does not check if any existing IMove traits are enabled.
2019-11-08 23:31:59 +01:00
abcdefg30
980c0c9cd4 Fix actors returning fire at invisible attackers 2019-11-08 23:31:59 +01:00
blackhand1001
d20182f158 Simplify for loop structure now that it only has one check
Simplify for loop structure now that it only has one check
2019-11-08 21:04:32 +01:00
blackhand1001
49d07e9d64 Fix MCV Manager glitch when restrict building area is enabled.
Fix MCV Manager glitch when restrict building area is enabled. It was checking if the location was close enough to the Base center instead of using the MCV Managers min and max ranges. This would cause it to often have no valid locations despite having a huge range.
2019-11-08 21:04:32 +01:00
matjaeck
ba73842747 Allow GrantCondition to grant conditions permanently. 2019-11-08 16:37:13 +01:00
matjaeck
900e857bfa Let AI ignore frozen actors and target original actors instead. 2019-11-08 15:32:06 +01:00
Abdurrahmaan Iqbal
d2819dca77 Show dialogue only when there are unsaved changes 2019-11-07 20:33:43 +01:00
blackhand1001
780982dbe2 Add PlaceDefenseTowardsEnemyChance trait to basebuilderbotmodule
Add PlaceDefenseTowardsEnemyChance trait to basebuilderbotmodule. This defeaults to 100 which is the current behavior. This change now allows you to set the chance that bots will place defenses evenly around the base like the AI in stock red alert and Tiberian sun did.
2019-11-06 10:30:36 +01:00
reaperrr
2de51ae73c Cache IPathFinder in Mobile at creation
Avoiding look-ups on every move order,
as well as reducing line lengths.
2019-11-03 20:53:29 +01:00
Paul Chote
27205b30e5 Remove landing behaviour from force-move orders on selectable buildings. 2019-11-02 18:29:16 +00:00
abcdefg30
34f4c9bdaa Prevent chronoshifting an empty selection 2019-11-02 11:29:28 +01:00
Abdurrahmaan Iqbal
023750db06 Prevent showing wall connections in unexplored terrain 2019-11-01 22:13:38 +01:00
teinarss
c94cf61069 Fix OccupiedCells for units sharing cells 2019-10-31 21:49:07 +00:00
Paul Chote
5315f8603f Override selection if the mouse is over an already selected actor. 2019-10-30 14:53:23 +01:00
Paul Chote
0e4cb53ada Pass contextual information to TargetOverridesSelection. 2019-10-30 14:53:23 +01:00
Paul Chote
3d6621f7ff Force selection cursor when selection overrides input. 2019-10-30 14:53:23 +01:00
Paul Chote
9d4f683d80 Remove WorldRenderer argument from InputOverridesSelection. 2019-10-30 14:53:23 +01:00
Paul Chote
0cfd6337ff Fix InputOverridesSelection only considering the closest actor. 2019-10-30 14:53:23 +01:00
Paul Chote
230a0b330c Fix EjectOnDeath pilot spawning. 2019-10-29 23:03:11 +01:00
Paul Chote
3ee697a54d Install x64 release into correct Program Files on Windows. 2019-10-28 21:03:49 +01:00
tovl
d2991247a3 Add separate condition to mobile for disabling nudging only. 2019-10-28 19:35:32 +01:00
tovl
38caadfdf0 Clean up nudging code. 2019-10-28 19:35:32 +01:00
tovl
c4d1468f62 Make locomotor cache and nudging logic aware of mobile trait status. 2019-10-28 19:35:32 +01:00
reaperrr
7e5b1abc0e Simplified initial Wanders countdown initialization
I don't see a technical reason for the old approach.
2019-10-27 18:03:34 +02:00
RoosterDragon
b98123d9f8 Use SegmentStream.CreateWithoutOwningStream to avoid reading data into memory.
To avoid creating copied data in memory (e.g. via MemoryStream), this method can be used to reference offsets on files on disk, reducing memory requirements.
2019-10-24 20:48:14 +02:00
blackhand1001
9a9bf441ba Add UseResourceStorage trait to CashTrickler 2019-10-23 20:20:03 +02:00
Paul Chote
1599eac66c Rename SelectionBoxRenderable to SelectionBoxAnnotationRenderable. 2019-10-20 23:46:33 +02:00
Paul Chote
43e84c89ef Rename SelectionBarsRenderable to SelectionBarsAnnotationRenderable. 2019-10-20 23:46:33 +02:00
Paul Chote
8e280ef0a7 Rename RangeCircleRenderable to RangeCircleAnnotationRenderable. 2019-10-20 23:46:33 +02:00
Paul Chote
81d9b705a6 Rename DetectionCircleRenderable to DetectionCircleAnnotationRenderable. 2019-10-20 23:46:33 +02:00
Paul Chote
4ec0fa299d Rename TextRenderable to TextAnnotationRenderable. 2019-10-20 23:46:33 +02:00
Paul Chote
7937383bf4 Replace scaleSizeWithZoom with SpriteAnnotation. 2019-10-20 23:46:33 +02:00
Paul Chote
e772adb0a9 Draw annotations using the UI renderers. 2019-10-20 23:46:33 +02:00
Paul Chote
8c1b0f1afe Add IEffectAnnotation interface. 2019-10-20 23:46:33 +02:00
Paul Chote
0ff078968d Change IPlaceBuildingDecorationInfo to use annotations. 2019-10-20 23:46:33 +02:00
Paul Chote
7d1ce0c83b Add annotation support to IOrderGenerator. 2019-10-20 23:46:33 +02:00
Paul Chote
1dc84f48de Migrate traits to IRenderAnnotations. 2019-10-20 23:46:33 +02:00
Paul Chote
edaa7918fc Add IRenderAnnotations(WhenSelected) interfaces. 2019-10-20 23:46:33 +02:00
Paul Chote
060ea80ca4 Fix infantry idle animations playing immediately after creation. 2019-10-20 16:38:25 +02:00
Paul Chote
c15a0a54bb Don't consider unit creation as movement. 2019-10-20 16:38:25 +02:00
Paul Chote
252c833320 Don't override spawn CenterPosition for non-aircraft reinforcements. 2019-10-19 23:45:42 +02:00
abcdefg30
fdd3bffa1d Throw a lua exception when setting an owner to null/nil 2019-10-19 13:34:43 +02:00
Paul Chote
988d6079e3 Disable Carryable while submerged. 2019-10-19 13:11:00 +02:00
Paul Chote
f14d3985a0 Allow carryall pickup orders on deployed vehicles. 2019-10-19 13:11:00 +02:00
Paul Chote
5f8fa7a35a Add UndeployOnPickup to GrantConditionOnDeploy. 2019-10-19 13:11:00 +02:00
Paul Chote
69970d42f3 Prevent movement pausing at invalid position. 2019-10-19 13:11:00 +02:00
Paul Chote
ae34410c80 Replace MoveIntoWorld with ReturnToCell/AssociateWithAirfield. 2019-10-17 23:31:15 +02:00
Paul Chote
9b4d149a06 Revert "Suppress MoveIntoWorldInit for map-placed Mobile actors."
This reverts commit f0c28cc153.
2019-10-17 23:31:15 +02:00
abcdefg30
f5f626cd89 Revert "Production should set SubCellInit"
This reverts commit fa1ca981ac.
2019-10-17 23:31:15 +02:00
Abdurrahmaan Iqbal
763e6d8109 Fix #17229: Refactor ReturnToBase.cs 2019-10-17 10:28:43 +02:00
reaperrr
aa953ba5a1 Remove unused and buggy stand2 sequence from ants
They were unused, their settings were wrong,
and even if fixed they'd make idle ants look
glitchy, because the game switches between
stand sequences randomly.
2019-10-15 14:48:11 +02:00
reaperrr
33bba98773 Fix zombie stand2 sequence and run tickrate 2019-10-14 17:28:46 +02:00
abc013
8b1f1b21e7 Adjusted die sequence length of zombie 2019-10-14 17:28:46 +02:00
abc013
3ec0aa55b9 Fixed zombie.shp
Added missing zombie attack frame
and other fixes.
2019-10-14 17:28:46 +02:00
tovl
33d089a9d6 Fix lastVisibleTarget not being set in FlyAttack and AttackActivity. 2019-10-14 01:22:04 +02:00
abcdefg30
1d90e08bd0 Guard against overlaps on HiDPI by having a 5px border on graphs 2019-10-14 01:02:23 +02:00
abcdefg30
acf028581a Special case the TD spectator UI to fit the minimum width 2019-10-14 01:02:23 +02:00
abcdefg30
9084295d7c Reduce the width of the combat stats tab 2019-10-14 01:02:23 +02:00
abcdefg30
3f89f74d8e Reduce the Width of INGAME_OBSERVERSTATS_BG 2019-10-14 01:02:23 +02:00
reaperrr
88d930579b Fix missing rules in prep update path 2019-10-13 22:37:03 +01:00
abc013
3d3814f336 Add isDead-check to the flamethrowers in allies06b 2019-10-13 18:14:10 +02:00
abc013
3e244998cd Make normal difficulty on allies06b easier 2019-10-13 18:14:10 +02:00
Nakarin Srijumrat
17bec1435b increased ingame edge scrollspeed to 30 from 10 2019-10-13 13:20:24 +02:00
teinarss
fa1ca981ac Production should set SubCellInit 2019-10-12 00:08:15 +02:00
abcdefg30
e9020048fb Add an update rule to remove 'yes' and 'no' 2019-10-12 00:07:05 +02:00
abcdefg30
76ad9962d7 Split off a new UpdatePath for changes not going into prep-1908 2019-10-12 00:07:05 +02:00
abcdefg30
55c3f313b1 Remove 'yes' and 'no' in favor of 'true' and 'false' 2019-10-12 00:07:05 +02:00
abc013
c4f48ad521 Use another plug location for placing plugs on a building when current plug location is already blocked 2019-10-11 22:52:55 +02:00
Paul Chote
ba2d2299d9 Update macOS launcher package.
This pulls in a fix for the missing libmono-native-compat.dylib
2019-10-11 21:58:32 +02:00
abcdefg30
f9f1167b62 Minor style fixes 2019-10-11 21:48:24 +02:00
abcdefg30
e2bbbde494 Reduce string allocations in ObserverStatsLogic 2019-10-11 21:48:24 +02:00
abcdefg30
3672b4e674 Keep army and income graph disabled if they were disabled once 2019-10-11 21:48:24 +02:00
abcdefg30
ee839869fc Replace "$/min" by "Income" and increase graph update rates 2019-10-11 21:48:24 +02:00
abcdefg30
4ca42f6e83 Remove $/min from the basic stats 2019-10-11 21:48:24 +02:00
abcdefg30
0ad8320bff Add an XAxisTicksPerLabel property to LineGraphWidget 2019-10-11 21:48:24 +02:00
abcdefg30
feb58801e0 Work around a recursive loop in TargetAndAttack 2019-10-11 21:00:53 +02:00
Paul Chote
3860cd1b98 Add "Deployed" checkbox in the map editor actor properties. 2019-10-10 19:50:05 +02:00
Paul Chote
c08e290f44 Add "Spawn Child Actor" checkbox in the map editor actor properties. 2019-10-10 19:50:05 +02:00
Paul Chote
966290a623 Add EditorActorCheckbox plumbing. 2019-10-10 19:50:05 +02:00
Paul Chote
5eaa99827d Suppress MoveIntoWorldInit for map-placed Mobile actors. 2019-10-07 19:02:48 +02:00
tovl
eed00ded0d pause MovePart when Mobile is paused. 2019-10-06 20:28:20 +01:00
Jonas A. Lind
1557f4c134 Redo buildpaletteorder for RA vehicles
Restructure RA's vehicle build tab. More streamlined and better looking.
2019-10-06 20:22:16 +02:00
abcdefg30
acea19312d Fix FallsToEarth queueing an activity in its ctor 2019-10-06 14:42:50 +01:00
abcdefg30
56726a0533 Add an ICreationActivity interface 2019-10-06 14:42:50 +01:00
abcdefg30
39f8d34494 Fix setting the position of the wrong actor 2019-10-06 14:42:50 +01:00
abcdefg30
ab87e78dff Fix the XAxis of LineGraphWidget not being updated properly 2019-10-06 13:10:58 +01:00
abcdefg30
548ff411ef Cache method call results in variables in Draw of LineGraphWidget 2019-10-06 13:10:58 +01:00
Chris Cameron
36c48e1785 feat: Using a glDebugMessageCallback instead of glGetError on devices that support it 2019-10-05 21:26:20 +01:00
Punsho
460f5bbb30 Make EMP dissable subterranean units while they're underground 2019-10-05 19:19:57 +02:00
Punsho
d9ec3e0d88 Make EMP dissable detection of mobile sensor array 2019-10-05 19:19:57 +02:00
Punsho
e1e7691fb4 Make laser fence dissable on emp 2019-10-05 19:19:57 +02:00
tovl
ac6431acf8 Clean up usage of CancelActivity. 2019-10-05 19:07:54 +02:00
teinarss
1e786b8e31 Add null check to EditorDefaultBrush for resources 2019-10-05 18:39:39 +02:00
Paul Chote
575541ff4e Remove double-negative from appimage wrapper. 2019-10-05 18:25:13 +02:00
Paul Chote
e94f20f7ca Reset environment variables before switching mods. 2019-10-05 18:25:13 +02:00
Paul Chote
3bda890f7b Add Engine.LaunchWrapper launch argument for mod switching. 2019-10-05 18:25:13 +02:00
Paul Chote
bdd0f68a4a Compile using Mono 6.4.0. 2019-10-05 18:24:45 +02:00
Paul Chote
275365917c Update packaged mono to 6.4.0. 2019-10-05 18:24:45 +02:00
SoScared
b9b7f435dd Redo buildpaletteorder for D2K buildings 2019-10-05 18:21:08 +02:00
Andre Mohren
7f7341a369 Fixed incorrect sequence frame amount checks using Stride. 2019-10-05 18:03:09 +02:00
Paul Chote
c30bb28210 Filter invalid actors when loading and saving games. 2019-10-05 17:50:10 +02:00
Paul Chote
3ad3c39b21 Replace actor list with count in UnitBuilderBotModule. 2019-10-05 17:50:10 +02:00
abcdefg30
b839796b89 Fix double clicking a save in the save game dialogue loading it 2019-10-05 17:39:23 +02:00
abcdefg30
ca92e13b24 Fix harvesters idling on Infiltration 2019-10-05 16:09:42 +02:00
abcdefg30
294908485f Fix the town attackers in Infiltration not stopping 2019-10-05 16:09:42 +02:00
abcdefg30
d2a2c11326 Remove unnecessary SearchFromHarvesterRadius overwrites from TD missions 2019-10-05 16:03:32 +02:00
abcdefg30
716aeb1e8c Add SearchFromProcRadius to TD missions that need it 2019-10-05 16:03:32 +02:00
abcdefg30
321c891bc0 Fix a crash when MaxLevel of GainsExperience is zero 2019-10-05 15:56:59 +02:00
teinarss
d34bce9eab Remove CanEnterCell from OccupiedCells 2019-10-05 14:37:54 +02:00
teinarss
9bfc324c04 Mark cells that have changed MovementType as dirty 2019-10-05 14:37:54 +02:00
Ivaylo Draganov
ad02adff3e Set duplicates flag for hotkeys in HotkeyManager 2019-10-05 13:17:20 +02:00
Punsho
38f5d2c100 RA balance changes for September 2019 2019-10-05 11:03:06 +01:00
Michael Silber
81eb939d4d Fix destroyed truck escaping ra mission sarin-gas-1 2019-10-04 22:41:10 +01:00
Paul Chote
865d8d77e0 Expire invalid instances from the SupportPowerBotModule cache. 2019-10-01 19:25:30 +02:00
Paul Chote
cf427f8cb3 Drop invalid power references when loading save games. 2019-10-01 19:25:30 +02:00
abcdefg30
6f85711252 Increase the SearchFromProcRadius radius in soviet05 2019-09-30 20:28:26 +02:00
abcdefg30
70c278dec5 Remove the now unnecessary Helper refinery 2019-09-30 20:28:26 +02:00
Punsho
9ca7eb6ab1 Make mine targetable on attack everything stance for AutoTargetGround 2019-09-28 14:20:23 +02:00
teinarss
93704ccfcf Add check to see if transport is dead to UnreserveSpace 2019-09-28 14:08:01 +02:00
abcdefg30
411316726b Fix the expansion mcv in soviet05 being transported off the map 2019-09-28 14:01:36 +02:00
abcdefg30
4d2b70acd1 Revert the search radius decrease in D2k 2019-09-28 13:58:24 +02:00
abcdefg30
c0620bd186 Revert the search radius decrease in TS 2019-09-28 13:58:24 +02:00
teinarss
0e6fa51bb0 Rename duplicated actors 2019-09-27 18:04:29 +02:00
teinarss
76034c198e Added Undo Redo to editor 2019-09-27 17:40:32 +02:00
teinarss
1f78b3a425 Cleanup in MapEditorTabsLogic 2019-09-27 17:40:32 +02:00
tovl
48059e8249 Skip rally point if order is queued after resupply. 2019-09-26 18:39:44 +02:00
tovl
09cd56b367 Add missing target line to aircraft taking off from resupplying. 2019-09-26 18:39:44 +02:00
tovl
145b6a05a3 Refactor unreserve actions. 2019-09-26 18:39:44 +02:00
tovl
5787f74af9 Prevent bogus attackmove on take-off. 2019-09-26 18:39:44 +02:00
Punsho
78d7f79817 Fix ctank and stank building faster then they should 2019-09-26 17:13:42 +02:00
abcdefg30
9356c8afd0 Fix unarmed units idling on the ts shellmap 2019-09-24 16:48:52 +02:00
abcdefg30
72bff74ca5 Fix passengers idling on the ts shellmap 2019-09-24 16:48:52 +02:00
abcdefg30
2d304efb73 Convert all spaces to tabs in the ts shellmap script 2019-09-24 16:48:52 +02:00
abcdefg30
c7784cbc8e Fix reinforcements on the ts shellmap not attack moving 2019-09-24 16:48:52 +02:00
Punsho
e1a5a725b0 Fix MRV not auto targeting vehicles 2019-09-22 18:46:56 +02:00
tovl
3d4838b5bc Make airlift landing direction configurable. 2019-09-21 18:16:34 +02:00
tovl
b4270af170 Fix airlift direction in isometric mods. 2019-09-21 18:16:34 +02:00
tovl
3fb54ea6ea Add option for airlift to arrive from player baseline. 2019-09-21 18:16:34 +02:00
tovl
ed7667683b Fix deployed units being nudgeable. 2019-09-19 20:52:13 +02:00
SoScared
61aaac888b Add map Climax to RA map pool 2019-09-16 00:21:47 +02:00
RoosterDragon
6c9fbd40dc Implement IEquatable on structs.
Any struct which overrides object.Equals(object obj) should implement IEquatable<T> to gain a more efficient Equals(T other) overload. This overload will be used by hashing collections like Dictionary which enables them to check equality without boxing the struct.
2019-09-15 19:56:58 +02:00
tovl
4a609bbee8 Allow units to give way when path is blocked by oncoming unit. 2019-09-15 17:51:34 +01:00
Ivaylo Draganov
32309bb8ea Add duplicate hotkey tracking with a boolean property on the definition 2019-09-15 16:35:18 +02:00
Paul Chote
df2300bee0 Fix player viewport saving for non-spectators. 2019-09-15 15:11:47 +02:00
Oliver Brakmann
6e18de4370 Fix idling aircraft on Intervention 2019-09-15 15:02:01 +02:00
abcdefg30
0462cfa507 Remove selling from Infilitration
It is weird, unsatisfying for the player and inconsistent with the rest of our missions
2019-09-15 14:51:32 +02:00
abcdefg30
aee9ee6187 Fix potentially bogus usages of OnAllRemovedFromWorld 2019-09-15 14:51:32 +02:00
RoosterDragon
31918e8712 Add UnionRectangles extension method. 2019-09-14 22:09:40 +02:00
Paul Chote
0e6c37d765 Convert TerrainGeometryOverlay to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
Paul Chote
f45423ed76 Convert EditorSelectionLayer to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
Paul Chote
b3984c8db4 Convert WarheadDebugOverlay to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
Paul Chote
999ad0e18a Convert CustomTerrainDebugOverlay to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
Paul Chote
ccd07b6cfe Convert ExitsDebugOverlay to IRenderAboveShroudWhenSelected. 2019-09-14 18:49:44 +02:00
Paul Chote
60e42c1ea1 Convert CombatDebugOverlay to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
Paul Chote
c9ed749908 Add (Polygon|Circle|Line)AnnotationRenderable. 2019-09-14 18:49:44 +02:00
Paul Chote
a9a43d54f7 Convert WithRangeCircle to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
abcdefg30
7f6149713e Fix actors with no footprint not being copied and pasted 2019-09-13 23:55:48 +01:00
tovl
eb39080248 Allow minefields to start and end on occupied cells. 2019-09-13 23:47:34 +01:00
matt barbier
97fe36af5a Moved GrantExternalConditionToProduced into the Traits/Conditions folder 2019-09-13 22:04:35 +01:00
teinarss
c15f66aa62 PlayerStatistics should stop ticking after lost/win 2019-09-13 21:42:11 +01:00
reaperrr
694680720e Updated AcceptsOrder check to be more readable
This hopefully also fixes handling of multiple enabled
RejectsOrders traits.
2019-09-13 19:49:19 +01:00
abcdefg30
465ee97090 Prevent users from selecting a directional target outside the map 2019-09-13 14:47:29 +02:00
Paul Chote
a8b1762464 Fix ActorPreviewWidget viewport manipulation. 2019-09-13 11:24:57 +02:00
tovl
46c0b4cf31 Fix crash with dead cargo. 2019-09-13 10:34:15 +02:00
Jan Beich
4f99982ef1 Extend Linux dllmap to other systems
- Drop `os` in Eluant config as it's only used on Linux
- Make generic to help BSDs and Solaris
- Update OpenAL-CS and SDL2-CS to get the same

Exception of type `System.DllNotFoundException`: lua51.dll
TypeName=``
  at (wrapper managed-to-native) Eluant.LuaApi.lua_newstate(Eluant.LuaRuntime/LuaAllocator,intptr)
  at Eluant.LuaRuntime..ctor ()
  at Eluant.MemoryConstrainedLuaRuntime..ctor ()
  at OpenRA.Scripting.ScriptContext..ctor (OpenRA.World world, OpenRA.Graphics.WorldRenderer worldRenderer, System.Collections.Generic.IEnumerable`1[T] scripts)
  at OpenRA.Mods.Common.Scripting.LuaScript.OpenRA.Traits.IWorldLoaded.WorldLoaded (OpenRA.World world, OpenRA.Graphics.WorldRenderer worldRenderer)
  at OpenRA.World.LoadComplete (OpenRA.Graphics.WorldRenderer wr)
  at OpenRA.Game.StartGame (System.String mapUID, OpenRA.WorldType type)
  at OpenRA.Game.LoadShellMap ()
  at OpenRA.Mods.Common.LoadScreens.BlankLoadScreen.StartGame (OpenRA.Arguments args)
  at OpenRA.Game.InitializeMod (System.String mod, OpenRA.Arguments args)
  at OpenRA.Game.Initialize (OpenRA.Arguments args)
  at OpenRA.Game.InitializeAndRun (System.String[] args)
  at OpenRA.Program.Main (System.String[] args)
2019-09-13 00:25:50 +02:00
Jan Beich
fe48eede0e command -v with more than one argument is non-portable
On FreeBSD build fails, so check if `msbuild` exists without arguments.

$ gmake
command: wrong number of arguments
OpenRA requires the 'msbuild -verbosity:m -nologo' tool provided by Mono >= 5.4.
gmake: *** [Makefile:154: core] Error 1

# FreeBSD sh
$ command -v echo ls
command: wrong number of arguments

# dash
$ command -v echo ls
echo

# ksh, bash, zsh
$ command -v echo ls
echo
/bin/ls
2019-09-13 00:25:50 +02:00
Paul Chote
afe3e24cda Remove duplication in Texture. 2019-09-12 18:58:37 +01:00
Paul Chote
ce8112fb5a Migrate rendering to OpenGL 3.2 / OpenGL ES 3.0. 2019-09-12 18:58:37 +01:00
Paul Chote
91c63034d3 Clean references to disposed textures. 2019-09-12 18:58:37 +01:00
teinarss
d712bdea85 Locomotor cache should handle custom layers 2019-09-09 21:39:25 +02:00
abcdefg30
912a424596 Replaced "Earned this min" by an Oil Derrick count in the economy statistics 2019-09-08 12:47:33 +02:00
abcdefg30
1e6660ecb2 Add an "UpdatesDerrickCount" trait 2019-09-08 12:47:33 +02:00
Paul Chote
8f267ebcef Remove IronCurtainable from RA aircraft. 2019-09-08 12:24:27 +02:00
teinarss
c13fb80257 Fix crushable logic for actors in cell 2019-09-07 13:31:57 +01:00
abcdefg30
ca8ca2df5c Fix a division by zero error in FindAndDeliverResources
by preventing an overflow through dividing directly
2019-09-07 10:48:20 +01:00
puritylake
aff3bf369b #17018 Gets rif of cutoff line in chat window 2019-09-06 23:02:50 +02:00
teinarss
6fe31e44cb More robust logic for ThisMinute stats 2019-09-06 14:00:42 +02:00
teinarss
6795fb6967 GetAvailableSubCell should block cells outside the map 2019-09-06 13:32:09 +02:00
abcdefg30
9516ee511d Remove the duplicate Selectable trait on TENF 2019-09-06 13:18:37 +02:00
Paul Chote
1d106e71c4 Save screenshots via the frame buffer. 2019-09-04 20:20:04 +02:00
Paul Chote
c0ee346c1c Render via an intermediate frame buffer. 2019-09-04 20:20:04 +02:00
Paul Chote
d2298b6f04 Allow FrameBuffer clear color to be customized. 2019-09-04 20:20:04 +02:00
Paul Chote
09dd66fd5a Correctly fix BlendMode.Subtractive alpha handling. 2019-09-04 20:20:04 +02:00
Paul Chote
b93c7cabb3 Render voxels before BeginFrame. 2019-09-04 20:20:04 +02:00
Oliver Brakmann
5d786f411f Update comment in Activity.cs
SequenceActivities() was removed.
2019-09-02 01:45:35 +02:00
reaperrr
801f5ba525 Rename FlyCircle to FlyIdle and make it tick TickIdle
It now handles both hovering and circling aircraft, for consistency.
2019-09-01 16:38:44 +02:00
teinarss
ce29dcad87 Update PlayerResources capacity from INotify* methods 2019-08-28 00:32:01 +02:00
reaperrr
8edd202b64 Move InflictDamage method back to DamageWarhead
From TargetDamageWarhead.
Saves a few lines and allows warheads that are not
TargetDamageWarhead-based to use it.
2019-08-27 23:05:19 +02:00
reaperrr
07de3ba5e0 Change default preview facing to 96
92 is not a multiple of 8, and all sprite actors
in the official mods have at most 32 facings.
2019-08-27 22:59:22 +02:00
Paul Chote
2b4ad71151 Remove unused OwnerLinkedProc field. 2019-08-25 17:20:38 +02:00
Paul Chote
815ea1e13b Make LastSearchFailed local to FindAndDeliverResources. 2019-08-25 17:20:38 +02:00
Paul Chote
1d2b3ac917 Update the displayed replay filename after renaming. 2019-08-25 16:10:29 +02:00
Paul Chote
c1be8d277e Disable player color for TD walls. 2019-08-25 15:33:46 +02:00
Paul Chote
19d9541aad Disable player color for RA walls. 2019-08-25 15:33:46 +02:00
teinarss
4dd8472d9b Reset server after game 2019-08-25 15:30:45 +02:00
Paul Chote
6702395357 Fix flare animation definition in RA and TD. 2019-08-25 15:24:32 +02:00
tovl
946c9f420b Fix Move not cancelling during turns. 2019-08-25 13:13:37 +02:00
Paul Chote
8b0f2e1462 Fix NRE in SquadManagerBotModule. 2019-08-24 14:33:11 +02:00
Paul Chote
d5f42c0628 Recalculate visibility during moves too. 2019-08-23 14:31:29 +02:00
Paul Chote
76d1447a91 Fix incorrect shroud visibility for stationary units. 2019-08-23 14:31:29 +02:00
Paul Chote
4db3da61e1 Avoid an integer (long) overflow in FindAndDeliverResources. 2019-08-23 14:15:51 +02:00
Ivaylo Draganov
be1f820674 Move hotkey dialog logic into SettingsLogic, fix bugs and improve usability of the dialog 2019-08-23 14:08:09 +02:00
tovl
ed8abe9861 Define nearenough parameter for aircraft so they can exit movement early when stuck. 2019-08-23 13:54:58 +02:00
reaperrr
e71001f4f8 Fix Resupply closeEnough bugs
Fixes that
- RepairableNear actors wouldn't move close enough
- isCloseEnough would return 'true' even if the host
  is invalid.
2019-08-22 10:26:36 +01:00
Paul Chote
8457dfdc39 Add Gatekeeper notice to macOS dmg. 2019-08-21 15:16:00 +01:00
Paul Chote
a491bae39b Bind triggers to RA Shellmap's APC passengers. 2019-08-21 11:24:20 +02:00
Paul Chote
f31cfe5b96 Fix SendParatroopers return value. 2019-08-21 11:24:20 +02:00
Paul Chote
ab94ea9715 Discourage harvesters from wandering too far from the refinery. 2019-08-20 20:22:39 +02:00
Paul Chote
7e4da8ea2c Don't reload after finishing a field. 2019-08-20 19:51:12 +02:00
Paul Chote
7311ae889f Clear placed mines queued fields too. 2019-08-20 19:51:12 +02:00
Paul Chote
9aec48aec3 Lay mines in order from start to end. 2019-08-20 19:51:12 +02:00
abcdefg30
3a51cf0ef8 Update AUTHORS 2019-08-20 19:26:02 +02:00
teinarss
7544d4b4e6 Cells with Temporary blockers should not exit early in locomotor cache 2019-08-19 19:06:57 +02:00
abcdefg30
345905bf68 Remove the gunboat from Lost Souls 2019-08-19 16:55:35 +02:00
abcdefg30
8cf6aa267c Allow single observers to use spectator team chat in mp 2019-08-19 16:45:15 +02:00
tovl
3fe78a8311 Add to AUTHORS. 2019-08-19 00:33:38 +02:00
tovl
2d394f33b8 Fix units from transports appearing at load point. 2019-08-19 00:33:38 +02:00
tovl
70459b311e Refactor FlyAttack to make strafing runs interruptible when target becomes invalid. 2019-08-18 12:50:20 +02:00
Paul Chote
e600848947 Fix crash for invalid Resupply hosts. 2019-08-18 12:48:17 +02:00
1946 changed files with 28281 additions and 22439 deletions

View File

@@ -1,5 +1,6 @@
; Top-most http://editorconfig.org/ file
root = true
charset=utf-8
; Unix-style newlines
[*]

View File

@@ -1,39 +0,0 @@
<!--
This is a guideline, which shall help to write enhancement requests or bug reports.
Fill in the placeholders below. Delete any headings and placeholders that you do not use.
Before you start check if a similar request/bug report already exists in this Github issue tracker and comment there.
When submitting a feature or enhancement request:
1. Explain briefly what the enhancement is and why you think it would be useful.
2. Provide any other necessary or useful information regarding your issue, such as (code) examples or related links.
When submitting a bug report, please follow the template below:
-->
### Issue Summary
<!-- Explanation of the issue. Expectation vs. actual behavior. -->
... ... ...
#### System Information
- **Operating System:** [e.g. Windows 10, Mac OS 10.12, Ubuntu 16.04, ...]
- **.NET / Mono Version:** [e.g. .NET 4.7.1, Mono 4.6.2, ...]
- **OpenRA Version:** [e.g. release-20180218, playtest-20180208, ...]
- **Mod:** [e.g. Red Alert, Tiberian Dawn, Dune2000, ...]
#### Additional Information:
- Steps to reproduce
1. Step
2. Step
3. ...
- Logs
<!-- If you have a log (e.g. debug.log, exception.log), zip and attach it. -->
- OpenRA Replays
<!-- You have to zip it before you can attach it. When does the issue appear [e.g. 10:33]? -->
- Screenshots & Videos
<!-- You should be able to attach screenshots by drag&drop. Videos need to be uploaded to an external platform (e.g. https://www.youtube.com, https://www.dropbox.com) -->

33
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@@ -0,0 +1,33 @@
---
name: Bug report
about: Report unexpected behavior or any issues you experienced in OpenRA.
title: ''
labels: Bug
assignees: ''
---
<!-- This is a guideline that shall help you to include information we need to understand and fix the issue you experienced. Please follow the instructions and replace any placeholders that are written in capital letters. Instructions like this comment will not be visible in your report. -->
<!-- Important: Help us to avoid duplicates and use the search function to find existing reports for your issue. Please do not submit duplicate reports! Try to help others to find your report by using a precise title. -->
## Issue Summary
<!-- Please provide a a clear and concise description of what the issue is below. -->
DESCRIPTION
## Reproduction
<!-- Please provide information about how the issue can be reproduced below. -->
STEPS TO REPRODUCE THE ISSUE
## Expected behavior
<!-- Please explain what you expected to happen below. -->
EXPECTED BEHAVIOR
## Screenshots / Screen recordings / Replays
<!-- If applicable, attach screenshots, screen recordings or replays to help explain your problem. -->

11
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: OpenRA Forum
url: https://forum.openra.net/
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."
- name: OpenRA IRC Channel
url: https://webchat.freenode.net/#openra
about: "Join our development IRC channel on freenode for discussion of development topics."

35
.github/ISSUE_TEMPLATE/crash-report.md vendored Normal file
View File

@@ -0,0 +1,35 @@
---
name: Crash report
about: Report a game crash.
title: My game crashed
labels: Crash
assignees: ''
---
<!-- This is a guideline that shall help you to include all the required information we depend on to investigate and fix game-breaking bugs. Please follow the instructions and replace any placeholders that are written in capital letters. Instructions like this comment will not be visible in your report. -->
## System Information
<!-- Information about the operating system, engine version, game mod and package source are mandatory for investigating and fixing crashes. -->
- Operating System: OPERATING SYSTEM
- OpenRA Version: ENGINE VERSION
- OpenRA Mod: GAME MOD
- Source: Official download package OR self-compiled OR third-party package
- For self-compiled or third-party packages: Mono version
## Exception log
<!-- Please replace the placeholder below with the content of the exception.log file. The three backticks before and after the placeholder are used for formatting, so don't remove them. If you don't find the log folder consult https://github.com/OpenRA/OpenRA/wiki/FAQ#my-game-just-crashed. -->
```
PASTE LOG HERE
```
## Replay
<!-- If you have a replay file for the game that crashed, and it crashes again when you play it back, it will be a great help for us to fix the issue. Please compress the replay into a zip file and drag it here to include it in the report. -->
## Additional information
<!-- Please tell us below everything that you think is important for us to know about the crash. Specifically, what you were doing in the moment before the crash or ideally steps to reproduce it are very valuable information. -->

View File

@@ -0,0 +1,35 @@
---
name: Feature / Enhancement request
about: Describe what you think is missing or could be improved in OpenRA.
title: ''
labels: Idea/Wishlist
assignees: ''
---
<!-- This is a guideline that shall help you to describe your idea for a missing feature or enhancement. Please follow the instructions and replace any placeholders that are written in capital letters. Instructions like this comment will not be visible in your report. -->
<!-- Important: Help us to avoid duplicates and use the search function to find existing requests. Please do not submit duplicate requests! Try to help others to find your request by using a precise title. -->
## Motivation
<!-- Please provide a clear and concise description of the motivation behind the request. If your request is related to a problem or limitation, describe it below. -->
REQUEST MOTIVATION
## Proposed solution
<!-- Please describe your idea and how it is intended to address the motivation of your request. Provide a clear and concise description of the proposed changes. -->
PROPOSED SOLUTION
## Side effects
<!-- Changes often have side effects or unintended consequences. If you expect that your solution has any side effects, please describe them below. -->
EXPECTED SIDE EFFECTS
## Alternatives
<!-- Please outline any alternative solutions you have considered. -->
ALTERNATIVES

2
.gitignore vendored
View File

@@ -26,7 +26,7 @@ mods/*/*.pdb
/*.exe
/*.exe.config
thirdparty/download/*
*.mmdb.gz
IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP
# backup files by various editors
*~

View File

@@ -1,9 +1,16 @@
# Travis-CI Build for OpenRA
# see travis-ci.org for details
dist: xenial
language: csharp
mono: 5.20.1
mono: 6.4.0
jobs:
include:
- os: linux
dist: xenial
- os: osx
if: tag IS present
osx_image: xcode10
cache:
directories:
@@ -14,13 +21,8 @@ addons:
packages:
- lua5.1
- dpkg
- markdown
- zlib1g-dev
- libbz2-dev
- cmake
- genisoimage
- fakeroot
- zsync
- markdown
# Environment variables
env:
@@ -34,14 +36,10 @@ env:
script:
- travis_retry make all-dependencies
- make all
- make check
- make check-scripts
- make test
- make nunit
# Automatically update the trait documentation and Lua API
after_success:
- test $TRAVIS_PULL_REQUEST == "false" && cd packaging && ./update-wiki.sh $TRAVIS_BRANCH; cd ..
- 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:
@@ -63,11 +61,13 @@ notifications:
skip_join: true
before_deploy:
- wget http://mirrors.kernel.org/ubuntu/pool/universe/n/nsis/nsis-common_3.03-2_all.deb
- wget http://mirrors.kernel.org/ubuntu/pool/universe/n/nsis/nsis_3.03-2_amd64.deb
- sudo dpkg -i nsis-common_3.03-2_all.deb
- sudo dpkg -i nsis_3.03-2_amd64.deb
- makensis -VERSION
- 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

20
AUTHORS
View File

@@ -3,26 +3,27 @@ hard work of many contributors.
The OpenRA developers are:
* Chris Forbes (chrisf)
* Igor Popov (ihptru)
* Lukas Franke (abcdefg30)
* Oliver Brakmann (obrakmann)
* Paul Chote (pchote)
* Reaperrr
* Tom Roostan (RoosterDragon)
Previous developers included:
* Alli Witheford (alzeih)
* Caleb Anderson (RobotCaleb)
* Curtis Shmyr (hamb)
* Daniel Hernandez (Mancano)
* Igor Popov (ihptru)
* Matthias Mailänder (Mailaender)
* Megan Bowra-Dean (beedee)
* Mike Bundy (kehaar)
* Oliver Brakmann (obrakmann)
* Pavel Penev (penev92)
* Robert Pepperell (ytinasni)
* ScottNZ
* Tom Roostan (RoosterDragon)
Also thanks to:
* abmyii
* Adam Valy (Tschokky)
* Akseli Virtanen (RAGEQUIT)
* Alexander Fast (mizipzor)
@@ -41,8 +42,9 @@ Also thanks to:
* Brendan Gluth (Mechanical_Man)
* Bryan Wilbur
* Bugra Cuhadaroglu (BugraC)
* Christer Ulfsparre (Holloweye)
* Chris Cameron (Vesuvian)
* Chris Grant (Unit158)
* Christer Ulfsparre (Holloweye)
* clem
* Cody Brittain (Generalcamo)
* Constantin Helmig (CH4Code)
@@ -140,6 +142,7 @@ Also thanks to:
* Tim Mylemans (gecko)
* Tirili
* Tomas Einarsson (Mesacer)
* Tom van Leth (tovl)
* Tristan Keating (Kilkakon)
* Tristan Mühlbacher (MicroBit)
* UnknownProgrammer
@@ -157,12 +160,6 @@ FreeType License.
Using OpenAL Soft distributed under the GNU LGPL.
Using MaxMind GeoIP2 .NET API distributed under
the Apache 2.0 license.
Using GeoLite2 data created by MaxMind and
distributed under the CC BY-SA 3.0 license.
Using SDL2-CS and OpenAL-CS created by Ethan
Lee and released under the zlib license.
@@ -182,6 +179,9 @@ Krueger and distributed under the GNU GPL terms.
Using rix0rrr.BeaconLib developed by Rico Huijbers
distributed under MIT License.
This site or product includes IP2Location LITE data
available from http://www.ip2location.com.
Finally, special thanks goes to the original teams
at Westwood Studios and EA for creating the classic
games which OpenRA aims to reimagine.

View File

@@ -40,7 +40,7 @@
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
# These are explicitly shipped alongside our core files by the packaging script
WHITELISTED_THIRDPARTY_ASSEMBLIES = ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll MaxMind.Db.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 rix0rrr.BeaconLib.dll Open.Nat.dll SDL2-CS.dll OpenAL-CS.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
@@ -151,16 +151,17 @@ test: core
all: dependencies core
core:
@command -v $(MSBUILD) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 5.4."; exit 1)
@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
@-$(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
@@ -173,30 +174,26 @@ cli-dependencies:
@ $(CP_R) thirdparty/download/*.dll.config .
@ test -f OpenRA.Game/obj/project.assets.json || $(MSBUILD) -t:restore
linux-dependencies: cli-dependencies geoip-dependencies linux-native-dependencies
linux-dependencies: cli-dependencies linux-native-dependencies
linux-native-dependencies:
@./thirdparty/configure-native-deps.sh
windows-dependencies: cli-dependencies geoip-dependencies
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
endif
osx-dependencies: cli-dependencies geoip-dependencies
osx-dependencies: cli-dependencies
@./thirdparty/fetch-thirdparty-deps-osx.sh
@ $(CP_R) thirdparty/download/osx/*.dylib .
@ $(CP_R) thirdparty/download/osx/*.dll.config .
geoip-dependencies:
@./thirdparty/fetch-geoip-db.sh
@ $(CP) thirdparty/download/GeoLite2-Country.mmdb.gz .
dependencies: $(os-dependencies)
all-dependencies: cli-dependencies windows-dependencies osx-dependencies geoip-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
@@ -219,10 +216,10 @@ install-engine:
@$(INSTALL_PROGRAM) OpenRA.Platforms.Default.dll "$(DATA_INSTALL_DIR)"
@$(INSTALL_DATA) OpenRA.Platforms.Default.dll.config "$(DATA_INSTALL_DIR)"
@$(INSTALL_DATA) "GeoLite2-Country.mmdb.gz" "$(DATA_INSTALL_DIR)/GeoLite2-Country.mmdb.gz"
@$(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)"
@@ -232,7 +229,6 @@ install-engine:
@$(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) MaxMind.Db.dll "$(DATA_INSTALL_DIR)"
@$(INSTALL_PROGRAM) rix0rrr.BeaconLib.dll "$(DATA_INSTALL_DIR)"
install-common-mod-files:
@@ -387,4 +383,4 @@ help:
.SUFFIXES:
.PHONY: check-scripts check nunit test all core clean distclean cli-dependencies linux-dependencies linux-native-dependencies windows-dependencies osx-dependencies geoip-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: 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

View File

@@ -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
@@ -40,21 +40,50 @@ namespace OpenRA.Activities
* Things to be aware of when writing activities:
*
* - Use "return true" at least once somewhere in the tick method.
* - Do not "reuse" (with "SequenceActivities", for example) activity objects that have already started running.
* - Do not "reuse" activity objects (by queuing them as next or child, for example) that have already started running.
* Queue a new instance instead.
* - Avoid calling actor.CancelActivity(). It is almost always a bug. Call activity.Cancel() instead.
* - Do not evaluate dynamic state (an actor's location, health, conditions, etc.) in the activity's constructor,
* as that might change before the activity gets to tick for the first time. Use the OnFirstRun() method instead.
*/
public abstract class Activity : IActivityInterface
{
public ActivityState State { get; private set; }
protected Activity ChildActivity { get; private set; }
public Activity NextActivity { get; private set; }
Activity childActivity;
protected Activity ChildActivity
{
get { return SkipDoneActivities(childActivity); }
private set { childActivity = value; }
}
Activity nextActivity;
public Activity NextActivity
{
get { return SkipDoneActivities(nextActivity); }
private set { nextActivity = value; }
}
internal static Activity SkipDoneActivities(Activity first)
{
// If first.Cancel() was called while it was queued (i.e. before it first ticked), its state will be Done
// rather than Queued (the activity system guarantees that it cannot be Active or Canceling).
// An unknown number of ticks may have elapsed between the Cancel() call and now,
// so we cannot make any assumptions on the value of first.NextActivity.
// We must not return first (ticking it would be bogus), but returning null would potentially
// drop valid activities queued after it. Walk the queue until we find a valid activity or
// (more likely) run out of activities.
while (first != null && first.State == ActivityState.Done)
first = first.NextActivity;
return first;
}
public bool IsInterruptible { get; protected set; }
public bool ChildHasPriority { get; protected set; }
public bool IsCanceling { get { return State == ActivityState.Canceling; } }
bool finishing;
bool firstRunCompleted;
bool lastRun;
public Activity()
@@ -71,9 +100,13 @@ namespace OpenRA.Activities
if (State == ActivityState.Queued)
{
OnFirstRun(self);
firstRunCompleted = true;
State = ActivityState.Active;
}
if (!firstRunCompleted)
throw new InvalidOperationException("Actor {0} attempted to tick activity {1} before running its OnFirstRun method.".F(self, GetType()));
// Only run the parent tick when the child is done.
// We must always let the child finish on its own before continuing.
if (ChildHasPriority)
@@ -169,7 +202,8 @@ namespace OpenRA.Activities
if (ChildActivity != null)
ChildActivity.Cancel(self);
State = ActivityState.Canceling;
// Directly mark activities that are queued and therefore didn't run yet as done
State = State == ActivityState.Queued ? ActivityState.Done : ActivityState.Canceling;
}
public void Queue(Activity activity)

View File

@@ -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

View File

@@ -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
@@ -44,7 +44,12 @@ namespace OpenRA
public bool WillDispose { get; private set; }
public bool Disposed { get; private set; }
public Activity CurrentActivity { get; private set; }
Activity currentActivity;
public Activity CurrentActivity
{
get { return Activity.SkipDoneActivities(currentActivity); }
private set { currentActivity = value; }
}
public int Generation;
public Actor ReplacedByActor;
@@ -82,6 +87,7 @@ namespace OpenRA
readonly INotifyIdle[] tickIdles;
readonly ITargetablePositions[] targetablePositions;
WPos[] staticTargetablePositions;
bool created;
internal Actor(World world, string name, TypeDictionary initDict)
{
@@ -138,6 +144,35 @@ namespace OpenRA
SyncHashes = TraitsImplementing<ISync>().Select(sync => new SyncHash(sync)).ToArray();
}
internal void Created()
{
created = true;
foreach (var t in TraitsImplementing<INotifyCreated>())
t.Created(this);
// 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;
foreach (var ica in TraitsImplementing<ICreationActivity>())
{
if (!ica.IsTraitEnabled())
continue;
if (creationActivity != null)
throw new InvalidOperationException("More than one enabled ICreationActivity trait: {0} and {1}".F(creationActivity.GetType().Name, ica.GetType().Name));
var activity = ica.GetCreationActivity();
if (activity == null)
continue;
creationActivity = ica;
activity.Queue(CurrentActivity);
CurrentActivity = activity;
}
}
public void Tick()
{
var wasIdle = IsIdle;
@@ -214,11 +249,15 @@ namespace OpenRA
{
if (!queued)
CancelActivity();
QueueActivity(nextActivity);
}
public void QueueActivity(Activity nextActivity)
{
if (!created)
throw new InvalidOperationException("An activity was queued before the actor was created. Queue it inside the INotifyCreated.Created callback instead.");
if (CurrentActivity == null)
CurrentActivity = nextActivity;
else

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -18,26 +19,23 @@ namespace OpenRA.Effects
public class DelayedImpact : IEffect
{
readonly Target target;
readonly Actor firedBy;
readonly IEnumerable<int> damageModifiers;
readonly IWarhead wh;
readonly WarheadArgs args;
int delay;
public DelayedImpact(int delay, IWarhead wh, Target target, Actor firedBy, IEnumerable<int> damageModifiers)
public DelayedImpact(int delay, IWarhead wh, Target target, WarheadArgs args)
{
this.wh = wh;
this.delay = delay;
this.target = target;
this.firedBy = firedBy;
this.damageModifiers = damageModifiers;
this.args = args;
}
public void Tick(World world)
{
if (--delay <= 0)
world.AddFrameEndTask(w => { w.Remove(this); wh.DoImpact(target, firedBy, damageModifiers); });
world.AddFrameEndTask(w => { w.Remove(this); wh.DoImpact(target, args); });
}
public IEnumerable<IRenderable> Render(WorldRenderer wr) { yield break; }

View File

@@ -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
@@ -24,4 +24,5 @@ namespace OpenRA.Effects
public interface ISpatiallyPartitionable { }
public interface IEffectAboveShroud { IEnumerable<IRenderable> RenderAboveShroud(WorldRenderer wr); }
public interface IEffectAnnotation { IEnumerable<IRenderable> RenderAnnotation(WorldRenderer wr); }
}

View File

@@ -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
@@ -16,6 +16,7 @@ using System.IO;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Primitives;
namespace OpenRA
{
@@ -30,6 +31,8 @@ namespace OpenRA
public readonly string LaunchPath;
public readonly string[] LaunchArgs;
public Sprite Icon { get; internal set; }
public Sprite Icon2x { get; internal set; }
public Sprite Icon3x { get; internal set; }
public static string MakeKey(Manifest mod) { return MakeKey(mod.Id, mod.Metadata.Version); }
public static string MakeKey(ExternalMod mod) { return MakeKey(mod.Id, mod.Version); }
@@ -41,14 +44,34 @@ namespace OpenRA
readonly Dictionary<string, ExternalMod> mods = new Dictionary<string, ExternalMod>();
readonly SheetBuilder sheetBuilder;
Sheet CreateSheet()
{
var sheet = new Sheet(SheetType.BGRA, new Size(512, 512));
// We must manually force the buffer creation to avoid a crash
// that is indirectly triggered by rendering from a Sheet that
// has not yet been written to.
sheet.CreateBuffer();
sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
return sheet;
}
public ExternalMods()
{
sheetBuilder = new SheetBuilder(SheetType.BGRA, 256);
// Don't try to load mod icons if we don't have a texture to put them in
if (Game.Renderer != null)
sheetBuilder = new SheetBuilder(SheetType.BGRA, CreateSheet);
// If the player has defined a local support directory (in the game directory)
// then this will override both the regular and system support dirs
var sources = new[] { Platform.SystemSupportDir, Platform.SupportDir };
foreach (var source in sources.Distinct())
// Several types of support directory types are available, depending on
// how the player has installed and launched the game.
// Read registration metadata from all of them
var sources = Enum.GetValues(typeof(SupportDirType))
.Cast<SupportDirType>()
.Select(t => Platform.GetSupportDir(t))
.Distinct();
foreach (var source in sources)
{
var metadataPath = Path.Combine(source, "ModMetadata");
if (!Directory.Exists(metadataPath))
@@ -73,11 +96,23 @@ namespace OpenRA
void LoadMod(MiniYaml yaml, string path = null, bool forceRegistration = false)
{
var mod = FieldLoader.Load<ExternalMod>(yaml);
var iconNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon");
if (iconNode != null && !string.IsNullOrEmpty(iconNode.Value.Value))
if (sheetBuilder != null)
{
using (var stream = new MemoryStream(Convert.FromBase64String(iconNode.Value.Value)))
mod.Icon = sheetBuilder.Add(new Png(stream));
var iconNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon");
if (iconNode != null && !string.IsNullOrEmpty(iconNode.Value.Value))
using (var stream = new MemoryStream(Convert.FromBase64String(iconNode.Value.Value)))
mod.Icon = sheetBuilder.Add(new Png(stream));
var icon2xNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon2x");
if (icon2xNode != null && !string.IsNullOrEmpty(icon2xNode.Value.Value))
using (var stream = new MemoryStream(Convert.FromBase64String(icon2xNode.Value.Value)))
mod.Icon2x = sheetBuilder.Add(new Png(stream), 1f / 2);
var icon3xNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon3x");
if (icon3xNode != null && !string.IsNullOrEmpty(icon3xNode.Value.Value))
using (var stream = new MemoryStream(Convert.FromBase64String(icon3xNode.Value.Value)))
mod.Icon3x = sheetBuilder.Add(new Png(stream), 1f / 3);
}
// Avoid possibly overwriting a valid mod with an obviously bogus one
@@ -91,35 +126,47 @@ namespace OpenRA
if (mod.Metadata.Hidden)
return;
var iconData = "";
var key = ExternalMod.MakeKey(mod);
var yaml = new MiniYamlNode("Registration", new MiniYaml("", new List<MiniYamlNode>()
{
new MiniYamlNode("Id", mod.Id),
new MiniYamlNode("Version", mod.Metadata.Version),
new MiniYamlNode("Title", mod.Metadata.Title),
new MiniYamlNode("LaunchPath", launchPath),
new MiniYamlNode("LaunchArgs", "Game.Mod=" + mod.Id)
}));
using (var stream = mod.Package.GetStream("icon.png"))
if (stream != null)
iconData = Convert.ToBase64String(stream.ReadAllBytes());
yaml.Value.Nodes.Add(new MiniYamlNode("Icon", Convert.ToBase64String(stream.ReadAllBytes())));
var key = ExternalMod.MakeKey(mod);
var yaml = new List<MiniYamlNode>()
{
new MiniYamlNode("Registration", new MiniYaml("", new List<MiniYamlNode>()
{
new MiniYamlNode("Id", mod.Id),
new MiniYamlNode("Version", mod.Metadata.Version),
new MiniYamlNode("Title", mod.Metadata.Title),
new MiniYamlNode("Icon", iconData),
new MiniYamlNode("LaunchPath", launchPath),
new MiniYamlNode("LaunchArgs", "Game.Mod=" + mod.Id)
}))
};
using (var stream = mod.Package.GetStream("icon-2x.png"))
if (stream != null)
yaml.Value.Nodes.Add(new MiniYamlNode("Icon2x", Convert.ToBase64String(stream.ReadAllBytes())));
using (var stream = mod.Package.GetStream("icon-3x.png"))
if (stream != null)
yaml.Value.Nodes.Add(new MiniYamlNode("Icon3x", Convert.ToBase64String(stream.ReadAllBytes())));
var sources = new List<string>();
if (registration.HasFlag(ModRegistration.System))
sources.Add(Platform.SystemSupportDir);
sources.Add(Platform.GetSupportDir(SupportDirType.System));
if (registration.HasFlag(ModRegistration.User))
sources.Add(Platform.SupportDir);
{
sources.Add(Platform.GetSupportDir(SupportDirType.User));
// If using the modern support dir we must also write the registration
// to the legacy support dir for older engine versions, but ONLY if it exists
var legacyPath = Platform.GetSupportDir(SupportDirType.LegacyUser);
if (Directory.Exists(legacyPath))
sources.Add(legacyPath);
}
// Make sure the mod is available for this session, even if saving it fails
LoadMod(yaml.First().Value, forceRegistration: true);
LoadMod(yaml.Value, forceRegistration: true);
var lines = new List<MiniYamlNode> { yaml }.ToLines().ToArray();
foreach (var source in sources.Distinct())
{
var metadataPath = Path.Combine(source, "ModMetadata");
@@ -127,7 +174,7 @@ namespace OpenRA
try
{
Directory.CreateDirectory(metadataPath);
File.WriteAllLines(Path.Combine(metadataPath, key + ".yaml"), yaml.ToLines().ToArray());
File.WriteAllLines(Path.Combine(metadataPath, key + ".yaml"), lines);
}
catch (Exception e)
{
@@ -148,10 +195,16 @@ namespace OpenRA
{
var sources = new List<string>();
if (registration.HasFlag(ModRegistration.System))
sources.Add(Platform.SystemSupportDir);
sources.Add(Platform.GetSupportDir(SupportDirType.System));
if (registration.HasFlag(ModRegistration.User))
sources.Add(Platform.SupportDir);
{
// User support dir may be using the modern or legacy value, or overridden by the user
// Add all the possibilities and let the .Distinct() below ignore the duplicates
sources.Add(Platform.GetSupportDir(SupportDirType.User));
sources.Add(Platform.GetSupportDir(SupportDirType.ModernUser));
sources.Add(Platform.GetSupportDir(SupportDirType.LegacyUser));
}
var activeModKey = ExternalMod.MakeKey(activeMod);
foreach (var source in sources.Distinct())
@@ -207,10 +260,16 @@ namespace OpenRA
{
var sources = new List<string>();
if (registration.HasFlag(ModRegistration.System))
sources.Add(Platform.SystemSupportDir);
sources.Add(Platform.GetSupportDir(SupportDirType.System));
if (registration.HasFlag(ModRegistration.User))
sources.Add(Platform.SupportDir);
{
// User support dir may be using the modern or legacy value, or overridden by the user
// Add all the possibilities and let the .Distinct() below ignore the duplicates
sources.Add(Platform.GetSupportDir(SupportDirType.User));
sources.Add(Platform.GetSupportDir(SupportDirType.ModernUser));
sources.Add(Platform.GetSupportDir(SupportDirType.LegacyUser));
}
var key = ExternalMod.MakeKey(mod);
mods.Remove(key);

View File

@@ -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
@@ -151,6 +151,26 @@ namespace OpenRA
return xs.ElementAt(r.Next(xs.Count));
}
public static Rectangle Union(this IEnumerable<Rectangle> rects)
{
// PERF: Avoid LINQ.
var first = true;
var result = Rectangle.Empty;
foreach (var rect in rects)
{
if (first)
{
first = false;
result = rect;
continue;
}
result = Rectangle.Union(rect, result);
}
return result;
}
public static float Product(this IEnumerable<float> xs)
{
return xs.Aggregate(1f, (a, x) => a * x);

View File

@@ -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
@@ -415,7 +415,13 @@ namespace OpenRA
}
}
else if (fieldType == typeof(bool))
return ParseYesNo(value, fieldType, fieldName);
{
bool result;
if (bool.TryParse(value.ToLowerInvariant(), out result))
return result;
return InvalidValueAction(value, fieldType, fieldName);
}
else if (fieldType == typeof(int2[]))
{
if (value != null)
@@ -592,20 +598,6 @@ namespace OpenRA
return null;
}
static object ParseYesNo(string p, Type fieldType, string field)
{
if (string.IsNullOrEmpty(p))
return InvalidValueAction(p, fieldType, field);
p = p.ToLowerInvariant();
if (p == "yes") return true;
if (p == "true") return true;
if (p == "no") return false;
if (p == "false") return false;
return InvalidValueAction(p, fieldType, field);
}
public sealed class FieldLoadInfo
{
public readonly FieldInfo Field;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -22,6 +22,7 @@ using System.Threading.Tasks;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Primitives;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Widgets;
@@ -38,9 +39,10 @@ namespace OpenRA
public static ModData ModData;
public static Settings Settings;
public static ICursor Cursor;
public static CursorManager Cursor;
public static bool HideCursor;
static WorldRenderer worldRenderer;
static string modLaunchWrapper;
internal static OrderManager OrderManager;
static Server.Server server;
@@ -264,7 +266,7 @@ namespace OpenRA
static void Initialize(Arguments args)
{
var supportDirArg = args.GetValue("Engine.SupportDir", null);
if (supportDirArg != null)
if (!string.IsNullOrEmpty(supportDirArg))
Platform.OverrideSupportDir(supportDirArg);
Console.WriteLine("Platform is {0}", Platform.CurrentPlatform);
@@ -336,8 +338,6 @@ namespace OpenRA
}
}
GeoIP.Initialize();
if (Settings.Server.DiscoverNatDevices)
discoverNat = UPnP.DiscoverNatDevices(Settings.Server.NatDiscoveryTimeout);
@@ -351,6 +351,8 @@ namespace OpenRA
foreach (var mod in Mods)
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Metadata.Title, mod.Value.Metadata.Version);
modLaunchWrapper = args.GetValue("Engine.LaunchWrapper", null);
ExternalMods = new ExternalMods();
Manifest currentMod;
@@ -433,28 +435,11 @@ namespace OpenRA
if (Cursor != null)
Cursor.Dispose();
if (Settings.Graphics.HardwareCursors)
{
try
{
Cursor = new HardwareCursor(ModData.CursorProvider);
}
catch (Exception e)
{
Log.Write("debug", "Failed to initialize hardware cursors. Falling back to software cursors.");
Log.Write("debug", "Error was: " + e.Message);
Console.WriteLine("Failed to initialize hardware cursors. Falling back to software cursors.");
Console.WriteLine("Error was: " + e.Message);
Cursor = new SoftwareCursor(ModData.CursorProvider);
}
}
else
Cursor = new SoftwareCursor(ModData.CursorProvider);
Cursor = new CursorManager(ModData.CursorProvider);
PerfHistory.Items["render"].HasNormalTick = false;
PerfHistory.Items["batches"].HasNormalTick = false;
PerfHistory.Items["render_world"].HasNormalTick = false;
PerfHistory.Items["render_widgets"].HasNormalTick = false;
PerfHistory.Items["render_flip"].HasNormalTick = false;
@@ -509,8 +494,15 @@ namespace OpenRA
{
try
{
var path = mod.LaunchPath;
var args = launchArguments != null ? mod.LaunchArgs.Append(launchArguments) : mod.LaunchArgs;
var p = Process.Start(mod.LaunchPath, args.Select(a => "\"" + a + "\"").JoinWith(" "));
if (modLaunchWrapper != null)
{
path = modLaunchWrapper;
args = new[] { mod.LaunchPath }.Concat(args);
}
var p = Process.Start(path, args.Select(a => "\"" + a + "\"").JoinWith(" "));
if (p == null || p.HasExited)
onFailed();
else
@@ -550,7 +542,7 @@ namespace OpenRA
var path = Path.Combine(directory, string.Concat(filename, ".png"));
Log.Write("debug", "Taking screenshot " + path);
Renderer.Context.SaveScreenshot(path);
Renderer.SaveScreenshot(path);
Debug("Saved screenshot " + filename);
}
}
@@ -626,7 +618,7 @@ namespace OpenRA
static void LogicTick()
{
delayedActions.PerformActions(RunTime);
PerformDelayedActions();
if (OrderManager.Connection.ConnectionState != lastConnectionState)
{
@@ -639,6 +631,11 @@ namespace OpenRA
InnerLogicTick(worldRenderer.World.OrderManager);
}
public static void PerformDelayedActions()
{
delayedActions.PerformActions(RunTime);
}
public static void TakeScreenshot()
{
takeScreenshot = true;
@@ -650,24 +647,39 @@ namespace OpenRA
{
++RenderFrame;
// worldRenderer is null during the initial install/download screen
if (worldRenderer != null)
// Prepare renderables (i.e. render voxels) before calling BeginFrame
using (new PerfSample("render_prepare"))
{
Renderer.BeginFrame(worldRenderer.Viewport.TopLeft, worldRenderer.Viewport.Zoom);
Sound.SetListenerPosition(worldRenderer.Viewport.CenterPosition);
Renderer.WorldModelRenderer.BeginFrame();
// Use worldRenderer.World instead of OrderManager.World to avoid a rendering mismatch while processing orders
if (!worldRenderer.World.IsLoadingGameSave)
// World rendering is disabled while the loading screen is displayed
if (worldRenderer != null && !worldRenderer.World.IsLoadingGameSave)
{
worldRenderer.Viewport.Tick();
worldRenderer.PrepareRenderables();
}
Ui.PrepareRenderables();
Renderer.WorldModelRenderer.EndFrame();
}
// worldRenderer is null during the initial install/download screen
// World rendering is disabled while the loading screen is displayed
// Use worldRenderer.World instead of OrderManager.World to avoid a rendering mismatch while processing orders
if (worldRenderer != null && !worldRenderer.World.IsLoadingGameSave)
{
Renderer.BeginWorld(worldRenderer.Viewport.Rectangle);
Sound.SetListenerPosition(worldRenderer.Viewport.CenterPosition);
using (new PerfSample("render_world"))
worldRenderer.Draw();
}
else
Renderer.BeginFrame(int2.Zero, 1f);
using (new PerfSample("render_widgets"))
{
Renderer.WorldModelRenderer.BeginFrame();
Ui.PrepareRenderables();
Renderer.WorldModelRenderer.EndFrame();
Renderer.BeginUI();
if (worldRenderer != null && !worldRenderer.World.IsLoadingGameSave)
worldRenderer.DrawAnnotations();
Ui.Draw();
@@ -695,6 +707,7 @@ namespace OpenRA
PerfHistory.Items["render"].Tick();
PerfHistory.Items["batches"].Tick();
PerfHistory.Items["render_world"].Tick();
PerfHistory.Items["render_widgets"].Tick();
PerfHistory.Items["render_flip"].Tick();
}
@@ -742,6 +755,7 @@ namespace OpenRA
var nextLogic = RunTime;
var nextRender = RunTime;
var forcedNextRender = RunTime;
var renderBeforeNextTick = false;
while (state == RunStatus.Running)
{
@@ -770,9 +784,9 @@ namespace OpenRA
var nextUpdate = Math.Min(nextLogic, nextRender);
if (now >= nextUpdate)
{
var forceRender = now >= forcedNextRender;
var forceRender = renderBeforeNextTick || now >= forcedNextRender;
if (now >= nextLogic)
if (now >= nextLogic && !renderBeforeNextTick)
{
nextLogic += logicInterval;
@@ -780,7 +794,7 @@ namespace OpenRA
// Force at least one render per tick during regular gameplay
if (OrderManager.World != null && !OrderManager.World.IsLoadingGameSave && !OrderManager.World.IsReplay)
forceRender = true;
renderBeforeNextTick = true;
}
var haveSomeTimeUntilNextLogic = now < nextLogic;
@@ -799,6 +813,7 @@ namespace OpenRA
forcedNextRender = now + maxRenderInterval;
RenderTick();
renderBeforeNextTick = false;
}
}
else
@@ -843,6 +858,11 @@ namespace OpenRA
state = RunStatus.Success;
}
public static void AddSystemLine(string text)
{
AddSystemLine("Battlefield Control", text);
}
public static void AddSystemLine(string name, string text)
{
OrderManager.AddChatLine(name, systemMessageColor, text, systemMessageColor);
@@ -881,7 +901,7 @@ namespace OpenRA
public static void CreateServer(ServerSettings settings)
{
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, ModData, false);
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, ModData, ServerType.Multiplayer);
}
public static int CreateLocalServer(string map)
@@ -893,7 +913,7 @@ namespace OpenRA
AdvertiseOnline = false
};
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, ModData, false);
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, ModData, ServerType.Local);
return server.Port;
}

View File

@@ -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

View File

@@ -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
@@ -44,7 +44,11 @@ namespace OpenRA
{
try
{
traits.Add(LoadTraitInfo(creator, t.Key.Split('@')[0], t.Value));
// 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);
if (trait != null)
traits.Add(trait);
}
catch (FieldLoader.MissingFieldsException e)
{
@@ -73,7 +77,13 @@ namespace OpenRA
if (!string.IsNullOrEmpty(my.Value))
throw new YamlException("Junk value `{0}` on trait node {1}"
.F(my.Value, traitName));
// 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<ITraitInfo>(traitName + "Info");
if (info == null)
return null;
try
{
FieldLoader.Load(info, my);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -33,6 +33,27 @@ namespace OpenRA.GameRules
public Target GuidedTarget;
}
public class WarheadArgs
{
public WeaponInfo Weapon;
public int[] DamageModifiers = { };
public WPos? Source;
public Actor SourceActor;
public Target WeaponTarget;
public WarheadArgs(ProjectileArgs args)
{
Weapon = args.Weapon;
DamageModifiers = args.DamageModifiers;
Source = args.Source;
SourceActor = args.SourceActor;
WeaponTarget = args.GuidedTarget;
}
// Default empty constructor for callers that want to initialize fields themselves
public WarheadArgs() { }
}
public interface IProjectile : IEffect { }
public interface IProjectileInfo { IProjectile Create(ProjectileArgs args); }
@@ -177,17 +198,33 @@ namespace OpenRA.GameRules
}
/// <summary>Applies all the weapon's warheads to the target.</summary>
public void Impact(Target target, Actor firedBy, IEnumerable<int> damageModifiers)
public void Impact(Target target, WarheadArgs args)
{
var world = args.SourceActor.World;
foreach (var warhead in Warheads)
{
var wh = warhead; // force the closure to bind to the current warhead
if (wh.Delay > 0)
firedBy.World.AddFrameEndTask(w => w.Add(new DelayedImpact(wh.Delay, wh, target, firedBy, damageModifiers)));
if (warhead.Delay > 0)
world.AddFrameEndTask(w => w.Add(new DelayedImpact(warhead.Delay, warhead, target, args)));
else
wh.DoImpact(target, firedBy, damageModifiers);
warhead.DoImpact(target, args);
}
}
/// <summary>Applies all the weapon's warheads to the target. Only use for projectile-less, special-case impacts.</summary>
public void Impact(Target target, Actor firedBy)
{
// The impact will happen immediately at target.CenterPosition.
var args = new WarheadArgs
{
Weapon = this,
SourceActor = firedBy,
WeaponTarget = target
};
if (firedBy.OccupiesSpace != null)
args.Source = firedBy.CenterPosition;
Impact(target, args);
}
}
}

View File

@@ -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

View File

@@ -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
@@ -66,6 +66,23 @@ namespace OpenRA.Graphics
return new IRenderable[] { imageRenderable };
}
public IRenderable[] RenderUI(WorldRenderer wr, int2 pos, WVec offset, int zOffset, PaletteReference palette, float scale)
{
var screenOffset = (scale * wr.ScreenVectorComponents(offset)).XY.ToInt2();
var imagePos = pos + screenOffset - new int2((int)(scale * Image.Size.X / 2), (int)(scale * Image.Size.Y / 2));
var imageRenderable = new UISpriteRenderable(Image, WPos.Zero + offset, imagePos, CurrentSequence.ZOffset + zOffset, palette, scale);
if (CurrentSequence.ShadowStart >= 0)
{
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
var shadowPos = pos - new int2((int)(scale * shadow.Size.X / 2), (int)(scale * shadow.Size.Y / 2));
var shadowRenderable = new UISpriteRenderable(shadow, WPos.Zero + offset, shadowPos, CurrentSequence.ShadowZOffset + zOffset, palette, scale);
return new IRenderable[] { shadowRenderable, imageRenderable };
}
return new IRenderable[] { imageRenderable };
}
public Rectangle ScreenBounds(WorldRenderer wr, WPos pos, WVec offset, float scale)
{
var xy = wr.ScreenPxPosition(pos) + wr.ScreenPxOffset(offset);

View File

@@ -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

View File

@@ -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
@@ -9,81 +9,142 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileSystem;
using OpenRA.Primitives;
namespace OpenRA.Graphics
{
[Flags]
public enum PanelSides
{
Left = 1,
Top = 2,
Right = 4,
Bottom = 8,
Center = 16,
Edges = Left | Top | Right | Bottom,
All = Edges | Center,
}
public static class PanelSidesExts
{
public static bool HasSide(this PanelSides self, PanelSides m)
{
// PERF: Enum.HasFlag is slower and requires allocations.
return (self & m) == m;
}
}
public static class ChromeProvider
{
struct Collection
public class Collection
{
public string Src;
public Dictionary<string, MappedImage> Regions;
public readonly string Image = null;
public readonly string Image2x = null;
public readonly string Image3x = null;
public readonly int[] PanelRegion = null;
public readonly PanelSides PanelSides = PanelSides.All;
public readonly Dictionary<string, Rectangle> Regions = new Dictionary<string, Rectangle>();
}
public static IReadOnlyDictionary<string, Collection> Collections { get; private set; }
static Dictionary<string, Collection> collections;
static Dictionary<string, Sheet> cachedSheets;
static Dictionary<string, Pair<Sheet, int>> cachedSheets;
static Dictionary<string, Dictionary<string, Sprite>> cachedSprites;
static Dictionary<string, Sprite[]> cachedPanelSprites;
static Dictionary<Collection, Pair<Sheet, int>> cachedCollectionSheets;
static IReadOnlyFileSystem fileSystem;
static float dpiScale = 1;
public static void Initialize(ModData modData)
{
Deinitialize();
// Load higher resolution images if available on HiDPI displays
if (Game.Renderer != null)
dpiScale = Game.Renderer.WindowScale;
fileSystem = modData.DefaultFileSystem;
collections = new Dictionary<string, Collection>();
cachedSheets = new Dictionary<string, Sheet>();
cachedSheets = new Dictionary<string, Pair<Sheet, int>>();
cachedSprites = new Dictionary<string, Dictionary<string, Sprite>>();
cachedPanelSprites = new Dictionary<string, Sprite[]>();
cachedCollectionSheets = new Dictionary<Collection, Pair<Sheet, int>>();
Collections = new ReadOnlyDictionary<string, Collection>(collections);
var chrome = MiniYaml.Merge(modData.Manifest.Chrome
.Select(s => MiniYaml.FromStream(fileSystem.Open(s), s)));
foreach (var c in chrome)
LoadCollection(c.Key, c.Value);
if (!c.Key.StartsWith("^", StringComparison.Ordinal))
LoadCollection(c.Key, c.Value);
}
public static void Deinitialize()
{
if (cachedSheets != null)
foreach (var sheet in cachedSheets.Values)
sheet.Dispose();
sheet.First.Dispose();
collections = null;
cachedSheets = null;
cachedSprites = null;
}
public static void Save(string file)
{
var root = new List<MiniYamlNode>();
foreach (var kv in collections)
root.Add(new MiniYamlNode(kv.Key, SaveCollection(kv.Value)));
root.WriteToFile(file);
}
static MiniYaml SaveCollection(Collection collection)
{
var root = new List<MiniYamlNode>();
foreach (var kv in collection.Regions)
root.Add(new MiniYamlNode(kv.Key, kv.Value.Save(collection.Src)));
return new MiniYaml(collection.Src, root);
cachedPanelSprites = null;
cachedCollectionSheets = null;
}
static void LoadCollection(string name, MiniYaml yaml)
{
if (Game.ModData.LoadScreen != null)
Game.ModData.LoadScreen.Display();
var collection = new Collection()
{
Src = yaml.Value,
Regions = yaml.Nodes.ToDictionary(n => n.Key, n => new MappedImage(yaml.Value, n.Value))
};
collections.Add(name, collection);
collections.Add(name, FieldLoader.Load<Collection>(yaml));
}
static Pair<Sheet, int> SheetForCollection(Collection c)
{
Pair<Sheet, int> sheetDensity;
// Outer cache avoids recalculating image names
if (!cachedCollectionSheets.TryGetValue(c, out sheetDensity))
{
var image = c.Image;
var density = 1;
if (dpiScale > 2 && !string.IsNullOrEmpty(c.Image3x))
{
image = c.Image3x;
density = 3;
}
else if (dpiScale > 1 && !string.IsNullOrEmpty(c.Image2x))
{
image = c.Image2x;
density = 2;
}
// Inner cache makes sure we share sheets between collections
if (!cachedSheets.TryGetValue(image, out sheetDensity))
{
Sheet sheet;
using (var stream = fileSystem.Open(image))
sheet = new Sheet(SheetType.BGRA, stream);
sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
sheetDensity = Pair.New(sheet, density);
cachedSheets.Add(image, sheetDensity);
}
cachedCollectionSheets.Add(c, sheetDensity);
}
return sheetDensity;
}
public static Sprite GetImage(string collectionName, string imageName)
@@ -104,33 +165,130 @@ namespace OpenRA.Graphics
return null;
}
MappedImage mi;
Rectangle mi;
if (!collection.Regions.TryGetValue(imageName, out mi))
return null;
// Cached sheet
Sheet sheet;
if (cachedSheets.ContainsKey(mi.Src))
sheet = cachedSheets[mi.Src];
else
{
using (var stream = fileSystem.Open(mi.Src))
sheet = new Sheet(SheetType.BGRA, stream);
cachedSheets.Add(mi.Src, sheet);
}
// Cache the sprite
var sheetDensity = SheetForCollection(collection);
if (cachedCollection == null)
{
cachedCollection = new Dictionary<string, Sprite>();
cachedSprites.Add(collectionName, cachedCollection);
}
var image = mi.GetImage(sheet);
var image = new Sprite(sheetDensity.First, sheetDensity.Second * mi, TextureChannel.RGBA, 1f / sheetDensity.Second);
cachedCollection.Add(imageName, image);
return image;
}
public static Sprite[] GetPanelImages(string collectionName)
{
if (string.IsNullOrEmpty(collectionName))
return null;
// Cached sprite
Sprite[] cachedSprites;
if (cachedPanelSprites.TryGetValue(collectionName, out cachedSprites))
return cachedSprites;
Collection collection;
if (!collections.TryGetValue(collectionName, out collection))
{
Log.Write("debug", "Could not find collection '{0}'", collectionName);
return null;
}
Sprite[] sprites;
if (collection.PanelRegion != null)
{
if (collection.PanelRegion.Length != 8)
{
Log.Write("debug", "Collection '{0}' does not define a valid PanelRegion", collectionName);
return null;
}
// Cache the sprites
var sheetDensity = SheetForCollection(collection);
var pr = collection.PanelRegion;
var ps = collection.PanelSides;
var sides = new[]
{
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]))
};
sprites = sides.Select(x => ps.HasSide(x.First) ? new Sprite(sheetDensity.First, sheetDensity.Second * x.Second, TextureChannel.RGBA, 1f / sheetDensity.Second) : null)
.ToArray();
}
else
{
// Support manual definitions for unusual dialog layouts
sprites = new[]
{
GetImage(collectionName, "corner-tl"),
GetImage(collectionName, "border-t"),
GetImage(collectionName, "corner-tr"),
GetImage(collectionName, "border-l"),
GetImage(collectionName, "background"),
GetImage(collectionName, "border-r"),
GetImage(collectionName, "corner-bl"),
GetImage(collectionName, "border-b"),
GetImage(collectionName, "corner-br")
};
}
cachedPanelSprites.Add(collectionName, sprites);
return sprites;
}
public static Size GetMinimumPanelSize(string collectionName)
{
if (string.IsNullOrEmpty(collectionName))
return new Size(0, 0);
Collection collection;
if (!collections.TryGetValue(collectionName, out collection))
{
Log.Write("debug", "Could not find collection '{0}'", collectionName);
return new Size(0, 0);
}
if (collection.PanelRegion == null || collection.PanelRegion.Length != 8)
{
Log.Write("debug", "Collection '{0}' does not define a valid PanelRegion", collectionName);
return new Size(0, 0);
}
var pr = collection.PanelRegion;
return new Size(pr[2] + pr[6], pr[3] + pr[7]);
}
public static void SetDPIScale(float scale)
{
if (dpiScale == scale)
return;
dpiScale = scale;
// Clear the sprite caches so the new artwork can be loaded
// Sheets are not cleared: we assume that the extra memory overhead
// of having the same sheet in memory in multiple DPIs is better than
// the overhead of having to dispose and reload everything.
// Changing the DPI scale is rare, but if it does happen then there
// is a reasonable chance that it may happen again this session.
cachedSprites.Clear();
cachedPanelSprites.Clear();
cachedCollectionSheets.Clear();
}
}
}

View File

@@ -0,0 +1,299 @@
#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;
namespace OpenRA.Graphics
{
public sealed class CursorManager
{
class Cursor
{
public string Name;
public int2 PaddedSize;
public Rectangle Bounds;
public int Length;
public Sprite[] Sprites;
public IHardwareCursor[] Cursors;
}
readonly Dictionary<string, Cursor> cursors = new Dictionary<string, Cursor>();
readonly SheetBuilder sheetBuilder;
readonly GraphicSettings graphicSettings;
Cursor cursor;
bool isLocked = false;
int2 lockedPosition;
bool hardwareCursorsDisabled = false;
bool hardwareCursorsDoubled = false;
public CursorManager(CursorProvider cursorProvider)
{
hardwareCursorsDisabled = Game.Settings.Graphics.DisableHardwareCursors;
graphicSettings = Game.Settings.Graphics;
sheetBuilder = new SheetBuilder(SheetType.BGRA);
foreach (var kv in cursorProvider.Cursors)
{
var frames = kv.Value.Frames;
var palette = !string.IsNullOrEmpty(kv.Value.Palette) ? cursorProvider.Palettes[kv.Value.Palette] : null;
var c = new Cursor
{
Name = kv.Key,
Bounds = Rectangle.FromLTRB(0, 0, 1, 1),
Length = 0,
Sprites = new Sprite[frames.Length],
Cursors = new IHardwareCursor[frames.Length]
};
// Hardware cursors have a number of odd platform-specific bugs/limitations.
// Reduce the number of edge cases by padding the individual frames such that:
// - the hotspot is inside the frame bounds (enforced by SDL)
// - all frames within a sequence have the same size (needed for macOS 10.15)
// - the frame size is a multiple of 8 (needed for Windows)
foreach (var f in frames)
{
// Hotspot is specified relative to the center of the frame
var hotspot = f.Offset.ToInt2() - kv.Value.Hotspot - new int2(f.Size) / 2;
// SheetBuilder expects data in BGRA
var data = FrameToBGRA(kv.Key, f, palette);
c.Sprites[c.Length++] = sheetBuilder.Add(data, f.Size, 0, hotspot);
// Bounds relative to the hotspot
c.Bounds = Rectangle.Union(c.Bounds, new Rectangle(hotspot, f.Size));
}
// Pad bottom-right edge to make the frame size a multiple of 8
c.PaddedSize = 8 * new int2((c.Bounds.Width + 7) / 8, (c.Bounds.Height + 7) / 8);
cursors.Add(kv.Key, c);
}
CreateOrUpdateHardwareCursors();
foreach (var s in sheetBuilder.AllSheets)
s.ReleaseBuffer();
Update();
}
void CreateOrUpdateHardwareCursors()
{
if (hardwareCursorsDisabled)
return;
// Dispose any existing cursors to avoid leaking native resources
ClearHardwareCursors();
try
{
foreach (var kv in cursors)
{
var template = kv.Value;
for (var i = 0; i < template.Sprites.Length; i++)
{
if (template.Cursors[i] != null)
template.Cursors[i].Dispose();
// Calculate the padding to position the frame within sequenceBounds
var paddingTL = -(template.Bounds.Location - template.Sprites[i].Offset.XY.ToInt2());
var paddingBR = template.PaddedSize - new int2(template.Sprites[i].Bounds.Size) - paddingTL;
template.Cursors[i] = CreateHardwareCursor(kv.Key, template.Sprites[i], paddingTL, paddingBR, -template.Bounds.Location);
}
}
}
catch (Exception e)
{
Log.Write("debug", "Failed to initialize hardware cursors. Falling back to software cursors.");
Log.Write("debug", "Error was: " + e.Message);
Console.WriteLine("Failed to initialize hardware cursors. Falling back to software cursors.");
Console.WriteLine("Error was: " + e.Message);
ClearHardwareCursors();
}
hardwareCursorsDoubled = graphicSettings.CursorDouble;
}
public void SetCursor(string cursorName)
{
if ((cursorName == null && cursor == null) || (cursor != null && cursorName == cursor.Name))
return;
if (cursorName == null || !cursors.TryGetValue(cursorName, out cursor))
cursor = null;
Update();
}
int frame;
int ticks;
public void Tick()
{
if (hardwareCursorsDoubled != graphicSettings.CursorDouble)
{
CreateOrUpdateHardwareCursors();
Update();
}
if (cursor == null || cursor.Cursors.Length == 1)
return;
if (++ticks > 2)
{
ticks -= 2;
frame++;
Update();
}
}
void Update()
{
if (cursor != null && frame >= cursor.Cursors.Length)
frame %= cursor.Cursors.Length;
if (cursor == null || isLocked)
Game.Renderer.Window.SetHardwareCursor(null);
else
Game.Renderer.Window.SetHardwareCursor(cursor.Cursors[frame]);
}
public void Render(Renderer renderer)
{
// Cursor is hidden
if (cursor == null)
return;
// Hardware cursor is enabled
if (!isLocked && cursor.Cursors[frame % cursor.Length] != null)
return;
// Render cursor in software
var doubleCursor = graphicSettings.CursorDouble;
var cursorSprite = cursor.Sprites[frame % cursor.Length];
var cursorSize = doubleCursor ? 2.0f * cursorSprite.Size : cursorSprite.Size;
// Cursor is rendered in native window coordinates
// Apply same scaling rules as hardware cursors
if (Game.Renderer.NativeWindowScale > 1.5f)
cursorSize = 2 * cursorSize;
var mousePos = isLocked ? lockedPosition : Viewport.LastMousePos;
renderer.RgbaSpriteRenderer.DrawSprite(cursorSprite,
mousePos,
cursorSize / Game.Renderer.WindowScale);
}
public void Lock()
{
lockedPosition = Viewport.LastMousePos;
Game.Renderer.Window.SetRelativeMouseMode(true);
isLocked = true;
Update();
}
public void Unlock()
{
Game.Renderer.Window.SetRelativeMouseMode(false);
isLocked = false;
Update();
}
public static byte[] FrameToBGRA(string name, ISpriteFrame frame, ImmutablePalette palette)
{
// Data is already in BGRA format
if (frame.Type == SpriteFrameType.BGRA)
return frame.Data;
// Cursors may be either native BGRA or Indexed.
// Indexed sprites are converted to BGRA using the referenced palette.
// All palettes must be explicitly referenced, even if they are embedded in the sprite.
if (frame.Type == SpriteFrameType.Indexed && palette == null)
throw new InvalidOperationException("Cursor sequence `{0}` attempted to load an indexed sprite but does not define Palette".F(name));
var width = frame.Size.Width;
var height = frame.Size.Height;
var data = new byte[4 * width * height];
for (var j = 0; j < height; j++)
{
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 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];
}
}
return data;
}
IHardwareCursor CreateHardwareCursor(string name, Sprite data, int2 paddingTL, int2 paddingBR, int2 hotspot)
{
var size = data.Bounds.Size;
var srcStride = data.Sheet.Size.Width;
var srcData = data.Sheet.GetData();
var newWidth = paddingTL.X + size.Width + paddingBR.X;
var newHeight = paddingTL.Y + size.Height + paddingBR.Y;
var rgbaData = new byte[4 * newWidth * newHeight];
for (var j = 0; j < size.Height; j++)
{
for (var i = 0; i < size.Width; i++)
{
var src = 4 * ((j + data.Bounds.Top) * srcStride + data.Bounds.Left + i);
var dest = 4 * ((j + paddingTL.Y) * newWidth + i + paddingTL.X);
Array.Copy(srcData, src, rgbaData, dest, 4);
}
}
return Game.Renderer.Window.CreateHardwareCursor(name, new Size(newWidth, newHeight), rgbaData, hotspot, graphicSettings.CursorDouble);
}
void ClearHardwareCursors()
{
foreach (var c in cursors.Values)
{
for (var i = 0; i < c.Cursors.Length; i++)
{
if (c.Cursors[i] != null)
{
c.Cursors[i].Dispose();
c.Cursors[i] = null;
}
}
}
}
public void Dispose()
{
ClearHardwareCursors();
cursors.Clear();
sheetBuilder.Dispose();
}
}
}

View File

@@ -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
@@ -36,6 +36,7 @@ namespace OpenRA.Graphics
pals[p.Palette] = p;
Palettes = nodesDict["Cursors"].Nodes.Select(n => n.Value.Value)
.Where(p => p != null)
.Distinct()
.ToDictionary(p => p, p => pals[p].ReadPalette(modData.DefaultFileSystem))
.AsReadOnly();
@@ -49,8 +50,6 @@ namespace OpenRA.Graphics
Cursors = cursors.AsReadOnly();
}
public static bool CursorViewportZoomed { get { return Game.Settings.Graphics.CursorDouble && Game.Settings.Graphics.PixelDouble; } }
public bool HasCursorSequence(string cursor)
{
return Cursors.ContainsKey(cursor);

View File

@@ -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

View File

@@ -1,192 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 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;
namespace OpenRA.Graphics
{
public sealed class HardwareCursor : ICursor
{
readonly Dictionary<string, IHardwareCursor[]> hardwareCursors = new Dictionary<string, IHardwareCursor[]>();
readonly CursorProvider cursorProvider;
readonly Dictionary<string, Sprite[]> sprites = new Dictionary<string, Sprite[]>();
readonly SheetBuilder sheetBuilder;
readonly HardwarePalette hardwarePalette = new HardwarePalette();
readonly Cache<string, PaletteReference> paletteReferences;
CursorSequence cursor;
bool isLocked = false;
int2 lockedPosition;
public HardwareCursor(CursorProvider cursorProvider)
{
this.cursorProvider = cursorProvider;
paletteReferences = new Cache<string, PaletteReference>(CreatePaletteReference);
foreach (var p in cursorProvider.Palettes)
hardwarePalette.AddPalette(p.Key, p.Value, false);
hardwarePalette.Initialize();
sheetBuilder = new SheetBuilder(SheetType.Indexed);
foreach (var kv in cursorProvider.Cursors)
{
var palette = cursorProvider.Palettes[kv.Value.Palette];
var hc = kv.Value.Frames
.Select(f => CreateCursor(f, palette, kv.Key, kv.Value))
.ToArray();
hardwareCursors.Add(kv.Key, hc);
var s = kv.Value.Frames.Select(a => sheetBuilder.Add(a)).ToArray();
sprites.Add(kv.Key, s);
}
sheetBuilder.Current.ReleaseBuffer();
Update();
}
PaletteReference CreatePaletteReference(string name)
{
var pal = hardwarePalette.GetPalette(name);
return new PaletteReference(name, hardwarePalette.GetPaletteIndex(name), pal, hardwarePalette);
}
IHardwareCursor CreateCursor(ISpriteFrame f, ImmutablePalette palette, string name, CursorSequence sequence)
{
var hotspot = sequence.Hotspot - f.Offset.ToInt2() + new int2(f.Size) / 2;
// Expand the frame if required to include the hotspot
var frameWidth = f.Size.Width;
var dataWidth = f.Size.Width;
var dataX = 0;
if (hotspot.X < 0)
{
dataX = -hotspot.X;
dataWidth += dataX;
hotspot = hotspot.WithX(0);
}
else if (hotspot.X >= frameWidth)
dataWidth = hotspot.X + 1;
var frameHeight = f.Size.Height;
var dataHeight = f.Size.Height;
var dataY = 0;
if (hotspot.Y < 0)
{
dataY = -hotspot.Y;
dataHeight += dataY;
hotspot = hotspot.WithY(0);
}
else if (hotspot.Y >= frameHeight)
dataHeight = hotspot.Y + 1;
var data = new byte[4 * dataWidth * dataHeight];
for (var j = 0; j < frameHeight; j++)
{
for (var i = 0; i < frameWidth; i++)
{
var bytes = BitConverter.GetBytes(palette[f.Data[j * frameWidth + i]]);
var start = 4 * ((j + dataY) * dataWidth + dataX + i);
for (var k = 0; k < 4; k++)
data[start + k] = bytes[k];
}
}
return Game.Renderer.Window.CreateHardwareCursor(name, new Size(dataWidth, dataHeight), data, hotspot);
}
public void SetCursor(string cursorName)
{
if ((cursorName == null && cursor == null) || (cursor != null && cursorName == cursor.Name))
return;
if (cursorName == null || !cursorProvider.Cursors.TryGetValue(cursorName, out cursor))
cursor = null;
Update();
}
int frame;
int ticks;
public void Tick()
{
if (cursor == null || cursor.Length == 1)
return;
if (++ticks > 2)
{
ticks -= 2;
frame++;
Update();
}
}
void Update()
{
if (cursor != null && frame >= cursor.Length)
frame %= cursor.Length;
if (cursor == null || isLocked)
Game.Renderer.Window.SetHardwareCursor(null);
else
Game.Renderer.Window.SetHardwareCursor(hardwareCursors[cursor.Name][frame]);
}
public void Render(Renderer renderer)
{
if (cursor.Name == null || !isLocked)
return;
var cursorSequence = cursorProvider.GetCursorSequence(cursor.Name);
var cursorSprite = sprites[cursor.Name][frame];
var cursorOffset = cursorSequence.Hotspot + (0.5f * cursorSprite.Size.XY).ToInt2();
renderer.SetPalette(hardwarePalette);
renderer.SpriteRenderer.DrawSprite(cursorSprite,
lockedPosition - cursorOffset,
paletteReferences[cursorSequence.Palette],
cursorSprite.Size);
}
public void Lock()
{
lockedPosition = Viewport.LastMousePos;
Game.Renderer.Window.SetRelativeMouseMode(true);
isLocked = true;
Update();
}
public void Unlock()
{
Game.Renderer.Window.SetRelativeMouseMode(false);
isLocked = false;
Update();
}
public void Dispose()
{
foreach (var cursors in hardwareCursors)
foreach (var cursor in cursors.Value)
cursor.Dispose();
sheetBuilder.Dispose();
hardwareCursors.Clear();
}
}
}

View File

@@ -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

View File

@@ -1,44 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 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.Primitives;
namespace OpenRA.Graphics
{
class MappedImage
{
readonly Rectangle rect = Rectangle.Empty;
public readonly string Src;
public MappedImage(string defaultSrc, MiniYaml info)
{
FieldLoader.LoadField(this, "rect", info.Value);
FieldLoader.Load(this, info);
if (Src == null)
Src = defaultSrc;
}
public Sprite GetImage(Sheet s)
{
return new Sprite(s, rect, TextureChannel.RGBA);
}
public MiniYaml Save(string defaultSrc)
{
var root = new List<MiniYamlNode>();
if (defaultSrc != Src)
root.Add(new MiniYamlNode("Src", Src));
return new MiniYaml(FieldSaver.FormatValue(this, GetType().GetField("rect")), root);
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -64,10 +64,10 @@ namespace OpenRA.Graphics
shader.SetTexture("Palette", palette);
}
public void SetViewportParams(Size screen, float zoom, int2 scroll)
public void SetViewportParams(Size screen, int2 scroll)
{
var a = 2f / renderer.SheetSize;
var view = new float[]
var view = new[]
{
a, 0, 0, 0,
0, -a, 0, 0,

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -15,9 +15,16 @@ using OpenRA.Primitives;
namespace OpenRA
{
public enum GLProfile
{
Modern,
Embedded,
Legacy
}
public interface IPlatform
{
IPlatformWindow CreateWindow(Size size, WindowMode windowMode, int batchSize);
IPlatformWindow CreateWindow(Size size, WindowMode windowMode, float scaleModifier, int batchSize, int videoDisplay, GLProfile profile);
ISoundEngine CreateSound(string device);
IFont CreateFont(byte[] data);
}
@@ -39,9 +46,15 @@ namespace OpenRA
{
IGraphicsContext Context { get; }
Size WindowSize { get; }
float WindowScale { get; }
event Action<float, float> OnWindowScaleChanged;
Size NativeWindowSize { get; }
Size EffectiveWindowSize { get; }
float NativeWindowScale { get; }
float EffectiveWindowScale { get; }
Size SurfaceSize { get; }
int DisplayCount { get; }
int CurrentDisplay { get; }
event Action<float, float, float, float> OnWindowScaleChanged;
void PumpInput(IInputHandler inputHandler);
string GetClipboardText();
@@ -50,9 +63,14 @@ namespace OpenRA
void GrabWindowMouseFocus();
void ReleaseWindowMouseFocus();
IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot);
IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot, bool pixelDouble);
void SetHardwareCursor(IHardwareCursor cursor);
void SetRelativeMouseMode(bool mode);
void SetScaleModifier(float scale);
GLProfile GLProfile { get; }
GLProfile[] SupportedGLProfiles { get; }
}
public interface IGraphicsContext : IDisposable
@@ -60,10 +78,10 @@ namespace OpenRA
IVertexBuffer<Vertex> CreateVertexBuffer(int size);
ITexture CreateTexture();
IFrameBuffer CreateFrameBuffer(Size s);
IFrameBuffer CreateFrameBuffer(Size s, Color clearColor);
IShader CreateShader(string name);
void EnableScissor(int left, int top, int width, int height);
void EnableScissor(int x, int y, int width, int height);
void DisableScissor();
void SaveScreenshot(string path);
void Present();
void DrawPrimitives(PrimitiveType pt, int firstVertex, int numVertices);
void Clear();
@@ -71,6 +89,7 @@ namespace OpenRA
void DisableDepthBuffer();
void ClearDepthBuffer();
void SetBlendMode(BlendMode mode);
void SetVSyncEnabled(bool enabled);
string GLVersion { get; }
}
@@ -109,6 +128,8 @@ namespace OpenRA
{
void Bind();
void Unbind();
void EnableScissor(Rectangle rect);
void DisableScissor();
ITexture Texture { get; }
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -153,8 +153,8 @@ namespace OpenRA.Graphics
var nextCorner = width / 2 * new float3(-nextDir.Y, nextDir.X, nextDir.Z);
// Vertices for the corners joining start-end to end-next
var cc = closed || i < limit ? IntersectionOf(end + corner, dir, end + nextCorner, nextDir) : end + corner;
var cd = closed || i < limit ? IntersectionOf(end - corner, dir, end - nextCorner, nextDir) : end - corner;
var cc = closed || i < limit - 1 ? IntersectionOf(end + corner, dir, end + nextCorner, nextDir) : end + corner;
var cd = closed || i < limit - 1 ? IntersectionOf(end - corner, dir, end - nextCorner, nextDir) : end - corner;
// Fill segment
vertices[0] = new Vertex(ca + Offset, r, g, b, a, 0, 0);

View File

@@ -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

View File

@@ -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
@@ -64,7 +64,7 @@ namespace OpenRA.Graphics
return Load(fileSystem, additionalSequences);
});
spriteCache = Exts.Lazy(() => new SpriteCache(fileSystem, modData.SpriteLoaders, new SheetBuilder(SheetType.Indexed)));
spriteCache = Exts.Lazy(() => new SpriteCache(fileSystem, modData.SpriteLoaders));
}
public ISpriteSequence GetSequence(string unitName, string sequenceName)
@@ -130,16 +130,21 @@ namespace OpenRA.Graphics
public void Preload()
{
SpriteCache.SheetBuilder.Current.CreateBuffer();
foreach (var sb in SpriteCache.SheetBuilders.Values)
sb.Current.CreateBuffer();
foreach (var unitSeq in sequences.Value.Values)
foreach (var seq in unitSeq.Value.Values) { }
SpriteCache.SheetBuilder.Current.ReleaseBuffer();
foreach (var sb in SpriteCache.SheetBuilders.Values)
sb.Current.ReleaseBuffer();
}
public void Dispose()
{
if (spriteCache.IsValueCreated)
spriteCache.Value.SheetBuilder.Dispose();
foreach (var sb in SpriteCache.SheetBuilders.Values)
sb.Dispose();
}
}
}

View File

@@ -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
@@ -79,7 +79,17 @@ namespace OpenRA.Graphics
public Png AsPng()
{
return new Png(GetData(), Size.Width, Size.Height);
var data = GetData();
// Convert BGRA to RGBA
for (var i = 0; i < Size.Width * Size.Height; i++)
{
var temp = data[i * 4];
data[i * 4] = data[i * 4 + 2];
data[i * 4 + 2] = temp;
}
return new Png(data, Size.Width, Size.Height);
}
public Png AsPng(TextureChannel channel, IPalette pal)

View File

@@ -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
@@ -36,6 +36,7 @@ namespace OpenRA.Graphics
public readonly SheetType Type;
readonly List<Sheet> sheets = new List<Sheet>();
readonly Func<Sheet> allocateSheet;
readonly int margin;
Sheet current;
TextureChannel channel;
@@ -47,19 +48,30 @@ namespace OpenRA.Graphics
return new Sheet(type, new Size(sheetSize, sheetSize));
}
public static SheetType FrameTypeToSheetType(SpriteFrameType t)
{
switch (t)
{
case SpriteFrameType.Indexed: return SheetType.Indexed;
case SpriteFrameType.BGRA: return SheetType.BGRA;
default: throw new NotImplementedException("Unknown SpriteFrameType {0}".F(t));
}
}
public SheetBuilder(SheetType t)
: this(t, Game.Settings.Graphics.SheetSize) { }
public SheetBuilder(SheetType t, int sheetSize)
: this(t, () => AllocateSheet(t, sheetSize)) { }
public SheetBuilder(SheetType t, int sheetSize, int margin = 1)
: this(t, () => AllocateSheet(t, sheetSize), margin) { }
public SheetBuilder(SheetType t, Func<Sheet> allocateSheet)
public SheetBuilder(SheetType t, Func<Sheet> allocateSheet, int margin = 1)
{
channel = t == SheetType.Indexed ? TextureChannel.Red : TextureChannel.RGBA;
Type = t;
current = allocateSheet();
sheets.Add(current);
this.allocateSheet = allocateSheet;
this.margin = margin;
}
public Sprite Add(ISpriteFrame frame) { return Add(frame.Data, frame.Size, 0, frame.Offset); }
@@ -76,9 +88,9 @@ namespace OpenRA.Graphics
return rect;
}
public Sprite Add(Png src)
public Sprite Add(Png src, float scale = 1f)
{
var rect = Allocate(new Size(src.Width, src.Height));
var rect = Allocate(new Size(src.Width, src.Height), scale);
Util.FastCopyIntoSprite(rect, src);
current.CommitBufferedData();
return rect;
@@ -102,19 +114,19 @@ namespace OpenRA.Graphics
return (TextureChannel)nextChannel;
}
public Sprite Allocate(Size imageSize) { return Allocate(imageSize, 0, float3.Zero); }
public Sprite Allocate(Size imageSize, float zRamp, float3 spriteOffset)
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)
{
if (imageSize.Width + p.X > current.Size.Width)
if (imageSize.Width + p.X + margin > current.Size.Width)
{
p = new int2(0, p.Y + rowHeight);
p = new int2(0, p.Y + rowHeight + margin);
rowHeight = imageSize.Height;
}
if (imageSize.Height > rowHeight)
rowHeight = imageSize.Height;
if (p.Y + imageSize.Height > current.Size.Height)
if (p.Y + imageSize.Height + margin > current.Size.Height)
{
var next = NextChannel(channel);
if (next == null)
@@ -131,8 +143,8 @@ namespace OpenRA.Graphics
p = int2.Zero;
}
var rect = new Sprite(current, new Rectangle(p.X, p.Y, imageSize.Width, imageSize.Height), zRamp, spriteOffset, channel, BlendMode.Alpha);
p += new int2(imageSize.Width, 0);
var rect = new Sprite(current, new Rectangle(p.X + margin, p.Y + margin, imageSize.Width, imageSize.Height), zRamp, spriteOffset, channel, BlendMode.Alpha, scale);
p += new int2(imageSize.Width + margin, 0);
return rect;
}

View File

@@ -1,119 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 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;
namespace OpenRA.Graphics
{
public interface ICursor : IDisposable
{
void Render(Renderer renderer);
void SetCursor(string cursor);
void Tick();
void Lock();
void Unlock();
}
public sealed class SoftwareCursor : ICursor
{
readonly HardwarePalette palette = new HardwarePalette();
readonly Cache<string, PaletteReference> paletteReferences;
readonly Dictionary<string, Sprite[]> sprites = new Dictionary<string, Sprite[]>();
readonly CursorProvider cursorProvider;
readonly SheetBuilder sheetBuilder;
bool isLocked = false;
int2 lockedPosition;
public SoftwareCursor(CursorProvider cursorProvider)
{
this.cursorProvider = cursorProvider;
paletteReferences = new Cache<string, PaletteReference>(CreatePaletteReference);
foreach (var p in cursorProvider.Palettes)
palette.AddPalette(p.Key, p.Value, false);
palette.Initialize();
sheetBuilder = new SheetBuilder(SheetType.Indexed);
foreach (var kv in cursorProvider.Cursors)
{
var s = kv.Value.Frames.Select(a => sheetBuilder.Add(a)).ToArray();
sprites.Add(kv.Key, s);
}
sheetBuilder.Current.ReleaseBuffer();
Game.Renderer.Window.SetHardwareCursor(null);
}
PaletteReference CreatePaletteReference(string name)
{
var pal = palette.GetPalette(name);
return new PaletteReference(name, palette.GetPaletteIndex(name), pal, palette);
}
string cursorName;
public void SetCursor(string cursor)
{
cursorName = cursor;
}
float cursorFrame;
public void Tick()
{
cursorFrame += 0.5f;
}
public void Render(Renderer renderer)
{
if (cursorName == null)
return;
var cursorSequence = cursorProvider.GetCursorSequence(cursorName);
var cursorSprite = sprites[cursorName][(int)cursorFrame % cursorSequence.Length];
var cursorSize = CursorProvider.CursorViewportZoomed ? 2.0f * cursorSprite.Size : cursorSprite.Size;
var cursorOffset = CursorProvider.CursorViewportZoomed ?
(2 * cursorSequence.Hotspot) + cursorSprite.Size.XY.ToInt2() :
cursorSequence.Hotspot + (0.5f * cursorSprite.Size.XY).ToInt2();
renderer.SetPalette(palette);
var mousePos = isLocked ? lockedPosition : Viewport.LastMousePos;
renderer.SpriteRenderer.DrawSprite(cursorSprite,
mousePos - cursorOffset,
paletteReferences[cursorSequence.Palette],
cursorSize);
}
public void Lock()
{
Game.Renderer.Window.SetRelativeMouseMode(true);
lockedPosition = Viewport.LastMousePos;
isLocked = true;
}
public void Unlock()
{
Game.Renderer.Window.SetRelativeMouseMode(false);
isLocked = false;
}
public void Dispose()
{
palette.Dispose();
sheetBuilder.Dispose();
}
}
}

View File

@@ -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
@@ -26,17 +26,17 @@ namespace OpenRA.Graphics
public readonly float3 FractionalOffset;
public readonly float Top, Left, Bottom, Right;
public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel)
: this(sheet, bounds, 0, float2.Zero, channel) { }
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)
public Sprite(Sheet sheet, Rectangle bounds, float zRamp, float3 offset, TextureChannel channel, BlendMode blendMode = BlendMode.Alpha, float scale = 1f)
{
Sheet = sheet;
Bounds = bounds;
Offset = offset;
ZRamp = zRamp;
Channel = channel;
Size = new float3(bounds.Size.Width, bounds.Size.Height, bounds.Size.Height * zRamp);
Size = scale * new float3(bounds.Size.Width, bounds.Size.Height, bounds.Size.Height * zRamp);
BlendMode = blendMode;
FractionalOffset = Size.Z != 0 ? offset / Size :
new float3(offset.X / Size.X, offset.Y / Size.Y, 0);

View File

@@ -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
@@ -13,7 +13,6 @@ using System;
using System.Linq;
using OpenRA.Primitives;
using OpenRA.Support;
using OpenRA.Widgets;
namespace OpenRA.Graphics
{
@@ -25,6 +24,8 @@ namespace OpenRA.Graphics
readonly Func<string, float> lineWidth;
readonly IFont font;
readonly Cache<Pair<char, Color>, GlyphInfo> glyphs;
readonly Cache<Tuple<char, Color, int>, Sprite> contrastGlyphs;
readonly Cache<int, float[]> dilationElements;
float deviceScale;
@@ -40,6 +41,8 @@ namespace OpenRA.Graphics
font = Game.Renderer.CreateFont(data);
glyphs = new Cache<Pair<char, Color>, GlyphInfo>(CreateGlyph, Pair<char, Color>.EqualityComparer);
contrastGlyphs = new Cache<Tuple<char, Color, int>, Sprite>(CreateContrastGlyph);
dilationElements = new Cache<int, float[]>(CreateCircularWeightMap);
// PERF: Cache these delegates for Measure calls.
Func<char, float> characterWidth = character => glyphs[Pair.New(character, Color.White)].Advance;
@@ -55,6 +58,7 @@ namespace OpenRA.Graphics
{
deviceScale = scale;
glyphs.Clear();
contrastGlyphs.Clear();
}
void PrecacheColor(Color c, string name)
@@ -65,44 +69,78 @@ namespace OpenRA.Graphics
throw new InvalidOperationException();
}
public void DrawText(string text, float2 location, Color c)
void DrawTextContrast(string text, float2 location, Color contrastColor, int contrastOffset)
{
// Offset from the baseline position to the top-left of the glyph for rendering
location += new float2(0, size);
var p = location;
// Calculate positions in screen pixel coordinates
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);
foreach (var s in text)
{
if (s == '\n')
{
location += new float2(0, size);
p = location;
screen = new int2((int)(location.X * deviceScale + 0.5f), (int)(location.Y * deviceScale + 0.5f));
continue;
}
var g = glyphs[Pair.New(s, Color.Black)];
// 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,
(screen + g.Offset - contrastVector) / deviceScale,
contrastSprite.Size / deviceScale);
}
screen += new int2((int)(g.Advance + 0.5f), 0);
}
}
public void DrawText(string text, float2 location, Color c)
{
// Offset from the baseline position to the top-left of the glyph for rendering
location += new float2(0, size);
// Calculate positions in screen pixel coordinates
var screen = new int2((int)(location.X * deviceScale + 0.5f), (int)(location.Y * deviceScale + 0.5f));
foreach (var s in text)
{
if (s == '\n')
{
location += new float2(0, size);
screen = new int2((int)(location.X * deviceScale + 0.5f), (int)(location.Y * deviceScale + 0.5f));
continue;
}
var g = glyphs[Pair.New(s, c)];
// Convert screen coordinates back to UI coordinates for drawing
if (g.Sprite != null)
Game.Renderer.RgbaSpriteRenderer.DrawSprite(g.Sprite,
new float2(
(int)Math.Round(p.X * deviceScale + g.Offset.X, 0) / deviceScale,
p.Y + g.Offset.Y / deviceScale),
g.Sprite.Size / deviceScale);
(screen + g.Offset).ToFloat2() / deviceScale,
g.Sprite.Size / deviceScale);
p += new float2(g.Advance / deviceScale, 0);
screen += new int2((int)(g.Advance + 0.5f), 0);
}
}
float3 Rotate(float3 v, float sina, float cosa, float2 offset)
float2 Rotate(float2 v, float sina, float cosa, float2 offset)
{
return new float3(
return new float2(
v.X * cosa - v.Y * sina + offset.X,
v.X * sina + v.Y * cosa + offset.Y,
0);
v.X * sina + v.Y * cosa + offset.Y);
}
public void DrawText(string text, float2 location, Color c, float angle)
{
// Offset from the baseline position to the top-left of the glyph for rendering
// All positions are calculated in UI coordinates
var offset = new float2(0, size);
var cosa = (float)Math.Cos(-angle);
var sina = (float)Math.Sin(-angle);
@@ -120,18 +158,25 @@ namespace OpenRA.Graphics
var g = glyphs[Pair.New(s, c)];
if (g.Sprite != null)
{
var tl = new float3(
(int)Math.Round(p.X * deviceScale + g.Offset.X, 0) / deviceScale,
p.Y + g.Offset.Y / deviceScale, 0);
var br = tl + g.Sprite.Size / deviceScale;
var tr = new float3(br.X, tl.Y, 0);
var bl = new float3(tl.X, br.Y, 0);
var tl = new float2(
p.X + g.Offset.X / deviceScale,
p.Y + g.Offset.Y / deviceScale);
var br = tl + g.Sprite.Size.XY / deviceScale;
var tr = new float2(br.X, tl.Y);
var bl = new float2(tl.X, br.Y);
var ra = Rotate(tl, sina, cosa, location);
var rb = Rotate(tr, sina, cosa, location);
var rc = Rotate(br, sina, cosa, location);
var rd = Rotate(bl, sina, cosa, location);
// 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,
Rotate(tl, sina, cosa, location),
Rotate(tr, sina, cosa, location),
Rotate(br, sina, cosa, location),
Rotate(bl, sina, cosa, location));
ra + screenOffset,
rb + screenOffset,
rc + screenOffset,
rd + screenOffset);
}
p += new float2(g.Advance / deviceScale, 0);
@@ -141,12 +186,7 @@ namespace OpenRA.Graphics
public void DrawTextWithContrast(string text, float2 location, Color fg, Color bg, int offset)
{
if (offset > 0)
{
DrawText(text, location + new float2(-offset / deviceScale, 0), bg);
DrawText(text, location + new float2(offset / deviceScale, 0), bg);
DrawText(text, location + new float2(0, -offset / deviceScale), bg);
DrawText(text, location + new float2(0, offset / deviceScale), bg);
}
DrawTextContrast(text, location, bg, offset);
DrawText(text, location, fg);
}
@@ -159,7 +199,12 @@ namespace OpenRA.Graphics
public void DrawTextWithShadow(string text, float2 location, Color fg, Color bg, int offset)
{
if (offset != 0)
DrawText(text, location + new float2(offset, offset), bg);
{
// Shadow offsets are rounded to an integer number of screen pixels.
// This makes sure the shadow will be positioned consistently everywhere on the screen.
var screenOffset = (int)(offset * deviceScale) / deviceScale;
DrawText(text, location + new float2(screenOffset, screenOffset), bg);
}
DrawText(text, location, fg);
}
@@ -172,7 +217,12 @@ namespace OpenRA.Graphics
public void DrawTextWithShadow(string text, float2 location, Color fg, Color bg, int offset, float angle)
{
if (offset != 0)
DrawText(text, location + new float2(offset, offset), bg, angle);
{
// Shadow offsets are rounded to an integer number of screen pixels.
// This makes sure the shadow will be positioned consistently everywhere on the screen.
var screenOffset = (int)(offset * deviceScale) / deviceScale;
DrawText(text, location + new float2(screenOffset, screenOffset), bg, angle);
}
DrawText(text, location, fg, angle);
}
@@ -239,6 +289,128 @@ namespace OpenRA.Graphics
return g;
}
float[] CreateCircularWeightMap(int r)
{
// Create circular weight maps that are used by CreateContrastGlyph for
// both the structuring element and to weight the resulting pixel value.
// The output is a 2 * r + 1 square array giving the pixel intersection
// with a circle of radius (r + 0.5).
//
// Example output for r=1:
// 0.60 1.00 0.60
// 1.00 1.00 1.00
// 0.60 1.00 0.60
//
// Example output for r=3:
// 0.00 0.44 0.80 1.00 0.80 0.44 0.00
// 0.44 1.00 1.00 1.00 1.00 1.00 0.44
// 0.80 1.00 1.00 1.00 1.00 1.00 0.80
// 1.00 1.00 1.00 1.00 1.00 1.00 1.00
// 0.80 1.00 1.00 1.00 1.00 1.00 0.80
// 0.44 1.00 1.00 1.00 1.00 1.00 0.44
// 0.00 0.44 0.80 1.00 0.80 0.44 0.00
var stride = 2 * r + 1;
var elem = new float[stride * stride];
for (var j = 0; j <= 2 * r; j++)
{
for (var i = 0; i <= 2 * r; i++)
{
var di = i - r;
var dj = j - r;
// No intersection with circle
if (di * di + dj * dj > (r + 1) * (r + 1))
continue;
// Fully contained within circle
if (di * di + dj * dj < (r - 1) * (r - 1))
{
elem[j * stride + i] = 1;
continue;
}
// Approximate sub-pixel intersection using a 5x5 grid
for (var jj = 0; jj < 5; jj++)
{
for (var ii = 0; ii < 5; ii++)
{
var si = di - (float)Math.Sign(di) * ii / 5;
var sj = dj - (float)Math.Sign(dj) * jj / 5;
if (si * si + sj * sj <= r * r)
elem[j * stride + i] += 0.04f;
}
}
}
}
return elem;
}
Sprite CreateContrastGlyph(Tuple<char, Color, int> 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 s = builder.Allocate(size);
var dest = s.Sheet.GetData();
var destStride = s.Sheet.Size.Width * 4;
var glyphData = glyph.Sprite.Sheet.GetData();
var glyphStride = glyph.Sprite.Sheet.Size.Width * 4;
var glyphBounds = glyph.Sprite.Bounds;
var elem = dilationElements[r];
var elemStride = 2 * r + 1;
// Expand the glyph by applying the greyscale dilation operator to the source glyph's alpha channel
for (var j = 0; j < s.Size.Y; j++)
{
for (var i = 0; i < s.Size.X; i++)
{
// Apply the weight map to the source glyph and find the largest weighted alpha
var first = true;
var alpha = (byte)0;
for (var wj = 0; wj <= 2 * r; wj++)
{
for (var wi = 0; wi <= 2 * r; wi++)
{
// Ignore pixels that are outside the source glyph bounds
var ii = i + wi - 2 * r;
var jj = j + wj - 2 * r;
if (ii < 0 || ii >= glyphBounds.Width || jj < 0 || jj >= glyphBounds.Height)
continue;
// Weighted alpha for this pixel
var weighted = (byte)(elem[wj * elemStride + wi] * glyphData[glyphStride * (jj + glyphBounds.Top) + 4 * (ii + glyphBounds.Left) + 3]);
if (first || weighted > alpha)
{
alpha = weighted;
first = false;
}
}
}
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;
}
}
}
s.Sheet.CommitBufferedData();
return s;
}
static Color GetContrastColor(Color fgColor, Color bgDark, Color bgLight)
{
return fgColor == Color.White || fgColor.GetBrightness() > 0.33 ? bgDark : bgLight;

View File

@@ -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
@@ -18,6 +18,8 @@ using OpenRA.Primitives;
namespace OpenRA.Graphics
{
public enum SpriteFrameType { Indexed, BGRA }
public interface ISpriteLoader
{
bool TryParseSprite(Stream s, out ISpriteFrame[] frames, out TypeDictionary metadata);
@@ -25,6 +27,8 @@ namespace OpenRA.Graphics
public interface ISpriteFrame
{
SpriteFrameType Type { get; }
/// <summary>
/// Size of the frame's `Data`.
/// </summary>
@@ -43,7 +47,7 @@ namespace OpenRA.Graphics
public class SpriteCache
{
public readonly SheetBuilder SheetBuilder;
public readonly Cache<SpriteFrameType, SheetBuilder> SheetBuilders;
readonly ISpriteLoader[] loaders;
readonly IReadOnlyFileSystem fileSystem;
@@ -51,9 +55,10 @@ namespace OpenRA.Graphics
readonly Dictionary<string, ISpriteFrame[]> unloadedFrames = new Dictionary<string, ISpriteFrame[]>();
readonly Dictionary<string, TypeDictionary> metadata = new Dictionary<string, TypeDictionary>();
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders)
{
SheetBuilder = sheetBuilder;
SheetBuilders = new Cache<SpriteFrameType, SheetBuilder>(t => new SheetBuilder(SheetBuilder.FrameTypeToSheetType(t)));
this.fileSystem = fileSystem;
this.loaders = loaders;
}
@@ -89,7 +94,7 @@ namespace OpenRA.Graphics
allSprites.Add(sprite);
}
// HACK: The sequency code relies on side-effects from getUsedFrames
// HACK: The sequence code relies on side-effects from getUsedFrames
var indices = getUsedFrames != null ? getUsedFrames(sprite.Length) :
Enumerable.Range(0, sprite.Length);
@@ -100,7 +105,7 @@ namespace OpenRA.Graphics
{
if (unloaded[i] != null)
{
sprite[i] = SheetBuilder.Add(unloaded[i]);
sprite[i] = SheetBuilders[unloaded[i].Type].Add(unloaded[i]);
unloaded[i] = null;
}
}

View File

@@ -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
@@ -64,8 +64,10 @@ namespace OpenRA.Graphics
public void RenderDebugGeometry(WorldRenderer wr)
{
var screenOffset = ScreenPosition(wr) + sprite.Offset;
Game.Renderer.WorldRgbaColorRenderer.DrawRect(screenOffset, screenOffset + sprite.Size, 1 / wr.Viewport.Zoom, Color.Red);
var pos = ScreenPosition(wr) + sprite.Offset;
var tl = wr.Viewport.WorldToViewPx(pos);
var br = wr.Viewport.WorldToViewPx(pos + sprite.Size);
Game.Renderer.RgbaColorRenderer.DrawRect(tl, br, 1, Color.Red);
}
public Rectangle ScreenBounds(WorldRenderer wr)

View File

@@ -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
@@ -155,22 +155,27 @@ namespace OpenRA.Graphics
shader.SetTexture("Palette", palette);
}
public void SetViewportParams(Size screen, float depthScale, float depthOffset, float zoom, int2 scroll)
public void SetViewportParams(Size screen, float depthScale, float depthOffset, int2 scroll)
{
shader.SetVec("Scroll", scroll.X, scroll.Y, scroll.Y);
shader.SetVec("r1",
zoom * 2f / screen.Width,
-zoom * 2f / screen.Height,
-depthScale * zoom / screen.Height);
shader.SetVec("r2", -1, 1, 1 - depthOffset);
2f / screen.Width,
2f / screen.Height,
-depthScale / screen.Height);
shader.SetVec("r2", -1, -1, 1 - depthOffset);
// Texture index is sampled as a float, so convert to pixels then scale
shader.SetVec("DepthTextureScale", 128 * depthScale * zoom / screen.Height);
shader.SetVec("DepthTextureScale", 128 * depthScale / screen.Height);
}
public void SetDepthPreviewEnabled(bool enabled)
{
shader.SetBool("EnableDepthPreview", enabled);
}
public void SetAntialiasingPixelsPerTexel(float pxPerTx)
{
shader.SetVec("AntialiasPixelsPerTexel", pxPerTx);
}
}
}

View File

@@ -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
@@ -46,12 +46,11 @@ namespace OpenRA.Graphics
if (!waypoints.Any())
return;
var sw = width / wr.Viewport.Zoom;
var first = wr.Screen3DPosition(waypoints.First());
var first = wr.Viewport.WorldToViewPx(wr.Screen3DPosition(waypoints.First()));
var a = first;
foreach (var b in waypoints.Skip(1).Select(pos => wr.Screen3DPosition(pos)))
foreach (var b in waypoints.Skip(1).Select(pos => wr.Viewport.WorldToViewPx(wr.Screen3DPosition(pos))))
{
Game.Renderer.WorldRgbaColorRenderer.DrawLine(a, b, sw, color);
Game.Renderer.RgbaColorRenderer.DrawLine(a, b, width, color);
DrawTargetMarker(wr, color, b, markerSize);
a = b;
}
@@ -59,13 +58,12 @@ namespace OpenRA.Graphics
DrawTargetMarker(wr, color, first);
}
public static void DrawTargetMarker(WorldRenderer wr, Color color, float3 location, int size = 1)
public static void DrawTargetMarker(WorldRenderer wr, Color color, int2 screenPos, int size = 1)
{
var sw = size / wr.Viewport.Zoom;
var offset = new float2(sw, sw);
var tl = location - offset;
var br = location + offset;
Game.Renderer.WorldRgbaColorRenderer.FillRect(tl, br, color);
var offset = new int2(size, size);
var tl = screenPos - offset;
var br = screenPos + offset;
Game.Renderer.RgbaColorRenderer.FillRect(tl, br, color);
}
public void RenderDebugGeometry(WorldRenderer wr) { }

View File

@@ -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

View File

@@ -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
@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.Primitives;
using OpenRA.Support;
@@ -34,7 +35,7 @@ namespace OpenRA.Graphics
public sealed class Theater : IDisposable
{
readonly Dictionary<ushort, TheaterTemplate> templates = new Dictionary<ushort, TheaterTemplate>();
readonly SheetBuilder sheetBuilder;
SheetBuilder sheetBuilder;
readonly Sprite missingTile;
readonly MersenneTwister random;
TileSet tileset;
@@ -53,7 +54,6 @@ namespace OpenRA.Graphics
return new Sheet(SheetType.Indexed, new Size(tileset.SheetSize, tileset.SheetSize));
};
sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate);
random = new MersenneTwister();
var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders);
@@ -75,6 +75,15 @@ namespace OpenRA.Graphics
var zOffset = tile != null ? -tile.ZOffset : 0;
var zRamp = tile != null ? tile.ZRamp : 1f;
var offset = new float3(f.Offset, zOffset);
var type = SheetBuilder.FrameTypeToSheetType(f.Type);
// Defer SheetBuilder creation until we know what type of frames we are loading!
// TODO: Support mixed indexed and BGRA frames
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.");
var s = sheetBuilder.Allocate(f.Size, zRamp, offset);
Util.FastCopyIntoChannel(s, f.Data);
@@ -102,7 +111,7 @@ namespace OpenRA.Graphics
}
// 1x1px transparent tile
missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1));
missingTile = sheetBuilder.Add(new byte[sheetBuilder.Type == SheetType.BGRA ? 4 : 1], new Size(1, 1));
Sheet.ReleaseBuffer();
}

View File

@@ -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

View File

@@ -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
@@ -61,23 +61,56 @@ namespace OpenRA.Graphics
public static void FastCopyIntoChannel(Sprite dest, byte[] src)
{
var data = dest.Sheet.GetData();
var srcStride = dest.Bounds.Width;
var destStride = dest.Sheet.Size.Width * 4;
var destOffset = destStride * dest.Bounds.Top + dest.Bounds.Left * 4 + ChannelMasks[(int)dest.Channel];
var destSkip = destStride - 4 * srcStride;
var destData = dest.Sheet.GetData();
var width = dest.Bounds.Width;
var height = dest.Bounds.Height;
var srcOffset = 0;
for (var j = 0; j < height; j++)
if (dest.Channel == TextureChannel.RGBA)
{
for (var i = 0; i < srcStride; i++, srcOffset++)
var destStride = dest.Sheet.Size.Width;
unsafe
{
data[destOffset] = src[srcOffset];
destOffset += 4;
}
// Cast the data to an int array so we can copy the src data directly
fixed (byte* bd = &destData[0])
{
var data = (int*)bd;
var x = dest.Bounds.Left;
var y = dest.Bounds.Top;
destOffset += destSkip;
var k = 0;
for (var j = 0; j < height; j++)
{
for (var i = 0; i < width; i++)
{
var r = src[k++];
var g = src[k++];
var b = src[k++];
var a = src[k++];
var cc = Color.FromArgb(a, r, g, b);
data[(y + j) * destStride + x + i] = PremultiplyAlpha(cc).ToArgb();
}
}
}
}
}
else
{
var destStride = dest.Sheet.Size.Width * 4;
var destOffset = destStride * dest.Bounds.Top + dest.Bounds.Left * 4 + ChannelMasks[(int)dest.Channel];
var destSkip = destStride - 4 * width;
var srcOffset = 0;
for (var j = 0; j < height; j++)
{
for (var i = 0; i < width; i++, srcOffset++)
{
destData[destOffset] = src[srcOffset];
destOffset += 4;
}
destOffset += destSkip;
}
}
}

View File

@@ -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

View File

@@ -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
@@ -19,6 +19,11 @@ namespace OpenRA.Graphics
[Flags]
public enum ScrollDirection { None = 0, Up = 1, Left = 2, Down = 4, Right = 8 }
public interface INotifyViewportZoomExtentsChanged
{
void ViewportZoomExtentsChanged(float minZoom, float maxZoom);
}
public static class ViewportExts
{
public static bool Includes(this ScrollDirection d, ScrollDirection s)
@@ -36,6 +41,8 @@ namespace OpenRA.Graphics
public class Viewport
{
readonly WorldRenderer worldRenderer;
readonly WorldViewportSizes viewportSizes;
readonly GraphicSettings graphicSettings;
// Map bounds (world-px)
readonly Rectangle mapBounds;
@@ -46,6 +53,7 @@ namespace OpenRA.Graphics
public WPos CenterPosition { get { return worldRenderer.ProjectedPosition(CenterLocation); } }
public Rectangle Rectangle { get { return new Rectangle(TopLeft, new Size(viewportSize.X, viewportSize.Y)); } }
public int2 TopLeft { get { return CenterLocation - viewportSize / 2; } }
public int2 BottomRight { get { return CenterLocation + viewportSize / 2; } }
int2 viewportSize;
@@ -54,14 +62,16 @@ namespace OpenRA.Graphics
ProjectedCellRegion allCells;
bool allCellsDirty = true;
readonly float[] availableZoomSteps = new[] { 2f, 1f, 0.5f, 0.25f };
WorldViewport lastViewportDistance;
float zoom = 1f;
float minZoom = 1f;
float maxZoom = 2f;
public float[] AvailableZoomSteps
{
get { return availableZoomSteps; }
}
bool unlockMinZoom;
float unlockedMinZoomScale;
float unlockedMinZoom = 1f;
public float Zoom
{
@@ -70,16 +80,37 @@ namespace OpenRA.Graphics
return zoom;
}
set
private set
{
var newValue = ClosestTo(AvailableZoomSteps, value);
zoom = newValue;
viewportSize = (1f / zoom * new float2(Game.Renderer.Resolution)).ToInt2();
zoom = value;
viewportSize = (1f / zoom * new float2(Game.Renderer.NativeResolution)).ToInt2();
cellsDirty = true;
allCellsDirty = true;
}
}
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 ToggleZoom()
{
// Unlocked zooms always reset to the default zoom
if (zoom < minZoom)
Zoom = minZoom;
else
Zoom = zoom > minZoom ? minZoom : maxZoom;
}
public void UnlockMinimumZoom(float scale)
{
unlockMinZoom = true;
unlockedMinZoomScale = scale;
UpdateViewportZooms(false);
}
public static long LastMoveRunTime = 0;
public static int2 LastMousePos;
@@ -119,6 +150,8 @@ namespace OpenRA.Graphics
{
worldRenderer = wr;
var grid = Game.ModData.Manifest.Get<MapGrid>();
viewportSizes = Game.ModData.Manifest.Get<WorldViewportSizes>();
graphicSettings = Game.Settings.Graphics;
// Calculate map bounds in world-px
if (wr.World.Type == WorldType.Editor)
@@ -140,8 +173,78 @@ namespace OpenRA.Graphics
CenterLocation = (tl + br) / 2;
}
Zoom = Game.Settings.Graphics.PixelDouble ? 2 : 1;
tileSize = grid.TileSize;
UpdateViewportZooms();
}
public void Tick()
{
if (lastViewportDistance != graphicSettings.ViewportDistance)
UpdateViewportZooms();
}
float CalculateMinimumZoom(float minHeight, float maxHeight)
{
var h = Game.Renderer.NativeResolution.Height;
// Check the easy case: the native resolution is within the maximum limit
// Also catches the case where the user may force a resolution smaller than the minimum window size
if (h <= maxHeight)
return 1;
// Find a clean fraction that brings us within the desired range to reduce aliasing
var step = 1f;
while (true)
{
var testZoom = 1f;
while (true)
{
var nextZoom = testZoom + step;
if (h < minHeight * nextZoom)
break;
testZoom = nextZoom;
}
if (h < maxHeight * testZoom)
return testZoom;
step /= 2;
}
}
void UpdateViewportZooms(bool resetCurrentZoom = true)
{
lastViewportDistance = graphicSettings.ViewportDistance;
var vd = graphicSettings.ViewportDistance;
if (viewportSizes.AllowNativeZoom && vd == WorldViewport.Native)
minZoom = 1;
else
{
var range = viewportSizes.GetSizeRange(vd);
minZoom = CalculateMinimumZoom(range.X, range.Y);
}
maxZoom = Math.Min(minZoom * viewportSizes.MaxZoomScale, Game.Renderer.NativeResolution.Height * 1f / viewportSizes.MaxZoomWindowHeight);
if (unlockMinZoom)
{
// Specators and the map editor support zooming out by an extra factor of two.
// TODO: Allow zooming out until the full map is visible
// We need to improve our viewport scroll handling to center the map as we zoom out
// before this will work well enough to enable
unlockedMinZoom = minZoom * unlockedMinZoomScale;
}
if (resetCurrentZoom)
Zoom = minZoom;
else
Zoom = Zoom.Clamp(minZoom, maxZoom);
foreach (var t in worldRenderer.World.WorldActor.TraitsImplementing<INotifyViewportZoomExtentsChanged>())
t.ViewportZoomExtentsChanged(minZoom, maxZoom);
}
public CPos ViewToWorld(int2 view)
@@ -209,8 +312,9 @@ namespace OpenRA.Graphics
yield return new MPos(u, v);
}
public int2 ViewToWorldPx(int2 view) { return (1f / Zoom * view.ToFloat2()).ToInt2() + TopLeft; }
public int2 WorldToViewPx(int2 world) { return (Zoom * (world - TopLeft).ToFloat2()).ToInt2(); }
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 void Center(IEnumerable<Actor> actors)
{
@@ -239,7 +343,6 @@ namespace OpenRA.Graphics
}
// Rectangle (in viewport coords) that contains things to be drawn
static readonly Rectangle ScreenClip = Rectangle.FromLTRB(0, 0, Game.Renderer.Resolution.Width, Game.Renderer.Resolution.Height);
public Rectangle GetScissorBounds(bool insideBounds)
{
// Visible rectangle in world coordinates (expanded to the corners of the cells)
@@ -249,12 +352,12 @@ namespace OpenRA.Graphics
var cbr = map.CenterOfCell(((MPos)bounds.BottomRight).ToCPos(map)) + new WVec(512, 512, 0);
// Convert to screen coordinates
var tl = WorldToViewPx(worldRenderer.ScreenPxPosition(ctl - new WVec(0, 0, ctl.Z))).Clamp(ScreenClip);
var br = WorldToViewPx(worldRenderer.ScreenPxPosition(cbr - new WVec(0, 0, cbr.Z))).Clamp(ScreenClip);
var tl = worldRenderer.ScreenPxPosition(ctl - new WVec(0, 0, ctl.Z)) - TopLeft;
var br = worldRenderer.ScreenPxPosition(cbr - new WVec(0, 0, cbr.Z)) - TopLeft;
// Add an extra one cell fudge in each direction for safety
return Rectangle.FromLTRB(tl.X - tileSize.Width, tl.Y - tileSize.Height,
br.X + tileSize.Width, br.Y + tileSize.Height);
// Add an extra half-cell fudge to avoid clipping isometric tiles
return Rectangle.FromLTRB(tl.X - tileSize.Width / 2, tl.Y - tileSize.Height / 2,
br.X + tileSize.Width / 2, br.Y + tileSize.Height / 2);
}
ProjectedCellRegion CalculateVisibleCells(bool insideBounds)

View File

@@ -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
@@ -39,6 +39,10 @@ namespace OpenRA.Graphics
readonly Func<string, PaletteReference> createPaletteReference;
readonly bool enableDepthBuffer;
readonly List<IFinalizedRenderable> preparedRenderables = new List<IFinalizedRenderable>();
readonly List<IFinalizedRenderable> preparedOverlayRenderables = new List<IFinalizedRenderable>();
readonly List<IFinalizedRenderable> preparedAnnotationRenderables = new List<IFinalizedRenderable>();
bool lastDepthPreviewEnabled;
internal WorldRenderer(ModData modData, World world)
@@ -103,7 +107,7 @@ namespace OpenRA.Graphics
palettes[name].Palette = pal;
}
List<IFinalizedRenderable> GenerateRenderables()
IEnumerable<IFinalizedRenderable> GenerateRenderables()
{
var actors = onScreenActors.Append(World.WorldActor);
if (World.RenderPlayer != null)
@@ -122,42 +126,74 @@ namespace OpenRA.Graphics
worldRenderables = worldRenderables.OrderBy(RenderableScreenZPositionComparisonKey);
Game.Renderer.WorldModelRenderer.BeginFrame();
var renderables = worldRenderables.Select(r => r.PrepareRender(this)).ToList();
Game.Renderer.WorldModelRenderer.EndFrame();
return renderables;
return worldRenderables.Select(r => r.PrepareRender(this));
}
List<IFinalizedRenderable> GenerateOverlayRenderables()
IEnumerable<IFinalizedRenderable> GenerateOverlayRenderables()
{
var aboveShroud = World.ActorsWithTrait<IRenderAboveShroud>()
var actors = World.ActorsWithTrait<IRenderAboveShroud>()
.Where(a => a.Actor.IsInWorld && !a.Actor.Disposed && (!a.Trait.SpatiallyPartitionable || onScreenActors.Contains(a.Actor)))
.SelectMany(a => a.Trait.RenderAboveShroud(a.Actor, this));
var aboveShroudSelected = World.Selection.Actors.Where(a => a.IsInWorld && !a.Disposed)
var selected = World.Selection.Actors.Where(a => a.IsInWorld && !a.Disposed)
.SelectMany(a => a.TraitsImplementing<IRenderAboveShroudWhenSelected>()
.Where(t => !t.SpatiallyPartitionable || onScreenActors.Contains(a))
.SelectMany(t => t.RenderAboveShroud(a, this)));
var aboveShroudEffects = World.Effects.Select(e => e as IEffectAboveShroud)
var effects = World.Effects.Select(e => e as IEffectAboveShroud)
.Where(e => e != null)
.SelectMany(e => e.RenderAboveShroud(this));
var aboveShroudOrderGenerator = SpriteRenderable.None;
var orderGenerator = SpriteRenderable.None;
if (World.OrderGenerator != null)
aboveShroudOrderGenerator = World.OrderGenerator.RenderAboveShroud(this, World);
orderGenerator = World.OrderGenerator.RenderAboveShroud(this, World);
var overlayRenderables = aboveShroud
.Concat(aboveShroudSelected)
.Concat(aboveShroudEffects)
.Concat(aboveShroudOrderGenerator);
return actors
.Concat(selected)
.Concat(effects)
.Concat(orderGenerator)
.Select(r => r.PrepareRender(this));
}
Game.Renderer.WorldModelRenderer.BeginFrame();
var finalOverlayRenderables = overlayRenderables.Select(r => r.PrepareRender(this)).ToList();
Game.Renderer.WorldModelRenderer.EndFrame();
IEnumerable<IFinalizedRenderable> GenerateAnnotationRenderables()
{
var actors = World.ActorsWithTrait<IRenderAnnotations>()
.Where(a => a.Actor.IsInWorld && !a.Actor.Disposed && (!a.Trait.SpatiallyPartitionable || onScreenActors.Contains(a.Actor)))
.SelectMany(a => a.Trait.RenderAnnotations(a.Actor, this));
return finalOverlayRenderables;
var selected = World.Selection.Actors.Where(a => a.IsInWorld && !a.Disposed)
.SelectMany(a => a.TraitsImplementing<IRenderAnnotationsWhenSelected>()
.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));
var orderGenerator = SpriteRenderable.None;
if (World.OrderGenerator != null)
orderGenerator = World.OrderGenerator.RenderAnnotations(this, World);
return actors
.Concat(selected)
.Concat(effects)
.Concat(orderGenerator)
.Select(r => r.PrepareRender(this));
}
public void PrepareRenderables()
{
if (World.WorldActor.Disposed)
return;
RefreshPalette();
// PERF: Reuse collection to avoid allocations.
onScreenActors.UnionWith(World.ScreenMap.RenderableActorsInBox(Viewport.TopLeft, Viewport.BottomRight));
preparedRenderables.AddRange(GenerateRenderables());
preparedOverlayRenderables.AddRange(GenerateOverlayRenderables());
preparedAnnotationRenderables.AddRange(GenerateAnnotationRenderables());
onScreenActors.Clear();
}
public void Draw()
@@ -171,10 +207,6 @@ namespace OpenRA.Graphics
Game.Renderer.WorldSpriteRenderer.SetDepthPreviewEnabled(lastDepthPreviewEnabled);
}
RefreshPalette();
onScreenActors.UnionWith(World.ScreenMap.RenderableActorsInBox(Viewport.TopLeft, Viewport.BottomRight));
var renderables = GenerateRenderables();
var bounds = Viewport.GetScissorBounds(World.Type != WorldType.Editor);
Game.Renderer.EnableScissor(bounds);
@@ -186,8 +218,8 @@ namespace OpenRA.Graphics
Game.Renderer.Flush();
for (var i = 0; i < renderables.Count; i++)
renderables[i].Render(this);
for (var i = 0; i < preparedRenderables.Count; i++)
preparedRenderables[i].Render(this);
if (enableDepthBuffer)
Game.Renderer.ClearDepthBuffer();
@@ -196,56 +228,68 @@ namespace OpenRA.Graphics
if (a.Actor.IsInWorld && !a.Actor.Disposed)
a.Trait.RenderAboveWorld(a.Actor, this);
var renderShroud = World.RenderPlayer != null ? World.RenderPlayer.Shroud : null;
if (enableDepthBuffer)
Game.Renderer.ClearDepthBuffer();
foreach (var a in World.ActorsWithTrait<IRenderShroud>())
a.Trait.RenderShroud(renderShroud, this);
a.Trait.RenderShroud(this);
if (enableDepthBuffer)
Game.Renderer.Context.DisableDepthBuffer();
Game.Renderer.DisableScissor();
var finalOverlayRenderables = GenerateOverlayRenderables();
// HACK: Keep old grouping behaviour
var groupedOverlayRenderables = finalOverlayRenderables.GroupBy(prs => prs.GetType());
var groupedOverlayRenderables = preparedOverlayRenderables.GroupBy(prs => prs.GetType());
foreach (var g in groupedOverlayRenderables)
foreach (var r in g)
r.Render(this);
Game.Renderer.Flush();
}
public void DrawAnnotations()
{
Game.Renderer.EnableAntialiasingFilter();
for (var i = 0; i < preparedAnnotationRenderables.Count; i++)
preparedAnnotationRenderables[i].Render(this);
Game.Renderer.DisableAntialiasingFilter();
// Engine debugging overlays
if (debugVis.Value != null && debugVis.Value.RenderGeometry)
{
for (var i = 0; i < renderables.Count; i++)
renderables[i].RenderDebugGeometry(this);
for (var i = 0; i < preparedRenderables.Count; i++)
preparedRenderables[i].RenderDebugGeometry(this);
foreach (var g in groupedOverlayRenderables)
foreach (var r in g)
r.RenderDebugGeometry(this);
for (var i = 0; i < preparedOverlayRenderables.Count; i++)
preparedOverlayRenderables[i].RenderDebugGeometry(this);
for (var i = 0; i < preparedAnnotationRenderables.Count; i++)
preparedAnnotationRenderables[i].RenderDebugGeometry(this);
}
if (debugVis.Value != null && debugVis.Value.ScreenMap)
{
foreach (var r in World.ScreenMap.RenderBounds(World.RenderPlayer))
Game.Renderer.WorldRgbaColorRenderer.DrawRect(
new float3(r.Left, r.Top, r.Bottom),
new float3(r.Right, r.Bottom, r.Bottom),
1 / Viewport.Zoom, Color.MediumSpringGreen);
{
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.MediumSpringGreen);
}
foreach (var r in World.ScreenMap.MouseBounds(World.RenderPlayer))
Game.Renderer.WorldRgbaColorRenderer.DrawRect(
new float3(r.Left, r.Top, r.Bottom),
new float3(r.Right, r.Bottom, r.Bottom),
1 / Viewport.Zoom, Color.OrangeRed);
{
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);
}
}
Game.Renderer.Flush();
// PERF: Reuse collection to avoid allocations.
onScreenActors.Clear();
preparedRenderables.Clear();
preparedOverlayRenderables.Clear();
preparedAnnotationRenderables.Clear();
}
public void RefreshPalette()

View File

@@ -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
@@ -20,6 +20,7 @@ namespace OpenRA
public readonly Hotkey Default = Hotkey.Invalid;
public readonly string Description = "";
public readonly HashSet<string> Types = new HashSet<string>();
public bool HasDuplicates { get; internal set; }
public HotkeyDefinition(string name, MiniYaml node)
{

View File

@@ -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
@@ -38,6 +38,9 @@ namespace OpenRA
if (definitions.ContainsKey(kv.Key))
keys[kv.Key] = kv.Value;
}
foreach (var hd in definitions)
hd.Value.HasDuplicates = GetFirstDuplicate(hd.Value.Name, this[hd.Value.Name].GetValue(), hd.Value) != null;
}
internal Func<Hotkey> GetHotkeyReference(string name)
@@ -65,6 +68,20 @@ namespace OpenRA
settings[name] = value;
else
settings.Remove(name);
var hadDuplicates = definition.HasDuplicates;
definition.HasDuplicates = GetFirstDuplicate(definition.Name, this[definition.Name].GetValue(), definition) != null;
if (hadDuplicates || definition.HasDuplicates)
{
foreach (var hd in definitions)
{
if (hd.Value == definition)
continue;
hd.Value.HasDuplicates = GetFirstDuplicate(hd.Value.Name, this[hd.Value.Name].GetValue(), hd.Value) != null;
}
}
}
public HotkeyDefinition GetFirstDuplicate(string name, Hotkey value, HotkeyDefinition definition)

View File

@@ -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

View File

@@ -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
@@ -9,9 +9,11 @@
*/
#endregion
using System;
namespace OpenRA
{
public struct Hotkey
public struct Hotkey : IEquatable<Hotkey>
{
public static Hotkey Invalid = new Hotkey(Keycode.UNKNOWN, Modifiers.None);
public bool IsValid()
@@ -74,6 +76,11 @@ namespace OpenRA
public override int GetHashCode() { return Key.GetHashCode() ^ Modifiers.GetHashCode(); }
public bool Equals(Hotkey other)
{
return other == this;
}
public override bool Equals(object obj)
{
var o = obj as Hotkey?;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -26,16 +26,12 @@ namespace OpenRA
readonly Dictionary<string, Manifest> mods;
readonly SheetBuilder sheetBuilder;
readonly Dictionary<string, Sprite> icons = new Dictionary<string, Sprite>();
public readonly IReadOnlyDictionary<string, Sprite> Icons;
/// <summary>Initializes the collection of locally installed mods.</summary>
/// <param name="searchPaths">Filesystem paths to search for mod packages.</param>
/// <param name="explicitPaths">Filesystem paths to additional mod packages.</param>
public InstalledMods(IEnumerable<string> searchPaths, IEnumerable<string> explicitPaths)
{
sheetBuilder = new SheetBuilder(SheetType.BGRA, 256);
Icons = new ReadOnlyDictionary<string, Sprite>(icons);
mods = GetInstalledMods(searchPaths, explicitPaths);
}
@@ -76,20 +72,7 @@ namespace OpenRA
package = new Folder(path);
if (package.Contains("mod.yaml"))
{
var manifest = new Manifest(id, package);
if (package.Contains("icon.png"))
{
using (var stream = package.GetStream("icon.png"))
if (stream != null)
icons[id] = sheetBuilder.Add(new Png(stream));
}
else if (!manifest.Metadata.Hidden)
Log.Write("debug", "Mod '{0}' is missing 'icon.png'.".F(path));
return manifest;
}
return new Manifest(id, package);
}
catch (Exception e)
{

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -71,5 +71,14 @@ namespace OpenRA
// for initialization syntax
public void Add(object o) { InitDict.Add(o); }
public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); }
public ActorReference Clone()
{
var clone = new ActorReference(Type);
foreach (var init in InitDict)
clone.InitDict.Add(init);
return clone;
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -824,6 +824,14 @@ namespace OpenRA
return new WDist(delta.Z);
}
public WVec Offset(CVec delta, int dz)
{
if (Grid.Type == MapGridType.Rectangular)
return new WVec(1024 * delta.X, 1024 * delta.Y, 0);
return new WVec(724 * (delta.X - delta.Y), 724 * (delta.X + delta.Y), 724 * dz);
}
/// <summary>
/// The size of the map Height step in world units
/// </summary>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

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