Compare commits

...

335 Commits

Author SHA1 Message Date
Paul Chote
0e845a9f3a Make tundra slightly less boring 2010-10-13 21:44:14 +13:00
Chris Forbes
2a3c149769 rename oasis map, since that wasn't what it was. 2010-10-13 21:18:26 +13:00
Chris Forbes
7cfcd94e23 #181, #286 fixed -- sharedrandom seed from server is now used. 2010-10-13 21:00:27 +13:00
Chris Forbes
247a8c9717 add Tiberian's TD map: 'The Sentinel (1v1)' 2010-10-13 20:52:40 +13:00
Chris Forbes
4afd8ad783 #289 lobby title should show servername -- fixed 2010-10-13 20:45:03 +13:00
Paul Chote
dca77956cb Revert to saving only non-default settings. 2010-10-13 19:57:53 +13:00
Paul Chote
22c6c3b3f6 Remove the default westwood maps from cnc. 2010-10-13 19:57:52 +13:00
Paul Chote
1e8e5c8f5c Remove aftermath mod - it has bitrotted beyond all usefulness. 2010-10-13 19:57:52 +13:00
Paul Chote
c0fcc862d6 Add some more mod metadata for beedee. Todo: enforce dependencies and standalone during game init. 2010-10-13 19:57:52 +13:00
Paul Chote
5a3ccdf0c5 fix ssm launcher rockets 2010-10-13 19:57:52 +13:00
Paul Chote
1bd802c386 Add tech building definitions to cnc; noncapturable map decorations until they have behavior implemented. 2010-10-13 19:57:52 +13:00
Paul Chote
3a4e2abedd Fix snow theatre 2010-10-13 19:57:18 +13:00
Paul Chote
f13343ef2e Fix tilesets colours for snow and blue tib, fix unit speed over tib, fix lst pathability. 2010-10-13 19:57:18 +13:00
Paul Chote
2b1ac6a60f WIP 1v1 map 2010-10-13 19:57:18 +13:00
Chris Forbes
8aa180c1f4 cleaned up unused bits in attackmove 2010-10-13 19:20:17 +13:00
Chris Forbes
260e420f85 fix crash in attackmove 2010-10-13 19:12:20 +13:00
Chris Forbes
1a203afd89 fix all the buggy crap around chat/teamchat... still hacked 2010-10-13 08:13:21 +13:00
max621
c150fd9475 Added attack move 2010-10-13 08:13:20 +13:00
Chris Forbes
566303a8f1 #276 fixed 2010-10-12 21:19:48 +13:00
Chris Forbes
10f8364b99 #240 declaring war should set the reciprocal state too 2010-10-12 21:19:48 +13:00
Chris Forbes
7c31f72db6 quick hack around the teamchat crash in lobby 2010-10-12 21:19:27 +13:00
Bob
6b6c9639f9 fix crash wrt chat in lobby 2010-10-12 20:37:36 +13:00
Bob
7ca9fcdac9 run the shellmap even while the lobby shows. remove Widget.SpecialOneArg 2010-10-12 18:33:16 +13:00
Bob
20276291ce move Game.world onto OrderManager. use call IssueOrder on world and/or on orderManager, not on Game 2010-10-12 17:30:27 +13:00
Bob
34fc207a6c FUCK YES 2010-10-12 17:30:24 +13:00
Bob
c974e61680 remove refs to Game.world in widgets 2010-10-12 17:30:22 +13:00
Bob
09db76f89f remove ref to Game.world in Move 2010-10-12 17:29:11 +13:00
Bob
6bbf878314 remove ref to Game.world in Viewport.ShroudBounds 2010-10-12 17:29:09 +13:00
Bob
4cd3195f9f call refreshPalette in the right place. make Game.worldRenderer PRIVATE (yay) 2010-10-12 17:29:06 +13:00
Bob
6ea2a06e4b pass WorldRenderer to Widget.Draw, DrawInner 2010-10-12 17:27:08 +13:00
Bob
597dba8584 untangling WorldRenderer from World 2010-10-12 17:24:23 +13:00
Bob
1c1483377c remove ref to Game.world in Combat 2010-10-12 17:24:19 +13:00
Bob
0873741983 don't pass world to Widget.Tick, either 2010-10-12 17:24:17 +13:00
Bob
e0afc08e5f move an access of Viewport into Game 2010-10-12 17:24:14 +13:00
Bob
cb1deacbb2 pass world into CheckSync. don't pass world into Widget.DrawInner 2010-10-12 17:24:12 +13:00
Bob
ab1e930ba3 pass worldRenderer around as necessary 2010-10-12 17:24:07 +13:00
Bob
10bf85f57e move Game.Current{Host,Port} into orderManager 2010-10-12 17:24:03 +13:00
Bob
17990ab8b7 move LobbyInfo onto OrderManager 2010-10-12 17:24:00 +13:00
Bob
beecb8aeb1 remove redundant parameter from ObjectCreator.Param attribute 2010-10-12 17:23:57 +13:00
Bob
6a25d989a7 remove many references to Game.world 2010-10-12 17:23:55 +13:00
Bob
f8776d773d extract FrameData from OrderManager. fix disconnect bug in NetworkConnection 2010-10-12 17:22:17 +13:00
Bob
3724f46a3e remove world arg to SyncLobbyInfo and HandleInput 2010-10-12 17:22:14 +13:00
Bob
915ad7fb7b extract replay saving from OrderManager 2010-10-12 17:22:12 +13:00
Chris Forbes
07023b6c35 add yaml setup for blue tiberium 2010-10-12 16:59:58 +13:00
Chris Forbes
b78b5b22a3 add blue tiberium art 2010-10-12 16:59:58 +13:00
Bob
eca098b0b4 use a getter for Aircraft.Location 2010-10-12 07:59:40 +13:00
Bob
011a20e8b4 add IHasLocation 2010-10-12 07:59:40 +13:00
Bob
9c362f7d41 remove setters on Mobile.{from,to}Cell. use SetLocation instead 2010-10-12 07:59:39 +13:00
Chris Forbes
99d92ee095 move ColorFromHSL out of the ui code 2010-10-11 19:52:46 +13:00
Chris Forbes
b905d343af fix mishandled CancelProduction 2010-10-11 19:37:45 +13:00
Chris Forbes
024b564b8c maybe this works better 2010-10-11 19:10:34 +13:00
Chris Forbes
9c0e3ac4c9 allow AppearsOnRadar to use Location rather than OccupiedCells, for things that don't occupy any cells 2010-10-11 18:54:13 +13:00
Chris Forbes
a2205e9031 fix some dumb (nonfatal) crashes in the editor with nothing loaded 2010-10-11 18:21:41 +13:00
Chris Forbes
0df9815d2c fix base-cycling for mac build, too? 2010-10-10 15:11:53 +13:00
Chris Forbes
79d6eb4a2b some widgets cleanup 2010-10-10 15:09:26 +13:00
Chris Forbes
0d8557eadb fix NRE in CancelableActivity 2010-10-10 11:04:39 +13:00
Matthew Bowra-Dean
70f6fc7a7a Removed git describe from checkout-and-build.sh 2010-10-09 22:26:17 +13:00
Paul Chote
11f6a8b945 Revert mono 2.8 deps; causes desyncs. 2010-10-09 20:05:37 +13:00
Chris Forbes
e3d71acb05 fix crash in CrateEffect 2010-10-09 13:40:57 +13:00
Chris Forbes
580f1cfe97 bot and humans hate each other, even if the host is on a team. 2010-10-09 13:40:55 +13:00
Andrew Riedi
3d7434f42e Fixed under VS 2010. 2010-10-09 13:40:52 +13:00
Chris Forbes
ef96604f9e #231 scroll jumping fixed 2010-10-09 13:40:49 +13:00
Chris Forbes
465f5d295b force master server url update, if old. 2010-10-09 13:40:47 +13:00
Chris Forbes
1feb377d43 fix bogus target lines being drawn to 0,0 2010-10-09 13:40:33 +13:00
Caleb Anderson
a065fb464e bandage to fix dogs not killing infantry in certain cases 2010-10-09 13:40:21 +13:00
Chris Forbes
e39917ca19 trim bbox for ftrk 2010-10-08 19:09:18 +13:00
Chris Forbes
318f496bf9 #202 fixed 2010-10-08 19:03:01 +13:00
Chris Forbes
ed8a155249 if c17 gets confused, just fly away 2010-10-08 18:57:14 +13:00
Chris Forbes
40ac5f7b6e FallsToEarth for cnc helis too 2010-10-08 18:45:52 +13:00
Chris Forbes
517754027e 8Inch and SubMissile minimum ranges temporarily disabled, until combat bugs are fixed 2010-10-08 18:33:38 +13:00
Caleb Anderson
ef4f478e10 Strip newlines from scrolling text. Frame-friendly update of scrolling text 2010-10-08 18:29:20 +13:00
Chris Forbes
92c30b89f8 FACT hp 1000 -> 1500 2010-10-08 18:26:25 +13:00
Chris Forbes
7331a9c4fb prevent aircraft shooting while landed 2010-10-08 18:25:26 +13:00
Chris Forbes
d2b9e150f1 add FallsToEarth for helicopters dying 2010-10-08 18:24:08 +13:00
Chris Forbes
8ba329f1be reduce cost of CA 3200 -> 2400 2010-10-08 18:03:34 +13:00
Chris Forbes
8868eab247 nerf hind chaingun from [x2] 40@3 to 20@10 2010-10-08 18:03:13 +13:00
Caleb Anderson
f12889e684 Sensible scroll cursor positions for cnc. RA seems to be totally different, didn't touch atm 2010-10-08 17:39:00 +13:00
Caleb Anderson
5c095bc174 more politic default motd text for cnc 2010-10-08 17:38:55 +13:00
Caleb Anderson
0c24a08436 sane default scroll speed 2010-10-08 17:38:48 +13:00
Chris Forbes
9762b540b0 fix bogus reverse-enter-transport (in ResolveOrder this time) 2010-10-08 17:38:07 +13:00
Paul Chote
fd34f2ba99 Fix #225 and some other uses of a.IsInWorld / a.IsDead() 2010-10-08 10:56:50 +13:00
Paul Chote
ad6481c8e8 Change master server url. Won't work until dns is set correctly. 2010-10-07 22:46:44 +13:00
Paul Chote
7426d47cd5 Fix some compile warnings 2010-10-07 22:46:44 +13:00
pdovy
761f62292f missing files from previous commit 2010-10-07 22:46:44 +13:00
unknown
63b8555bc9 Fix bug that prevented ground units from attacking landed aircraft. 2010-10-07 22:46:44 +13:00
Bob
3209da4a4a fixed PlaceBuilding and Chronosphere ordergenerators 2010-10-07 22:07:13 +13:00
Bob
aebef4f1c8 rename IIssueOrder2 -> IIssueOrder 2010-10-07 22:07:13 +13:00
Bob
d3244184c1 implement order targeter for everything else 2010-10-07 22:07:13 +13:00
Bob
39e62354a8 implement order targeter for passenger 2010-10-07 22:07:12 +13:00
Bob
f525c3808e implement order targeter for cargo 2010-10-07 22:07:12 +13:00
Bob
87a0b52ce5 more order targeters 2010-10-07 22:07:12 +13:00
Bob
4bc9e01516 use new orders system in various traits 2010-10-07 22:07:12 +13:00
Bob
711d05da98 use IIssueOrder2 in AttackBase 2010-10-07 22:07:12 +13:00
Bob
3d805ff40d added IIssueOrder2. most orders are broken, but Minelayer is fixed 2010-10-07 22:07:12 +13:00
Bob
0cd140849b fix some support powers 2010-10-07 22:07:12 +13:00
Bob
d6110b9ef0 add Sync.AssertUnsynced. use it in OrderGenerator.set 2010-10-07 22:07:12 +13:00
Bob
26d1db778e push the check-synchash-doesn't-change pattern into a utility fn. furthur reduce the number of uses on Game.world 2010-10-07 22:07:11 +13:00
Bob
f41aa474aa remove more uses of Game.world 2010-10-07 22:07:11 +13:00
Paul Chote
0002e80a19 Use new deps package, built on mono 2.8. Enable new sgen garbage collector. 2010-10-07 22:05:43 +13:00
Chris Forbes
759a52d86e fix build failure from bad merge in prev 2010-10-07 18:24:40 +13:00
max621
44fe0396bb Added shift+right click on build menu cancels 5 orders. Added ctrl+shift+right click on build menu cancels all orders 2010-10-07 18:23:26 +13:00
rasco
dd6d8d916e hackyAI 2010-10-07 07:42:40 +13:00
Chris Forbes
5af8f5e2d9 bots choose random colors 2010-10-07 07:41:14 +13:00
Caleb Anderson
c85503811c Clamp, scroll, scrollspeed, sliders
Reduced clamp duplication
Fixed scrolling speed issue
Modified scrollspeed slider to use a range
Fixed scrollspeed, volume, and sound sliders not showing current setting.
2010-10-06 20:53:56 +13:00
Chris Forbes
ab431fe9ee fix crash on warhead=null 2010-10-06 20:17:03 +13:00
Chris Forbes
7ec9958d47 hackyai should only attack humans 2010-10-06 20:04:36 +13:00
rasco
cfc74a6dee HackyAI: builds defense now. rally points are rechosen so units are more scattered in the base. builds only e1-3 and 1-3tnks. 2010-10-06 19:14:29 +13:00
Chris Forbes
cecdd73e08 destroy ore in all smudged cells 2010-10-06 18:37:32 +13:00
Chris Forbes
381e080b11 tweak nuke timing back 2010-10-06 18:32:33 +13:00
Chris Forbes
c6a047cb1a fix silent nukes 2010-10-06 18:29:05 +13:00
Chris Forbes
4c51733e04 actually add the cratenuke warhead 2010-10-06 18:25:07 +13:00
Chris Forbes
8f613b80e8 ban cloak crate on infantry 2010-10-06 18:16:09 +13:00
Chris Forbes
10de282daa add mechanism to exclude particular actor types from picking up any crate 2010-10-06 18:13:29 +13:00
Chris Forbes
915e123956 add minimum ranges for mig/yak/ca/msub/hind/v2rl/arty 2010-10-06 18:05:31 +13:00
Chris Forbes
8cb7a7b8ce add support for WeaponInfo.MinRange 2010-10-06 17:41:52 +13:00
Chris Forbes
ce5cf93077 prevent infantry going prone due to tib damage 2010-10-06 17:37:23 +13:00
Chris Forbes
1390bb7428 ra: reduce parabombs charge to 1min 2010-10-06 17:32:04 +13:00
Chris Forbes
3c5b136216 ra: reduce nuke charge time 13min -> 9 min 2010-10-06 17:29:45 +13:00
Chris Forbes
66785e606a ra: brik hp 1500 => 1000 2010-10-06 17:23:12 +13:00
Chris Forbes
e2239fa50c #215 obli misses moving units fixed 2010-10-06 17:22:11 +13:00
Chris Forbes
7f7712aa64 #203 dogs eating walls fixed 2010-10-06 17:20:20 +13:00
Chris Forbes
b1605e115a #206 badr/badr.bomber appear in tooltips 2010-10-06 17:15:52 +13:00
Chris Forbes
69b2da86be RA: +20% 4tnk HP 2010-10-06 17:13:39 +13:00
Chris Forbes
18e965e5aa fix desync on destroying ore storage buildings 2010-10-06 10:59:46 +13:00
Chris Forbes
24f0c28f56 fix massive player/client confusion after people drop 2010-10-06 10:59:45 +13:00
Paul Chote
25af51b4ac Prevent a race condition 2010-10-05 19:00:36 +13:00
Paul Chote
ecd7064cc3 Add an example mod that adds a soviet supply truck 2010-10-05 18:48:00 +13:00
Chris Forbes
477a21e782 fix 'minv/minp' showing up in tooltips 2010-10-05 17:58:30 +13:00
Chris Forbes
899d9af62b CNC: +25% HP on FACT/MCV 2010-10-05 17:58:29 +13:00
Paul Chote
17eca983ef Fix wall sell exploit 2010-10-05 17:56:30 +13:00
max621
2fc219ecd5 Fixed auto attack not working properly due to code expecting 'Idle' activity but most units use 'IdleAnimation' in RA mod 2010-10-05 17:45:29 +13:00
Chris Forbes
49a645cd2d fix ubuntu-64 support (Tao.FreeType was quite bogus.) 2010-10-05 17:42:13 +13:00
Matthew
7cb8da411d Updated git url to point to new upstream location. 2010-10-05 17:42:13 +13:00
Matthew
4bcdf3cf11 Netcode discussion from Etherpad. 2010-10-05 17:36:03 +13:00
Matthew
1b525ff809 Export FTP server and added username/password to VERSION file upload. 2010-10-05 17:36:03 +13:00
Caleb Anderson
cdec3fce26 Don't tell all players about my yaks 2010-10-05 17:25:30 +13:00
Caleb Anderson
7bdf6a953f New slider Range parameter. Palette modifications. Potential crash fix. Clamp function.
Range parameter added to slider. Supports returning a range of values
rather than just 0-1. Allows you to not have to post process the offset.
Modified palette selector to not have full range, which was causing
blown out units.
Introduced exension method Clamp<T>(min, max)
Fixed crash deserializing out of bound color value using above
extension.
2010-10-05 17:25:25 +13:00
Chris Forbes
06b20c8ba5 fix blatant wrongness in parallel builds 2010-10-02 20:55:43 +13:00
Paul Chote
9b484b53ec Show mod info in server browser 2010-10-02 20:37:25 +13:00
Paul Chote
9620b4ed46 Add mod metadata, and filter valid mods on startup. 2010-10-02 20:37:22 +13:00
Caleb Anderson
d8908c44d0 Nicer default ticker text 2010-10-02 01:13:55 -05:00
Caleb Anderson
cfe705531a Async motd grab. Client and server version in MasterServerQuery 2010-10-02 01:13:53 -05:00
Caleb Anderson
9a2fd38ab6 MOTD ticker. ScrollingText Widget 2010-10-02 01:13:51 -05:00
Chris Forbes
911e7f62de fix retardedly putting everyone in slot 0. 2010-10-02 18:33:29 +13:00
Chris Forbes
403b81bdc9 apply the balance stick to BIKE 2010-10-02 15:49:42 +13:00
Chris Forbes
a0714b00b3 a bit of cleanup 2010-10-02 15:49:42 +13:00
Chris Forbes
d5239ee77a add tib and spawns to new map 2010-10-02 15:49:41 +13:00
Chris Forbes
03ec97f302 unfinished 2v2 cnc map 2010-10-02 15:49:41 +13:00
Chris Forbes
3255f95ee9 ffs, more paths 2010-10-02 15:35:48 +13:00
Chris Forbes
4c8fd5e73d oops 2010-10-02 15:30:16 +13:00
Chris Forbes
7179ef0f45 fix packaging script 2010-10-02 15:19:14 +13:00
Alli
6d5918b11d Remove compiler warnings 2010-10-02 14:30:54 +13:00
Matthew Bowra-Dean
81c484d1c9 Fixed debian package prereqs 2010-10-02 13:28:22 +13:00
Chris Forbes
de1044c24c hack around imagelist deserialization being completely busted across platforms 2010-10-02 13:22:54 +13:00
Paul Chote
e4c31939d9 Save all settings to settings.yaml, not just non-defaults. 2010-10-02 12:15:15 +13:00
Paul Chote
7f48d6796e Fix scroll ticks 2010-10-02 12:01:11 +13:00
Matthew Bowra-Dean
4fd77aec8e Only add 'Latest:' text if query succeeds. 2010-10-02 11:39:56 +13:00
Matthew Bowra-Dean
92fece01de Added latest version information underneath current version in main menu. 2010-10-02 11:39:54 +13:00
geckosoft
d8d987f844 Fixed Settings menu issue (overlapping text) 2010-10-02 11:38:42 +13:00
unknown
de429a4c62 Added new setting : Scroll Speed (added to cnc & ra) 2010-10-02 11:38:39 +13:00
Chris Forbes
c0ca35a4ff fix AI jam in cnc 2010-10-02 11:33:50 +13:00
Chris Forbes
1bff8559fb pull HasAdequatePower out into a function 2010-10-02 11:33:47 +13:00
Chris Forbes
de98274165 fix #184 crashes while placing minefield 2010-10-02 11:33:04 +13:00
Chris Forbes
59e2228b2a shader fallback path for cg-2.1, which misinterprets 'latest' 2010-10-02 11:32:14 +13:00
geckosoft
96d1408d45 Fixed crash bug #197 2010-10-02 11:31:55 +13:00
Paul Chote
ff45ae2d16 Fix direct connect in cnc 2010-10-02 11:31:19 +13:00
Chris Forbes
47950c9113 Revert "remove setters on Mobile.{from,to}Cell. use SetLocation instead"
This reverts commit 911db3feb1.
2010-09-28 07:45:14 +13:00
Chris Forbes
f402ec7898 Revert "add IHasLocation"
This reverts commit 699b4b1154.
2010-09-28 07:43:49 +13:00
Chris Forbes
a3c0448e15 fix broken mac packaging script 2010-09-27 21:44:23 +13:00
Bob
699b4b1154 add IHasLocation 2010-09-26 18:17:23 +12:00
Bob
911db3feb1 remove setters on Mobile.{from,to}Cell. use SetLocation instead 2010-09-26 16:46:22 +12:00
Paul Chote
c790db8e84 Fix and bulletproof osx packaging script; cleanup some obsolete .gitignore entries 2010-09-26 10:18:22 +13:00
Bob
d6dd392028 use Invariant culture for float parsing (workaround a mono bug) 2010-09-26 09:11:26 +12:00
Bob
636b2a8ea7 fix Direct Connect window 2010-09-25 19:26:02 +12:00
Chris Forbes
959d3f8bd7 fix crash in giving a harv DeliverOre order after its proc has died, but it hasnt noticed yet 2010-09-25 07:34:51 +12:00
Matthew
193cb929f1 Fixing error with Windows package script launching 2010-09-24 22:12:26 +12:00
Chris Forbes
f93e270fe4 reduce v2 range and damage slightly 2010-09-24 21:49:26 +12:00
Chris Forbes
f19953c39a nerf ftrk heavily vs most ground, and reduce hp from 300 to 120 2010-09-24 21:44:57 +12:00
Matthew
59d5ce1bc8 +x permissions for checkout-and-build.sh 2010-09-24 20:42:29 +12:00
Matthew
43cf7cd074 Yet another packaging script. 2010-09-24 20:42:26 +12:00
Chris Forbes
aba76f4b50 don't look up resource type every cell for ore, too 2010-09-24 20:40:56 +12:00
Bob
8021fc3b20 Deduplicate shroud rendering code 2010-09-24 18:11:11 +12:00
Bob
7bf4cb85fa fix perf in ShroudRenderer 2010-09-24 18:11:08 +12:00
Bob
6dd03bb339 bugfix in ResourceLayer 2010-09-24 18:11:06 +12:00
Bob
14e517cab5 Autoflush renderer. Sprite.DrawAt convenience function. 2010-09-24 18:11:03 +12:00
Bob
cdcfeb6276 render perf improvement: BufferSubData, and don't use the same buffer back-to-back 2010-09-24 18:11:00 +12:00
Matthew
c77c63a380 Fix #130.
Windows installer now checks version of OpenAL32.dll and downloads and updates if necessary.
2010-09-24 16:40:55 +12:00
Matthew
9921fe8fad Linux package parallelisation. 2010-09-24 16:40:55 +12:00
Matthew
f848c5d7d4 Parallel building of packages. 2010-09-24 16:40:55 +12:00
Matthew
62c47e3b12 Reordered packaging platforms due to popular demand. 2010-09-24 16:40:55 +12:00
Matthew
094986d066 Tag prefixes change upload location for packages. 2010-09-24 16:40:55 +12:00
Chris Forbes
d87e02ab41 more tweaks, make DD a detector again (wtf?) 2010-09-23 22:23:39 +12:00
Chris Forbes
3f415a8fdf tweak torps more 2010-09-23 22:09:56 +12:00
Chris Forbes
846371cf3e homing torps, bubble trail 2010-09-23 22:09:56 +12:00
Chris Forbes
45c77e64ee fix various desyncs when using cheats 2010-09-23 22:09:55 +12:00
Bob
66493031c8 fix crash with idle units and pathdebug 2010-09-23 21:06:44 +12:00
Bob
384b26db60 fix fieldloader bug caused by foreach language-bug 2010-09-23 17:24:06 +12:00
Bob
d66dbeb312 removing unused stuff from TraitsInterfaces 2010-09-23 15:43:34 +12:00
Chris Forbes
ba9611f544 un-FP Building.cs power stuff 2010-09-22 21:43:04 +12:00
Chris Forbes
b6e56560d4 fix a crash in RepairIndicator with a dead building 2010-09-22 20:48:45 +12:00
Chris Forbes
1f047d439f back out editor icon hack -- it breaks the packaged editor on windows 2010-09-22 19:26:09 +12:00
Chris Forbes
5233ae4770 remove spam from Util.GetFacing 2010-09-22 19:21:22 +12:00
Chris Forbes
562e07264a remove lots of debug spam 2010-09-22 19:19:18 +12:00
Chris Forbes
4dab4ed73f reenable crates 2010-09-22 19:15:45 +12:00
Chris Forbes
a97ddffa53 fix cnc movement (argh) 2010-09-22 19:00:07 +12:00
Bob
8e589e3c16 fix infantry anims 2010-09-22 13:32:58 +12:00
Bob
96f72ce842 new map in ra_perf 2010-09-22 13:08:02 +12:00
Bob
d8de477edb fix IdleAnimation. add IsAttacking to AttackBase 2010-09-22 12:21:49 +12:00
Bob
694fb6831a fix target line on Move that has not yet calculated path 2010-09-22 12:03:45 +12:00
Bob
c16a515224 make more activities cancelable. remove many uses of CurrentActivity is T 2010-09-22 11:53:58 +12:00
Bob
e2eae7973b removing warning 2010-09-22 11:18:47 +12:00
Bob
9e3c938706 removing cancelable from Move. remove unnecessary qualified names from Production 2010-09-22 10:46:54 +12:00
Bob
ef665df2e9 refactor activity queueing 2010-09-22 10:13:13 +12:00
Bob
271a3eea8d fix harv 2010-09-22 08:49:56 +12:00
Bob
2f6315b816 make the pathfinder use integers 2010-09-22 08:04:52 +12:00
Bob
ac8d408ba7 allow queuing non-buildings while the queue is ready 2010-09-22 08:02:20 +12:00
Bob
0fdd49c96a MovePart becomes an Activity 2010-09-22 08:02:17 +12:00
Bob
e390cf8ab0 fix real-ra map importer when map isn't in game root 2010-09-22 08:02:15 +12:00
Bob
64d700cd70 make c&c work too 2010-09-22 08:02:12 +12:00
Bob
d3db9d3710 yes, i do want += 2010-09-22 08:02:09 +12:00
Bob
9eb05a43f9 show perf widget 2010-09-22 08:02:06 +12:00
Bob
3165ec5359 create widgets on demand 2010-09-22 08:02:03 +12:00
Bob
f4699132d6 made OpenWindow and CloseWindow static 2010-09-22 08:02:00 +12:00
Bob
086bdfb4bd new object creation logic 2010-09-22 08:01:57 +12:00
Chris Forbes
61fd12c7da oops; prev didnt run 2010-09-22 07:19:18 +12:00
Chris Forbes
9979209c34 more useful debug, less debug 2010-09-21 22:42:31 +12:00
Chris Forbes
b0c06d4cd9 force consistent conversion to float in a few places 2010-09-21 22:08:40 +12:00
Chris Forbes
3a617f8934 sync the last path generated, to try and catch this MUCH earlier 2010-09-21 21:43:16 +12:00
Chris Forbes
b35a7d9f8d stacktrace on set_Facing too 2010-09-21 21:06:37 +12:00
Chris Forbes
67fa079658 more debug 2010-09-21 21:05:28 +12:00
Chris Forbes
c9edbd8a80 report the tick in debug 2010-09-21 18:10:05 +12:00
Chris Forbes
4b49bf03dc reset local tick # at gamestart 2010-09-21 18:05:54 +12:00
Chris Forbes
6cfad6f2ab stacktrace in SetLocation 2010-09-20 22:52:28 +12:00
Chris Forbes
c0c4e7299b log changes to synced parameters in Mobile 2010-09-20 22:07:16 +12:00
Bob
afda1647fd moved more traits from engine into mods 2010-09-20 21:17:50 +12:00
Bob
aff6889995 moved traits from engine into mod 2010-09-20 20:58:42 +12:00
Bob
65515d54af fix crash where harv and linked proc get destroyed by the same bullet 2010-09-20 20:58:39 +12:00
Chris Forbes
c5b7c43d23 add pathspam in debug 2010-09-20 19:06:43 +12:00
Chris Forbes
dba5adc91c more debug 2010-09-20 18:33:48 +12:00
Chris Forbes
0073a03ca4 add debug for nudges 2010-09-20 18:27:31 +12:00
Chris Forbes
5509d0d2e9 suspecting drag instead 2010-09-20 17:55:16 +12:00
Chris Forbes
fe52e3722e more debug 2010-09-20 17:45:27 +12:00
Chris Forbes
3ddd1581f1 add debug for this desync 2010-09-20 17:28:06 +12:00
Iran
56efc3930b Pretty up HACKING and add some info 2010-09-19 23:10:33 +02:00
Iran
2f8d81a0f7 Fix OnFormClosing's MessageBox.Show under mono, unix newline and Environment.Newline didn't work, but Windows newline does work 2010-09-19 22:39:00 +02:00
Iran
46486073ab Display icon while running the Editor under mono, cant test it on windows 2010-09-19 19:31:10 +02:00
Chris Forbes
3dc11eaa05 fix crash in cnc when placing WEAP 2010-09-19 20:13:19 +12:00
Caleb Anderson
b62ee4d37c Fixed sequence crash 2010-09-19 19:13:15 +12:00
Paul Chote
532afc3ff8 Fix random logging 2010-09-19 19:03:18 +12:00
Paul Chote
9ddb2beced Apply the same to bibs and smudges 2010-09-19 18:57:42 +12:00
Matthew Bowra-Dean
1e758ec3e0 Removed website from main repository.
Moved to http://github.com/beedee/OpenRAWebsite/
2010-09-19 18:53:55 +12:00
Chris Forbes
aa1d44428d fix prev 2010-09-19 18:50:34 +12:00
Paul Chote
23da8a24bd Only render shroud/ore that is in the current viewport 2010-09-19 18:34:23 +12:00
Iran
fef291a27e don't switch production tab while selecting building not owned by you 2010-09-19 18:12:22 +12:00
Paul Chote
f49e56d660 3x faster syncreport 2010-09-19 17:13:44 +12:00
Paul Chote
927ab00f4d Use the correct number of players in the lobby team selector 2010-09-18 22:33:41 +12:00
Paul Chote
3f870e7e48 Remove yaml cruft; rename music repeat -> loop. 2010-09-18 22:19:57 +12:00
Paul Chote
f2a321186f Fix osx packaging 2010-09-18 21:53:22 +12:00
Paul Chote
410daecab6 sync SharedRandom 2010-09-18 21:53:10 +12:00
Paul Chote
966e3bb71a Remove debug spam 2010-09-18 20:47:24 +12:00
Paul Chote
652f06f604 Route the power check for support powers via the tech tree 2010-09-18 20:46:01 +12:00
Paul Chote
2a10af2007 Fix z-offset 2010-09-18 20:46:00 +12:00
Paul Chote
4cb26c0e3c Try again, with less fail. 2010-09-18 20:46:00 +12:00
Paul Chote
8455dadb3c Powerdown etc... untested 2010-09-18 20:46:00 +12:00
Paul Chote
3c19b3df73 Update power on damage 2010-09-18 20:46:00 +12:00
Paul Chote
c796e155e7 Fix UpdateTotals(); add debug info. 2010-09-18 20:46:00 +12:00
Paul Chote
ce9caec291 Begin splitting power into its own trait; incomplete and non-working. 2010-09-18 20:46:00 +12:00
Chris Forbes
0330ef2b9e blah 2010-09-18 19:57:45 +12:00
Chris Forbes
872a304714 all traits can contribute to the synchash 2010-09-18 18:34:57 +12:00
Chris Forbes
59cc50df4c hack synchash to sync the traitdict contents (just ITick impls for now) 2010-09-18 18:31:36 +12:00
Chris Forbes
a1fd84fb15 make actors collection sync order-dependent, since the actors themselves are. 2010-09-18 18:26:03 +12:00
Chris Forbes
317007f7ce temporarily disable crates (stability problem) 2010-09-18 17:23:47 +12:00
Matthew
387212d9ea Fixed RPM build script file listing 2010-09-18 16:07:10 +12:00
Matthew
c9ca5e207b Updated RPM build script to include menu, desktop and icon files. 2010-09-18 14:10:48 +12:00
Chris Forbes
ce78944a9e more editor hax 2010-09-18 13:30:12 +12:00
Chris Forbes
1fb336b7da unwtf the editor a bit 2010-09-18 13:26:45 +12:00
katzsmile
e4d05407d9 Added export minimap to PNG. Hided unfinished Tools and Bitmap import menus.
Added hack to render building roofs of they have same name but have "2" in name. (weap and weap2)

Signed-off-by: katzsmile <katzsmile@lead-games.com>
2010-09-18 12:56:08 +12:00
Chris Forbes
f7eca1157e fix walkability of sh30 template in RA temperate and snow 2010-09-18 11:56:22 +12:00
Chris Forbes
a64245fc10 fix it so it compiles with VS again 2010-09-18 11:52:51 +12:00
Paul Chote
ad8038867d PlayerProductionQueue -> ClassicProductionQueue. 2010-09-18 11:28:50 +12:00
Paul Chote
fb90400524 Rename TechTreeCache -> TechTree 2010-09-18 11:28:48 +12:00
Paul Chote
08b25d10c1 Remove dead TechTree code 2010-09-18 11:28:46 +12:00
Paul Chote
ba09bbba8e Remove TechLevel from special powers, and identify the performance problem. 2010-09-18 11:28:43 +12:00
Paul Chote
0d2e1d7de5 Hidden debug parameter for perf tick logging 2010-09-18 11:28:39 +12:00
Paul Chote
22861fca5a Sanitize ProductionQueue and fix bugs in TechTreeCache.
Gives perf win on every tick, and fixes bugs where you lose prereqs when buildings are low power.
2010-09-18 11:28:33 +12:00
Chris Forbes
692ef539f9 fix timings of infantry idle anims 2010-09-18 11:25:45 +12:00
Matthew
d07b0e4400 Linux desktop/menu entries. 2010-09-17 20:21:16 +12:00
Chris Forbes
9848d1f403 hack WEAP door z 2010-09-17 20:21:22 +12:00
Chris Forbes
83eae029b7 add explicit Z to Renderable. eating my hat, etc. 2010-09-17 20:21:21 +12:00
Paul Chote
99e225c279 Fix cnc fact footprint 2010-09-17 20:18:21 +12:00
Paul Chote
1785c4e4a8 Support for arbitrary building art offset relative to footprint 2010-09-17 20:18:14 +12:00
Chris Forbes
69753f8a08 ffs 2010-09-17 19:54:20 +12:00
Chris Forbes
5593b9ffdd start splitting up tsb; fix a wtf in the save code 2010-09-17 19:00:09 +12:00
Chris Forbes
1b66635670 fix A10 exploit 2010-09-17 19:00:08 +12:00
Chris Forbes
f1b1f3bd52 make hackyAI less of a tard 2010-09-17 19:00:08 +12:00
Chris Forbes
ff611dac32 hack BelowUnits z 2010-09-17 19:00:07 +12:00
Chris Forbes
e0a4cb4763 hack around some more z-glitches 2010-09-17 19:00:07 +12:00
Paul Chote
a3246866fb Better perf logging 2010-09-17 10:02:24 +12:00
Paul Chote
b94c2fc7c4 Fix d2k colour picker (fact doesn't exist yet) 2010-09-17 09:21:14 +12:00
Paul Chote
d530cf22da Include resources in the editor preview. 2010-09-17 09:09:36 +12:00
Chris Forbes
94e5b02a39 fix some editor weirdness (2/2) 2010-09-17 07:58:06 +12:00
Chris Forbes
40533a50c1 fix some editor weirdness (1/2) 2010-09-17 07:57:57 +12:00
Paul Chote
d4182b1929 Tweaks to minimap preview 2010-09-16 22:54:49 +12:00
Paul Chote
482129499d Fix editor makefile 2010-09-16 22:32:35 +12:00
katzsmile
366cd02761 Changed path text box to editable on save 2010-09-16 22:32:35 +12:00
katzsmile
f549e7e5a8 added map preview image on save and on load 2010-09-16 22:32:35 +12:00
katzsmile
4cab7c7fc4 added minimap preview 2010-09-16 22:32:35 +12:00
katzsmile
e3939d4805 Fixed most of bugs. Redone open/save dialog 2010-09-16 22:32:35 +12:00
katzsmile
2ae6983bc2 floater window changes 2010-09-16 22:32:34 +12:00
katzsmile
ad00193a17 Little fix for "indian" code
Signed-off-by: katzsmile <katzsmile@lead-games.com>
2010-09-16 22:32:34 +12:00
katzsmile
810667abbc changed border in open/save dialog 2010-09-16 22:32:34 +12:00
katzsmile
a66efd56f2 Title display in open/save dialogs
Signed-off-by: katzsmile <katzsmile@lead-games.com>
2010-09-16 22:32:34 +12:00
katzsmile
36ba15e7f9 Displaying map theater name in open/save dialogs 2010-09-16 22:32:34 +12:00
katzsmile
d809fb1e7b Updated Map Editor:
New Open/Save dialogs
Added icon for program
Hacked Actors Tab.
Started work on floater with tools

Signed-off-by: katzsmile <katzsmile@lead-games.com>
2010-09-16 22:32:34 +12:00
Chris Forbes
d0bc834a57 #151 fixed 2010-09-16 18:32:03 +12:00
Chris Forbes
483ca8cc4c #82 deliver to allied proc -- fixed 2010-09-16 18:22:45 +12:00
Chris Forbes
06aba5da46 fix remote engineer repair exploit 2010-09-16 18:19:06 +12:00
Chris Forbes
106fbcd5af remove some crashes 2010-09-16 18:18:16 +12:00
Chris Forbes
f456e41a45 check if a passenger is appropriate for reverse-enter-transport 2010-09-16 18:07:42 +12:00
Chris Forbes
7dc3aee4a2 #68 dog attacking ground fixed 2010-09-16 17:56:19 +12:00
Chris Forbes
c91bee8091 add option to ban attacking ground 2010-09-16 17:53:59 +12:00
Chris Forbes
82875e15f9 remove some bogosity; there will likely be regressions, but not a huge deal. 2010-09-16 17:50:52 +12:00
Chris Forbes
d6f8b7d850 fix z-order bug 2010-09-16 17:43:17 +12:00
Chris Forbes
72fe873b26 #105 fixed 2010-09-16 10:23:37 +12:00
Paul Chote
e9f34b1e21 Quick fix for #87, #88. Real fix will come when we nest activities. 2010-09-16 07:45:29 +12:00
Paul Chote
d15ab79370 Add new tileset source 2010-09-15 20:54:39 +12:00
Paul Chote
303613b052 Create valid maps for custom tilesets 2010-09-15 19:31:21 +12:00
Paul Chote
051c451867 Support custom tile size ingame 2010-09-15 19:31:21 +12:00
Paul Chote
ac8a3526a4 Custom tilesize support for editor 2010-09-15 19:31:21 +12:00
Paul Chote
be47fb55e8 Initial support for custom tile sizes 2010-09-15 19:31:21 +12:00
Paul Chote
5b8fc75d4a d2k shadows 2010-09-15 19:31:20 +12:00
Paul Chote
629e73ac29 support d2k remap range 2010-09-15 19:31:20 +12:00
Paul Chote
7e5b861caf Hacky beginnings of a standalone d2k mod 2010-09-15 19:31:20 +12:00
Chris Forbes
f3dcc14fca remove JEEP from soviet 2010-09-15 07:50:57 +12:00
Matthew
fee68d0231 Fixing permissions in deb scripts 2010-09-14 22:03:25 +12:00
524 changed files with 14399 additions and 13189 deletions

11
.gitignore vendored
View File

@@ -12,20 +12,11 @@ mods/*/*.dll
# Red Alert binary files
mods/*/packages/*.[mM][iI][xX]
# Crap generated by OpenRa
sheet-*.png
log.txt
*.rep
#binary stuff
/*.dll
*.pdb
*.mdb
*.exe
OpenRA
OpenRA.app
*.vqa
# backup files by various editors
*~
@@ -33,10 +24,8 @@ OpenRA.app
# dependency DLLs (different for every platform!)
cg.dll
cgGL.dll
glfw.dll
/OpenRa.Gl.dll
settings.ini
#monodevelop
*.pidb

View File

@@ -6,4 +6,5 @@ The OpenRA developers are:
* Matthew Bowra-Dean
* Paul Chote
* Alli Witheford
* Joakim Lindberg
* Joakim Lindberg
* Andrew Riedi

75
HACKING
View File

@@ -5,43 +5,82 @@ There are n main sections to OpenRA: UI, Rendering, unit behaviour, ...
All units/structures/most things in the map are Actors. Actors contain a collection of traits.
Traits consist of an info class and a class that does stuff
Actor assembly is done via the mod's yaml files. A section exists for each actor type, and within that section we list the traits the actor should have. These get looked up in the loaded mod DLLs. Each trait can contain properties, which are automatically loaded into the corresponding fields on the trait's ITraitInfo.
Actor assembly is done via the mod's yaml files. A section exists for each actor type,
and within that section we list the traits the actor should have.
These get looked up in the loaded mod DLLs. Each trait can contain properties,
which are automatically loaded into the corresponding fields on the trait's ITraitInfo.
- Traits: look at TraitInterfaces.cs
We've tried to make individual traits implement as self-contained a unit of functionality as possible - all cross-trait references should be in terms of an interface from TraitInterfaces.cs.
We've tried to make individual traits implement as self-contained a unit of functionality
as possible - all cross-trait references should be in terms of an interface from
TraitInterfaces.cs.
- Things an actor can be *doing* are represented as IActivity implementations. Actor has a queue of these. There's a standard set of activities in OpenRa.Game/Traits/Activities, and mods tend to define more as they need them. (RA defines various special-infantry actions as activities).
- Things an actor can be *doing* are represented as IActivity implementations.
Actor has a queue of these. There's a standard set of activities in
OpenRa.Game/Traits/Activities, and mods tend to define more as they need them. (RA
defines various special-infantry actions as activities).
- Units offer orders they can perform (given context) through traits that implement IIssueOrder. Every trait with this interface is given a chance to generate orders for the current context.
- Units offer orders they can perform (given context) through traits that implement IIssueOrder.
Every trait with this interface is given a chance to generate orders for the current context.
- For more complex things that require modal UI (like special abilities, RA-style sell/repair buttons, etc) we have IOrderGenerator implementations. This can completely replace the normal actors-provide-orders model temporarily. IOGs wiring is provided through OpenRa.Game/Controller.cs (ToggleInputMode<T>, CancelInputMode)
- For more complex things that require modal UI (like special abilities,
RA-style sell/repair buttons, etc) we have IOrderGenerator implementations. This can
completely replace the normal actors-provide-orders model temporarily. IOGs wiring is
provided through OpenRa.Game/Controller.cs (ToggleInputMode<T>, CancelInputMode)
- Things that don't affect gameplay, or (increasingly) are just transient are implemented as IEffect, rather than real Actors. This is similar to the temp ents mechanism in many other game engines.
- Things that don't affect gameplay, or (increasingly) are just transient are implemented as
IEffect, rather than real Actors. This is similar to the temp ents mechanism in many other
game engines.
- Most player-level or global-level game behavior is implemented as traits on special Player and World actors. These are accessible via Player.PlayerActor and World.WorldActor. This includes production queue support, ore/tiberium growth, various palette manipulation magic.
- Most player-level or global-level game behavior is implemented as traits on special Player
and World actors. These are accessible via Player.PlayerActor and World.WorldActor. This
includes production queue support, ore/tiberium growth, various palette manipulation magic.
- Many traits can be modified by adding an appropriate IFooModifier implementation to the unit. This includes rendering, where IRenderModifier allows you to define an arbitrary transform on the Renderables emitted by the actor's IRender implementation(s). Examples are things like cloaking, invisibility to certain players, flying units with shadows, etc. Other modifiers can affect movement speed, damage taken, weapon firepower, etc.
- Many traits can be modified by adding an appropriate IFooModifier implementation to the unit.
This includes rendering, where IRenderModifier allows you to define an arbitrary transform on
the Renderables emitted by the actor's IRender implementation(s). Examples are things like
cloaking, invisibility to certain players, flying units with shadows, etc. Other modifiers
can affect movement speed, damage taken, weapon firepower, etc.
Game code is collected into "Mod" units. Mods can be added prior to starting the game. Currently there is no dependancy mechanism, but provided you are doing additions or overrides you can add multiple mods without problem.
Game code is collected into "Mod" units. Mods can be added prior to starting the game.
Currently there is no dependancy mechanism, but provided you are doing additions or overrides
you can add multiple mods without problem.
Everything is a mod (including RA - which is loaded by default).
The contents of the mod is defined in a manifest file mod.yaml. This lists the packages containing art assets (typically .mix files), yaml files defining actor defintions, and ini files containing legacy information that have yet to be ported over to the (relatively new) yaml system.
The contents of the mod is defined in a manifest file mod.yaml. This lists the packages
containing art assets (typically .mix files), yaml files defining actor defintions,
and ini files containing legacy information that have yet to be ported over to
the (relatively new) yaml system.
The unit artwork itself must be defined in a Sequences file (typically Sequences.xml; check mod.yaml for a list of what the mod uses); the format is self explanatory. There is also the SequenceEditor tool to make this easy.
The unit artwork itself must be defined in a Sequences file (typically Sequences.xml;
check mod.yaml for a list of what the mod uses); the format is self explanatory. There is
also the SequenceEditor tool to make this easy.
Chrome artwork is similarly defined in Chrome.xml. Chrome is already mod dependent. Sortof ;) mod-dependent *behavior* would be nice too, not just skinning. This is a property of the traits however; once we port UI into traits this will become a non-issue.
Chrome artwork is similarly defined in Chrome.xml. Chrome is already mod dependent. Sortof ;)
mod-dependent *behavior* would be nice too, not just skinning. This is a property of the traits
however; once we port UI into traits this will become a non-issue.
Rendering
OpenRa.Game/Chrome.cs is the user interface.
Three renderers (SpriteRenderer, LineRenderer, Rgba?Renderer) render most stuff. Don't forget to flush the renderer (if you want to see anything).
Three renderers (SpriteRenderer, LineRenderer, Rgba?Renderer) render most stuff. Don't forget
to flush the renderer (if you want to see anything).
UserSettings stores the data loaded from settings.ini (or defaults). Eventually we need to be able to save values changed in game into settings.ini (not yet implemented)
UserSettings stores the data loaded from settings.ini (or defaults). Eventually we need to be
able to save values changed in game into settings.ini (not yet implemented)
Bugs: There is a list of known bugs and features at http://red-bull.ijw.co.nz:3690/OpenRA . There's also a few at http://github.com/chrisforbes/OpenRA/issues (which won't be ported over, but no more bugs should be added here).
Bugs: There is a list of known bugs and features at http://red-bull.ijw.co.nz:3690/OpenRA .
We also have a website at http://www.open-ra.org/ .
As far as using git, get your own repository on github. You probably want to set up the gitbot to spam irc when you make commits (its nice to know). Push your changes into your git repository, and it will/might :P be merged into chrisforbes/OpenRA . Alli: setup howto for this?
Our IRC channel is #openra on irc.freenode.net .
As far as using git, get your own repository on github. You probably want to set up the gitbot
to spam irc when you make commits (its nice to know). Push your changes into your git
repository, and it will/might :P be merged into chrisforbes/OpenRA .
See http://help.github.com/ for working with GitHub and see http://progit.org/ for working
with Git.
Other things we probably want to put in here:
- A guide on how to add a generic unit via yaml using existing traits
@@ -50,6 +89,6 @@ Other things we probably want to put in here:
- VFS (OpenRa.FileFormats.FileSystem, Package, Folder classes)
- Trait inheritance (and the magicness of ^ActorType)
- Removing inherited traits (prepend `-` to the trait name)
- Multiple instances of a trait (`@` and all subsequent characters are ignored for the purposes
of looking up the trait.
- Multiple instances of a trait (`@` and all subsequent characters are ignored for
the purposes of looking up the trait.

View File

@@ -58,7 +58,7 @@ editor_TARGET = OpenRA.Editor.exe
editor_KIND = winexe
editor_DEPS = $(fileformats_TARGET) $(game_TARGET)
editor_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll System.Data.dll $(editor_DEPS)
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
ralint_SRCS = $(shell find RALint/ -iname '*.cs')
ralint_TARGET = RALint.exe
@@ -150,9 +150,12 @@ mod_cnc: $(cnc_TARGET) $(ralint_TARGET)
mono RALint.exe cnc
mods: mod_ra mod_cnc
OpenRA.Editor.MapSelect.resources:
resgen2 OpenRA.Editor/MapSelect.resx OpenRA.Editor.MapSelect.resources 1> /dev/null
OpenRA.Editor.Form1.resources:
resgen2 OpenRA.Editor/Form1.resx OpenRA.Editor.Form1.resources 1> /dev/null
editor: OpenRA.Editor.Form1.resources $(editor_TARGET)
editor: OpenRA.Editor.MapSelect.resources OpenRA.Editor.Form1.resources $(editor_TARGET)
ralint: $(ralint_TARGET)
seqed: SequenceEditor.Form1.resources $(seqed_TARGET)
SequenceEditor.Form1.resources:

View File

@@ -30,8 +30,9 @@
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.toolStripContainer1 = new System.Windows.Forms.ToolStripContainer();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.splitContainer2 = new System.Windows.Forms.SplitContainer();
this.pmMiniMap = new System.Windows.Forms.PictureBox();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tilePalette = new System.Windows.Forms.FlowLayoutPanel();
@@ -50,6 +51,8 @@
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.cCRedAlertMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.bitmapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuExport = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMinimapToPNG = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
this.exotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -57,40 +60,29 @@
this.resizeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator();
this.spawnpointsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.layersFloaterToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.tt = new System.Windows.Forms.ToolTip(this.components);
this.folderBrowser = new System.Windows.Forms.FolderBrowserDialog();
this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
this.splitContainer3 = new System.Windows.Forms.SplitContainer();
this.surface1 = new OpenRA.Editor.Surface();
this.toolStripContainer1.ContentPanel.SuspendLayout();
this.toolStripContainer1.TopToolStripPanel.SuspendLayout();
this.toolStripContainer1.SuspendLayout();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
this.splitContainer2.Panel1.SuspendLayout();
this.splitContainer2.Panel2.SuspendLayout();
this.splitContainer2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pmMiniMap)).BeginInit();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.tabPage3.SuspendLayout();
this.menuStrip1.SuspendLayout();
this.splitContainer3.Panel1.SuspendLayout();
this.splitContainer3.Panel2.SuspendLayout();
this.splitContainer3.SuspendLayout();
this.SuspendLayout();
//
// toolStripContainer1
//
//
// toolStripContainer1.ContentPanel
//
this.toolStripContainer1.ContentPanel.Controls.Add(this.splitContainer1);
this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(985, 681);
this.toolStripContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.toolStripContainer1.Location = new System.Drawing.Point(0, 0);
this.toolStripContainer1.Name = "toolStripContainer1";
this.toolStripContainer1.Size = new System.Drawing.Size(985, 705);
this.toolStripContainer1.TabIndex = 1;
this.toolStripContainer1.Text = "toolStripContainer1";
//
// toolStripContainer1.TopToolStripPanel
//
this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.menuStrip1);
//
// splitContainer1
//
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
@@ -99,15 +91,45 @@
//
// splitContainer1.Panel1
//
this.splitContainer1.Panel1.Controls.Add(this.tabControl1);
this.splitContainer1.Panel1.Controls.Add(this.splitContainer2);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.surface1);
this.splitContainer1.Size = new System.Drawing.Size(985, 681);
this.splitContainer1.Size = new System.Drawing.Size(985, 744);
this.splitContainer1.SplitterDistance = 198;
this.splitContainer1.TabIndex = 0;
//
// splitContainer2
//
this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer2.Location = new System.Drawing.Point(0, 0);
this.splitContainer2.Name = "splitContainer2";
this.splitContainer2.Orientation = System.Windows.Forms.Orientation.Horizontal;
//
// splitContainer2.Panel1
//
this.splitContainer2.Panel1.Controls.Add(this.pmMiniMap);
//
// splitContainer2.Panel2
//
this.splitContainer2.Panel2.Controls.Add(this.tabControl1);
this.splitContainer2.Size = new System.Drawing.Size(198, 744);
this.splitContainer2.SplitterDistance = 182;
this.splitContainer2.TabIndex = 1;
//
// pmMiniMap
//
this.pmMiniMap.BackColor = System.Drawing.Color.Black;
this.pmMiniMap.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.pmMiniMap.Dock = System.Windows.Forms.DockStyle.Fill;
this.pmMiniMap.Location = new System.Drawing.Point(0, 0);
this.pmMiniMap.Name = "pmMiniMap";
this.pmMiniMap.Size = new System.Drawing.Size(198, 182);
this.pmMiniMap.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pmMiniMap.TabIndex = 1;
this.pmMiniMap.TabStop = false;
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
@@ -115,19 +137,21 @@
this.tabControl1.Controls.Add(this.tabPage3);
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl1.Location = new System.Drawing.Point(0, 0);
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
this.tabControl1.Multiline = true;
this.tabControl1.Name = "tabControl1";
this.tabControl1.Padding = new System.Drawing.Point(6, 0);
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(198, 681);
this.tabControl1.Size = new System.Drawing.Size(198, 558);
this.tabControl1.TabIndex = 0;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.tilePalette);
this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Location = new System.Drawing.Point(4, 20);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(190, 655);
this.tabPage1.Size = new System.Drawing.Size(190, 534);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Templates";
this.tabPage1.UseVisualStyleBackColor = true;
@@ -139,16 +163,16 @@
this.tilePalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.tilePalette.Location = new System.Drawing.Point(3, 3);
this.tilePalette.Name = "tilePalette";
this.tilePalette.Size = new System.Drawing.Size(184, 649);
this.tilePalette.Size = new System.Drawing.Size(184, 528);
this.tilePalette.TabIndex = 1;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.actorPalette);
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Location = new System.Drawing.Point(4, 20);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(190, 655);
this.tabPage2.Size = new System.Drawing.Size(190, 534);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Actors";
this.tabPage2.UseVisualStyleBackColor = true;
@@ -160,15 +184,15 @@
this.actorPalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.actorPalette.Location = new System.Drawing.Point(3, 3);
this.actorPalette.Name = "actorPalette";
this.actorPalette.Size = new System.Drawing.Size(184, 649);
this.actorPalette.Size = new System.Drawing.Size(184, 528);
this.actorPalette.TabIndex = 2;
//
// tabPage3
//
this.tabPage3.Controls.Add(this.resourcePalette);
this.tabPage3.Location = new System.Drawing.Point(4, 22);
this.tabPage3.Location = new System.Drawing.Point(4, 20);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(190, 655);
this.tabPage3.Size = new System.Drawing.Size(190, 534);
this.tabPage3.TabIndex = 2;
this.tabPage3.Text = "Resources";
this.tabPage3.UseVisualStyleBackColor = true;
@@ -180,15 +204,15 @@
this.resourcePalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.resourcePalette.Location = new System.Drawing.Point(0, 0);
this.resourcePalette.Name = "resourcePalette";
this.resourcePalette.Size = new System.Drawing.Size(190, 655);
this.resourcePalette.Size = new System.Drawing.Size(190, 534);
this.resourcePalette.TabIndex = 3;
//
// menuStrip1
//
this.menuStrip1.Dock = System.Windows.Forms.DockStyle.None;
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.fileToolStripMenuItem,
this.mapToolStripMenuItem});
this.mapToolStripMenuItem,
this.toolsToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(985, 24);
@@ -205,6 +229,7 @@
this.saveAsToolStripMenuItem,
this.toolStripSeparator2,
this.toolStripMenuItem1,
this.mnuExport,
this.toolStripSeparator3,
this.exotToolStripMenuItem});
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
@@ -216,20 +241,20 @@
this.newToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("newToolStripMenuItem.Image")));
this.newToolStripMenuItem.ImageTransparentColor = System.Drawing.Color.Fuchsia;
this.newToolStripMenuItem.Name = "newToolStripMenuItem";
this.newToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.newToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
this.newToolStripMenuItem.Text = "&New...";
this.newToolStripMenuItem.Click += new System.EventHandler(this.NewClicked);
//
// toolStripSeparator1
//
this.toolStripSeparator1.Name = "toolStripSeparator1";
this.toolStripSeparator1.Size = new System.Drawing.Size(149, 6);
this.toolStripSeparator1.Size = new System.Drawing.Size(120, 6);
//
// openToolStripMenuItem
//
this.openToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("openToolStripMenuItem.Image")));
this.openToolStripMenuItem.Name = "openToolStripMenuItem";
this.openToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.openToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
this.openToolStripMenuItem.Text = "&Open...";
this.openToolStripMenuItem.Click += new System.EventHandler(this.OpenClicked);
//
@@ -237,21 +262,21 @@
//
this.saveToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image")));
this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
this.saveToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.saveToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
this.saveToolStripMenuItem.Text = "&Save";
this.saveToolStripMenuItem.Click += new System.EventHandler(this.SaveClicked);
//
// saveAsToolStripMenuItem
//
this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
this.saveAsToolStripMenuItem.Text = "Save &As...";
this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.SaveAsClicked);
//
// toolStripSeparator2
//
this.toolStripSeparator2.Name = "toolStripSeparator2";
this.toolStripSeparator2.Size = new System.Drawing.Size(149, 6);
this.toolStripSeparator2.Size = new System.Drawing.Size(120, 6);
//
// toolStripMenuItem1
//
@@ -259,7 +284,7 @@
this.cCRedAlertMapToolStripMenuItem,
this.bitmapToolStripMenuItem});
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(152, 22);
this.toolStripMenuItem1.Size = new System.Drawing.Size(123, 22);
this.toolStripMenuItem1.Text = "&Import";
//
// cCRedAlertMapToolStripMenuItem
@@ -276,16 +301,33 @@
this.bitmapToolStripMenuItem.Name = "bitmapToolStripMenuItem";
this.bitmapToolStripMenuItem.Size = new System.Drawing.Size(195, 22);
this.bitmapToolStripMenuItem.Text = "&Bitmap...";
this.bitmapToolStripMenuItem.Visible = false;
//
// mnuExport
//
this.mnuExport.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuMinimapToPNG});
this.mnuExport.Name = "mnuExport";
this.mnuExport.Size = new System.Drawing.Size(123, 22);
this.mnuExport.Text = "&Export";
//
// mnuMinimapToPNG
//
this.mnuMinimapToPNG.Image = ((System.Drawing.Image)(resources.GetObject("mnuMinimapToPNG.Image")));
this.mnuMinimapToPNG.Name = "mnuMinimapToPNG";
this.mnuMinimapToPNG.Size = new System.Drawing.Size(163, 22);
this.mnuMinimapToPNG.Text = "Minimap to PNG";
this.mnuMinimapToPNG.Click += new System.EventHandler(this.mnuMinimapToPNG_Click);
//
// toolStripSeparator3
//
this.toolStripSeparator3.Name = "toolStripSeparator3";
this.toolStripSeparator3.Size = new System.Drawing.Size(149, 6);
this.toolStripSeparator3.Size = new System.Drawing.Size(120, 6);
//
// exotToolStripMenuItem
//
this.exotToolStripMenuItem.Name = "exotToolStripMenuItem";
this.exotToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.exotToolStripMenuItem.Size = new System.Drawing.Size(123, 22);
this.exotToolStripMenuItem.Text = "E&xit";
this.exotToolStripMenuItem.Click += new System.EventHandler(this.CloseClicked);
//
@@ -329,17 +371,59 @@
this.spawnpointsToolStripMenuItem.Text = "&Spawnpoints";
this.spawnpointsToolStripMenuItem.Click += new System.EventHandler(this.SpawnPointsClicked);
//
// toolsToolStripMenuItem
//
this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.layersFloaterToolStripMenuItem});
this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
this.toolsToolStripMenuItem.Size = new System.Drawing.Size(48, 20);
this.toolsToolStripMenuItem.Text = "Tools";
this.toolsToolStripMenuItem.Visible = false;
//
// layersFloaterToolStripMenuItem
//
this.layersFloaterToolStripMenuItem.Name = "layersFloaterToolStripMenuItem";
this.layersFloaterToolStripMenuItem.Size = new System.Drawing.Size(144, 22);
this.layersFloaterToolStripMenuItem.Text = "Layers floater";
this.layersFloaterToolStripMenuItem.Click += new System.EventHandler(this.layersFloaterToolStripMenuItem_Click);
//
// tt
//
this.tt.ShowAlways = true;
//
// saveFileDialog
//
this.saveFileDialog.DefaultExt = "*.png";
this.saveFileDialog.Filter = "PNG Image (*.png)|";
this.saveFileDialog.Title = "Export minimap to PNG";
//
// splitContainer3
//
this.splitContainer3.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer3.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
this.splitContainer3.IsSplitterFixed = true;
this.splitContainer3.Location = new System.Drawing.Point(0, 0);
this.splitContainer3.Name = "splitContainer3";
this.splitContainer3.Orientation = System.Windows.Forms.Orientation.Horizontal;
//
// splitContainer3.Panel1
//
this.splitContainer3.Panel1.Controls.Add(this.menuStrip1);
//
// splitContainer3.Panel2
//
this.splitContainer3.Panel2.Controls.Add(this.splitContainer1);
this.splitContainer3.Size = new System.Drawing.Size(985, 773);
this.splitContainer3.SplitterDistance = 25;
this.splitContainer3.TabIndex = 6;
//
// surface1
//
this.surface1.BackColor = System.Drawing.Color.Black;
this.surface1.Dock = System.Windows.Forms.DockStyle.Fill;
this.surface1.Location = new System.Drawing.Point(0, 0);
this.surface1.Name = "surface1";
this.surface1.Size = new System.Drawing.Size(783, 681);
this.surface1.Size = new System.Drawing.Size(783, 744);
this.surface1.TabIndex = 5;
this.surface1.Text = "surface1";
//
@@ -347,36 +431,40 @@
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(985, 705);
this.Controls.Add(this.toolStripContainer1);
this.ClientSize = new System.Drawing.Size(985, 773);
this.Controls.Add(this.splitContainer3);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.KeyPreview = true;
this.MainMenuStrip = this.menuStrip1;
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "OpenRA Editor";
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OnFormClosing);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.toolStripContainer1.ContentPanel.ResumeLayout(false);
this.toolStripContainer1.TopToolStripPanel.ResumeLayout(false);
this.toolStripContainer1.TopToolStripPanel.PerformLayout();
this.toolStripContainer1.ResumeLayout(false);
this.toolStripContainer1.PerformLayout();
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.ResumeLayout(false);
this.splitContainer2.Panel1.ResumeLayout(false);
this.splitContainer2.Panel2.ResumeLayout(false);
this.splitContainer2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pmMiniMap)).EndInit();
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.splitContainer3.Panel1.ResumeLayout(false);
this.splitContainer3.Panel1.PerformLayout();
this.splitContainer3.Panel2.ResumeLayout(false);
this.splitContainer3.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ToolStripContainer toolStripContainer1;
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.ToolTip tt;
private System.Windows.Forms.TabControl tabControl1;
@@ -385,8 +473,7 @@
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.FlowLayoutPanel actorPalette;
private System.Windows.Forms.TabPage tabPage3;
private System.Windows.Forms.FlowLayoutPanel resourcePalette;
private System.Windows.Forms.FolderBrowserDialog folderBrowser;
private System.Windows.Forms.FlowLayoutPanel resourcePalette;
private Surface surface1;
private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
@@ -406,6 +493,14 @@
private System.Windows.Forms.ToolStripMenuItem resizeToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator4;
private System.Windows.Forms.ToolStripMenuItem spawnpointsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem toolsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem layersFloaterToolStripMenuItem;
private System.Windows.Forms.PictureBox pmMiniMap;
private System.Windows.Forms.SplitContainer splitContainer2;
private System.Windows.Forms.ToolStripMenuItem mnuExport;
private System.Windows.Forms.ToolStripMenuItem mnuMinimapToPNG;
private System.Windows.Forms.SaveFileDialog saveFileDialog;
private System.Windows.Forms.SplitContainer splitContainer3;
}
}

View File

@@ -11,12 +11,11 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Editor
@@ -32,18 +31,20 @@ namespace OpenRA.Editor
Text = "OpenRA Editor (mod:{0})".F(currentMod);
Game.modData = new ModData( currentMod );
Game.modData = new ModData(currentMod);
Rules.LoadRules(Game.modData.Manifest, new Map());
folderBrowser.SelectedPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
.Aggregate(Path.Combine);
surface1.AfterChange += OnMapChanged;
}
surface1.AfterChange += MakeDirty;
void OnMapChanged()
{
MakeDirty();
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
}
void MakeDirty() { dirty = true; }
string loadedMapName;
string currentMod = "ra";
TileSet tileset;
@@ -57,7 +58,7 @@ namespace OpenRA.Editor
loadedMapName = mapname;
Game.modData = new ModData( currentMod );
Game.modData = new ModData(currentMod);
// load the map
var map = new Map(new Folder(mapname));
@@ -81,31 +82,31 @@ namespace OpenRA.Editor
loadedMapName = null;
Game.modData = new ModData( currentMod );
Game.modData = new ModData(currentMod);
PrepareMapResources(Game.modData.Manifest, map);
MakeDirty();
}
// this code is insanely stupid, and mostly my fault -- chrisf
void PrepareMapResources(Manifest manifest, Map map)
{
Rules.LoadRules(manifest, map);
Rules.LoadRules(manifest, map);
tileset = Rules.TileSets[map.Theater];
tileset.LoadTiles();
var palette = new Palette(FileSystem.Open(tileset.Palette), true);
surface1.Bind(map, tileset, palette);
surface1.Bind(map, tileset, palette);
// construct the palette of tiles
var palettes = new[] { tilePalette, actorPalette, resourcePalette };
foreach (var p in palettes) { p.Visible = false; p.SuspendLayout(); }
foreach (var t in tileset.Templates)
{
try
{
var bitmap = RenderTemplate(tileset, (ushort)t.Key, palette);
var bitmap = RenderUtils.RenderTemplate(tileset, (ushort)t.Key, palette);
var ibox = new PictureBox
{
Image = bitmap,
@@ -119,7 +120,6 @@ namespace OpenRA.Editor
var template = t.Value;
tilePalette.Controls.Add(ibox);
tt.SetToolTip(ibox,
"{1}:{0} ({2}x{3})".F(
template.Image,
@@ -137,16 +137,18 @@ namespace OpenRA.Editor
try
{
var info = Rules.Info[a];
if( !info.Traits.Contains<RenderSimpleInfo>() ) continue;
var template = RenderActor(info, tileset, palette);
if (!info.Traits.Contains<RenderSimpleInfo>()) continue;
var template = RenderUtils.RenderActor(info, tileset, palette);
var ibox = new PictureBox
{
Image = template.Bitmap,
Width = template.Bitmap.Width / 2,
Height = template.Bitmap.Height / 2,
SizeMode = PictureBoxSizeMode.StretchImage
Width = 32,
Height = 32,
SizeMode = PictureBoxSizeMode.Zoom,
BorderStyle = BorderStyle.FixedSingle
};
ibox.Click += (_, e) => surface1.SetActor(template);
actorPalette.Controls.Add(ibox);
@@ -168,15 +170,18 @@ namespace OpenRA.Editor
{
try
{
var template = RenderResourceType(a, tileset.Extensions, palette);
var template = RenderUtils.RenderResourceType(a, tileset.Extensions, palette);
var ibox = new PictureBox
{
Image = template.Bitmap,
Width = template.Bitmap.Width,
Height = template.Bitmap.Height,
SizeMode = PictureBoxSizeMode.StretchImage
Width = 32,
Height = 32,
SizeMode = PictureBoxSizeMode.Zoom,
BorderStyle = BorderStyle.FixedSingle
};
ibox.Click += (_, e) => surface1.SetResource(template);
resourcePalette.Controls.Add(ibox);
@@ -193,103 +198,12 @@ namespace OpenRA.Editor
surface1.BindResourceTemplates(resourceTemplates);
foreach (var p in palettes) { p.Visible = true; p.ResumeLayout(); }
}
static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p)
{
var template = ts.Templates[n];
var tile = ts.Tiles[n];
var bitmap = new Bitmap(24 * template.Size.X, 24 * template.Size.Y);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
foreach (var p in palettes)
{
int* q = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
if (tile.TileBitmapBytes[u + v * template.Size.X] != null)
{
var rawImage = tile.TileBitmapBytes[u + v * template.Size.X];
for (var i = 0; i < 24; i++)
for (var j = 0; j < 24; j++)
q[(v * 24 + j) * stride + u * 24 + i] = p.GetColor(rawImage[i + 24 * j]).ToArgb();
}
else
{
for (var i = 0; i < 24; i++)
for (var j = 0; j < 24; j++)
q[(v * 24 + j) * stride + u * 24 + i] = Color.Transparent.ToArgb();
}
}
bitmap.UnlockBits(data);
return bitmap;
}
static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p)
{
var ri = info.Traits.Get<RenderSimpleInfo>();
string image = null;
if (ri.OverrideTheater != null)
for (int i = 0; i < ri.OverrideTheater.Length; i++)
if (ri.OverrideTheater[i] == tileset.Id)
image = ri.OverrideImage[i];
image = image ?? ri.Image ?? info.Name;
using (var s = FileSystem.OpenWithExts(image, tileset.Extensions))
{
var shp = new ShpReader(s);
var frame = shp[0];
var bitmap = new Bitmap(shp.Width, shp.Height);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
}
bitmap.UnlockBits(data);
return new ActorTemplate { Bitmap = bitmap, Info = info, Centered = !info.Traits.Contains<BuildingInfo>() };
}
}
static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p)
{
var image = info.SpriteNames[0];
using (var s = FileSystem.OpenWithExts(image, exts))
{
var shp = new ShpReader(s);
var frame = shp[shp.ImageCount - 1];
var bitmap = new Bitmap(shp.Width, shp.Height);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
}
bitmap.UnlockBits(data);
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 };
p.Visible = true;
p.ResumeLayout();
}
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
}
void ResizeClicked(object sender, EventArgs e)
@@ -318,7 +232,7 @@ namespace OpenRA.Editor
surface1.Invalidate();
}
}
void SaveClicked(object sender, EventArgs e)
{
if (loadedMapName == null)
@@ -328,28 +242,62 @@ namespace OpenRA.Editor
surface1.Map.PlayerCount = surface1.Map.Waypoints.Count;
surface1.Map.Package = new Folder(loadedMapName);
surface1.Map.Save(loadedMapName);
dirty = false;
}
}
void SaveAsClicked(object sender, EventArgs e)
{
folderBrowser.ShowNewFolderButton = true;
if (DialogResult.OK == folderBrowser.ShowDialog())
using (var nms = new MapSelect())
{
loadedMapName = folderBrowser.SelectedPath;
SaveClicked(sender, e);
nms.MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
.Aggregate(Path.Combine);
nms.txtNew.ReadOnly = false;
nms.btnOk.Text = "Save";
nms.txtNew.Text = "unnamed";
nms.txtPathOut.ReadOnly = false;
if (DialogResult.OK == nms.ShowDialog())
{
if (nms.txtNew.Text == "")
nms.txtNew.Text = "unnamed";
string mapfoldername = Path.Combine(nms.MapFolderPath, nms.txtNew.Text);
loadedMapName = mapfoldername;
try
{
Directory.CreateDirectory(mapfoldername);
}
catch (Exception ed)
{
MessageBox.Show("Directory creation failed: {0}", ed.ToString());
}
SaveClicked(sender, e);
}
}
}
void OpenClicked(object sender, EventArgs e)
{
folderBrowser.ShowNewFolderButton = true;
using (var nms = new MapSelect())
{
nms.MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
.Aggregate(Path.Combine);
if (DialogResult.OK == folderBrowser.ShowDialog())
LoadMap(folderBrowser.SelectedPath);
nms.txtNew.ReadOnly = true;
nms.txtPathOut.ReadOnly = true;
nms.btnOk.Text = "Open";
if (DialogResult.OK == nms.ShowDialog())
{
string mapfoldername = Path.Combine(nms.MapFolderPath, nms.txtNew.Text);
LoadMap(mapfoldername);
}
}
}
void NewClicked(object sender, EventArgs e)
@@ -362,13 +310,12 @@ namespace OpenRA.Editor
if (DialogResult.OK == nmd.ShowDialog())
{
var map = new Map();
var map = new Map(nmd.theater.SelectedItem as string);
map.Resize((int)nmd.width.Value, (int)nmd.height.Value);
map.TopLeft = new int2((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value);
map.BottomRight = new int2((int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value);
map.Tileset = nmd.theater.SelectedItem as string;
map.Players.Add("Neutral", new PlayerReference("Neutral", Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
NewMap(map);
}
@@ -405,9 +352,11 @@ namespace OpenRA.Editor
void ImportLegacyMapClicked(object sender, EventArgs e)
{
var currentDirectory = Directory.GetCurrentDirectory();
using (var ofd = new OpenFileDialog { Filter = "Legacy maps (*.ini;*.mpr)|*.ini;*.mpr" })
if (DialogResult.OK == ofd.ShowDialog())
{
Directory.SetCurrentDirectory( currentDirectory );
/* massive hack: we should be able to call NewMap() with the imported Map object,
* but something's not right internally in it, unless loaded via the real maploader */
@@ -416,9 +365,9 @@ namespace OpenRA.Editor
var map = LegacyMapImporter.Import(ofd.FileName);
map.Package = new Folder(savePath);
map.Players.Add("Neutral", new PlayerReference("Neutral",
map.Players.Add("Neutral", new PlayerReference("Neutral",
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
map.Save(savePath);
LoadMap(savePath);
loadedMapName = null; /* editor needs to think this hasnt been saved */
@@ -432,7 +381,7 @@ namespace OpenRA.Editor
{
if (!dirty) return;
switch (MessageBox.Show("The map has been modified since it was last saved. Save changes now?",
switch (MessageBox.Show("The map has been modified since it was last saved. " + "\r\n" + "Save changes now?",
"Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation))
{
case DialogResult.Yes: SaveClicked(null, EventArgs.Empty); break;
@@ -440,5 +389,38 @@ namespace OpenRA.Editor
case DialogResult.Cancel: e.Cancel = true; break;
}
}
private void layersFloaterToolStripMenuItem_Click(object sender, EventArgs e)
{
var pb = new PaletteBox();
pb.Show();
}
private void mnuMinimapToPNG_Click(object sender, EventArgs e)
{
try
{
saveFileDialog.InitialDirectory = new string[] { Environment.CurrentDirectory, "maps" }
.Aggregate(Path.Combine);
FileInfo file = new FileInfo(loadedMapName + ".png");
string name = file.Name;
saveFileDialog.FileName = name;
saveFileDialog.ShowDialog();
if (saveFileDialog.FileName == "")
{
saveFileDialog.FileName = name;
}
else
{
Bitmap png = new Bitmap(pmMiniMap.Image);
png.Save(saveFileDialog.FileName, System.Drawing.Imaging.ImageFormat.Png);
}
}
catch { }
}
}
}
}

View File

@@ -118,7 +118,7 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>309, 17</value>
<value>198, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="newToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
@@ -237,6 +237,23 @@
z2ki+Wo1CWklROkMCiT8wEm0kXEsCTmrAiTbDtcEpTVdZOS1oDfWk5xZ6RPeQZeUR8zxK0Qe1BO65xjr
t0YotXhjAEAeQ7It8ZSESUjkznIq2bYsTGYW29JZxIs2nFEdLOSdfwFwpvLxRKIY2AAAAABJRU5ErkJg
gg==
</value>
</data>
<data name="mnuMinimapToPNG.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAACR0lE
QVQ4T6WTXUiTARSGdxkRRBdB0IUREV1EKRFEYYuQAklL8sKQfphUoJSUWJbLxAVZWqyBio5WajorM1PL
xExUlLQfbU5n0lygRerMP/qxOZ92vpjfCKLAi3P5Puc957xHA2gWUoo49147gWUqbSPrdjOXChrQm56S
lFVFvKEcXaqV2OQiohMt7Esw+6Ro5gGeWfhbff0BY9NzDI3N0f/JS6fLy7rd6f8HcNsdOI6EYD8cjK3V
roiLawdYu+vivwHSWcQM1THz/DQv96+ixeHlVvU71oQFAGTmP+37bdsPBf8WZ4fRFhVEXdcsBQ9srN6Z
pjqQhQUCAmcW29JZxA8fvaWyY5YcawdBOy6oANm2H9A3MMypDLNS7b1flJnFtnQWcVmrB2NhMytD9SpA
TiUA5+CYInQOjWPrH2V7RBzmijdo9x5VKr+yj6ImD9nmelZsS1UBcme/+OPIJIOfv/Gi201ZXQ/hMfFU
Peuktqnbd3QN+U/cXM6tYfmW8ypAQiKdh91TTE7PYHNOYKl6z916F3m+eSNjT1B4vxHjzWoFYrhRwbLN
51SAJOynx8vo5Ay9rimKHzu5XtJDpuU1WZY2Eg1WgrXRJOpNxKdcUyBLN6WoAInnyPh3XvW6KW/4MC9O
z2ki+Wo1CWklROkMCiT8wEm0kXEsCTmrAiTbDtcEpTVdZOS1oDfWk5xZ6RPeQZeUR8zxK0Qe1BO65xjr
t0YotXhjAEAeQ7It8ZSESUjkznIq2bYsTGYW29JZxIs2nFEdLOSdfwFwpvLxRKIY2AAAAABJRU5ErkJg
gg==
</value>
</data>
<data name="propertiesToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
@@ -291,7 +308,247 @@
<metadata name="tt.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="folderBrowser.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>182, 17</value>
<metadata name="saveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>76, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>45</value>
</metadata>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAIAMDAAAAEAIACoJQAAJgAAACAgAAABACAAqBAAAM4lAAAoAAAAMAAAAGAAAAABACAAAAAAAAAk
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAQAAAAQAAAAJQAA
ADcAAAA+AAAAOAAAACoAAAAYAAAACwAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAUAAAApAAAAVAAAAGIBAQFNAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAASAAAAOgAA
AFkAAAA6AAAAMQEBAUYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA
AAoAAAAkAAAAUQAAAHkAAACJAAAAhQAAAHMAAABTAAAAMAAAABUAAAAGAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAIAAAAkAAAAaQEBAZYCAgLaAAAAWgAAAAsAAAABAAAAAAAAAAAAAAAAAAAABwAA
AB8AAABMAAAAfwAAAHkAAAA8AgIAwgEBAWkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAQAAAA8AAAA9AAAAgwAAALMAAADFHRcU3QAAAMMAAACgAAAAdwAAAEUAAAAeAAAABwAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAAAAUgAAAJgDBATpAgIG/wEAAI8AAAAYAAAABAAA
AAIAAAAOAAAALgAAAGIAAACVAAAApgEAAJUEBADsAwQK/wAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABYAAABPAAAAngAAAMx3YFX3jXZv/5RuY/9mT0X2GxENygcG
BYsAAABKAAAAGgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAKAAAAQAAAAJMBAQHRBApN/wQK
U/8CAADQAQEARwAAACkAAABIAAAAeQAAAKMAAAC5AgAA1QQGJf8FC1v/AQEHrAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABwAAACEAAABcAAAApQICAtOFc2z8hnJt/5h6
cf+hfXL/mHty/3VkXewZExGLAAAAOQAAAAwAAAABAAAAAQAAAAIAAAAFAAAACAAAABAAAAAqAAAAYwAA
AKABAAC8AwAV+QUWxv8ED4P/BgcX/AEAALAAAACWAAAAsQAAAMkEBArzBAli/wMOtf8CCVD/AwIAbAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAEAAAADQAAAB1AAAAsgcE
BNmHcGj8mYiB/6GMhf+lkIj/moiB/5qIgP9dTUfqAgICYAAAACAAAAAGAAAABAAAAAoAAAAZAAAAKgAA
AEEAAABqAQEBmgEBAbkHCw7dBgcH+QEAi/8FHf//AgG0/wIABP8GFRntBiIw6wcYHf8BAET/AgR6/wMF
X/8DACD5AAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAFAAAAGwAA
AE8AAACXAAAAxQwLCuGSfHX9momC/5yLg/+cjIX/mYaA/5aGf/+MdWv/GhUSoQAAAEAAAAAXAAAAEAAA
AB8AAAA+AAAAZgAAAIwAAACtCQkJx0A5N+UYdqT/JsXu/wgdZ/8AAIr/Cyx0/x6Rwf8luf3/Jbv//yCd
3P8TYIj/FWaB/xdtjf8EDhfkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAEAAAAIAAAAKQAAAG4AAACxBwYD1HdiWPmcioL/mYiA/56Nhf+ejoX/lYV//5WGf/+Wgnv/U0M96AAA
AHUAAAA4AAAALwAAAEYAAABzAAAApAAAAMIkGRHhIBkT6F1WVfYqPUb/KM3//yOt5f8NN0b/J8r+/ybE
+P8ZfqT/G4ay/x6Tz/8hpej/IKTl/xuLwf8FExmmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAIAAAANAAAANwAAAIQAAAC+IhoW5Jt2av+Qfnf/no6G/5WHgP+vnpb/koJ7/5iG
f/+Zh4D/k4B6/kU4M8UAAABvAAAAagAAAIcAAACsAAAAzAMDAt+FW0z8fV5R/VtQS/2PgHn/UUhH/yKV
tf8z////I62//wcXX/8CBMz/AABw/w9HXv8muv3/Iq30/xh0p/8BAABfAAAABAAAAAIAAAABAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAYAAAAWAAAASAAAAJQAAADESzkz86CCd/+mlI3/rJyT/4Z5
cf+djIX/m4qD/5CAef9xZF7/jHx1/3BiWe0GBQSzAAAAsAAAAMQBAQDWCgUE5U83KfaCa2D/lH11/3hp
Y/+QgHn/noyF/xQODf8SU4X/CBuY/wUK//8BAOn/Cypv/yfC5v8luvf/IJvN/yKx+f8MKzrlAAAAIgAA
ABAAAAAHAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAwAAAAqAAAAZgAAAKgAAADMVEdA+LKg
mP+pmZH/rp+U/4Z3b/9+cGr/joB5/4R3cf9zZ1//dmhi/4p5cv8fHRjlAAAA3AYEBOQgGhfzV0U4/pqA
df+wnpX/no6F/4V1bv9yZF7/ERIX/wUNzf8AAJ//AgK+/wAA8v8LJlr/K9bh/y/w//8NO0r/EEh+/ynZ
//8SVHj/AAAAywAAAEgAAAAnAAAAEgAAAAQAAAABAAAAAAAAAAAAAAABAAAABAAAABcAAABIAAAAjwAA
AMAAAADZZlxV+rSkmv+4qZ//oZGJ/419dv+QgHn/eGlh/35waP+Nf3b/emxl/5KCe/9kVEr+GxQO+Ug9
OP2Mf3j+loZ+/52LhP+qmpH/oZGI/15STf8ICTL/CB30/wUTzv8il4j/HYac/wgcRf8qz93/NP///xZg
av8AAJb/D0W8/y3h/f8TWZ7/AQBY/wYEAPABAQCJAAAAQwAAAB0AAAAIAAAAAAAAAAAAAAABAAAACQAA
ACgAAABoAAAArQAAANCCaV74pJSN/8i4rf+omY//koF6/4t7dP9+b2j/koB5/5uJgv+UhHz/iXlx/3Bh
XP9lW1f/UEM8/4F0bf+jk4r/m4qC/52Nhf+gj4f/OjIs/wgUf/8KKv//AgDw/xlhU/87////L+b//y3g
8P8w7v//F2N//wAAqP8BAP//E1SY/y7n//8PPn//AADr/wYWv/8GCCv/AQMEuQAAAEkAAAAWAAAAAAAA
AAAAAAAEAAAAEQAAADwAAACCAAAAvCUbGOKhjoT+sKCW/7ionf+Yh4D/gHBp/3hoYP+KeHH/kYF4/5+P
h/+Xhn//h3hx/3hoYf+XhoD/cF5V/5WEff+ejYX/nYyF/21hWv8LCQz/ChmV/wop//8IJPr/Ch/z/wcS
of8eiZD/Nv///zP///8jrKD/AABe/wYZ//8CAJ3/H4+m/yrT/v8IGoz/BAzS/wUWy/8GFKX/BQYm/wUG
BOUBAQFBAAAAAAAAAAEAAAAHAAAAHgAAAFUAAACbAAAAyUc/Ou6ejYX/pJOL/6WUjP+ejoX/iXpz/4t7
cv+Xh37/mId//5+Ohv+pmI//koJ5/5GBeP+cjIP/dGNb/4t7dP+bioP/iHx2/zEtKf8hHyT/KipE/yYk
Jv8lIiX/ISEp/xkSPP8REA7/Gnh5/zb//f86//D/IqGV/wAAlf8NMYr/Nv///xhkgf8eKzT/KDg//xca
Hf8lLDP/ERUd/wYHCu0BAQFxAAAAAAAAAAEAAAAMAAAAMAAAAHQAAAC0AwMD1WleWfidjYT/pZSL/5yK
g/+OfHX/hnly/5CBef+Pfnb/m4uA/6aTiP+di4P/moqC/5mJgf+VhX3/lIN7/5eFfv+gjof/nIqE/5iH
gP+djYT/kIF4/5CAeP+Le3P/hnZv/4x9df+UhX3/SD04/xA6bf8XW6z/EESi/wYMPv8y+f//JKu7/1uA
kv+Nx+P/kcvn/1d4jv9KVmr/LD9N/xIfKacAAAAUAAAAAAAAAAIAAAAQAAAARAAAAJMAAADGKSYj5KWV
jP+woJb/pZSM/4V0b/+MfXb/nYyE/5iJgf+UhHv/pI+G/6GRh/+Qf3j/lYR9/6CRiv+ZiID/mYeA/5mI
gf+ci4P/n46G/5iIf/+KenP/gXBo/31tZf+GdG3/iHdv/4d1b/+LhYP/WGRm/wYASP8AAP//BAmf/zHr
4f8jrK3/WH6O/3y71P+JxeH/jcjj/4292f9FWWj+JC86+QkPE3EAAAANAAAAAAAAAAIAAAATAAAAUAAA
AKIAAADNh3p0/K2dk/+snZL/no2F/4N0bf+RgXr/jXx1/5yLg/+YiID/mYiA/5ODfP+NfHX/mYiB/56M
hf+Yh4D/nY2E/5CBeP+Sgnr/loZ+/5qJgf+nl47/nY2E/5SEe/+PfXb/e3Rx/1Zocv9fg5L/Pml+/x4s
Pf8OKmv/Ip6E/xhrdf9kjqD/i8zm/4HC3P+Fwdz/iL7X/32xyv8xPkn/Hiw28wUIClcAAAAMAAAAAAAA
AAIAAAARAAAATQAAAKEAAADWqZqR/6STi/+ikon/b2Nd/3xqZP9wYlr/fm5n/4p5cv+OfXb/i3t0/4V1
bv+MfHX/loR9/5qJgf+WhX3/jn53/4h3b/+Id2//mYmA/6OSiv+hkYn/qJiP/5uNhP9zdnj/T2h6/0uO
rf9UlbP/Z7LP/052hv8RMD3/CSPV/woMIf+GxOD/gsbf/3+/3P+Dvdf/erDJ/3epwv9jla//HTxM6wAD
BEQAAAAFAAAAAAAAAAMAAAAQAAAASgAAAJ4AAADQopOK/56Mhf+gj4f/kX95/4NzbP+DdG3/fGxl/35u
Z/96a2P/dGZf/4R0bf+Nfnb/i3pz/5B/d/+TgXj/nY2E/5+Ohv+di4T/o5KK/6CPiP+fjof/oJGJ/2Vw
dv8/X3T/Y6XF/1WiyP9cosb/drzY/3e51P8JD3b/Ch/e/z1WXv9/wNr/gL3W/4C92v+GxN3/baK9/4G8
1P9/wuH/ETJIlwAAABQAAAACAAAAAQAAAAYAAAAXAAAAUAAAAKIAAADMjoJ5/6iYj/+qmpH/oI+H/5GB
ev+SgXr/lYN8/5GBev+RgXn/koF6/41+dv+Le3L/jXdt/4x6c/+XhX3/mYeA/5iHgP+ejYX/opKJ/5qK
gf+NfnX/a3By/zhhdv9orsv/YKvP/0uZv/9krc3/c7zZ/3u72P8sP1P/Cg8t/2qbrv9zrsf/e7TN/4W/
2P+FwNv/erbR/3Oiwv9pqsf/AwkOUgAAAAgAAAABAAAAAwAAAA0AAAAoAAAAZQAAAKwAAADQm4yE/7Sl
mv+klIv/oI+H/5iGgP+Le3T/lIN8/5ODfP+Ug33/lIJ7/5iHf/+ch3//kX54/3JjXf+Ugnz/loV+/5WE
ff+ai4L/jHx0/4NzbP+HhYP/R2p//1iny/+Iyeb/O3Wo/0+fwv9vvNv/eL/c/3m72P9LcH7/DAoA/4jG
3v93uNH/fL3X/4zD2/9/udX/f8De/4y+1/87cJDxAQIDLgAAAAcAAAAAAAAABwAAABwAAABKAAAAiQAA
AL4AAADap5iP/66elf+hkIj/oI+I/5SDfP+Qf3j/koB5/5KAef+aioL/lYR8/56Ohf+ci4T/mIZ//4Ry
bP+RgXr/momC/458df97bmX/gGRU/4l2bP9Qh6b/XqrO/2Oozf9hp8v/Ya3O/2q72v94vdz/gcbi/3y9
2/9nnbD/U3OB/4zN5/+Bw9z/gL7a/32zyf92sMn/iMfg/3251f8pUWjIAQEBIQAAAAIAAAAAAAAADQAA
ADQAAAB1AAAAsAAAAM8pIyDsrJuS/56Nhf+ejIX/k4J7/4Z1bv+Pfnf/kYF6/4d1b/+cjIP/mouD/5qI
gf+UhH3/i3pz/4t5cv+XhX7/koB5/2teVf94fH//dK/I/2e42P9RkL7/YrDR/1qoyf9eqsv/WqbJ/3bB
3v97w9//fcTh/32+3P+DxN//g8Db/4TJ4/9/v93/gbzX/3Kmv/9qqMD/i7/b/1N/p/8ZLjp9AgQEFgAA
AAAAAAAAAAAAGAAAAEwAAACWAAAAxickIemAcWj/loV+/4t5cv9/bmf/fW1m/3BjW/96aGL/bmBZ/31t
Zv+Ne3X/koF6/4x8df+FdW7/i3t0/5SCe/+Qf3j/gnFq/2trav9rtdT/bLTU/2KjyP9tt9f/X6XI/2Ow
zf9Zp8r/Z7DQ/3m/3v+Axd//fL3b/3/B3v+IzOb/h8nk/4rL5P+ExeP/hMXe/2qeuf92scb/oc7q/0yC
pv8OHihoAQEBDQAAAAAAAAAAAAAAJwAAAGMAAACqBwYG03FjXvqTgnv/bl9Y/3dnYP91Z2D/d2dg/3Bg
W/98bGX/gnNs/3trZP+BcGj/fGxk/3NlXv+EdG3/lIV9/6COh/+NfHX/ZF5a/0p5nP9ajar/WJO9/3K+
2v9/vdz/YKPG/2muzv9cqcn/ZbHR/3K72P9+wN3/hcXi/4fI5P+Jy+T/f8Dc/4fF3/+NzOX/iMbf/3m3
0f9nlrT/b5uz/yhVb+YFCw5KAAEBCQAAAAAAAAAAAAAAQAAAAIMAAAC7CAUF21BEPv5uYFj/hndw/4l6
cv+KenT/momB/5KBev+RgXr/k4F6/5mJgv+Tgnr/iHdw/4p5c/+ThH3/m4yF/6CPiP+CdXH/TnKL/0tv
k/8hITb/M0Zh/2OjyP90u9j/abHO/2etzf9cqMn/Z7HR/3e92f95u9j/eb7b/5PV8P+Mzeb/fsPd/3/D
3f+Szeb/h8Lf/3/A3v+Mu9T/RnGF/hEiMcwAAABAAAAABwAAAAAAAAAAAAAAXgAAAKQAAADMKCUj6ZmH
gP+ejIX/lIN8/5iHf/+YiH//mYeA/5OCe/+UhH3/hXRu/4x6dP+SgHn/mYeA/5qJgf+bioP/loV+/4h3
cf9bXl//bLrc/3S/4P9LdJj/KiNI/z1ehf9mr9L/d77b/1uoy/9Vo8b/bLDN/3q/3P97vdr/hMrj/5LQ
7P+Oz+v/iMzm/4TF3/+Gwdz/hMbh/4rO6P+Oxd7/PGyF/hocHNUCAwNeAAABEQAAAAEAAAAAAAAAdQAA
ALUAAADekIB7/pODev+ejob/mIeA/6iXj/+jkor/mIZ//5KAef+RgHn/jn12/5qIgf+cioP/no2F/6OR
iv+hkYj/iHdw/2JVTf9NfJX/YqrR/3O31/93weH/VoKj/2+y0f9ppM3/ebvb/1Kfxf9nsdD/YKPG/3G3
1v96vNn/gsTg/4rL5/+FyuT/gsTh/4jK5v+Fw93/d7/b/5zT7/97r8//Y6vF/zVZaNwRGx5dAAABEgAA
AAIAAAAAAAAAiQAAAL8jHxzoq5yR/56Nhf+hkIj/rJyT/6mZkP+qmpH/m4uD/5KBev+WhX3/kH55/5WD
fP+VhH3/oo+J/6iXj/+cjIP/c2Ja/3xwaP9WncX/abLS/3O62f9qtNT/d8Hd/3vD4P+MxuP/Y6bM/1up
yv9qtdT/ZK3M/3jA3f95wN//hMrl/4rM5/+Ky+X/hcbk/4rO6P98u9v/hMni/6zZ9f9km77/K1V37gkQ
FGoBAQEHAAAAAAAAAAAAAAAAAAAAngAAAMlZUEzxoI+H/6uckv+omI//oZCJ/6STi/+ikIr/nImD/5aE
ff+aiIH/j313/4x7dP+UhH3/m4mC/6SUi/+Ugnv/cVxO/3ymuv9KibL/dLnZ/3rB3v9fpsj/b73b/3G5
1v99x+P/ZLLQ/02Xwf9rtNj/fMXh/3O52P91vt3/eb7b/37A3f+HyOL/js/p/4/Q6v+Dx+T/erPX/5XL
5/9Jl7v+GjJBrgEBAQoAAAAAAAAAAAAAAAAAAAAAAAAApw0NDdaIeHD9kX95/6qbkf+unpX/j395/459
dv+pmJD/n46H/56Ohf+gkIj/kH95/4x8dv+JeXL/kIB4/5WFfP9yZmH/b36H/2aqzv9nr8//esLe/3m/
3v9rtdT/arbW/2iz0P9rvdr/UqbG/2q41P9gqs3/crjX/2Spzf+AyeT/f8Hd/3m+2/+Cx+H/k9Ht/4rH
5P+Fx+T/mc7p/2amxP8nSF36AAAAawAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqBUSEN2Ug3r9lYV8/6OT
iv+klIv/l4V+/4p6dP+omI//p5aO/56Ohf+WhX3/j394/3hoZP9uXFb/emtk/3NnXv9ydXn/bLXV/2Sp
zv92vdz/fcbh/3zE4f9xu9v/Z67Q/16kx/9QnMD/Xq/O/2Wy0f94wN3/c7jV/3q83P9encj/gsrj/33C
3v+CxN//jMjk/4bI4/+Lz+n/lM/q/0d+nf8sLiv3BQYHTwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArg8P
DdqSgX38qZiQ/6WVjP+ci4P/lYR9/419d/+KeHH/opGJ/5WFfP91YlX/hGpX/2ZkY/9HUlj/OFVn/1eQ
tf9fpcj/Y6jP/3W+3f96wt7/drrX/36/3f9+x+L/bbjV/2241f9hsc7/ZrTS/2u41P92udX/h83o/4fI
5f97wd3/dr3a/3K72/+DxuL/hsfj/3jA3P+c0+//fLPT/2avyf5HfZLyHzI3SwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAux0aGuGWhH39rp6V/6qbkf+Yh3//koB6/5B/ef+Rf3j/fWtk/4huXf+jrK//d7jX/2Ow
1v9kstb/Up3I/2Wlyv9krdD/Y6/S/2y52f9ut9b/er3Z/4PG4v99wt7/f8Xh/3jE4P91wd7/bbrW/3W9
2v99w97/hMnl/4jL5/+BxuD/i8/p/3m+3v+Izef/fbzc/4XK4/+s2fX/ZZ7C/y1dhOwTJzK9FxobTQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAxzo0Muqbi4T/saKY/7Cgl/+fjYb/kIB6/49+d/+Bcmn/fGxg/3u7
1P9sqc3/Z6vP/2Kny/9vuNf/abfW/3O72P95w9//cLjV/3C+2v9wuNX/gsTh/33A3/9wudb/db7b/2i1
0v9uutf/cLzY/4HG4v+P0er/icvk/4XH4v+Ozej/itDr/43S7P+O0Ov/hcnm/3q02P+TyeX+SZu//yNH
XKEHBwcnCgkITAAAAAEAAAAAAAAAAAAAAAAAAAABCwsNtZKEfPicjIX/sqKY/66elP+hj4n/opGJ/5GC
ef+OfnP/icbj/1qdw/9ZmL//f8Xh/3fA3f91wd3/eb7d/4PL5f+EyuP/fsbg/3e+3f93vNv/gMHe/3u9
3P9wt9T/dbnW/2m21f9rtNP/cbnW/3693f9dh7T/Ypa8/4bH4f9zp8f/gsLf/47M6P+R0On/jtDs/5jP
6v9mp8X/GTJFrgAAACYCAgISAgMDEwYGBxAAAAAAAAAAAAAAAAAAAAABExMTgJCGffWdj4f/t6ee/6iX
jv+tnJT/pZWM/5KBc/+WtML/ZqbL/2Gkyv9xvt3/fMXh/3rB3v93vdz/g8nl/37E4P90vdn/ecDd/3nA
3f97vdz/d7jV/3a71/96wd7/fr/d/3G41f9zuNX/hcfk/1yMtP9Fa5n/LUd8/2yhxP9RcJj/cqPG/4nC
3/+MyuP/hc3n/5PO6v9Hf5//AwUFYgAAAB8AAAAHBAMDCAsLDBoEBAQHAAAAAAAAAAAAAAAAAAAADwcH
BzMPDg1MPTk2ro6EevKbjYT/o5SK/6GKev95vNn/aqrO/3O61/99xOP/esLe/37E3/96xd//e8Pf/3i9
2v9qstL/a7bT/3W+2v9wtNH/dLnV/2+20/9yvdf/eLnW/36+2/+Mzur/i9Pt/16cxP85XpP/Q1mD/2CV
vf9roMP/jMfi/4nF4f+DyOL/hMnm/2yfwv5lvNn/TImj2wAAABMAAAADAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAABAAAABgAAABYAAAA4FBIQlIKCgux4qsn3dKvM/H/A3f+Ky+j/i8nl/4HG
4v94vdz/gsLf/4TI4v90u9j/dbva/3W51v9xuNf/bbXS/3O82f99vtz/ervZ/4jK5f+T1fL/iMvn/3m8
3v98vt3/TnWg/1qQvP96ttf/h8jk/1aErf9qs9P/n9Tv/2ufv/8lUoL+ECQ0jwAAAAwAAAABAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAEAAAACgAAAB4OEBFRHiktejZN
WKdagZTVaY2i4GiRpPF+ssv/kdPv/5DV8f+Fy+f/hMPf/4bI5P9/xuP/ebzb/3m92v94vNn/fMHd/4/Q
6v+W1PD/l9jy/4fF4f9HcqH/aqHI/3Ot0f9Mf6v/h8Xi/3y93f8lTIL/iL/f/3Cx1P8mTG3QAAAAHwAA
AAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAABAAAAAwAAAAcDBAQYBQYHJQYICTsNEhVlJTM8w1Buf/9Zeo7/i87q/4PE4P+SzOn/icbj/3e4
1f97wt//isbi/5PR7f+b2PX/ldPp/4S72v9hmcL/ZqHI/1mMuv+Gw+D/aaPK/1CLuf9hibj/ic3n/kh4
qf8OGCV2AAAADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAFAAAADgAAADIAAAByJzlD0Xmz
zvx/vNn/gb/e/3W20/+Exd//k8vn/5nU7/+V0Oz/mNTw/5/a8v9xrtL/UIW0/1WBsP80YJn/h8Pi/4fN
6P9nmsb/SYqz/1+WsvIHCw4+AAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAQAAAAPAAAAHxAVGmwxSVajUHqN00Jkdsg8WWW2NlFewXOftfSc1PD/kc7r/4O72/9zrtH/bpzE/2OL
u/9Zi73/ib3d/2WSvf9oiLf/TYCr/z9phdIDBQcsAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAHAwQFFAEBARUAAAAUAAAAJQYHCFUyQkquUnmO7m+i
yf9oosb/cKPC/1N4rP9ZgKz/isPg/2SXwv9Yibf/OnGf/xkoSawAAAAbAAAAAQAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAA
AAcAAAAPAAAAGwUGB2UGBgiAIC40vHGbv/pnm8H+jcfg/1yJvf+Bt9f/T4Op+Q8bInUAAAANAAAAAQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAALAAAAGgkLD1UfLDWMITVCrT1ced93pMf/c6bE/BMd
IVUAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAAIAAAAFgID
AysUHSFgHC02gQAAAAoAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AB/gfgP
AAD8AD+AcA8AAPwAH8AADwAA/AAPgAAfAAD4AAAAAB8AAPgAAAAAHwAA8AAAAAA/AADwAAAAAD8AAPAA
AAAABwAA4AAAAAABAADgAAAAAAAAAMAAAAAAAAAAwAAAAAAAAADAAAAAAAAAAIAAAAAAAAAAgAAAAAAA
AACAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAA
AAAAAwAAAAAAAAADAAAAAAAAAAMAAAAAAAAAAwAAAAAAAAABAAAAAAAAAAEAAAAAAAAABwAAAAAAAAAP
AAAAAAAAAB8AAAAAAAAAHwAAAAAAAAAfAAAAAAAAAB8AAAAAAAAADgAAAAAAAAAOAAAAAAAAAAcAAAAA
AAAAPwAAwAAAAAA/AADwAAAAAH8AAP8AAAAA/wAA//gAAAD/AAD//wAAAP8AAP//wAAA/wAA///+AAD/
AAD////wAf8AAP////wB/wAAKAAAACAAAABAAAAAAQAgAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAABAAAAEQAAADsAAABeAAAAXwAAAEIAAAAeAAAACAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAFQAAAF8CAgKIAAAAMAAAAAMAAAAAAAAAAAAAAAQAAAAhAAAAXQAAAFMBAQB6AQEBLAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAmAAAAgwAAALwdFxTdAAAAsgAAAHcAAAAyAAAABwAA
AAAAAAAAAAAAAAAAAAAAAAAJAAAAUgICAsECAgb/AQAAVAAAAAQAAAAIAAAALgAAAHwAAACmAgIAwQME
Cv8AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABgAAADkAAACiQTYw5Yp0bv+ObWP9WkVA5SYg
HJQAAAAqAAAABQAAAAEAAAACAAAABAAAABIAAABSAQEBsAQFMPwEC2f0BAQLogEAAG4AAACVAQECxgMF
MeoEC2L/AwIEjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAQAAAAVQAAALJIOzbrmYiB/6OO
h/+aiIH/fGtk9QICAmAAAAATAAAABAAAABIAAAAqAAAAVgEBAZoFBgjLBgcH+QMPxf8CAbT/BAsO9gYi
MOsEDDH/AgR6/wMDP/wAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAACIAAACCAwICzWxd
V/aaiYH/nY2F/5eGgP+UgXn/Ny0nxQAAAEIAAAAgAAAARgAAAIUJBgS4FBEO2DdQXvcnyff/DkGI/xl7
uf8ho9f/IKHZ/x2Ox/8bhbP/DkZf4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAANwAA
AKEiGhbklnpx/56Ohv+ik4v/koJ7/5mHgP+TgHr+Ih0amgAAAGoAAACaAAAAzEQvJ+59XlH9dmlj/lFI
R/8rytr/I62//wUOlv8AAHD/G4Gu/yKt9P8MOlSvAAAABAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAgAA
ABUAAABXAAAAs09BOvaplIz/rZ6U/4p8dP+VhX7/f3Fq/4FybP9IQDrhAAAAxgoJB90wJh3yh29k/ZmG
ff+AcWr/WE9O/wscgP8FD6v/BQzN/xuAqP8iqsr/GHKm/xqDq/kAAAB3AAAAIgAAAAsAAAACAAAAAAAA
AAEAAAAEAAAAMAAAAI8AAADNZlxV+rannf+hkYn/j394/3hpYf+GeG//emxl/3trY/8bFA75a15Y/paG
fv+kk4v/oZGI/zMuQP8IHfT/FFWr/x2GnP8ZdpH/NP///wswgP8PRbz/IJ3O/wEAWP8EAwC9AAAAQwAA
ABMAAAAAAAAAAgAAAA0AAABUAAAAtVNGP+qqmpL/sKGX/4l5cv+Dc2z/koF5/5qJgf+IeXH/emtm/2BR
Sf+Wh3//nIuE/25iXf8iJmH/CSPe/wYQ8v8ff6H/M/P//y3f5P8MMm//AwfR/xlyn/8chcL/Agbf/wYS
l/8DBBXcAgICYgAAAAAAAAAEAAAAHgAAAHgAAADJcmZg96STi/+ikYn/iXpz/5GBeP+Yh3//pJOL/5KC
ef+Xh37/dGNb/5ODfP+IfHb/KSYn/yoqRP8mIyb/ISEp/xURJf8aeHn/OP/3/yKhlf8HGZD/Nv///xtI
W/8oOD//HiMo/xEVHf8DBQWvAAAAAAAAAAgAAAA6AAAAoRcVEt2XiH/+pZSM/49+eP+Sg3v/k4R7/6CN
g/+ejIP/mIeA/5qKgv+XhX7/nIqD/56Mhf+Whn7/iXlw/4h4cP+Hd2//jX95/1BRT/8MJpn/Cieh/yOo
s/8+laX/fLLL/4/K5f9deY//KTZD/AcMEE8AAAAAAAAACwAAAFAAAAC4h3p0/K2dk/+ejYX/int0/418
df+aioL/mYiA/5CAef+ZiIH/m4qD/52NhP+Rgnn/loZ+/6GQiP+djYT/koF5/3t0cf9bdoL/Pml+/xYr
VP8inoT/Pn2L/4vM5v+Dwtz/iL7X/1d4iv8eLDbzAwQFMgAAAAAAAAAKAAAATAAAALqml47/oZGI/4Bx
a/99bWb/fW1m/4R0bf+AcWr/iXly/5F/eP+VhHz/loZ+/5OCev+ejoX/oZGJ/6SVjP9tdXr/WYeg/1Wa
vP9vt9T/OFyE/woh2v9Teo//gcLb/4LA2/90qcP/d6/K/xc2S8EAAQEYAAAAAQAAAA8AAABQAAAAt46C
ef+pmZD/oI+H/5KBev+Vg3z/kYF6/5KBev+MfXT/jXdt/5KAeP+Zh4D/m4qD/6KSif+UhHv/a3By/1CI
of9gq8//WKPG/3O82f9UfZb/Cg8t/2+lu/97tM3/hcDa/3q20f9upsX/AwkOUgAAAAUAAAAFAAAAJwAA
AHcAAADFoZKK/6qakf+gj4j/koF6/5OCe/+VhH7/lYN8/5yKgv+Vgnz/h3dw/5iHgP+Pf3f/hnBk/3l+
gf9Tiqf/abDT/06Ru/9otdX/fcPf/2qiuf8wP0H/hMTd/36+2f+AuNH/hMTf/1uPqu4BAgIoAAAAAwAA
AA0AAABVAAAAsBUREd6sm5L/no2F/5OCe/+LenP/kYF6/5KBef+ai4P/l4Z//4t6c/+Rf3j/koB5/3Jt
av90r8j/XKTL/2Kw0f9cqcr/WqbJ/3nC3/99xOH/gMHe/4PA2/+CxOD/gbzX/26nwP+Lv9v/NlZxvgIE
BBYAAAAAAAAAIAAAAHwDAgLNal9Z+YJya/9+bmf/empj/3ZmYP94amP/gnFq/4d3b/+Dc2z/kIB5/5WD
fP9zaGL/X4qh/2Kkyf9xttb/YKTH/2GszP9msdH/e8Dd/4HB3/+GyeP/g8Xg/4nJ4/+Gxt//cKjC/4i1
z/8iQFOmAQEBCwAAAAAAAABAAAAAnwgFBdtfUkv/hndw/4p6c/+aiYH/koF6/5OBev+Whn7/iHdw/49/
eP+bjIX/kYJ9/05yi/82SGX/M0Zh/2yv0P9psc7/YqvL/2ex0f94vNn/eb7b/5DR6/9+w93/icji/4fC
3/+Gvtn/RnGF/gkRGYYAAAAHAAAAAAAAAGoAAADBXVJO9JuKgv+WhX7/n4+G/5mHgP+Tgnv/inly/5WD
ff+cioP/n46G/49+d/9lam3/Z7LX/2urzP9AU3b/X5m+/3i92/9bp8r/ZqrK/3m82v+Dx+L/jM7p/4XI
5P+GxeD/fsPe/4zG4f9QjKb/GCUqnAAAARIAAAABAAAAiREQD9SrnJH/oI+H/6yck/+qmpH/m4uD/5SD
fP+Qfnn/lYR9/6KPif+ikon/c2Ja/2mHl/9pstL/b7fX/3fB3f+ExeL/Y6bM/2Ovz/9krcz/ecDe/4TK
5f+KzOb/hcbk/4PF4v+EyeL/iLra/ytVd+4FCQs5AAAAAAAAAAAAAACjPDYz5JmHgP+rnJL/mIiB/6CP
h/+ejIX/nIuD/5B+eP+Ofnf/loV9/5CBef9wbWv/ZaPD/3e+3P9wt9b/bbrZ/3G82f9brMv/YazP/3e/
3P9zu9r/fMDc/4HE3/+R0Ov/icrm/4rB4P9blLH+DRohjQEBAQMAAAAAAAAAAAAAAKhVSkbtlYV8/6SU
i/+XhX7/mYmC/6eWjv+aioH/j394/3NiXf96a2T/c25s/2y11f9ts9X/fcbh/3fA3v9nrtD/V6DE/16v
zv9vudf/c7jV/2yt0v+CyuP/gMPf/4zI5P+JzOb/lM/q/zlWY/sFBgdPAAAAAAAAAAAAAAAAAAAAtVZM
SO2sm5P/oZGI/5SCfP+PfXf/kH53/46BeP9+kZf/Xoaa/0V5mP9gosb/Y6zR/3O82/94vNj/f8Tg/3a/
2/9vvNn/arfU/3W92f+Gy+f/g8fj/4HG4v9+xOH/gsLg/5LO6f9xqcv/PG2F5xsmKUwAAAAAAAAAAAAA
AAAAAADHa19a9bGimP+ol4//kIB6/4h4cP98bGD/dLLR/2erz/9psNH/abfW/3a/3P9wuNX/cLvY/4LE
4f93vdv/db7b/2u41f9wvNj/iMzm/4nL5P+KyuX/itDr/47R7P+Fyeb/h7/f/0mbv/8VJzJkCgkITAAA
AAEAAAAAAAAAARAQEJuXioL7taWb/6qZkP+kk4v/ko6J/3i21/9ipsv/fsXh/3jA3f9+xOH/f8bh/3zD
3/95vt3/fL3a/3e82v96vNr/brfV/3vA3f9gj7j/SG+c/26gwf96s9P/jsrl/4rP6v92sc//DhwliAEB
ARgDAwMOBgYGDQAAAAAAAAABAAAADwsLCkA9OTaulImA+aOUiv+No6r/aqrO/3i/3f96wt7/fMXf/3vD
3/9xuNb/a7bT/3O51v90udX/cbrV/3i51v+FxuP/i9Pt/0x9rP9DWYP/ZpvA/4zH4v+Gx+L/hMnm/2mu
zv9MiaPbAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAVCgkIT0NPWJVJan27Zpas33mq
xPB4ssz8isvn/4TJ5f99v93/e8De/3O51/95vdv/e77b/5HR7f+Q0u3/ca3Q/1yLtP9lncT/h8fj/1mR
uP+Uyuf/Snuh9AgSGlcAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA
AAMCAgIQBQYHJQoND1AlMzzDVXSH/4vO6v+LyOX/icbj/3m92v+KxuL/l9Xx/5XT6f9zqs7/ZqHI/3Co
zf9po8r/WYq5/4nN5/4rSGe7AAAADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAcAAAAuFB0ieE9zhsNonLbpXo+k32SNo+CQxeD9ldHu/4K9
3P9fkbz/Un6x/4jA4P9vocn/S4Wv/ypEU4wAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABQMEBRQBAQEVAAAAJRwl
KoJSeY7ubKLI/3Cjwv9WfKz/isPg/16Qvf86cZ//DRQlZAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAEAAAABAAAABgAAAA4DAwQ+ERcaa0BccbdWfpDWZY+092GVtvsJDxE3AAAAAQAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABQAAABYLEBJGHC02gQAAAAYAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADwD4MD8AeAA+AAAAfgAAAH4AAAD+AAAAPAAAAAgAAAAIAAAACAAAAAgAAAAIAA
AACAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAAAAAAAAwAAAAMAAAAHAAAABwAAAAIAAAACAAAAD4AA
AA/4AAAf/4AAH//wAB///gAf///wPw==
</value>
</data>
</root>

View File

@@ -17,6 +17,7 @@ using OpenRA;
using OpenRA.FileFormats;
using OpenRA.Traits;
using System.Drawing;
using System.Globalization;
namespace OpenRA.Editor
{
@@ -401,7 +402,7 @@ namespace OpenRA.Editor
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit(parts[0]),
new HealthInit(float.Parse(parts[2])/256),
new HealthInit(float.Parse(parts[2], NumberFormatInfo.InvariantInfo)/256),
new FacingInit((section == "INFANTRY") ? int.Parse(parts[6]) : int.Parse(parts[4])),
new ActorStanceInit(stance),
};

375
OpenRA.Editor/MapSelect.Designer.cs generated Normal file
View File

@@ -0,0 +1,375 @@
namespace OpenRA.Editor
{
partial class MapSelect
{
/// <summary>
/// TODO
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// TODO
/// </summary>
/// <param name="disposing">TODO</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором форм Windows
/// <summary>
/// TODO
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MapSelect));
this.MapList = new System.Windows.Forms.ListView();
this.colMapName = new System.Windows.Forms.ColumnHeader("(отсутствует)");
this.MapIconsList = new System.Windows.Forms.ImageList(this.components);
this.btnCancel = new System.Windows.Forms.Button();
this.btnOk = new System.Windows.Forms.Button();
this.lblNew = new System.Windows.Forms.Label();
this.txtNew = new System.Windows.Forms.TextBox();
this.pbMinimap = new System.Windows.Forms.PictureBox();
this.pnlBottom = new System.Windows.Forms.Panel();
this.txtPathOut = new System.Windows.Forms.TextBox();
this.lblPathOut = new System.Windows.Forms.Label();
this.lblPath = new System.Windows.Forms.Label();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.lblMapList = new System.Windows.Forms.Label();
this.txtDesc = new System.Windows.Forms.TextBox();
this.lblDesc = new System.Windows.Forms.Label();
this.txtTheater = new System.Windows.Forms.TextBox();
this.lblTheater = new System.Windows.Forms.Label();
this.txtAuthor = new System.Windows.Forms.TextBox();
this.lblAuthor = new System.Windows.Forms.Label();
this.txtTitle = new System.Windows.Forms.TextBox();
this.lblMapName = new System.Windows.Forms.Label();
this.lblMinimap = new System.Windows.Forms.Label();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pbMinimap)).BeginInit();
this.pnlBottom.SuspendLayout();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// MapList
//
this.MapList.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.MapList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.colMapName});
this.MapList.FullRowSelect = true;
this.MapList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
this.MapList.LargeImageList = this.MapIconsList;
this.MapList.Location = new System.Drawing.Point(15, 25);
this.MapList.MultiSelect = false;
this.MapList.Name = "MapList";
this.MapList.Size = new System.Drawing.Size(273, 294);
this.MapList.SmallImageList = this.MapIconsList;
this.MapList.StateImageList = this.MapIconsList;
this.MapList.TabIndex = 0;
this.MapList.UseCompatibleStateImageBehavior = false;
this.MapList.View = System.Windows.Forms.View.Details;
this.MapList.SelectedIndexChanged += new System.EventHandler(this.MapList_SelectedIndexChanged);
//
// colMapName
//
this.colMapName.Text = "Map name";
this.colMapName.Width = 240;
//
// MapIconsList
//
this.MapIconsList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
this.MapIconsList.ImageSize = new System.Drawing.Size(24, 24);
this.MapIconsList.TransparentColor = System.Drawing.Color.Transparent;
//
// btnCancel
//
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(407, 35);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 3;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
//
// btnOk
//
this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnOk.Location = new System.Drawing.Point(326, 35);
this.btnOk.Name = "btnOk";
this.btnOk.Size = new System.Drawing.Size(75, 23);
this.btnOk.TabIndex = 2;
this.btnOk.Text = "Open";
this.btnOk.UseVisualStyleBackColor = true;
//
// lblNew
//
this.lblNew.AutoSize = true;
this.lblNew.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
this.lblNew.Location = new System.Drawing.Point(12, 40);
this.lblNew.Name = "lblNew";
this.lblNew.Size = new System.Drawing.Size(69, 13);
this.lblNew.TabIndex = 3;
this.lblNew.Text = "Map name:";
//
// txtNew
//
this.txtNew.BackColor = System.Drawing.SystemColors.Window;
this.txtNew.Location = new System.Drawing.Point(88, 37);
this.txtNew.Name = "txtNew";
this.txtNew.ReadOnly = true;
this.txtNew.Size = new System.Drawing.Size(232, 20);
this.txtNew.TabIndex = 1;
//
// pbMinimap
//
this.pbMinimap.BackColor = System.Drawing.Color.Black;
this.pbMinimap.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.pbMinimap.Location = new System.Drawing.Point(32, 25);
this.pbMinimap.Name = "pbMinimap";
this.pbMinimap.Size = new System.Drawing.Size(124, 124);
this.pbMinimap.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pbMinimap.TabIndex = 5;
this.pbMinimap.TabStop = false;
//
// pnlBottom
//
this.pnlBottom.Controls.Add(this.pictureBox1);
this.pnlBottom.Controls.Add(this.txtPathOut);
this.pnlBottom.Controls.Add(this.lblPathOut);
this.pnlBottom.Controls.Add(this.lblPath);
this.pnlBottom.Controls.Add(this.btnCancel);
this.pnlBottom.Controls.Add(this.btnOk);
this.pnlBottom.Controls.Add(this.txtNew);
this.pnlBottom.Controls.Add(this.lblNew);
this.pnlBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
this.pnlBottom.Location = new System.Drawing.Point(0, 332);
this.pnlBottom.MaximumSize = new System.Drawing.Size(0, 70);
this.pnlBottom.Name = "pnlBottom";
this.pnlBottom.Size = new System.Drawing.Size(494, 70);
this.pnlBottom.TabIndex = 6;
//
// txtPathOut
//
this.txtPathOut.BackColor = System.Drawing.SystemColors.Window;
this.txtPathOut.Location = new System.Drawing.Point(55, 10);
this.txtPathOut.Name = "txtPathOut";
this.txtPathOut.ReadOnly = true;
this.txtPathOut.Size = new System.Drawing.Size(265, 20);
this.txtPathOut.TabIndex = 0;
this.txtPathOut.TextChanged += new System.EventHandler(this.txtPathOut_TextChanged);
//
// lblPathOut
//
this.lblPathOut.AutoSize = true;
this.lblPathOut.Location = new System.Drawing.Point(55, 13);
this.lblPathOut.Name = "lblPathOut";
this.lblPathOut.Size = new System.Drawing.Size(0, 13);
this.lblPathOut.TabIndex = 6;
//
// lblPath
//
this.lblPath.AutoSize = true;
this.lblPath.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
this.lblPath.Location = new System.Drawing.Point(12, 13);
this.lblPath.Name = "lblPath";
this.lblPath.Size = new System.Drawing.Size(37, 13);
this.lblPath.TabIndex = 5;
this.lblPath.Text = "Path:";
//
// splitContainer1
//
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
this.splitContainer1.Name = "splitContainer1";
//
// splitContainer1.Panel1
//
this.splitContainer1.Panel1.Controls.Add(this.lblMapList);
this.splitContainer1.Panel1.Controls.Add(this.MapList);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.txtDesc);
this.splitContainer1.Panel2.Controls.Add(this.lblDesc);
this.splitContainer1.Panel2.Controls.Add(this.txtTheater);
this.splitContainer1.Panel2.Controls.Add(this.lblTheater);
this.splitContainer1.Panel2.Controls.Add(this.txtAuthor);
this.splitContainer1.Panel2.Controls.Add(this.lblAuthor);
this.splitContainer1.Panel2.Controls.Add(this.txtTitle);
this.splitContainer1.Panel2.Controls.Add(this.lblMapName);
this.splitContainer1.Panel2.Controls.Add(this.lblMinimap);
this.splitContainer1.Panel2.Controls.Add(this.pbMinimap);
this.splitContainer1.Size = new System.Drawing.Size(494, 332);
this.splitContainer1.SplitterDistance = 300;
this.splitContainer1.TabIndex = 7;
//
// lblMapList
//
this.lblMapList.AutoSize = true;
this.lblMapList.Location = new System.Drawing.Point(12, 9);
this.lblMapList.Name = "lblMapList";
this.lblMapList.Size = new System.Drawing.Size(81, 13);
this.lblMapList.TabIndex = 1;
this.lblMapList.Text = "Available maps:";
//
// txtDesc
//
this.txtDesc.BackColor = System.Drawing.SystemColors.ButtonFace;
this.txtDesc.Location = new System.Drawing.Point(16, 289);
this.txtDesc.Name = "txtDesc";
this.txtDesc.ReadOnly = true;
this.txtDesc.Size = new System.Drawing.Size(162, 20);
this.txtDesc.TabIndex = 14;
//
// lblDesc
//
this.lblDesc.AutoSize = true;
this.lblDesc.Location = new System.Drawing.Point(13, 273);
this.lblDesc.Name = "lblDesc";
this.lblDesc.Size = new System.Drawing.Size(63, 13);
this.lblDesc.TabIndex = 13;
this.lblDesc.Text = "Description:";
//
// txtTheater
//
this.txtTheater.BackColor = System.Drawing.SystemColors.ButtonFace;
this.txtTheater.Location = new System.Drawing.Point(16, 252);
this.txtTheater.Name = "txtTheater";
this.txtTheater.ReadOnly = true;
this.txtTheater.Size = new System.Drawing.Size(162, 20);
this.txtTheater.TabIndex = 12;
//
// lblTheater
//
this.lblTheater.AutoSize = true;
this.lblTheater.Location = new System.Drawing.Point(13, 236);
this.lblTheater.Name = "lblTheater";
this.lblTheater.Size = new System.Drawing.Size(47, 13);
this.lblTheater.TabIndex = 11;
this.lblTheater.Text = "Theater:";
//
// txtAuthor
//
this.txtAuthor.BackColor = System.Drawing.SystemColors.ButtonFace;
this.txtAuthor.Location = new System.Drawing.Point(16, 214);
this.txtAuthor.Name = "txtAuthor";
this.txtAuthor.ReadOnly = true;
this.txtAuthor.Size = new System.Drawing.Size(162, 20);
this.txtAuthor.TabIndex = 10;
//
// lblAuthor
//
this.lblAuthor.AutoSize = true;
this.lblAuthor.Location = new System.Drawing.Point(13, 198);
this.lblAuthor.Name = "lblAuthor";
this.lblAuthor.Size = new System.Drawing.Size(41, 13);
this.lblAuthor.TabIndex = 9;
this.lblAuthor.Text = "Author:";
//
// txtTitle
//
this.txtTitle.BackColor = System.Drawing.SystemColors.ButtonFace;
this.txtTitle.Location = new System.Drawing.Point(16, 177);
this.txtTitle.Name = "txtTitle";
this.txtTitle.ReadOnly = true;
this.txtTitle.Size = new System.Drawing.Size(162, 20);
this.txtTitle.TabIndex = 8;
//
// lblMapName
//
this.lblMapName.AutoSize = true;
this.lblMapName.Location = new System.Drawing.Point(13, 161);
this.lblMapName.Name = "lblMapName";
this.lblMapName.Size = new System.Drawing.Size(30, 13);
this.lblMapName.TabIndex = 7;
this.lblMapName.Text = "Title:";
//
// lblMinimap
//
this.lblMinimap.AutoSize = true;
this.lblMinimap.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
this.lblMinimap.Location = new System.Drawing.Point(29, 9);
this.lblMinimap.Name = "lblMinimap";
this.lblMinimap.Size = new System.Drawing.Size(71, 13);
this.lblMinimap.TabIndex = 6;
this.lblMinimap.Text = "Map preview:";
//
// pictureBox1
//
this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
this.pictureBox1.Location = new System.Drawing.Point(336, -9);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(54, 35);
this.pictureBox1.TabIndex = 7;
this.pictureBox1.TabStop = false;
this.pictureBox1.Visible = false;
//
// MapSelect
//
this.AcceptButton = this.btnOk;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(494, 402);
this.Controls.Add(this.splitContainer1);
this.Controls.Add(this.pnlBottom);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "MapSelect";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Select map";
this.Load += new System.EventHandler(this.MapSelect_Load);
((System.ComponentModel.ISupportInitialize)(this.pbMinimap)).EndInit();
this.pnlBottom.ResumeLayout(false);
this.pnlBottom.PerformLayout();
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel1.PerformLayout();
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.Panel2.PerformLayout();
this.splitContainer1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
#endregion
public System.Windows.Forms.ListView MapList;
public System.Windows.Forms.Button btnCancel;
public System.Windows.Forms.Button btnOk;
public System.Windows.Forms.Label lblNew;
public System.Windows.Forms.TextBox txtNew;
public System.Windows.Forms.ColumnHeader colMapName;
public System.Windows.Forms.ImageList MapIconsList;
public System.Windows.Forms.PictureBox pbMinimap;
public System.Windows.Forms.Panel pnlBottom;
public System.Windows.Forms.SplitContainer splitContainer1;
public System.Windows.Forms.Label lblMinimap;
public System.Windows.Forms.TextBox txtTheater;
public System.Windows.Forms.Label lblTheater;
public System.Windows.Forms.TextBox txtAuthor;
public System.Windows.Forms.Label lblAuthor;
public System.Windows.Forms.TextBox txtTitle;
public System.Windows.Forms.Label lblMapName;
public System.Windows.Forms.TextBox txtDesc;
public System.Windows.Forms.Label lblDesc;
public System.Windows.Forms.Label lblMapList;
public System.Windows.Forms.Label lblPathOut;
public System.Windows.Forms.Label lblPath;
public System.Windows.Forms.TextBox txtPathOut;
private System.Windows.Forms.PictureBox pictureBox1;
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.IO;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Graphics;
namespace OpenRA.Editor
{
public partial class MapSelect : Form
{
public string MapFolderPath;
public MapSelect()
{
InitializeComponent();
MapIconsList.Images.Add(pictureBox1.Image);
}
void MapSelect_Load(object sender, EventArgs e)
{
DirectoryInfo directory = new DirectoryInfo(MapFolderPath);
DirectoryInfo[] directories = directory.GetDirectories();
MapList.Items.Clear();
txtPathOut.Text = MapFolderPath;
foreach (DirectoryInfo subDirectory in directories)
{
ListViewItem map1 = new ListViewItem(subDirectory.Name);
map1.ImageIndex = 0;
MapList.Items.Add(map1);
}
// hack
if (txtNew.Text != "unnamed")
MapList.Items[0].Selected = true;
}
void MapList_SelectedIndexChanged(object sender, EventArgs e)
{
if (MapList.SelectedItems.Count == 1)
{
txtNew.Text = MapList.SelectedItems[0].Text;
var map = new Map(new Folder(Path.Combine(MapFolderPath, MapList.SelectedItems[0].Text)));
txtTitle.Text = map.Title;
txtAuthor.Text = map.Author;
txtTheater.Text = map.Theater;
txtDesc.Text = map.Description;
pbMinimap.Image = null;
try
{
pbMinimap.Image = Minimap.AddStaticResources(map, Minimap.TerrainBitmap(map, true));
}
catch (Exception ed)
{
Console.WriteLine("No map preview image found: {0}", ed.ToString());
}
finally { }
}
}
void txtPathOut_TextChanged(object sender, EventArgs e)
{
MapFolderPath = txtPathOut.Text;
}
}
}

View File

@@ -0,0 +1,177 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="MapIconsList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="pictureBox1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAArjSURBVFhHrVcJUFRXFmVpkE0Wg0ZEMoIBl8RodGSMmVES
R0NiChVxCyIIAmFfhe6maeh9AZodZHFpUFQWcQmKisiuLKLEKFFEcIuljtZMYmI5Uc/c14EZYyapmpq8
qlP/9/+/373v3HPu+19P7/cf+jSlEWHCOEuzZfNn2Yvo3Pj3D/PTjCwYAwtgyeFwFk163Tos2tvtWJZw
zeUjmYFP6vL9fhw31vRPI8/9LnmMrtCWZhtPcJ7hbC/W8DwfnS0LR0t5NKoFazHcqsaprE3YGbMQLrYW
W/7fBAxogjGEd5wcXuPK4jxa60qD75VrfIbKMrYMD7VlPX/Ul49rp8RoyPbFIaEnhpuU6NRGoVa2HKuX
zEj/X8vAVmlIsDY2Nna2sjBd+ee5b7Yq4tfgfm8a7pxNw60OFa6e4uFmhxr/uFSIexfz0VsZh7PaIJzb
F42u8hAcV2/ANz3KF8Hub52kucb+Fv+jAccbm5quWOfxYX5y6Mcnq/IDh1oreX/vOcx9drdbjTudUgye
Tsb1piT0H4/DACUw0JiEh33ZePhlFi7UxOCLtI1o2x6IW2cUqM/egLtdediV9MnjSTYm60bE+Ys8rMzN
zd1c3/vLgVRV3lN1XjkqyzNoNaEUjIvrLXwMtQsw1JqEy/UxuHg0DJcp+KXj8bh0IobOucSGDA8vpqE6
+VNINixBU0kQbp5JJ8jxDSXdeyAE5arlAxTZ/BfRra2tS8Tqwh9L9tQhq6gSabm7odLkoP8oF90V/rjR
LsRgExc32oS40ZFCiQgw2Mgj+gW42pBI4OPSsUh6Jgn1mX4ojXJH865IXDzCx50uDe6fV+P8oQQ4Tx6r
pOATmVteKgdjXu/Mhk1h328rO4TMwn3gp2YhmquEX7gAfYfjcb4qGH0HQ3D5WAiunU7ApfpofH0ymhIS
UwkSqQRb6VoYvm6IZvXG7W4VBVbjwQU1/tanIQZkGDqtwOmSjzHXxXaLsZnZpy85QpdAnfunax/mllRD
ma2FQJyHxORMJAqzwBVpUJgtRLF8E7bxlqKjzA991QEYaIijgFwMt6VggJK60hCFr46F4sqprbjbLaf6
S0icIh1rwy1i3OvNQff+GEgj3r87/c1JLIGfjX1LP/F6KJDlIy1vN4SyQohVRdAU7IVIXQxuSiZ8/OOw
JYyP8EiqfV04Lh2JoHIwMSbiwoFgtO1ah97aTSTMKGIjDl/WhONWl5jKlYrbZ9OJGRWVIg/+axf8SK5a
8WoC5fPm//l2qqIIOaVVECm3QZG5C7L0HZCklYJLTCQKNUiWFYAnykJYRDRaywNxrTGRyhKNKyciiIEY
dFd743z1ZioT6eJkHK41kXDbRFSKbHzTpcJwsxoHc71fTLGzyBix+L/zUFlaWX+VTcFZ4NzSamQXV1Lw
EggkeeBRAsnSfKgyy6DKKcNnxEahIgRfHg5B/7EoDDYn4ma7FD0VAThfG4Cemi3EDI90IKWVq3GbHHKz
nUpCbrh6QokEr5mPTEw4773MQij9aPZY5fNYrC6hEhRAnrkTjJEkcS5ieWokS/IhUZdCrtlJbGQiIjQQ
/YeD0VMVhoTVbmgs8iVBctG11xtdlUHkDGpQpIN7velUAhmG2+W43spclI6K9JWY6TyxlGKOGxWjG53s
5HBMBpZ7+iI6UY44vhoiVTH4ohxCLoTyArqu1OlBll6CZHE20mI9EOjuis3L5uFCbTh6D4Wgu8offYeC
qSRccgcPD/qyMEiBb55VYahFgSuNckhjlr2YaGMqH2ntOiKmEAQGBgbnNviGPg2LFSM4UoiAUD78ghLo
yEVojBhRiQqEx0nAI5sKiBH/z+OgVfuic7c/Lh+NwZndfughDfQdCtL1hKFmEW51ymn1EjpSAh1ytFCL
Pl+nhKebY8XLTYn16DWEgzY2ttdzyI6yjB06+uP4acRANokvhzRRjBR5oe4aN4WupeYgNCIWZ2vj0b17
I/UKf3Tt34jOis9otTyyILmkORUDTRKyqxj9DSI07Y0k26Yhes38Roo3YVQH7OVhGiGR0K7O0epEqCRB
shKwRIQkQrZqMelAIM6ncihII9uQSCXZEi2HSMjDXvVqXKSGdTLbg6z6OVkwGcfLQvHB4jkYbJMS/UL0
1aeSM6So1Hg/oljTR93AupEVYSXhGE+soZa8X+cIlgALzFhg5/HJ6YhIzACXVs9EKiHRMmckSfMQGx0G
rXIldU4/dJSvJx3EoSDZC7OszHByTxTOfZGEq00y9B3lo70iElamhp4Ujy1eN8wIrEOd0BRW6DpiWEwq
giKSdYiIl5IOUskRKh39AmKECZNP7Mg0O6Ci59Pzd4O/NQK7FBvQULyGOmMUpBsX4KqjGTL5qzHQIqJy
iNG6Px5dtYlY7jqhmeKxvUE32C7FGKiP58uf5W6v0ekgPkmNrYIMor4YqcoinQBFdGQrl2ZsB4/cwBJR
Zml/+k0sxcQnQZzgDWHIIni9NQHSHU5IS15EPSEN11ok6G9UQs1dh/lvv/GdkZHR3NEETOhkIUE7zvb1
wRRFwYv0vD3UBTORJCEdSHMhydgFCXVHVnuWEGvZrDewjqmzKbHDNjHmFl5KBlasWokiFwtop5nhyL6p
2JO/CN2HBdSgMpHJ88GH82c8s7b4T1vmUPA3CFxCp19QzBPdtpxdRqon2kkDKRSYXeOJcyBUFMI7IJ70
kYsEgRLTXGbgrzNnwmWqC2Y4OsLZZjx43El4ggXI1zohy24MAFd4u9tj8YLpmD71DTiMtwGHY1A7ygB7
52N29CLULV7qeT+HnFCoPairu87/RC9rTjE8JYJoY/p4lR8lVQAp7Rc+/pHY7OKE61NN8a21MbQpfwC+
m4fbQ7MQNdcCfWMMsTPWDi2yyRgyNkDhOGPYGhpeo97jP5oAcwJjYQ4hk3DOyzvwn9v3HtUJjHXAzSFc
RHHlCAznIyAsCZa2k56u3xT2gtHPmGHCdXtnHh47mKBqjS1K5Q7ITrCjlf8RqXPM0bDUCr3bp2C9nj70
DDinKMYSwmujCbAjY4G9ZrN3tyMLP/D4IT1vP/J21CBeoKaa55MTUhAeK8J7i91v0DMdxqZmgw7Oc74N
iFQ8T5YX6ZzisWI9Uiebo8rKCOcsjLAv1Z72BydUxE5ElcTuKf2P9RunEeGzmD8bTIzsI0I7wc7xdgyf
NiayWVoueZ1qz7zPT8l5McnBqZieYZsYO/a4zF7yaKWP4HlASMKLj9xX4WrXWzhdMxUFlkaI1tPDAZE9
Htc4wWuhOas5Y/oXgUezYDdZdmK2N6zzCfuB1V1GFkulNswT5cFllms73f+QMIWwjCDjGJnUW1rbfu2z
wvXJk85pUH5gieNJdugvd8QV7RSc0TjgiMwevkvH3np1xa/+ZplZE9jecNh14UcPmO8VmnLyfzGr/feU
mB/dY7VjybItdSZhrb6+fvEYY6PuMWOMn7ZbGeILfQNYmnN+mO1o/OBdCw74HAMsMjR8NjL/r+Yx+p3H
XhjKZs93uxMZr4Z/uOb54qWf3bGf4pw3EpC1UPYsS3g0EU9K4uBsI86zYHPOY3MOp4zuRRLyDfT1O941
Mrzvb86Bob4h+0r6zcEmdiFICA2vvT55kLFBYOJhnYt9or06TOmCJ7HTbGxgADpndmaJMU29QxAQKvTo
vhnHkN1nX12/OlgCNoT3CZsIvgRWc9ao2IT/bTD3+BID7N1/zisBWCKOBB/CagKf8PboJP8CoUmu3yhA
ga8AAAAASUVORK5CYII=
</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -12,6 +12,9 @@
<AssemblyName>OpenRA.Editor</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ApplicationIcon>OpenRA.Editor.Icon.ico</ApplicationIcon>
<StartupObject>
</StartupObject>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -33,6 +36,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@@ -59,12 +63,24 @@
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="LegacyMapImporter.cs" />
<Compile Include="MapSelect.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MapSelect.Designer.cs">
<DependentUpon>MapSelect.cs</DependentUpon>
</Compile>
<Compile Include="NewMapDialog.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="NewMapDialog.Designer.cs">
<DependentUpon>NewMapDialog.cs</DependentUpon>
</Compile>
<Compile Include="PaletteBox.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="PaletteBox.Designer.cs">
<DependentUpon>PaletteBox.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="PropertiesDialog.cs">
<SubType>Form</SubType>
@@ -76,9 +92,15 @@
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="MapSelect.resx">
<DependentUpon>MapSelect.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="NewMapDialog.resx">
<DependentUpon>NewMapDialog.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="PaletteBox.resx">
<DependentUpon>PaletteBox.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="PropertiesDialog.resx">
<DependentUpon>PropertiesDialog.cs</DependentUpon>
</EmbeddedResource>
@@ -103,6 +125,7 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="RenderUtils.cs" />
<Compile Include="ResizeDialog.cs">
<SubType>Form</SubType>
</Compile>
@@ -123,6 +146,9 @@
<Name>OpenRA.Game</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="OpenRA.Editor.Icon.ico" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

165
OpenRA.Editor/PaletteBox.Designer.cs generated Normal file
View File

@@ -0,0 +1,165 @@
namespace OpenRA.Editor
{
partial class PaletteBox
{
/// <summary>
/// Требуется переменная конструктора.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
/// <param name="disposing">истинно, если управляемый ресурс должен быть удален; иначе ложно.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором форм Windows
/// <summary>
/// Обязательный метод для поддержки конструктора - не изменяйте
/// содержимое данного метода при помощи редактора кода.
/// </summary>
private void InitializeComponent()
{
this.LayerBox = new System.Windows.Forms.ComboBox();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.pbtilePalette = new System.Windows.Forms.FlowLayoutPanel();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.pbactorPalette = new System.Windows.Forms.FlowLayoutPanel();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.pbresourcePalette = new System.Windows.Forms.FlowLayoutPanel();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.tabPage3.SuspendLayout();
this.SuspendLayout();
//
// LayerBox
//
this.LayerBox.Dock = System.Windows.Forms.DockStyle.Top;
this.LayerBox.FormattingEnabled = true;
this.LayerBox.Location = new System.Drawing.Point(0, 0);
this.LayerBox.Name = "LayerBox";
this.LayerBox.Size = new System.Drawing.Size(194, 21);
this.LayerBox.TabIndex = 0;
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Controls.Add(this.tabPage3);
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl1.Location = new System.Drawing.Point(0, 21);
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
this.tabControl1.Multiline = true;
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(194, 357);
this.tabControl1.TabIndex = 1;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.pbtilePalette);
this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(186, 331);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Templates";
this.tabPage1.UseVisualStyleBackColor = true;
//
// pbtilePalette
//
this.pbtilePalette.AutoScroll = true;
this.pbtilePalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.pbtilePalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.pbtilePalette.Location = new System.Drawing.Point(3, 3);
this.pbtilePalette.Name = "pbtilePalette";
this.pbtilePalette.Size = new System.Drawing.Size(180, 325);
this.pbtilePalette.TabIndex = 1;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.pbactorPalette);
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(186, 331);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Actors";
this.tabPage2.UseVisualStyleBackColor = true;
//
// pbactorPalette
//
this.pbactorPalette.AutoScroll = true;
this.pbactorPalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.pbactorPalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.pbactorPalette.Location = new System.Drawing.Point(3, 3);
this.pbactorPalette.Name = "pbactorPalette";
this.pbactorPalette.Size = new System.Drawing.Size(180, 325);
this.pbactorPalette.TabIndex = 2;
//
// tabPage3
//
this.tabPage3.Controls.Add(this.pbresourcePalette);
this.tabPage3.Location = new System.Drawing.Point(4, 22);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(186, 331);
this.tabPage3.TabIndex = 2;
this.tabPage3.Text = "Resources";
this.tabPage3.UseVisualStyleBackColor = true;
//
// pbresourcePalette
//
this.pbresourcePalette.AutoScroll = true;
this.pbresourcePalette.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.pbresourcePalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.pbresourcePalette.Location = new System.Drawing.Point(0, 0);
this.pbresourcePalette.Name = "pbresourcePalette";
this.pbresourcePalette.Size = new System.Drawing.Size(186, 331);
this.pbresourcePalette.TabIndex = 3;
//
// PaletteBox
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(194, 378);
this.Controls.Add(this.tabControl1);
this.Controls.Add(this.LayerBox);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PaletteBox";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Palette Box";
this.TopMost = true;
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
public System.Windows.Forms.ComboBox LayerBox;
public System.Windows.Forms.TabControl tabControl1;
public System.Windows.Forms.TabPage tabPage1;
public System.Windows.Forms.FlowLayoutPanel pbtilePalette;
public System.Windows.Forms.TabPage tabPage2;
public System.Windows.Forms.FlowLayoutPanel pbactorPalette;
public System.Windows.Forms.TabPage tabPage3;
public System.Windows.Forms.FlowLayoutPanel pbresourcePalette;
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace OpenRA.Editor
{
public partial class PaletteBox : Form
{
public PaletteBox()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,136 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
using System.Drawing.Imaging;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Editor
{
static class RenderUtils
{
public static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p)
{
var template = ts.Templates[n];
var tile = ts.Tiles[n];
var bitmap = new Bitmap(ts.TileSize * template.Size.X, ts.TileSize * template.Size.Y);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
if (tile.TileBitmapBytes[u + v * template.Size.X] != null)
{
var rawImage = tile.TileBitmapBytes[u + v * template.Size.X];
for (var i = 0; i < ts.TileSize; i++)
for (var j = 0; j < ts.TileSize; j++)
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = p.GetColor(rawImage[i + ts.TileSize * j]).ToArgb();
}
else
{
for (var i = 0; i < ts.TileSize; i++)
for (var j = 0; j < ts.TileSize; j++)
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = Color.Transparent.ToArgb();
}
}
bitmap.UnlockBits(data);
return bitmap;
}
static Bitmap RenderShp(ShpReader shp, Palette p)
{
var frame = shp[0];
var bitmap = new Bitmap(shp.Width, shp.Height);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride2 = data.Stride >> 2;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride2 + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
}
bitmap.UnlockBits(data);
return bitmap;
}
public static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p)
{
var ri = info.Traits.Get<RenderSimpleInfo>();
string image = null;
if (ri.OverrideTheater != null)
for (int i = 0; i < ri.OverrideTheater.Length; i++)
if (ri.OverrideTheater[i] == tileset.Id)
image = ri.OverrideImage[i];
image = image ?? ri.Image ?? info.Name;
using (var s = FileSystem.OpenWithExts(image, tileset.Extensions))
{
var shp = new ShpReader(s);
var bitmap = RenderShp(shp, p);
try
{
using (var s2 = FileSystem.OpenWithExts(image + "2", tileset.Extensions))
{
var shp2 = new ShpReader(s2);
var roofBitmap = RenderShp(shp2, p);
using (var g = System.Drawing.Graphics.FromImage(bitmap))
g.DrawImage(roofBitmap, 0, 0);
}
}
catch { }
return new ActorTemplate { Bitmap = bitmap, Info = info, Centered = !info.Traits.Contains<BuildingInfo>() };
}
}
public static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p)
{
var image = info.SpriteNames[0];
using (var s = FileSystem.OpenWithExts(image, exts))
{
var shp = new ShpReader(s);
var frame = shp[shp.ImageCount - 1];
var bitmap = new Bitmap(shp.Width, shp.Height);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* q = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride + i] = p.GetColor(frame.Image[i + shp.Width * j]).ToArgb();
}
bitmap.UnlockBits(data);
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 };
}
}
}
}

View File

@@ -87,6 +87,8 @@ namespace OpenRA.Editor
{
base.OnMouseWheel(e);
if (Map == null) return;
Zoom *= e.Delta > 0 ? 4.0f / 3.0f : .75f;
Invalidate();
@@ -114,6 +116,8 @@ namespace OpenRA.Editor
{
base.OnMouseMove(e);
if (Map == null) return;
var oldMousePos = MousePos;
MousePos = new int2(e.Location);
@@ -332,6 +336,8 @@ namespace OpenRA.Editor
{
base.OnMouseDown(e);
if (Map == null) return;
if (!IsPanning)
{
if (e.Button == MouseButtons.Right) Erase();
@@ -346,7 +352,7 @@ namespace OpenRA.Editor
Bitmap RenderChunk(int u, int v)
{
var bitmap = new Bitmap(ChunkSize * 24, ChunkSize * 24);
var bitmap = new Bitmap(ChunkSize * TileSet.TileSize, ChunkSize * TileSet.TileSize);
bitmap.SetPixel(0, 0, Color.Green);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
@@ -364,9 +370,9 @@ namespace OpenRA.Editor
var tile = TileSet.Tiles[tr.type];
var index = (tr.image < tile.TileBitmapBytes.Count) ? tr.image : (byte)0;
var rawImage = tile.TileBitmapBytes[index];
for (var x = 0; x < 24; x++)
for (var y = 0; y < 24; y++)
p[(j * 24 + y) * stride + i * 24 + x] = Palette.GetColor(rawImage[x + 24 * y]).ToArgb();
for (var x = 0; x < TileSet.TileSize; x++)
for (var y = 0; y < TileSet.TileSize; y++)
p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = Palette.GetColor(rawImage[x + TileSet.TileSize * y]).ToArgb();
if (Map.MapResources[u * ChunkSize + i, v * ChunkSize + j].type != 0)
{
@@ -377,12 +383,12 @@ namespace OpenRA.Editor
int* q = (int*)srcdata.Scan0.ToPointer();
var srcstride = srcdata.Stride >> 2;
for (var x = 0; x < 24; x++)
for (var y = 0; y < 24; y++)
for (var x = 0; x < TileSet.TileSize; x++)
for (var y = 0; y < TileSet.TileSize; y++)
{
var c = q[y * srcstride + x];
if ((c & 0xff000000) != 0) /* quick & dirty, i cbf doing real alpha */
p[(j * 24 + y) * stride + i * 24 + x] = c;
p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = c;
}
resourceImage.UnlockBits(srcdata);
@@ -398,16 +404,16 @@ namespace OpenRA.Editor
{
var vX = (int)Math.Floor((MousePos.X - Offset.X) / Zoom);
var vY = (int)Math.Floor((MousePos.Y - Offset.Y) / Zoom);
return new int2(vX / 24, vY / 24);
return new int2(vX / TileSet.TileSize, vY / TileSet.TileSize);
}
void DrawActor(System.Drawing.Graphics g, int2 p, ActorTemplate t)
{
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - 12 : 0;
float DrawX = 24 * p.X * Zoom + Offset.X - OffsetX;
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - TileSet.TileSize/2 : 0;
float DrawX = TileSet.TileSize * p.X * Zoom + Offset.X - OffsetX;
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - 12 : 0;
float DrawY = 24 * p.Y * Zoom + Offset.Y - OffsetY;
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - TileSet.TileSize/2 : 0;
float DrawY = TileSet.TileSize * p.Y * Zoom + Offset.Y - OffsetY;
float width = t.Bitmap.Width * Zoom;
float height = t.Bitmap.Height * Zoom;
@@ -418,11 +424,11 @@ namespace OpenRA.Editor
void DrawImage(System.Drawing.Graphics g, Bitmap bmp, int2 location)
{
float OffsetX = bmp.Width / 2 - 12;
float DrawX = 24 * location.X * Zoom + Offset.X - OffsetX;
float OffsetX = bmp.Width / 2 - TileSet.TileSize / 2;
float DrawX = TileSet.TileSize * location.X * Zoom + Offset.X - OffsetX;
float OffsetY = bmp.Height / 2 - 12;
float DrawY = 24 * location.Y * Zoom + Offset.Y - OffsetY;
float OffsetY = bmp.Height / 2 - TileSet.TileSize / 2;
float DrawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - OffsetY;
float width = bmp.Width * Zoom;
float height = bmp.Height * Zoom;
@@ -433,16 +439,12 @@ namespace OpenRA.Editor
void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t)
{
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - 12 : 0;
float DrawX = 24 * p.X * Zoom + Offset.X - OffsetX;
float OffsetX = t.Centered ? t.Bitmap.Width / 2 - TileSet.TileSize / 2 : 0;
float DrawX = TileSet.TileSize * p.X * Zoom + Offset.X - OffsetX;
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - 12 : 0;
float DrawY = 24 * p.Y * Zoom + Offset.Y - OffsetY;
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - TileSet.TileSize / 2 : 0;
float DrawY = TileSet.TileSize * p.Y * Zoom + Offset.Y - OffsetY;
float width = t.Bitmap.Width * Zoom;
float height = t.Bitmap.Height * Zoom;
RectangleF sourceRect = new RectangleF(0, 0, t.Bitmap.Width, t.Bitmap.Height);
RectangleF destRect = new RectangleF(DrawX, DrawY, width, height);
g.DrawRectangle(CordonPen,
DrawX, DrawY,
t.Bitmap.Width * Zoom, t.Bitmap.Height * Zoom);
@@ -461,32 +463,32 @@ namespace OpenRA.Editor
Bitmap bmp = Chunks[x];
float DrawX = 24.0f * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
float DrawY = 24.0f * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
float DrawX = TileSet.TileSize* 1f * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
float DrawY = TileSet.TileSize * 1f * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
RectangleF destRect = new RectangleF(DrawX, DrawY, bmp.Width * Zoom, bmp.Height * Zoom);
e.Graphics.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
}
e.Graphics.DrawRectangle(CordonPen,
Map.XOffset * 24 * Zoom + Offset.X,
Map.YOffset * 24 * Zoom + Offset.Y,
Map.Width * 24 * Zoom,
Map.Height * 24 * Zoom);
Map.XOffset * TileSet.TileSize * Zoom + Offset.X,
Map.YOffset * TileSet.TileSize * Zoom + Offset.Y,
Map.Width * TileSet.TileSize * Zoom,
Map.Height * TileSet.TileSize * Zoom);
foreach (var ar in Map.Actors)
DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type]);
foreach (var wp in Map.Waypoints)
e.Graphics.DrawRectangle(Pens.LimeGreen,
24 * wp.Value.X * Zoom + Offset.X + 4,
24 * wp.Value.Y * Zoom + Offset.Y + 4,
16 * Zoom, 16 * Zoom);
TileSet.TileSize * wp.Value.X * Zoom + Offset.X + 4,
TileSet.TileSize * wp.Value.Y * Zoom + Offset.Y + 4,
(TileSet.TileSize - 8) * Zoom, (TileSet.TileSize - 8) * Zoom);
if (Brush != null)
e.Graphics.DrawImage(Brush.Bitmap,
24 * GetBrushLocation().X * Zoom + Offset.X,
24 * GetBrushLocation().Y * Zoom + Offset.Y,
TileSet.TileSize * GetBrushLocation().X * Zoom + Offset.X,
TileSet.TileSize * GetBrushLocation().Y * Zoom + Offset.Y,
Brush.Bitmap.Width * Zoom,
Brush.Bitmap.Height * Zoom);
@@ -498,9 +500,9 @@ namespace OpenRA.Editor
if (Waypoint != null)
e.Graphics.DrawRectangle(Pens.LimeGreen,
24 * GetBrushLocation().X * Zoom + Offset.X + 4,
24 * GetBrushLocation().Y * Zoom + Offset.Y + 4,
16 * Zoom, 16 * Zoom);
TileSet.TileSize * GetBrushLocation().X * Zoom + Offset.X + 4,
TileSet.TileSize * GetBrushLocation().Y * Zoom + Offset.Y + 4,
(TileSet.TileSize - 8) * Zoom, (TileSet.TileSize - 8) * Zoom);
if (Brush == null && Actor == null && Resource == null)
{

22
OpenRA.FileFormats/Exts.cs Normal file → Executable file
View File

@@ -73,5 +73,27 @@ namespace OpenRA
{
return mi.GetCustomAttributes(typeof(T), true).Length != 0;
}
public static T[] GetCustomAttributes<T>( this MemberInfo mi, bool inherit )
where T : class
{
return (T[])mi.GetCustomAttributes( typeof( T ), inherit );
}
public static T[] GetCustomAttributes<T>( this ParameterInfo mi )
where T : class
{
return (T[])mi.GetCustomAttributes( typeof( T ), true );
}
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
{
if (val.CompareTo(min) < 0)
return min;
else if (val.CompareTo(max) > 0)
return max;
else
return val;
}
}
}

21
OpenRA.FileFormats/FieldLoader.cs Normal file → Executable file
View File

@@ -13,6 +13,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace OpenRA.FileFormats
{
@@ -99,7 +100,7 @@ namespace OpenRA.FileFormats
else if (fieldType == typeof(float))
{
float res;
if (float.TryParse(x.Replace("%",""), out res))
if (float.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res))
return res * (x.Contains( '%' ) ? 0.01f : 1f);
return InvalidValueAction(x,fieldType, field);
}
@@ -111,9 +112,9 @@ namespace OpenRA.FileFormats
{
var parts = x.Split(',');
if (parts.Length == 3)
return Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]));
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255));
if (parts.Length == 4)
return Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]));
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255), int.Parse(parts[3]).Clamp(0, 255));
return InvalidValueAction(x,fieldType, field);
}
@@ -177,11 +178,12 @@ namespace OpenRA.FileFormats
{
var ret = new Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>>();
foreach( var field in type.GetFields() )
foreach( var ff in type.GetFields() )
{
var load = (LoadAttribute[])field.GetCustomAttributes( typeof( LoadAttribute ), false );
var loadUsing = (LoadUsingAttribute[])field.GetCustomAttributes( typeof( LoadUsingAttribute ), false );
var fromYamlKey = (FieldFromYamlKeyAttribute[])field.GetCustomAttributes( typeof( FieldFromYamlKeyAttribute ), false );
var field = ff;
var load = field.GetCustomAttributes<LoadAttribute>( false );
var loadUsing = field.GetCustomAttributes<LoadUsingAttribute>( false );
var fromYamlKey = field.GetCustomAttributes<FieldFromYamlKeyAttribute>( false );
if( loadUsing.Length != 0 )
ret[ field ] = ( _1, fieldType, yaml ) => loadUsing[ 0 ].LoaderFunc( field )( yaml );
else if( fromYamlKey.Length != 0 )
@@ -262,7 +264,10 @@ namespace OpenRA.FileFormats
if (f.FieldType == typeof(Color))
{
var c = (Color)v;
return "{0},{1},{2},{3}".F(c.A,c.R,c.G,c.B);
return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255),
((int)c.R).Clamp(0, 255),
((int)c.G).Clamp(0, 255),
((int)c.B).Clamp(0, 255));
}
return f.FieldType.IsArray

View File

@@ -52,13 +52,13 @@ namespace OpenRA.FileFormats.Graphics
public interface IVertexBuffer<T>
{
void Bind();
void SetData( T[] vertices );
void SetData( T[] vertices, int length );
}
public interface IIndexBuffer
{
void Bind();
void SetData( ushort[] indices );
void SetData( ushort[] indices, int length );
}
public interface IShader

View File

@@ -18,18 +18,21 @@ namespace OpenRA.FileFormats
public class Manifest
{
public readonly string[]
Folders, Packages, Rules,
Mods, Folders, Packages, Rules,
Sequences, Cursors, Chrome, Assemblies, ChromeLayout,
Weapons, Voices, Music, Movies, TileSets;
public readonly string ShellmapUid, LoadScreen;
public readonly int TileSize = 24;
public Manifest(string[] mods)
{
Mods = mods;
var yaml = mods
.Select(m => MiniYaml.FromFile("mods/" + m + "/mod.yaml"))
.Aggregate(MiniYaml.Merge);
// Todo: Use fieldloader
Folders = YamlList(yaml, "Folders");
Packages = YamlList(yaml, "Packages");
Rules = YamlList(yaml, "Rules");
@@ -46,6 +49,9 @@ namespace OpenRA.FileFormats
ShellmapUid = yaml.First( x => x.Key == "ShellmapUid" ).Value.Value;
LoadScreen = yaml.First( x => x.Key == "LoadScreen" ).Value.Value;
if (yaml.FirstOrDefault( x => x.Key == "TileSize" ) != null)
TileSize = int.Parse(yaml.First( x => x.Key == "TileSize" ).Value.Value);
}
static string[] YamlList(List<MiniYamlNode> ys, string key)

View File

@@ -17,15 +17,15 @@ namespace OpenRA.FileFormats
{
public readonly List<byte[]> TileBitmapBytes = new List<byte[]>();
public Terrain( Stream stream )
public Terrain( Stream stream, int size )
{
// Try loading as a cnc .tem
BinaryReader reader = new BinaryReader( stream );
int Width = reader.ReadUInt16();
int Height = reader.ReadUInt16();
if( Width != 24 || Height != 24 )
throw new InvalidDataException( string.Format( "{0}x{1}", Width, Height ) );
if( Width != size || Height != size )
throw new InvalidDataException( "{0}x{1} != {2}x{2}".F(Width, Height, size ) );
/*NumTiles = */reader.ReadUInt16();
/*Zero1 = */reader.ReadUInt16();
@@ -46,9 +46,7 @@ namespace OpenRA.FileFormats
reader = new BinaryReader( stream );
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
if( Width != 24 || Height != 24 )
throw new InvalidDataException( string.Format( "{0}x{1}", Width, Height ) );
/*NumTiles = */reader.ReadUInt16();
reader.ReadUInt16();
/*XDim = */reader.ReadUInt16();
@@ -67,8 +65,8 @@ namespace OpenRA.FileFormats
{
if (b != 255)
{
stream.Position = ImgStart + b * 24 * 24;
TileBitmapBytes.Add(new BinaryReader(stream).ReadBytes(24 * 24));
stream.Position = ImgStart + b * size * size;
TileBitmapBytes.Add(new BinaryReader(stream).ReadBytes(size * size));
}
else
TileBitmapBytes.Add(null);

View File

@@ -74,11 +74,12 @@ namespace OpenRA.FileFormats
public string Name;
public string Id;
public string Palette;
public int TileSize = 24;
public string[] Extensions;
public Dictionary<string, TerrainTypeInfo> Terrain = new Dictionary<string, TerrainTypeInfo>();
public Dictionary<ushort, Terrain> Tiles = new Dictionary<ushort, Terrain>();
public Dictionary<ushort, TileTemplate> Templates = new Dictionary<ushort, TileTemplate>();
static List<string> fields = new List<string>() {"Name", "Id", "Palette", "Extensions"};
static List<string> fields = new List<string>() {"Name", "TileSize", "Id", "Palette", "Extensions"};
public TileSet() {}
public TileSet( string filepath )
@@ -103,20 +104,13 @@ namespace OpenRA.FileFormats
using( Stream s = FileSystem.OpenWithExts(t.Value.Image, Extensions) )
{
if( !Tiles.ContainsKey( t.Key ) )
Tiles.Add( t.Key, new Terrain( s ) );
Tiles.Add( t.Key, new Terrain( s, TileSize ) );
}
}
public void Save(string filepath)
{
var root = new List<MiniYamlNode>();
foreach (var field in fields)
{
FieldInfo f = this.GetType().GetField(field);
if (f.GetValue(this) == null) continue;
root.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) );
}
var gen = new List<MiniYamlNode>();
foreach (var field in fields)
{
@@ -144,7 +138,7 @@ namespace OpenRA.FileFormats
if( Tiles.TryGetValue( r.type, out tile ) )
return tile.TileBitmapBytes[ r.image ];
byte[] missingTile = new byte[ 24 * 24 ];
byte[] missingTile = new byte[ TileSize * TileSize ];
for( int i = 0 ; i < missingTile.Length ; i++ )
missingTile[ i ] = 0x36;

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</ProjectGuid>
<OutputType>Library</OutputType>

View File

@@ -8,11 +8,8 @@
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System;
namespace OpenRA.FileFormats
{
@@ -57,6 +54,7 @@ namespace OpenRA.FileFormats
colors[0] = 0;
if (remapTransparent)
{
colors[1] = 178u << 24; // Hack for d2k; may have side effects
colors[3] = 178u << 24;
colors[4] = 140u << 24;
}

View File

@@ -15,15 +15,16 @@ using System.Linq;
namespace OpenRA.FileFormats
{
// TODO: ship this out of here.
public enum PaletteFormat { ra, cnc, d2k }
public class PlayerColorRemap : IPaletteRemap
{
Dictionary<int, Color> remapColors;
public PlayerColorRemap(Color c1, Color c2, bool useSplitRamp)
public PlayerColorRemap(Color c1, Color c2, PaletteFormat fmt)
{
var baseIndex = useSplitRamp ? 0xb0 : 80;
var ramp = useSplitRamp
var baseIndex = (fmt == PaletteFormat.cnc) ? 0xb0 : (fmt == PaletteFormat.d2k) ? 240 : 80;
var ramp = (fmt == PaletteFormat.cnc)
? new[] { 0, 2, 4, 6, 8, 10, 13, 15, 1, 3, 5, 7, 9, 11, 12, 14 }
: new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
@@ -45,5 +46,34 @@ namespace OpenRA.FileFormats
return remapColors.TryGetValue(index, out c)
? c : original;
}
// hk is hue in the range [0,1] instead of [0,360]
public static Color ColorFromHSL(float hk, float s, float l)
{
// Convert from HSL to RGB
var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s);
var p = 2 * l - q;
float[] trgb = { hk + 1 / 3.0f,
hk,
hk - 1/3.0f };
float[] rgb = { 0, 0, 0 };
for (int k = 0; k < 3; k++)
{
while (trgb[k] < 0) trgb[k] += 1.0f;
while (trgb[k] > 1) trgb[k] -= 1.0f;
}
for (int k = 0; k < 3; k++)
{
if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); }
else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; }
else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); }
else { rgb[k] = p; }
}
return Color.FromArgb((int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255));
}
}
}

View File

@@ -25,6 +25,7 @@ namespace OpenRA
public static int2 operator -(int2 a, int2 b) { return new int2(a.X - b.X, a.Y - b.Y); }
public static int2 operator *(int a, int2 b) { return new int2(a * b.X, a * b.Y); }
public static int2 operator *(int2 b, int a) { return new int2(a * b.X, a * b.Y); }
public static int2 operator /(int2 a, int b) { return new int2(a.X / b, a.Y / b); }
public static bool operator ==(int2 me, int2 other) { return (me.X == other.X && me.Y == other.Y); }
public static bool operator !=(int2 me, int2 other) { return !(me == other); }
@@ -59,5 +60,15 @@ namespace OpenRA
{
return (uint)((orig & 0xff000000) >> 24) | ((orig & 0x00ff0000) >> 8) | ((orig & 0x0000ff00) << 8) | ((orig & 0x000000ff) << 24);
}
public static int Lerp( int a, int b, int mul, int div )
{
return a + ( b - a ) * mul / div;
}
public static int2 Lerp( int2 a, int2 b, int mul, int div )
{
return a + ( b - a ) * mul / div;
}
}
}

View File

@@ -18,6 +18,8 @@ namespace OpenRA.Thirdparty
{
uint[] mt = new uint[624];
int index = 0;
public int Last;
public Random() : this(Environment.TickCount) { }
@@ -39,7 +41,8 @@ namespace OpenRA.Thirdparty
y ^= y >> 18;
index = (index + 1) % 624;
return (int)(y % int.MaxValue);
Last = (int)(y % int.MaxValue);
return Last;
}
public int Next(int low, int high) { return low + Next() % (high - low); }

View File

@@ -6,15 +6,15 @@
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Traits;
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Support;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA
@@ -26,7 +26,8 @@ namespace OpenRA
public readonly World World;
public readonly uint ActorID;
public int2 Location { get { return Trait<IOccupySpace>().TopLeft; } }
public int2 Location { get { return Trait<IOccupySpace>().TopLeft; } }
public float2 CenterLocation { get { return Trait<IHasLocation>().PxPosition; } }
[Sync]
public Player Owner;
@@ -52,9 +53,6 @@ namespace OpenRA
AddTrait(trait.Create(init));
}
if( CenterLocation == float2.Zero && HasTrait<IOccupySpace>() )
CenterLocation = Traits.Util.CenterOfCell(Location);
Size = Lazy.New(() =>
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
@@ -74,8 +72,13 @@ namespace OpenRA
while (currentActivity != null)
{
var a = currentActivity;
var sw = new Stopwatch();
currentActivity = a.Tick(this) ?? new Idle();
var dt = sw.ElapsedTime();
if(dt > Game.Settings.Debug.LongTickThreshold)
Log.Write("perf", "[{2}] Activity: {0} ({1:0.000} ms)", a, dt * 1000, Game.LocalTick);
if (a == currentActivity) break;
if (currentActivity is Idle)
@@ -94,8 +97,6 @@ namespace OpenRA
get { return currentActivity == null || currentActivity is Idle; }
}
public float2 CenterLocation;
OpenRA.FileFormats.Lazy<float2> Size;
public IEnumerable<Renderable> Render()
@@ -105,23 +106,6 @@ namespace OpenRA
return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
}
public Order Order( int2 xy, MouseInput mi, Actor underCursor )
{
if (Owner != World.LocalPlayer)
return null;
if (!World.Map.IsInMap(xy.X, xy.Y))
return null;
if (Destroyed)
return null;
return TraitsImplementing<IIssueOrder>()
.OrderByDescending( x => x.OrderPriority( this, xy, mi, underCursor ) )
.Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
.FirstOrDefault( x => x != null );
}
public RectangleF GetBounds(bool useAltitude)
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
@@ -146,16 +130,9 @@ namespace OpenRA
public void QueueActivity( IActivity nextActivity )
{
if( currentActivity == null )
{
currentActivity = nextActivity;
return;
}
var act = currentActivity;
while( act.NextActivity != null )
{
act = act.NextActivity;
}
act.NextActivity = nextActivity;
else
currentActivity.Queue( nextActivity );
}
public void CancelActivity()

View File

@@ -20,9 +20,9 @@ namespace OpenRA
sequence = CursorProvider.GetCursorSequence(cursor);
}
public void Draw(int frame, float2 pos)
public void Draw(WorldRenderer wr, int frame, float2 pos)
{
Game.Renderer.SpriteRenderer.DrawSprite(sequence.GetSprite(frame), pos - sequence.Hotspot, sequence.Palette);
sequence.GetSprite(frame).DrawAt(wr, pos - sequence.Hotspot, sequence.Palette);
}
}
}

View File

@@ -40,7 +40,7 @@ namespace OpenRA.Effects
public IEnumerable<Renderable> Render()
{
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow");
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow", (int)pos.Y);
}
}
}

22
OpenRA.Game/Exts.cs Normal file → Executable file
View File

@@ -34,17 +34,17 @@ namespace OpenRA
return xs.Aggregate(1f, (a, x) => a * x);
}
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k )
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k)
where V : new()
{
return d.GetOrAdd( k, _ => new V() );
return d.GetOrAdd(k, _ => new V());
}
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k, Func<K, V> createFn )
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k, Func<K, V> createFn)
{
V ret;
if( !d.TryGetValue( k, out ret ) )
d.Add( k, ret = createFn( k ) );
if (!d.TryGetValue(k, out ret))
d.Add(k, ret = createFn(k));
return ret;
}
@@ -54,18 +54,18 @@ namespace OpenRA
return xs[r.Next(xs.Length)];
}
public static void DoTimed<T>( this IEnumerable<T> e, Action<T> a, string text, double time )
public static void DoTimed<T>(this IEnumerable<T> e, Action<T> a, string text, double time)
{
var sw = new Stopwatch();
e.Do( x =>
e.Do(x =>
{
var t = sw.ElapsedTime();
a( x );
a(x);
var dt = sw.ElapsedTime() - t;
if( dt > time )
Log.Write("perf", text, x, dt * 1000);
} );
if (dt > time)
Log.Write("perf", text, x, dt * 1000, Game.LocalTick);
});
}
}
}

View File

@@ -6,33 +6,33 @@
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
#endregion
using System;
using System.Drawing;
using System.IO;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Traits;
using OpenRA.Widgets;
using Timer = OpenRA.Support.Timer;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Widgets;
using XRandom = OpenRA.Thirdparty.Random;
namespace OpenRA
{
public static class Game
{
public static readonly int CellSize = 24;
public static int CellSize { get { return modData.Manifest.TileSize; } }
public static ModData modData;
public static World world;
private static WorldRenderer worldRenderer;
public static Viewport viewport;
public static Settings Settings;
@@ -41,37 +41,25 @@ namespace OpenRA
public static XRandom CosmeticRandom = new XRandom(); // not synced
public static Renderer Renderer;
public static Session LobbyInfo = new Session();
public static bool HasInputFocus = false;
static void LoadMap(string uid)
{
var map = modData.PrepareMap(uid);
viewport = new Viewport(new float2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer);
world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
world = new World(modData.Manifest, map);
}
public static void MoveViewport(int2 loc)
{
viewport.Center(loc);
}
internal static string CurrentHost = "";
internal static int CurrentPort = 0;
internal static void JoinServer(string host, int port)
{
if (orderManager != null) orderManager.Dispose();
CurrentHost = host;
CurrentPort = port;
var replayFilename = ChooseReplayFilename();
string path = Path.Combine( Game.SupportDir, "Replays" );
if( !Directory.Exists( path ) ) Directory.CreateDirectory( path );
var replayFile = File.Create( Path.Combine( path, replayFilename ) );
orderManager = new OrderManager( host, port, new ReplayRecorderConnection( new NetworkConnection( host, port ), replayFile ) );
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged();
orderManager = new OrderManager(new NetworkConnection(host, port), ChooseReplayFilename());
ConnectionStateChanged(orderManager);
}
static string ChooseReplayFilename()
@@ -81,71 +69,36 @@ namespace OpenRA
static void JoinLocal()
{
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged();
if (orderManager != null) orderManager.Dispose();
orderManager = new OrderManager(new EchoConnection());
}
static int lastTime = Environment.TickCount;
static void ResetTimer()
{
lastTime = Environment.TickCount;
orderManager = new OrderManager("<no server>", -1, new EchoConnection());
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged( orderManager );
}
internal static int RenderFrame = 0;
internal static int LocalTick = 0;
internal static int LocalTick { get { return orderManager.LocalFrameNumber; } }
const int NetTickScale = 3; // 120ms net tick for 40ms local tick
public static event Action ConnectionStateChanged = () => { };
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
internal static event Action<OrderManager> ConnectionStateChanged = _ => { };
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } }
static void Tick()
static void Tick( OrderManager orderManager, Viewport viewPort )
{
if (orderManager.Connection.ConnectionState != lastConnectionState)
{
lastConnectionState = orderManager.Connection.ConnectionState;
ConnectionStateChanged();
}
int t = Environment.TickCount;
int dt = t - lastTime;
if (dt >= Settings.Game.Timestep)
if (orderManager.Connection.ConnectionState != lastConnectionState)
{
using (new PerfSample("tick_time"))
{
lastTime += Settings.Game.Timestep;
Widget.DoTick(world);
Sound.Tick();
orderManager.TickImmediate(world);
var isNetTick = LocalTick % NetTickScale == 0;
if (!isNetTick || orderManager.IsReadyForNextFrame)
{
++LocalTick;
if (isNetTick) orderManager.Tick(world);
world.OrderGenerator.Tick(world);
world.Selection.Tick(world);
world.Tick();
PerfHistory.Tick();
}
else
if (orderManager.FrameNumber == 0)
lastTime = Environment.TickCount;
}
lastConnectionState = orderManager.Connection.ConnectionState;
ConnectionStateChanged( orderManager );
}
Tick( orderManager );
if( orderManager.world != worldRenderer.world )
Tick( worldRenderer.world.orderManager );
using (new PerfSample("render"))
{
++RenderFrame;
viewport.DrawRegions(world);
viewport.DrawRegions(worldRenderer);
Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height));
}
@@ -157,64 +110,85 @@ namespace OpenRA
MasterServerQuery.Tick();
}
private static void Tick( OrderManager orderManager )
{
int t = Environment.TickCount;
int dt = t - orderManager.LastTickTime;
if (dt >= Settings.Game.Timestep)
using( new PerfSample( "tick_time" ) )
{
orderManager.LastTickTime += Settings.Game.Timestep;
Widget.DoTick();
var world = orderManager.world;
if( orderManager.GameStarted && world.LocalPlayer != null )
++Viewport.TicksSinceLastMove;
Sound.Tick();
Sync.CheckSyncUnchanged( world, () => { orderManager.TickImmediate(); } );
var isNetTick = LocalTick % NetTickScale == 0;
if( !isNetTick || orderManager.IsReadyForNextFrame )
{
++orderManager.LocalFrameNumber;
Log.Write( "debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local" );
if( isNetTick ) orderManager.Tick();
world.OrderGenerator.Tick( world );
world.Selection.Tick( world );
world.Tick();
worldRenderer.Tick();
PerfHistory.Tick();
}
else
if( orderManager.NetFrameNumber == 0 )
orderManager.LastTickTime = Environment.TickCount;
}
}
internal static event Action LobbyInfoChanged = () => { };
internal static void SyncLobbyInfo(string data)
internal static void SyncLobbyInfo()
{
LobbyInfo = Session.Deserialize(data);
if( !world.GameHasStarted )
world.SharedRandom = new XRandom( LobbyInfo.GlobalSettings.RandomSeed );
if (orderManager.Connection.ConnectionState == ConnectionState.Connected)
world.SetLocalPlayer(orderManager.Connection.LocalClientId);
if (orderManager.FramesAhead != LobbyInfo.GlobalSettings.OrderLatency
&& !orderManager.GameStarted)
{
orderManager.FramesAhead = LobbyInfo.GlobalSettings.OrderLatency;
Debug("Order lag is now {0} frames.".F(LobbyInfo.GlobalSettings.OrderLatency));
}
LobbyInfoChanged();
}
public static void IssueOrder(Order o) { orderManager.IssueOrder(o); } /* avoid exposing the OM to mod code */
public static event Action AfterGameStart = () => {};
public static event Action<World> AfterGameStart = _ => {};
public static event Action BeforeGameStart = () => {};
internal static void StartGame(string map)
internal static void StartGame(string mapUID)
{
BeforeGameStart();
LoadMap(map);
if (orderManager.GameStarted) return;
Widget.SelectedWidget = null;
orderManager.StartGame();
viewport.RefreshPalette();
AfterGameStart();
var map = modData.PrepareMap(mapUID);
viewport = new Viewport(new float2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer);
orderManager.world = new World(modData.Manifest, map, orderManager);
worldRenderer = new WorldRenderer(orderManager.world);
if (orderManager.GameStarted) return;
Widget.SelectedWidget = null;
orderManager.LocalFrameNumber = 0;
orderManager.StartGame();
worldRenderer.RefreshPalette();
AfterGameStart( orderManager.world );
}
public static void DispatchMouseInput(MouseInputEvent ev, MouseEventArgs e, Modifiers modifierKeys)
{
if (world == null)
return;
int sync = world.SyncHash();
var initialWorld = world;
var mi = new MouseInput
Sync.CheckSyncUnchanged( orderManager.world, () =>
{
Button = (MouseButton)(int)e.Button,
Event = ev,
Location = new int2(e.Location),
Modifiers = modifierKeys,
};
Widget.HandleInput(world, mi);
if (sync != world.SyncHash() && world == initialWorld)
throw new InvalidOperationException("Desync in DispatchMouseInput");
var mi = new MouseInput
{
Button = (MouseButton)(int)e.Button,
Event = ev,
Location = new int2( e.Location ),
Modifiers = modifierKeys,
};
Widget.HandleInput( mi );
} );
}
public static bool IsHost
@@ -222,23 +196,12 @@ namespace OpenRA
get { return orderManager.Connection.LocalClientId == 0; }
}
internal static Session.Client LocalClient
{
get { return LobbyInfo.Clients.FirstOrDefault(c => c.Index == orderManager.Connection.LocalClientId); }
}
public static void HandleKeyEvent(KeyInput e)
{
if (world == null)
return;
int sync = world.SyncHash();
if (Widget.HandleKeyPress(e))
return;
if (sync != Game.world.SyncHash())
throw new InvalidOperationException("Desync in OnKeyPress");
Sync.CheckSyncUnchanged( orderManager.world, () =>
{
Widget.HandleKeyPress( e );
} );
}
static Modifiers modifiers;
@@ -247,37 +210,83 @@ namespace OpenRA
internal static void Initialize(Arguments args)
{
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
var defaultSupport = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
+ Path.DirectorySeparatorChar + "OpenRA";
SupportDir = args.GetValue("SupportDir", defaultSupport);
Settings = new Settings(SupportDir + "settings.yaml", args);
Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar;
Log.AddChannel("perf", "perf.log");
Log.AddChannel("debug", "debug.log");
Log.AddChannel("sync", "syncreport.log");
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
var defaultSupport = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
+ Path.DirectorySeparatorChar + "OpenRA";
SupportDir = args.GetValue("SupportDir", defaultSupport);
Settings = new Settings(SupportDir + "settings.yaml", args);
// force master server upgrade -- remove once everyone is switched over.
if (Settings.Server.MasterServer == "http://open-ra.org/master/")
Settings.Server.MasterServer = "http://master.open-ra.org/";
Settings.Save();
Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar;
Log.AddChannel("perf", "perf.log");
Log.AddChannel("debug", "debug.log");
Log.AddChannel("sync", "syncreport.log");
FileSystem.Mount("."); // Needed to access shaders
Renderer.Initialize( Game.Settings.Graphics.Mode );
Renderer.SheetSize = Settings.Game.SheetSize;
Renderer = new Renderer();
LobbyInfo.GlobalSettings.Mods = Settings.Game.Mods;
modData = new ModData( LobbyInfo.GlobalSettings.Mods );
Console.WriteLine("Available mods:");
foreach(var mod in ModData.AllMods)
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
// Discard any invalid mods
var mods = Settings.Game.Mods.Where( m => ModData.AllMods.ContainsKey( m ) ).ToArray();
Console.WriteLine("Loading mods: {0}",string.Join(",",mods));
modData = new ModData( mods );
Sound.Initialize();
PerfHistory.items["render"].hasNormalTick = false;
PerfHistory.items["batches"].hasNormalTick = false;
PerfHistory.items["text"].hasNormalTick = false;
PerfHistory.items["cursor"].hasNormalTick = false;
PerfHistory.items["cursor"].hasNormalTick = false;
JoinLocal();
StartGame(modData.Manifest.ShellmapUid);
Game.AfterGameStart += world => Widget.OpenWindow("INGAME_ROOT", new Dictionary<string,object>{{"world", world},{"orderManager",orderManager}});
Game.ConnectionStateChanged += orderManager =>
{
Widget.CloseWindow();
switch( orderManager.Connection.ConnectionState )
{
case ConnectionState.PreConnecting:
Widget.OpenWindow("MAINMENU_BG");
break;
case ConnectionState.Connecting:
Widget.OpenWindow( "CONNECTING_BG",
new Dictionary<string, object> { { "host", orderManager.Host }, { "port", orderManager.Port } } );
break;
case ConnectionState.NotConnected:
Widget.OpenWindow( "CONNECTION_FAILED_BG",
new Dictionary<string, object> { { "host", orderManager.Host }, { "port", orderManager.Port } } );
break;
case ConnectionState.Connected:
var lobby = Widget.OpenWindow( "SERVER_LOBBY", new Dictionary<string, object> { { "orderManager", orderManager } } );
lobby.GetWidget<ChatDisplayWidget>("CHAT_DISPLAY").ClearChat();
lobby.GetWidget("CHANGEMAP_BUTTON").Visible = true;
lobby.GetWidget("LOCKTEAMS_CHECKBOX").Visible = true;
lobby.GetWidget("DISCONNECT_BUTTON").Visible = true;
//r.GetWidget("INGAME_ROOT").GetWidget<ChatDisplayWidget>("CHAT_DISPLAY").ClearChat();
break;
}
};
modData.WidgetLoader.LoadWidget( new Dictionary<string,object>(), Widget.RootWidget, "PERF_BG" );
Widget.OpenWindow("MAINMENU_BG");
Game.orderManager.LastTickTime = Environment.TickCount;
}
static bool quit;
@@ -285,50 +294,48 @@ namespace OpenRA
{
while (!quit)
{
{
Tick( orderManager, viewport );
Application.DoEvents();
}
}
public static void Exit() { quit = true; }
public static void Exit() { quit = true; }
public static Action<Color,string,string> AddChatLine = (c,n,s) => {};
public static void Debug(string s)
{
public static void Debug(string s, params object[] args)
{
AddChatLine(Color.White, "Debug", String.Format(s,args));
}
public static void Disconnect()
{
orderManager.Dispose();
var shellmap = modData.Manifest.ShellmapUid;
var shellmap = modData.Manifest.ShellmapUid;
LobbyInfo = new Session();
JoinLocal();
StartGame(shellmap);
Widget.RootWidget.CloseWindow();
Widget.RootWidget.OpenWindow("MAINMENU_BG");
}
static string baseSupportDir = null;
public static string SupportDir
{
set
{
var dir = value;
// Expand paths relative to the personal directory
if (dir.ElementAt(0) == '~')
dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + dir.Substring(1);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
Widget.CloseWindow();
Widget.OpenWindow("MAINMENU_BG");
}
static string baseSupportDir = null;
public static string SupportDir
{
set
{
var dir = value;
// Expand paths relative to the personal directory
if (dir.ElementAt(0) == '~')
dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + dir.Substring(1);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
baseSupportDir = dir + Path.DirectorySeparatorChar;
}
}
get { return baseSupportDir; }
}
public static T CreateObject<T>( string name )
@@ -336,4 +343,4 @@ namespace OpenRA
return modData.ObjectCreator.CreateObject<T>( name );
}
}
}
}

View File

@@ -18,8 +18,6 @@ namespace OpenRA
{
public static class Rules
{
public static TechTree TechTree;
public static Dictionary<string, ActorInfo> Info;
public static Dictionary<string, WeaponInfo> Weapons;
public static Dictionary<string, VoiceInfo> Voices;
@@ -41,8 +39,6 @@ namespace OpenRA
var t = new TileSet(file);
TileSets.Add(t.Id,t);
}
TechTree = new TechTree();
}
static Dictionary<string, T> LoadYamlRules<T>(string[] files, List<MiniYamlNode> dict, Func<MiniYamlNode, Dictionary<string, MiniYaml>, T> f)

View File

@@ -8,13 +8,13 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
using System;
namespace OpenRA.GameRules
{
@@ -24,7 +24,7 @@ namespace OpenRA.GameRules
public int ListenPort = 1234;
public int ExternalPort = 1234;
public bool AdvertiseOnline = true;
public string MasterServer = "http://open-ra.org/master/";
public string MasterServer = "http://master.open-ra.org/";
public bool AllowCheats = false;
}
@@ -33,6 +33,7 @@ namespace OpenRA.GameRules
public bool PerfGraph = false;
public bool RecordSyncReports = true;
public bool ShowCollisions = false;
public float LongTickThreshold = 0.001f;
}
public class GraphicSettings
@@ -68,6 +69,7 @@ namespace OpenRA.GameRules
// Behaviour settings
public bool ViewportEdgeScroll = true;
public bool InverseDragScroll = false;
public float ViewportEdgeScrollStep = 10f;
// Internal game settings
public int Timestep = 40;
@@ -105,12 +107,12 @@ namespace OpenRA.GameRules
FieldLoader.UnknownFieldAction = (s,f) =>
{
System.Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
};
if (File.Exists(SettingsFile))
{
System.Console.WriteLine("Loading settings file {0}",SettingsFile);
Console.WriteLine("Loading settings file {0}",SettingsFile);
var yaml = MiniYaml.DictFromFile(SettingsFile);
foreach (var kv in Sections)
@@ -122,7 +124,7 @@ namespace OpenRA.GameRules
foreach (var kv in Sections)
foreach (var f in kv.Value.GetType().GetFields())
if (args.Contains(kv.Key+"."+f.Name))
OpenRA.FileFormats.FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
FieldLoader.UnknownFieldAction = err1;
FieldLoader.InvalidValueAction = err2;
@@ -132,16 +134,11 @@ namespace OpenRA.GameRules
{
var root = new List<MiniYamlNode>();
foreach( var kv in Sections )
root.Add( new MiniYamlNode( kv.Key, SectionYaml( kv.Value ) ) );
root.Add( new MiniYamlNode( kv.Key, FieldSaver.SaveDifferences(kv.Value, Activator.CreateInstance(kv.Value.GetType())) ) );
root.WriteToFile(SettingsFile);
}
MiniYaml SectionYaml(object section)
{
return FieldSaver.SaveDifferences(section, Activator.CreateInstance(section.GetType()));
}
void LoadSectionYaml(MiniYaml yaml, object section)
{
object defaults = Activator.CreateInstance(section.GetType());

View File

@@ -1,100 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.GameRules
{
public class TechTree
{
readonly Cache<string, List<ActorInfo>> producesIndex = new Cache<string, List<ActorInfo>>(x => new List<ActorInfo>());
public TechTree()
{
foreach( var info in Rules.Info.Values )
{
var pi = info.Traits.GetOrDefault<ProductionInfo>();
if (pi != null)
foreach( var p in pi.Produces )
producesIndex[ p ].Add( info );
}
}
public Cache<string, List<Actor>> GatherBuildings( Player player )
{
var ret = new Cache<string, List<Actor>>( x => new List<Actor>() );
if (player == null)
return ret;
foreach( var b in player.World.Queries.OwnedBy[player].Where( x=>x.Info.Traits.Contains<BuildingInfo>() ) )
{
ret[ b.Info.Name ].Add( b );
var tt = b.Info.Traits.GetOrDefault<TooltipInfo>();
if( tt != null )
foreach( var alt in tt.AlternateName )
ret[ alt ].Add( b );
}
return ret;
}
public bool CanBuild( ActorInfo info, Player player, Cache<string, List<Actor>> playerBuildings )
{
if (player == null)
return false;
var bi = info.Traits.GetOrDefault<BuildableInfo>();
if( bi == null ) return false;
if( !bi.Owner.Contains( player.Country.Race ) )
return false;
foreach( var p in bi.Prerequisites )
if( playerBuildings[ p ].Count == 0 )
return false;
if( producesIndex[ bi.Queue ].All( x => playerBuildings[ x.Name ].Count == 0 ) )
return false;
return true;
}
public IEnumerable<string> BuildableItems( Player player, params string[] categories )
{
if (player == null)
yield break;
var playerBuildings = GatherBuildings( player );
foreach (var unit in AllBuildables(categories))
if( CanBuild( unit, player, playerBuildings ) )
yield return unit.Name;
}
public IEnumerable<ActorInfo> AllBuildables(params string[] categories)
{
return Rules.Info.Values
.Where( x => x.Name[ 0 ] != '^' )
.Where( x => x.Traits.Contains<BuildableInfo>() )
.Where( x => categories.Contains(x.Traits.Get<BuildableInfo>().Queue) );
}
public IEnumerable<ActorInfo> UnitBuiltAt( ActorInfo info )
{
var bi = info.Traits.Get<BuildableInfo>();
var builtAt = bi.BuiltAt;
if( builtAt.Length != 0 )
return builtAt.Select( x => Rules.Info[ x.ToLowerInvariant() ] );
else
return producesIndex[ bi.Queue ];
}
}
}

View File

@@ -31,7 +31,7 @@ namespace OpenRA.GameRules
: new Dictionary<string, string[]>();
}
public readonly Lazy<Dictionary<string, VoicePool>> Pools;
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, VoicePool>> Pools;
public VoiceInfo( MiniYaml y )
{
@@ -41,6 +41,9 @@ namespace OpenRA.GameRules
if (!Voices.ContainsKey("Attack"))
Voices.Add("Attack", Voices["Move"]);
if (!Voices.ContainsKey("AttackMove"))
Voices.Add("AttackMove", Voices["Move"]);
Pools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new VoicePool(a.Value) ));
}

View File

@@ -32,6 +32,7 @@ namespace OpenRA.GameRules
[FieldLoader.Load] public readonly int Damage = 0; // how much (raw) damage to deal
[FieldLoader.Load] public readonly int Delay = 0; // delay in ticks before dealing the damage. 0=instant (old model)
[FieldLoader.Load] public readonly DamageModel DamageModel = DamageModel.Normal; // which damage model to use
[FieldLoader.Load] public readonly bool PreventProne = false; // whether we should prevent prone response in infantry.
public float EffectivenessAgainst(Actor self)
{
@@ -92,6 +93,7 @@ namespace OpenRA.GameRules
[FieldLoader.Load] public readonly bool Underwater = false;
[FieldLoader.Load] public readonly string[] ValidTargets = { "Ground" };
[FieldLoader.Load] public readonly int BurstDelay = 5;
[FieldLoader.Load] public readonly float MinRange = 0;
[FieldLoader.LoadUsing( "LoadProjectile" )] public IProjectileInfo Projectile;
[FieldLoader.LoadUsing( "LoadWarheads" )] public List<WarheadInfo> Warheads;

View File

@@ -13,45 +13,46 @@ using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public class LineRenderer
public class LineRenderer : Renderer.IBatchRenderer
{
Renderer renderer;
IVertexBuffer<Vertex> vertexBuffer;
IIndexBuffer indexBuffer; /* kindof a waste of space, but the GPU likes indexing, oh well */
const int linesPerBatch = 1024;
Vertex[] vertices = new Vertex[ 2 * linesPerBatch ];
ushort[] indices = new ushort[ 2 * linesPerBatch ];
int lines = 0;
Vertex[] vertices = new Vertex[ Renderer.TempBufferSize ];
ushort[] indices = new ushort[ Renderer.TempBufferSize ];
int nv = 0, ni = 0;
public LineRenderer( Renderer renderer )
{
this.renderer = renderer;
vertexBuffer = renderer.Device.CreateVertexBuffer(vertices.Length );
indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length );
}
public void Flush()
{
if( lines > 0 )
if( ni > 0 )
{
renderer.LineShader.Render( () =>
{
vertexBuffer.SetData( vertices );
indexBuffer.SetData( indices );
renderer.DrawBatch( vertexBuffer, indexBuffer,
var vb = renderer.GetTempVertexBuffer();
var ib = renderer.GetTempIndexBuffer();
vb.SetData( vertices, nv );
ib.SetData( indices, ni );
renderer.DrawBatch( vb, ib,
nv, ni / 2, PrimitiveType.LineList );
} );
nv = 0; ni = 0;
lines = 0;
}
}
public void DrawLine( float2 start, float2 end, Color startColor, Color endColor )
{
Renderer.CurrentBatchRenderer = this;
if( ni + 2 > Renderer.TempBufferSize )
Flush();
if( nv + 2 > Renderer.TempBufferSize )
Flush();
indices[ ni++ ] = (ushort)nv;
vertices[ nv++ ] = new Vertex( start,
@@ -63,9 +64,6 @@ namespace OpenRA.Graphics
vertices[ nv++ ] = new Vertex( end,
new float2( endColor.R / 255.0f, endColor.G / 255.0f ),
new float2( endColor.B / 255.0f, endColor.A / 255.0f ) );
if( ++lines >= linesPerBatch )
Flush();
}
public void FillRect( RectangleF r, Color color )

View File

@@ -14,16 +14,29 @@ using System.Drawing.Imaging;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
using System.IO;
namespace OpenRA.Graphics
{
public class Minimap
{
public static Bitmap TerrainBitmap(Map map)
{
return TerrainBitmap(map, false);
}
public static Bitmap TerrainBitmap(Map map, bool actualSize)
{
var tileset = Rules.TileSets[map.Tileset];
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
Bitmap terrain = new Bitmap(size, size);
var width = map.Width;
var height = map.Height;
if (!actualSize)
{
width = height = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
}
Bitmap terrain = new Bitmap(width, height);
var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
@@ -38,6 +51,9 @@ namespace OpenRA.Graphics
var mapX = x + map.TopLeft.X;
var mapY = y + map.TopLeft.Y;
var type = tileset.GetTerrainType(map.MapTiles[mapX, mapY]);
if (!tileset.Terrain.ContainsKey(type))
throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type));
*(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[type].Color.ToArgb();
}
}

View File

@@ -16,6 +16,7 @@ using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
using OpenRA.Support;
using System.Windows.Forms;
using System.Collections.Generic;
namespace OpenRA.Graphics
{
@@ -23,10 +24,10 @@ namespace OpenRA.Graphics
{
internal static int SheetSize;
public IShader SpriteShader { get; private set; } /* note: shared shader params */
public IShader LineShader { get; private set; }
public IShader RgbaSpriteShader { get; private set; }
public IShader WorldSpriteShader { get; private set; }
internal IShader SpriteShader { get; private set; } /* note: shared shader params */
internal IShader LineShader { get; private set; }
internal IShader RgbaSpriteShader { get; private set; }
internal IShader WorldSpriteShader { get; private set; }
public SpriteRenderer SpriteRenderer { get; private set; }
public SpriteRenderer RgbaSpriteRenderer { get; private set; }
@@ -37,6 +38,12 @@ namespace OpenRA.Graphics
public readonly SpriteFont RegularFont, BoldFont, TitleFont;
internal const int TempBufferSize = 8192;
const int TempBufferCount = 8;
Queue<IVertexBuffer<Vertex>> tempBuffersV = new Queue<IVertexBuffer<Vertex>>();
Queue<IIndexBuffer> tempBuffersI = new Queue<IIndexBuffer>();
public Renderer()
{
SpriteShader = device.CreateShader(FileSystem.Open("shaders/world-shp.fx"));
@@ -52,9 +59,15 @@ namespace OpenRA.Graphics
RegularFont = new SpriteFont("FreeSans.ttf", 14);
BoldFont = new SpriteFont("FreeSansBold.ttf", 14);
TitleFont = new SpriteFont("titles.ttf", 48);
for( int i = 0 ; i < TempBufferCount ; i++ )
{
tempBuffersV.Enqueue( device.CreateVertexBuffer( TempBufferSize ) );
tempBuffersI.Enqueue( device.CreateIndexBuffer( TempBufferSize ) );
}
}
public IGraphicsDevice Device { get { return device; } }
internal IGraphicsDevice Device { get { return device; } }
public void BeginFrame(float2 scroll)
{
@@ -81,6 +94,7 @@ namespace OpenRA.Graphics
public void EndFrame()
{
Flush();
device.End();
device.Present();
}
@@ -111,15 +125,9 @@ namespace OpenRA.Graphics
public void Flush()
{
WorldSpriteRenderer.Flush();
RgbaSpriteRenderer.Flush();
LineRenderer.Flush();
CurrentBatchRenderer = null;
}
static IGraphicsDevice device;
public static Size Resolution { get { return device.WindowSize; } }
@@ -154,5 +162,49 @@ namespace OpenRA.Graphics
}
throw new NotImplementedException();
}
internal IVertexBuffer<Vertex> GetTempVertexBuffer()
{
var ret = tempBuffersV.Dequeue();
tempBuffersV.Enqueue( ret );
return ret;
}
internal IIndexBuffer GetTempIndexBuffer()
{
var ret = tempBuffersI.Dequeue();
tempBuffersI.Enqueue( ret );
return ret;
}
public interface IBatchRenderer
{
void Flush();
}
static IBatchRenderer currentBatchRenderer;
public static IBatchRenderer CurrentBatchRenderer
{
get { return currentBatchRenderer; }
set
{
if( currentBatchRenderer == value ) return;
if( currentBatchRenderer != null )
currentBatchRenderer.Flush();
currentBatchRenderer = value;
}
}
public void EnableScissor(int left, int top, int width, int height)
{
Flush();
Device.EnableScissor( left, top, width, height );
}
public void DisableScissor()
{
Flush();
Device.DisableScissor();
}
}
}

View File

@@ -49,6 +49,21 @@ namespace OpenRA.Graphics
{
return uvhax[ k ];
}
public void DrawAt( WorldRenderer wr, float2 location, string palette )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, wr, palette, this.size );
}
public void DrawAt( float2 location, int paletteIndex )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, this.size );
}
public void DrawAt( float2 location, int paletteIndex, float2 size )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, size );
}
}
public enum TextureChannel

View File

@@ -80,17 +80,20 @@ namespace OpenRA.Graphics
GlyphInfo CreateGlyph(Pair<char,Color> c)
{
var index = FT.FT_Get_Char_Index(face, (uint)c.First);
FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER);
if (0 != FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER))
throw new InvalidOperationException( "FT_Load_Glyph failed." );
var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec));
var _glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(_face.glyph, typeof(FT_GlyphSlotRec));
var s = builder.Allocate(new Size(_glyph.metrics.width >> 6, _glyph.metrics.height >> 6));
var s = builder.Allocate(
new Size(_glyph.metrics.width.ToInt32() >> 6,
_glyph.metrics.height.ToInt32() >> 6));
var g = new GlyphInfo
{
Sprite = s,
Advance = _glyph.metrics.horiAdvance / 64f,
Advance = _glyph.metrics.horiAdvance.ToInt32() / 64f,
Offset = { X = _glyph.bitmap_left, Y = -_glyph.bitmap_top }
};

View File

@@ -12,28 +12,20 @@ using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public class SpriteRenderer
public class SpriteRenderer : Renderer.IBatchRenderer
{
IVertexBuffer<Vertex> vertexBuffer;
IIndexBuffer indexBuffer;
Renderer renderer;
IShader shader;
const int spritesPerBatch = 1024;
Vertex[] vertices = new Vertex[4 * spritesPerBatch];
ushort[] indices = new ushort[6 * spritesPerBatch];
Vertex[] vertices = new Vertex[Renderer.TempBufferSize];
ushort[] indices = new ushort[Renderer.TempBufferSize];
Sheet currentSheet = null;
int sprites = 0;
int nv = 0, ni = 0;
public SpriteRenderer(Renderer renderer, IShader shader)
{
this.renderer = renderer;
this.shader = shader;
vertexBuffer = renderer.Device.CreateVertexBuffer( vertices.Length );
indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length );
}
public SpriteRenderer(Renderer renderer)
@@ -41,14 +33,16 @@ namespace OpenRA.Graphics
public void Flush()
{
if (sprites > 0)
if (ni > 0)
{
shader.SetValue( "DiffuseTexture", currentSheet.Texture );
shader.Render(() =>
{
vertexBuffer.SetData(vertices);
indexBuffer.SetData(indices);
renderer.DrawBatch(vertexBuffer, indexBuffer,
var vb = renderer.GetTempVertexBuffer();
var ib = renderer.GetTempIndexBuffer();
vb.SetData(vertices, nv);
ib.SetData(indices, ni);
renderer.DrawBatch(vb, ib,
new Range<int>(0, nv),
new Range<int>(0, ni),
PrimitiveType.TriangleList,
@@ -57,30 +51,34 @@ namespace OpenRA.Graphics
nv = 0; ni = 0;
currentSheet = null;
sprites = 0;
}
}
public void DrawSprite(Sprite s, float2 location, string palette)
public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette)
{
DrawSprite(s, location, Game.world.WorldRenderer.GetPaletteIndex(palette), s.size);
DrawSprite(s, location, wr.GetPaletteIndex(palette), s.size);
}
public void DrawSprite(Sprite s, float2 location, string palette, float2 size)
public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette, float2 size)
{
DrawSprite(s, location, Game.world.WorldRenderer.GetPaletteIndex(palette), size);
DrawSprite(s, location, wr.GetPaletteIndex(palette), size);
}
public void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size)
{
Renderer.CurrentBatchRenderer = this;
if (s.sheet != currentSheet)
Flush();
if( nv + 4 > Renderer.TempBufferSize )
Flush();
if( ni + 6 > Renderer.TempBufferSize )
Flush();
currentSheet = s.sheet;
Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, paletteIndex, nv, ni, size);
nv += 4; ni += 6;
if (++sprites >= spritesPerBatch)
Flush();
}

View File

@@ -31,7 +31,6 @@ namespace OpenRA.Graphics
this.map = world.Map;
Size tileSize = new Size( Game.CellSize, Game.CellSize );
var tileMapping = new Cache<TileReference<ushort,byte>, Sprite>(
x => Game.modData.SheetBuilder.Add(world.TileSet.GetBytes(x), tileSize));
@@ -47,7 +46,7 @@ namespace OpenRA.Graphics
{
Sprite tile = tileMapping[map.MapTiles[i, j]];
// TODO: The zero below should explicitly refer to the terrain palette, but this code is called
// before the palettes are created
// before the palettes are created. Therefore assumes that "terrain" is the first palette to be defined
Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, 0, nv, ni, tile.size);
nv += 4;
ni += 6;
@@ -57,20 +56,20 @@ namespace OpenRA.Graphics
}
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer( vertices.Length );
vertexBuffer.SetData( vertices );
vertexBuffer.SetData( vertices, nv );
indexBuffer = Game.Renderer.Device.CreateIndexBuffer( indices.Length );
indexBuffer.SetData( indices );
indexBuffer.SetData( indices, ni );
}
public void Draw( Viewport viewport )
public void Draw( WorldRenderer wr, Viewport viewport )
{
int indicesPerRow = map.Width * 6;
int verticesPerRow = map.Width * 4;
int visibleRows = (int)(viewport.Height / 24.0f + 2);
int visibleRows = (int)(viewport.Height * 1f / Game.CellSize + 2);
int firstRow = (int)((viewport.Location.Y) / 24.0f - map.YOffset);
int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.YOffset);
int lastRow = firstRow + visibleRows;
if (lastRow < 0 || firstRow > map.Height)
@@ -99,7 +98,7 @@ namespace OpenRA.Graphics
PrimitiveType.TriangleList, Game.Renderer.SpriteShader));
foreach (var r in world.WorldActor.TraitsImplementing<IRenderOverlay>())
r.Render();
r.Render( wr );
}
}
}

View File

@@ -11,7 +11,6 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Support;
using OpenRA.Traits;
using OpenRA.Widgets;
@@ -96,34 +95,23 @@ namespace OpenRA.Graphics
this.scrollPosition = Game.CellSize* mapStart;
}
public void DrawRegions( World world )
public void DrawRegions( WorldRenderer wr )
{
renderer.BeginFrame(scrollPosition);
world.WorldRenderer.Draw();
wr.Draw();
Widget.DoDraw(world);
Widget.DoDraw( wr );
var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default";
var c = new Cursor(cursorName);
c.Draw((int)cursorFrame, Viewport.LastMousePos + Location);
renderer.RgbaSpriteRenderer.Flush();
renderer.SpriteRenderer.Flush();
renderer.WorldSpriteRenderer.Flush();
c.Draw(wr, (int)cursorFrame, Viewport.LastMousePos + Location);
renderer.EndFrame();
}
public void RefreshPalette()
{
Game.world.WorldRenderer.palette.Update(
Game.world.WorldActor.TraitsImplementing<IPaletteModifier>());
}
public void Tick()
{
cursorFrame += 0.5f;
RefreshPalette();
}
public float2 ViewToWorld(int2 loc)
@@ -151,12 +139,21 @@ namespace OpenRA.Graphics
scrollPosition = this.NormalizeScrollPosition((avgPos - .5f * new float2(Width, Height)));
}
public Rectangle? ShroudBounds()
public Rectangle ShroudBounds( World world )
{
var localPlayer = Game.world.LocalPlayer;
if (localPlayer == null) return null;
if (localPlayer.Shroud.Disabled) return null;
return localPlayer.Shroud.Bounds;
var localPlayer = world.LocalPlayer;
if( localPlayer == null ) return world.Map.Bounds;
if( localPlayer.Shroud.Disabled ) return world.Map.Bounds;
if( !localPlayer.Shroud.Bounds.HasValue ) return world.Map.Bounds;
return Rectangle.Intersect( localPlayer.Shroud.Bounds.Value, world.Map.Bounds );
}
public Rectangle ViewBounds()
{
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
return Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y);
}
}
}

View File

@@ -19,9 +19,9 @@ namespace OpenRA.Graphics
{
public class WorldRenderer
{
readonly World world;
public readonly World world;
internal readonly TerrainRenderer terrainRenderer;
internal readonly UiOverlay uiOverlay;
public readonly UiOverlay uiOverlay;
internal readonly HardwarePalette palette;
internal WorldRenderer(World world)
@@ -31,6 +31,9 @@ namespace OpenRA.Graphics
terrainRenderer = new TerrainRenderer(world, this);
uiOverlay = new UiOverlay();
palette = new HardwarePalette(world.Map);
foreach( var pal in world.traitDict.ActorsWithTraitMultiple<IPalette>( world ) )
pal.Trait.InitPalette( this );
}
public int GetPaletteIndex(string name) { return palette.GetPaletteIndex(name); }
@@ -41,11 +44,7 @@ namespace OpenRA.Graphics
{
public int Compare(Renderable x, Renderable y)
{
var result = x.ZOffset.CompareTo(y.ZOffset);
if (result == 0)
result = x.Pos.Y.CompareTo(y.Pos.Y);
return result;
return (x.Z + x.ZOffset).CompareTo(y.Z + y.ZOffset);
}
}
@@ -93,33 +92,26 @@ namespace OpenRA.Graphics
public void Draw()
{
RefreshPalette();
var bounds = GetBoundsRect();
Game.Renderer.Device.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
Game.Renderer.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
terrainRenderer.Draw(Game.viewport);
terrainRenderer.Draw(this, Game.viewport);
if (world.OrderGenerator != null)
world.OrderGenerator.RenderBeforeWorld(world);
world.OrderGenerator.RenderBeforeWorld(this, world);
Game.Renderer.SpriteRenderer.Flush();
Game.Renderer.LineRenderer.Flush();
foreach (var image in worldSprites)
Game.Renderer.SpriteRenderer.DrawSprite(image.Sprite, image.Pos, image.Palette);
uiOverlay.Draw(world);
Game.Renderer.SpriteRenderer.Flush();
foreach( var image in worldSprites )
image.Sprite.DrawAt( image.Pos, this.GetPaletteIndex( image.Palette ) );
uiOverlay.Draw(this, world);
if (world.OrderGenerator != null)
world.OrderGenerator.RenderAfterWorld(world);
world.OrderGenerator.RenderAfterWorld(this, world);
if (world.LocalPlayer != null)
world.LocalPlayer.Shroud.Draw();
world.LocalPlayer.Shroud.Draw( this );
Game.Renderer.SpriteRenderer.Flush();
Game.Renderer.Device.DisableScissor();
Game.Renderer.LineRenderer.Flush();
Game.Renderer.DisableScissor();
}
void DrawBox(RectangleF r, Color color)
@@ -142,8 +134,8 @@ namespace OpenRA.Graphics
for (var j = 0; j < world.Map.MapSize.Y;
j += world.WorldActor.Info.Traits.Get<SpatialBinsInfo>().BinSize)
{
Game.Renderer.LineRenderer.DrawLine(new float2(0, j * 24), new float2(world.Map.MapSize.X * 24, j * 24), Color.Black, Color.Black);
Game.Renderer.LineRenderer.DrawLine(new float2(j * 24, 0), new float2(j * 24, world.Map.MapSize.Y * 24), Color.Black, Color.Black);
Game.Renderer.LineRenderer.DrawLine(new float2(0, j * Game.CellSize), new float2(world.Map.MapSize.X * Game.CellSize, j * Game.CellSize), Color.Black, Color.Black);
Game.Renderer.LineRenderer.DrawLine(new float2(j * Game.CellSize, 0), new float2(j * Game.CellSize, world.Map.MapSize.Y * Game.CellSize), Color.Black, Color.Black);
}
}
@@ -197,5 +189,10 @@ namespace OpenRA.Graphics
prev = pos;
}
}
public void RefreshPalette()
{
palette.Update( world.WorldActor.TraitsImplementing<IPaletteModifier>() );
}
}
}

View File

@@ -62,14 +62,22 @@ namespace OpenRA
public Rectangle Bounds { get { return Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); } }
public Map()
{
// Do nothing; not a valid map (editor hack)
}
public Map(string tileset)
{
MapSize = new int2(1, 1);
Tileset = tileset;
MapResources = new TileReference<byte, byte>[1, 1];
MapTiles = new TileReference<ushort, byte>[1, 1]
{ { new TileReference<ushort, byte> {
type = (ushort)0xffffu,
image = (byte)0xffu,
index = (byte)0xffu } } };
var tile = OpenRA.Rules.TileSets[Tileset].Templates.First();
MapTiles = new TileReference<ushort, byte>[1, 1]
{ { new TileReference<ushort, byte> {
type = tile.Key,
image = (byte)(tile.Value.PickAny ? 0xffu : 0),
index = (byte)(tile.Value.PickAny ? 0xffu : 0) } } };
PlayerCount = 0;
TopLeft = new int2(0, 0);

View File

@@ -19,15 +19,48 @@ namespace OpenRA
{
public class ModData
{
public static readonly Dictionary<string,Mod> AllMods = ValidateMods(Directory.GetDirectories("mods").Select(x => x.Substring(5)).ToArray());
public static Dictionary<string,Mod> ValidateMods(string[] mods)
{
var ret = new Dictionary<string,Mod>();
foreach (var m in mods)
{
if (!File.Exists("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"))
continue;
var yaml = new MiniYaml( null, MiniYaml.FromFile("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"));
if (!yaml.NodesDict.ContainsKey("Metadata"))
{
System.Console.WriteLine("Invalid mod: "+m);
continue;
}
ret.Add(m,FieldLoader.Load<Mod>(yaml.NodesDict["Metadata"]));
}
return ret;
}
public class Mod
{
public string Title;
public string Description;
public string Version;
public string Author;
public string[] RequiresMods;
public bool Standalone = false;
}
public readonly Manifest Manifest;
public readonly ObjectCreator ObjectCreator;
public readonly SheetBuilder SheetBuilder;
public readonly CursorSheetBuilder CursorSheetBuilder;
public readonly Dictionary<string, MapStub> AvailableMaps;
public readonly WidgetLoader WidgetLoader;
public ILoadScreen LoadScreen = null;
public ModData( params string[] mods )
{
{
Manifest = new Manifest( mods );
ObjectCreator = new ObjectCreator( Manifest );
LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen);
@@ -39,6 +72,7 @@ namespace OpenRA
SheetBuilder = new SheetBuilder( TextureChannel.Red );
CursorSheetBuilder = new CursorSheetBuilder( this );
AvailableMaps = FindMaps( mods );
WidgetLoader = new WidgetLoader( this );
}
// TODO: Do this nicer

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Network
Connected,
}
interface IConnection
interface IConnection : IDisposable
{
int LocalClientId { get; }
ConnectionState ConnectionState { get; }
@@ -73,9 +73,11 @@ namespace OpenRA.Network
foreach( var p in packets )
packetFn( p.FromClient, p.Data );
}
public virtual void Dispose() { }
}
class NetworkConnection : EchoConnection, IDisposable
class NetworkConnection : EchoConnection
{
TcpClient socket;
int clientId;
@@ -112,12 +114,13 @@ namespace OpenRA.Network
receivedPackets.Add( new ReceivedPacket { FromClient = client, Data = buf } );
}
}
catch( SocketException )
catch { }
finally
{
connectionState = ConnectionState.NotConnected;
if( socket != null )
socket.Close();
}
catch ( IOException ) { socket.Close(); }
catch (ThreadAbortException ) { socket.Close(); }
}
) { IsBackground = true };
t.Start();
@@ -132,12 +135,10 @@ namespace OpenRA.Network
try
{
var ms = new MemoryStream();
ms.Write(BitConverter.GetBytes((int)packet.Length));
ms.Write(packet);
ms.WriteTo(socket.GetStream());
}
catch (SocketException) { /* drop this on the floor; we'll pick up the disconnect from the reader thread */ }
catch (ObjectDisposedException) { /* ditto */ }
@@ -145,7 +146,7 @@ namespace OpenRA.Network
bool disposed = false;
public void Dispose ()
public override void Dispose ()
{
if (disposed) return;
disposed = true;
@@ -160,48 +161,4 @@ namespace OpenRA.Network
~NetworkConnection() { Dispose(); }
}
class ReplayConnection : IConnection
{
//uint nextFrame = 1;
FileStream replayStream;
public ReplayConnection( string replayFilename )
{
replayStream = File.OpenRead( replayFilename );
}
public int LocalClientId
{
get { return 0; }
}
public ConnectionState ConnectionState
{
get { return ConnectionState.Connected; }
}
public void Send( byte[] packet )
{
// do nothing; ignore locally generated orders
}
public void Receive( Action<int, byte[]> packetFn )
{
if( replayStream == null ) return;
var reader = new BinaryReader( replayStream );
while( replayStream.Position < replayStream.Length )
{
var client = reader.ReadInt32();
var packetLen = reader.ReadInt32();
var packet = reader.ReadBytes( packetLen );
packetFn( client, packet );
if( !Game.orderManager.GameStarted )
return;
}
replayStream = null;
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.Network
{
class FrameData
{
public struct ClientOrder
{
public int Client;
public Order Order;
}
readonly Dictionary<int, int> clientQuitTimes = new Dictionary<int, int>();
readonly Dictionary<int, Dictionary<int, byte[]>> framePackets = new Dictionary<int, Dictionary<int, byte[]>>();
public IEnumerable<int> ClientsPlayingInFrame( int frame )
{
return clientQuitTimes
.Where( x => frame <= x.Value )
.Select( x => x.Key )
.OrderBy( x => x );
}
public void ClientQuit( int clientId, int lastClientFrame )
{
clientQuitTimes.Add( clientId, lastClientFrame );
}
public void AddFrameOrders( int clientId, int frame, byte[] orders )
{
var frameData = framePackets.GetOrAdd( frame );
frameData.Add( clientId, orders );
}
public bool IsReadyForFrame( int frame )
{
var frameData = framePackets.GetOrAdd( frame );
return ClientsPlayingInFrame( frame )
.All( client => frameData.ContainsKey( client ) );
}
public IEnumerable<ClientOrder> OrdersForFrame( World world, int frame )
{
var frameData = framePackets[ frame ];
var clientData = ClientsPlayingInFrame( frame )
.ToDictionary( k => k, v => frameData[ v ] );
return clientData
.SelectMany( x => x.Value
.ToOrderList( world )
.Select( o => new ClientOrder { Client = x.Key, Order = o } ) );
}
}
}

View File

@@ -187,9 +187,9 @@ namespace OpenRA
return new Order("PauseProduction", subject, new int2( pause ? 1 : 0, 0 ), item);
}
public static Order CancelProduction(Actor subject, string item)
public static Order CancelProduction(Actor subject, string item, int count)
{
return new Order("CancelProduction", subject, item);
return new Order("CancelProduction", subject, new int2( count, 0 ), item);
}
}
}

View File

@@ -18,45 +18,44 @@ namespace OpenRA.Network
{
class OrderManager : IDisposable
{
SyncReport syncReport = new SyncReport();
readonly SyncReport syncReport;
readonly FrameData frameData = new FrameData();
public int FrameNumber { get; private set; }
public Session LobbyInfo = new Session( Game.Settings.Game.Mods );
public Session.Client LocalClient { get { return LobbyInfo.ClientWithIndex( Connection.LocalClientId ); } }
public World world;
public readonly string Host;
public readonly int Port;
public int NetFrameNumber { get; private set; }
public int LocalFrameNumber;
public int FramesAhead = 0;
public bool GameStarted { get { return FrameNumber != 0; } }
public int LastTickTime = Environment.TickCount;
public bool GameStarted { get { return NetFrameNumber != 0; } }
public IConnection Connection { get; private set; }
public readonly int SyncHeaderSize = 9;
Dictionary<int, int> clientQuitTimes = new Dictionary<int, int>();
Dictionary<int, Dictionary<int, byte[]>> frameClientData =
new Dictionary<int, Dictionary<int, byte[]>>();
List<Order> localOrders = new List<Order>();
FileStream replaySaveFile;
public void StartGame()
{
if (GameStarted) return;
FrameNumber = 1;
for( int i = FrameNumber ; i <= FramesAhead ; i++ )
NetFrameNumber = 1;
for( int i = NetFrameNumber ; i <= FramesAhead ; i++ )
Connection.Send( new List<Order>().Serialize( i ) );
}
public OrderManager( IConnection conn )
public OrderManager( string host, int port, IConnection conn )
{
this.Host = host;
this.Port = port;
Connection = conn;
}
public OrderManager( IConnection conn, string replayFilename )
: this( conn )
{
string path = Game.SupportDir + "Replays" + Path.DirectorySeparatorChar;
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
replaySaveFile = File.Create( path + replayFilename );
syncReport = new SyncReport( this );
}
public void IssueOrders( Order[] orders )
@@ -70,7 +69,7 @@ namespace OpenRA.Network
localOrders.Add( order );
}
public void TickImmediate( World world )
public void TickImmediate()
{
var immediateOrders = localOrders.Where( o => o.IsImmediate ).ToList();
if( immediateOrders.Count != 0 )
@@ -84,21 +83,18 @@ namespace OpenRA.Network
{
var frame = BitConverter.ToInt32( packet, 0 );
if( packet.Length == 5 && packet[ 4 ] == 0xBF )
clientQuitTimes[ clientId ] = frame;
frameData.ClientQuit( clientId, frame );
else if( packet.Length >= 5 && packet[ 4 ] == 0x65 )
CheckSync( packet );
else if( frame == 0 )
immediatePackets.Add( Pair.New( clientId, packet ) );
else
frameClientData.GetOrAdd( frame ).Add( clientId, packet );
frameData.AddFrameOrders( clientId, frame, packet );
} );
foreach( var p in immediatePackets )
{
foreach( var o in p.Second.ToOrderList( world ) )
UnitOrders.ProcessOrder( world, p.First, o );
WriteImmediateToReplay( immediatePackets );
}
UnitOrders.ProcessOrder( this, world, p.First, o );
}
Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>();
@@ -134,14 +130,9 @@ namespace OpenRA.Network
syncForFrame.Add(frame, packet);
}
void OutOfSync( int frame , int index)
{
var frameData = clientQuitTimes
.Where( x => frame <= x.Value )
.OrderBy( x => x.Key )
.ToDictionary( k => k.Key, v => frameClientData[ FrameNumber ][ v.Key ] );
var order = frameData.SelectMany( o => o.Value.ToOrderList( Game.world ).Select( a => new { Client = o.Key, Order = a } ) ).ElementAt(index);
void OutOfSync(int frame, int index)
{
var order = frameData.OrdersForFrame( world, frame ).ElementAt(index);
throw new InvalidOperationException("Out of sync in frame {0}.\n {1}".F(frame, order.Order.ToString()));
}
@@ -157,72 +148,34 @@ namespace OpenRA.Network
public bool IsReadyForNextFrame
{
get
{
return FrameNumber > 0 &&
clientQuitTimes
.Where( x => FrameNumber <= x.Value )
.All( x => frameClientData.GetOrAdd( FrameNumber ).ContainsKey( x.Key ) );
}
get { return NetFrameNumber >= 1 && frameData.IsReadyForFrame( NetFrameNumber ); }
}
public void Tick( World world )
public void Tick()
{
if( !IsReadyForNextFrame )
throw new InvalidOperationException();
Connection.Send( localOrders.Serialize( FrameNumber + FramesAhead ) );
Connection.Send( localOrders.Serialize( NetFrameNumber + FramesAhead ) );
localOrders.Clear();
var frameData = clientQuitTimes
.Where( x => FrameNumber <= x.Value )
.OrderBy( x => x.Key )
.ToDictionary( k => k.Key, v => frameClientData[ FrameNumber ][ v.Key ] );
var sync = new List<int>();
sync.Add( world.SyncHash() );
foreach( var order in frameData.SelectMany( o => o.Value.ToOrderList( world ).Select( a => new { Client = o.Key, Order = a } ) ) )
foreach( var order in frameData.OrdersForFrame( world, NetFrameNumber) )
{
UnitOrders.ProcessOrder( world, order.Client, order.Order );
UnitOrders.ProcessOrder( this, world, order.Client, order.Order );
sync.Add( world.SyncHash() );
}
var ss = sync.SerializeSync( FrameNumber );
var ss = sync.SerializeSync( NetFrameNumber );
Connection.Send( ss );
WriteToReplay( frameData, ss );
syncReport.UpdateSyncReport();
CheckSync( ss );
++FrameNumber;
}
void WriteToReplay( Dictionary<int, byte[]> frameData, byte[] syncData )
{
if( replaySaveFile == null ) return;
foreach( var f in frameData )
{
replaySaveFile.Write( BitConverter.GetBytes( f.Key ) );
replaySaveFile.Write( BitConverter.GetBytes( f.Value.Length ) );
replaySaveFile.Write( f.Value );
}
replaySaveFile.Write( BitConverter.GetBytes( (int)0 ) );
replaySaveFile.Write( BitConverter.GetBytes( (int)syncData.Length ) );
replaySaveFile.Write( syncData );
}
void WriteImmediateToReplay( List<Pair<int, byte[]>> immediatePackets )
{
if( replaySaveFile == null ) return;
foreach( var i in immediatePackets )
{
replaySaveFile.Write( BitConverter.GetBytes( i.First ) );
replaySaveFile.Write( BitConverter.GetBytes( i.Second.Length ) );
replaySaveFile.Write( i.Second );
}
++NetFrameNumber;
}
bool disposed;
@@ -230,11 +183,7 @@ namespace OpenRA.Network
{
if (disposed) return;
if (replaySaveFile != null)
replaySaveFile.Dispose();
var disposableConnection = Connection as IDisposable;
if (disposableConnection != null) disposableConnection.Dispose();
Connection.Dispose();
disposed = true;
GC.SuppressFinalize(this);

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace OpenRA.Network
{
class ReplayConnection : IConnection
{
//uint nextFrame = 1;
FileStream replayStream;
public ReplayConnection( string replayFilename )
{
replayStream = File.OpenRead( replayFilename );
}
public int LocalClientId
{
get { return 0; }
}
public ConnectionState ConnectionState
{
get { return ConnectionState.Connected; }
}
public void Send( byte[] packet )
{
// do nothing; ignore locally generated orders
}
public void Receive( Action<int, byte[]> packetFn )
{
if( replayStream == null ) return;
var reader = new BinaryReader( replayStream );
while( replayStream.Position < replayStream.Length )
{
var client = reader.ReadInt32();
var packetLen = reader.ReadInt32();
var packet = reader.ReadBytes( packetLen );
packetFn( client, packet );
}
replayStream = null;
}
public void Dispose() { }
}
class ReplayRecorderConnection : IConnection
{
IConnection inner;
FileStream replayFile;
BinaryWriter writer;
public ReplayRecorderConnection( IConnection inner, FileStream replayFile )
{
this.inner = inner;
this.replayFile = replayFile;
this.writer = new BinaryWriter( replayFile );
}
public int LocalClientId { get { return inner.LocalClientId; } }
public ConnectionState ConnectionState { get { return inner.ConnectionState; } }
public void Send( byte[] packet )
{
inner.Send( packet );
}
public void Receive( Action<int, byte[]> packetFn )
{
inner.Receive( ( client, data ) =>
{
writer.Write( client );
writer.Write( data.Length );
writer.Write( data );
packetFn( client, data );
} );
}
bool disposed;
public void Dispose()
{
if( disposed )
return;
writer.Close();
disposed = true;
}
~ReplayRecorderConnection()
{
Dispose();
}
}
}

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Network
@@ -20,6 +21,16 @@ namespace OpenRA.Network
public List<Slot> Slots = new List<Slot>();
public Global GlobalSettings = new Global();
public Client ClientWithIndex( int clientID )
{
return Clients.SingleOrDefault( c => c.Index == clientID );
}
public Client ClientInSlot( Slot slot )
{
return Clients.SingleOrDefault( c => c.Slot == slot.Index );
}
public enum ClientState
{
NotReady,
@@ -51,6 +62,7 @@ namespace OpenRA.Network
public class Global
{
public string ServerName;
public string Map;
public string[] Mods = { "ra" }; // mod names
public int OrderLatency = 3;
@@ -59,6 +71,11 @@ namespace OpenRA.Network
public bool AllowCheats = false;
}
public Session( string[] mods )
{
this.GlobalSettings.Mods = mods.ToArray();
}
public string Serialize()
{
var clientData = new List<MiniYamlNode>();
@@ -76,8 +93,7 @@ namespace OpenRA.Network
public static Session Deserialize(string data)
{
var session = new Session();
session.GlobalSettings.Mods = Game.Settings.Game.Mods;
var session = new Session( Game.Settings.Game.Mods );
var ys = MiniYaml.FromString(data);
foreach (var y in ys)

View File

@@ -3,61 +3,89 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRA.FileFormats;
using OpenRA.Support;
namespace OpenRA.Network
{
class SyncReport
{
Queue<Pair<int, string>> syncReports = new Queue<Pair<int, string>>();
readonly OrderManager orderManager;
const int numSyncReports = 5;
Report[] syncReports = new Report[numSyncReports];
int curIndex = 0;
public SyncReport( OrderManager orderManager )
{
this.orderManager = orderManager;
for (var i = 0; i < numSyncReports; i++)
syncReports[i] = new SyncReport.Report();
}
internal void UpdateSyncReport()
{
if (!Game.Settings.Debug.RecordSyncReports)
return;
while (syncReports.Count >= numSyncReports) syncReports.Dequeue();
syncReports.Enqueue(Pair.New(Game.orderManager.FrameNumber, GenerateSyncReport()));
GenerateSyncReport(syncReports[curIndex]);
curIndex = ++curIndex % numSyncReports;
}
string GenerateSyncReport()
void GenerateSyncReport(Report report)
{
var sb = new StringBuilder();
sb.AppendLine("Actors:");
foreach (var a in Game.world.Actors)
sb.AppendLine("\t {0} {1} {2} ({3})".F(
a.ActorID,
a.Info.Name,
(a.Owner == null) ? "null" : a.Owner.InternalName,
Sync.CalculateSyncHash(a)));
sb.AppendLine("Tick Actors:");
foreach (var a in Game.world.Queries.WithTraitMultiple<object>())
report.Frame = orderManager.NetFrameNumber;
report.SyncedRandom = orderManager.world.SharedRandom.Last;
report.Traits.Clear();
foreach (var a in orderManager.world.Queries.WithTraitMultiple<object>())
{
var sync = Sync.CalculateSyncHash(a.Trait);
if (sync != 0)
sb.AppendLine("\t {0} {1} {2} {3} ({4})".F(
a.Actor.ActorID,
a.Actor.Info.Name,
(a.Actor.Owner == null) ? "null" : a.Actor.Owner.InternalName,
a.Trait.GetType().Name,
sync));
report.Traits.Add(new TraitReport()
{
ActorID = a.Actor.ActorID,
Type = a.Actor.Info.Name,
Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.InternalName,
Trait = a.Trait.GetType().Name,
Hash = sync
});
}
return sb.ToString();
}
internal void DumpSyncReport(int frame)
{
var f = syncReports.FirstOrDefault(a => a.First == frame);
if (f == default(Pair<int, string>))
{
Log.Write("sync", "No sync report available!");
return;
}
Log.Write("sync", "Sync for net frame {0} -------------", f.First);
Log.Write("sync", "{0}", f.Second);
foreach (var r in syncReports)
if (r.Frame == frame)
{
Log.Write("sync", "Sync for net frame {0} -------------", r.Frame);
Log.Write("sync", "SharedRandom: "+r.SyncedRandom);
Log.Write("sync", "Synced Traits:");
foreach (var a in r.Traits)
Log.Write("sync", "\t {0} {1} {2} {3} ({4})".F(
a.ActorID,
a.Type,
a.Owner,
a.Trait,
a.Hash
));
return;
}
Log.Write("sync", "No sync report available!");
}
class Report
{
public int Frame;
public int SyncedRandom;
public List<TraitReport> Traits = new List<TraitReport>();
}
struct TraitReport
{
public uint ActorID;
public string Type;
public string Owner;
public string Trait;
public int Hash;
}
}
}

View File

@@ -16,18 +16,16 @@ namespace OpenRA.Network
{
static class UnitOrders
{
static Session.Client FindClientById(int id)
static Player FindPlayerByClient( this World world, Session.Client c)
{
return Game.LobbyInfo.Clients.FirstOrDefault(c => c.Index == id);
/* todo: this is still a hack.
* the cases we're trying to avoid are the extra players on the host's client -- Neutral, other MapPlayers,
* bots,.. */
return world.players.Values.FirstOrDefault(
p => p.ClientIndex == c.Index && p.PlayerName == c.Name);
}
static Player FindPlayerByClientId(int id)
{
/* todo: find the interactive player. */
return Game.world.players.Values.FirstOrDefault(p => p.ClientIndex == id);
}
public static void ProcessOrder( World world, int clientId, Order order )
public static void ProcessOrder( OrderManager orderManager, World world, int clientId, Order order )
{
// Drop exploiting orders
if (order.Subject != null && order.Subject.Owner.ClientIndex != clientId)
@@ -40,32 +38,40 @@ namespace OpenRA.Network
{
case "Chat":
{
var client = FindClientById(clientId);
var client = orderManager.LobbyInfo.ClientWithIndex( clientId );
if (client != null)
{
var player = FindPlayerByClientId(clientId);
if (player != null && player.WinState == WinState.Lost)
Game.AddChatLine(client.Color1, client.Name + " (Dead)", order.TargetString);
else
Game.AddChatLine(client.Color1, client.Name, order.TargetString);
var player = world != null ? world.FindPlayerByClient(client) : null;
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : "";
Game.AddChatLine(client.Color1, client.Name, order.TargetString);
}
else
Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString);
break;
}
case "TeamChat":
{
var client = FindClientById(clientId);
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
if (client != null)
{
var player = FindPlayerByClientId(clientId);
var display = (world.GameHasStarted) ?
player != null && (world.LocalPlayer != null && player.Stances[world.LocalPlayer] == Stance.Ally
|| player.WinState == WinState.Lost) :
client == Game.LocalClient || (client.Team == Game.LocalClient.Team && client.Team != 0);
if (display)
if (world == null)
{
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : " (Team)";
Game.AddChatLine(client.Color1, client.Name + suffix, order.TargetString);
if (client.Team == orderManager.LocalClient.Team)
Game.AddChatLine(client.Color1, client.Name + " (Team)",
order.TargetString);
}
else
{
var player = world.FindPlayerByClient(client);
var display = player != null
&& (world.LocalPlayer != null && player.Stances[world.LocalPlayer] == Stance.Ally
|| player.WinState == WinState.Lost);
if (display)
{
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : " (Team)";
Game.AddChatLine(client.Color1, client.Name + suffix, order.TargetString);
}
}
}
break;
@@ -73,25 +79,43 @@ namespace OpenRA.Network
case "StartGame":
{
Game.AddChatLine(Color.White, "Server", "The game has started.");
Game.StartGame(Game.LobbyInfo.GlobalSettings.Map);
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map);
break;
}
case "SyncInfo":
{
Game.SyncLobbyInfo(order.TargetString);
orderManager.LobbyInfo = Session.Deserialize( order.TargetString );
//if( !world.GameHasStarted )
// world.SharedRandom = new XRandom( LobbyInfo.GlobalSettings.RandomSeed );
//if (orderManager.Connection.ConnectionState == ConnectionState.Connected)
// world.SetLocalPlayer(orderManager.Connection.LocalClientId);
if( orderManager.FramesAhead != orderManager.LobbyInfo.GlobalSettings.OrderLatency
&& !orderManager.GameStarted )
{
orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency;
Game.Debug( "Order lag is now {0} frames.".F( orderManager.LobbyInfo.GlobalSettings.OrderLatency ) );
}
Game.SyncLobbyInfo();
break;
}
case "SetStance":
{
var targetPlayer = order.Player.World.players[order.TargetLocation.X];
var oldStance = order.Player.Stances[targetPlayer];
order.Player.Stances[targetPlayer] = (Stance)order.TargetLocation.Y;
if (targetPlayer == world.LocalPlayer)
world.WorldActor.Trait<Shroud>().UpdatePlayerStance(world, order.Player, oldStance, order.Player.Stances[targetPlayer]);
var newStance = (Stance)order.TargetLocation.Y;
SetPlayerStance(world, order.Player, targetPlayer, newStance);
// automatically declare war reciprocally
if (newStance == Stance.Enemy)
SetPlayerStance(world, targetPlayer, order.Player, newStance);
Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F(
order.Player.PlayerName, targetPlayer.PlayerName, order.Player.Stances[targetPlayer]));
order.Player.PlayerName, targetPlayer.PlayerName, newStance));
break;
}
default:
@@ -103,5 +127,13 @@ namespace OpenRA.Network
}
}
}
static void SetPlayerStance(World w, Player a, Player b, Stance s)
{
var oldStance = a.Stances[b];
a.Stances[b] = s;
if (b == w.LocalPlayer)
w.WorldActor.Trait<Shroud>().UpdatePlayerStance(w, b, oldStance, s);
}
}
}

View File

@@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using OpenRA.FileFormats;
using System.Collections.Generic;
namespace OpenRA
{
@@ -30,19 +31,63 @@ namespace OpenRA
public static Action<string> MissingTypeAction =
s => { throw new InvalidOperationException("Cannot locate type: {0}".F(s)); };
public T CreateObject<T>(string classname)
public T CreateObject<T>(string className)
{
foreach (var mod in ModAssemblies)
{
var fullTypeName = mod.Second + "." + classname;
var obj = mod.First.CreateInstance(fullTypeName);
if (obj != null)
return (T)obj;
}
return CreateObject<T>( className, new Dictionary<string, object>() );
}
MissingTypeAction(classname);
public T CreateObject<T>( string className, Dictionary<string, object> args )
{
foreach( var mod in ModAssemblies )
{
var type = mod.First.GetType( mod.Second + "." + className, false );
if( type == null ) continue;
var ctors = type.GetConstructors( BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance ).Where( x => x.HasAttribute<UseCtorAttribute>() ).ToList();
if( ctors.Count == 0 )
return (T)CreateBasic( type );
else if( ctors.Count == 1 )
return (T)CreateUsingArgs( ctors[ 0 ], args );
else
throw new InvalidOperationException( "ObjectCreator: UseCtor on multiple constructors; invalid." );
}
MissingTypeAction(className);
return default(T);
}
public object CreateBasic( Type type )
{
return type.GetConstructor( new Type[ 0 ] ).Invoke( new object[ 0 ] );
}
public object CreateUsingArgs( ConstructorInfo ctor, Dictionary<string, object> args )
{
var p = ctor.GetParameters();
var a = new object[ p.Length ];
for( int i = 0 ; i < p.Length ; i++ )
{
var attrs = p[ i ].GetCustomAttributes<ParamAttribute>();
if( attrs.Length != 1 ) throw new InvalidOperationException( "ObjectCreator: argument in [UseCtor] doesn't have [Param]" );
a[ i ] = args[ attrs[ 0 ].ParamName ?? p[i].Name ];
}
return ctor.Invoke( a );
}
[AttributeUsage( AttributeTargets.Parameter )]
public class ParamAttribute : Attribute
{
public string ParamName { get; private set; }
public ParamAttribute() { }
public ParamAttribute( string paramName )
{
ParamName = paramName;
}
}
[AttributeUsage( AttributeTargets.Constructor )]
public class UseCtorAttribute : Attribute
{
}
}
}

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -75,7 +75,6 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Effects\RepairIndicator.cs" />
<Compile Include="GameRules\WeaponInfo.cs" />
<Compile Include="Group.cs" />
<Compile Include="Orders\GenericSelectTarget.cs" />
@@ -83,7 +82,6 @@
<Compile Include="Traits\BaseBuilding.cs" />
<Compile Include="Traits\LintAttributes.cs" />
<Compile Include="Traits\Player\PlayerResources.cs" />
<Compile Include="Traits\Player\TechTreeCache.cs" />
<Compile Include="Traits\World\Shroud.cs" />
<Compile Include="Widgets\ChatEntryWidget.cs" />
<Compile Include="Widgets\Delegates\ConnectionDialogsDelegate.cs" />
@@ -99,7 +97,6 @@
<Compile Include="Effects\MoveFlash.cs" />
<Compile Include="Exts.cs" />
<Compile Include="GameRules\ActorInfo.cs" />
<Compile Include="GameRules\TechTree.cs" />
<Compile Include="GameRules\VoiceInfo.cs" />
<Compile Include="Effects\IEffect.cs" />
<Compile Include="Graphics\ChromeProvider.cs" />
@@ -137,7 +134,6 @@
<Compile Include="Traits\Activities\RemoveSelf.cs" />
<Compile Include="Traits\Activities\Sell.cs" />
<Compile Include="Orders\IOrderGenerator.cs" />
<Compile Include="Orders\PlaceBuildingOrderGenerator.cs" />
<Compile Include="Player.cs" />
<Compile Include="Graphics\Sheet.cs" />
<Compile Include="PathFinder.cs" />
@@ -157,23 +153,15 @@
<Compile Include="Graphics\TerrainRenderer.cs" />
<Compile Include="Traits\Activities\Move.cs" />
<Compile Include="Traits\Activities\Turn.cs" />
<Compile Include="Traits\Buildable.cs" />
<Compile Include="Traits\Building.cs" />
<Compile Include="Traits\World\BuildingInfluence.cs" />
<Compile Include="Traits\Player\PlaceBuilding.cs" />
<Compile Include="Traits\World\PlayerColorPalette.cs" />
<Compile Include="Traits\World\ResourceLayer.cs" />
<Compile Include="Traits\World\ResourceType.cs" />
<Compile Include="Traits\SupportPower.cs" />
<Compile Include="Traits\ProvidesRadar.cs" />
<Compile Include="Traits\Selectable.cs" />
<Compile Include="Traits\Player\ProductionQueue.cs" />
<Compile Include="Traits\Mobile.cs" />
<Compile Include="Traits\Production.cs" />
<Compile Include="Traits\RallyPoint.cs" />
<Compile Include="Traits\Render\RenderSimple.cs" />
<Compile Include="Traits\TraitsInterfaces.cs" />
<Compile Include="Traits\Turreted.cs" />
<Compile Include="Traits\World\UnitInfluence.cs" />
<Compile Include="Network\UnitOrders.cs" />
<Compile Include="Traits\Util.cs" />
@@ -193,8 +181,6 @@
<Compile Include="Widgets\BackgroundWidget.cs" />
<Compile Include="Widgets\LabelWidget.cs" />
<Compile Include="Widgets\CheckboxWidget.cs" />
<Compile Include="Traits\World\BibLayer.cs" />
<Compile Include="Traits\World\SmudgeLayer.cs" />
<Compile Include="Widgets\Delegates\MusicPlayerDelegate.cs" />
<Compile Include="Widgets\PerfGraphWidget.cs" />
<Compile Include="Widgets\Delegates\PerfDebugDelegate.cs" />
@@ -202,7 +188,6 @@
<Compile Include="Widgets\ColorBlockWidget.cs" />
<Compile Include="GameRules\MusicInfo.cs" />
<Compile Include="Widgets\ImageWidget.cs" />
<Compile Include="Traits\SharesCell.cs" />
<Compile Include="Widgets\TextFieldWidget.cs" />
<Compile Include="Widgets\ChatDisplayWidget.cs" />
<Compile Include="Widgets\Delegates\MapChooserDelegate.cs" />
@@ -217,16 +202,16 @@
<Compile Include="Traits\RevealsShroud.cs" />
<Compile Include="Traits\Targetable.cs" />
<Compile Include="Traits\Health.cs" />
<Compile Include="Traits\RepairableBuilding.cs" />
<Compile Include="Traits\Activities\Drag.cs" />
<Compile Include="Widgets\VqaPlayerWidget.cs" />
<Compile Include="Widgets\Delegates\VideoPlayerDelegate.cs" />
<Compile Include="Traits\MPStartLocations.cs" />
<Compile Include="GameRules\Settings.cs" />
<Compile Include="Support\Arguments.cs" />
<Compile Include="Traits\ActorStance.cs" />
<Compile Include="Traits\Armor.cs" />
<Compile Include="Graphics\CursorProvider.cs" />
<Compile Include="Traits\Player\TechTree.cs" />
<Compile Include="Traits\Player\PowerManager.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
@@ -237,12 +222,17 @@
<Compile Include="ActorReference.cs" />
<Compile Include="ModData.cs" />
<Compile Include="Map.cs" />
<Compile Include="Network\FrameData.cs" />
<Compile Include="Network\ReplayConnection.cs" />
<Compile Include="Network\Session.cs" />
<Compile Include="ObjectCreator.cs" />
<Compile Include="Network\SyncReport.cs" />
<Compile Include="TraitDictionary.cs" />
<Compile Include="Traits\PrimaryBuilding.cs" />
<Compile Include="Traits\SharesCell.cs" />
<Compile Include="Traits\Valued.cs" />
<Compile Include="Traits\World\BibLayer.cs" />
<Compile Include="Widgets\Delegates\DeveloperModeDelegate.cs" />
<Compile Include="Widgets\ScrollingTextWidget.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">

View File

@@ -10,18 +10,27 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Orders
{
public class GenericSelectTarget : IOrderGenerator
{
readonly Actor subject;
readonly IEnumerable<Actor> subjects;
readonly string order;
readonly string cursor;
public GenericSelectTarget(IEnumerable<Actor> subjects, string order, string cursor)
{
this.subjects = subjects;
this.order = order;
this.cursor = cursor;
}
public GenericSelectTarget(Actor subject, string order, string cursor)
{
this.subject = subject;
this.subjects = new Actor[] { subject };
this.order = order;
this.cursor = cursor;
}
@@ -36,12 +45,34 @@ namespace OpenRA.Orders
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left && world.Map.IsInMap(xy))
yield return new Order(order, subject, xy);
{
world.CancelInputMode();
foreach (var subject in subjects)
yield return new Order(order, subject, xy);
}
}
public virtual void Tick(World world) { }
public void RenderAfterWorld(World world) { }
public void RenderBeforeWorld(World world) { }
public void RenderBeforeWorld(WorldRenderer wr, World world)
{
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
t.RenderBeforeWorld(wr, a);
Game.Renderer.Flush();
}
public void RenderAfterWorld(WorldRenderer wr, World world)
{
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
t.RenderAfterWorld(wr, a);
Game.Renderer.Flush();
}
public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
}
@@ -63,5 +94,4 @@ namespace OpenRA.Orders
world.CancelInputMode();
}
}
}

View File

@@ -9,6 +9,7 @@
#endregion
using System.Collections.Generic;
using OpenRA.Graphics;
namespace OpenRA
{
@@ -16,8 +17,8 @@ namespace OpenRA
{
IEnumerable<Order> Order(World world, int2 xy, MouseInput mi);
void Tick(World world);
void RenderBeforeWorld(World world);
void RenderAfterWorld(World world);
void RenderBeforeWorld(WorldRenderer wr, World world);
void RenderAfterWorld(WorldRenderer wr, World world);
string GetCursor(World world, int2 xy, MouseInput mi);
}
}

View File

@@ -6,11 +6,11 @@
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Orders
@@ -25,59 +25,127 @@ namespace OpenRA.Orders
.FirstOrDefault();
var orders = world.Selection.Actors
.Select(a => a.Order(xy, mi, underCursor))
.Select(a => OrderForUnit(a, xy, mi, underCursor))
.Where(o => o != null)
.ToArray();
var actorsInvolved = orders.Select(o => o.Subject).Distinct();
var actorsInvolved = orders.Select(o => o.self).Distinct();
if (actorsInvolved.Any())
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor,
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()));
foreach (var o in orders)
yield return o;
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()));
foreach( var o in orders )
yield return CheckSameOrder( o.iot, o.trait.IssueOrder( o.self, o.iot, o.target ) );
}
public void Tick( World world ) {}
public void RenderBeforeWorld(World world)
public void RenderBeforeWorld( WorldRenderer wr, World world )
{
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
t.RenderBeforeWorld(a);
t.RenderBeforeWorld( wr, a );
Game.Renderer.Flush();
}
public void RenderAfterWorld( World world )
public void RenderAfterWorld( WorldRenderer wr, World world )
{
foreach (var a in world.Selection.Actors)
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
t.RenderAfterWorld(a);
t.RenderAfterWorld( wr, a );
Game.Renderer.Flush();
}
public string GetCursor( World world, int2 xy, MouseInput mi )
{
if (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any())
{
var underCursor = world.FindUnitsAtMouse(mi.Location)
.Where(a => a.Info.Traits.Contains<SelectableInfo>())
.Any();
if (underCursor)
return "select";
}
var underCursor = world.FindUnitsAtMouse(mi.Location)
.Where(a => a.Info.Traits.Contains<TargetableInfo>())
.OrderByDescending(a => a.Info.Traits.Contains<SelectableInfo>() ? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
.FirstOrDefault();
var c = Order(world, xy, mi)
.Select(o => o.Subject.TraitsImplementing<IOrderCursor>()
.Select(pc => pc.CursorForOrder(o.Subject, o)).FirstOrDefault(a => a != null))
.FirstOrDefault(a => a != null);
return c ?? "default";
if( mi.Modifiers.HasModifier( Modifiers.Shift ) || !world.Selection.Actors.Any() )
if( underCursor != null )
return "select";
var orders = world.Selection.Actors
.Select(a => OrderForUnit(a, xy, mi, underCursor))
.Where(o => o != null)
.ToArray();
if( orders.Length == 0 ) return "default";
return orders[ 0 ].cursor ?? "default";
}
static UnitOrderResult OrderForUnit( Actor self, int2 xy, MouseInput mi, Actor underCursor )
{
if (self.Owner != self.World.LocalPlayer)
return null;
if (!self.World.Map.IsInMap(xy.X, xy.Y))
return null;
if (self.Destroyed)
return null;
//var old = self.TraitsImplementing<IIssueOrder>()
// .OrderByDescending( x => x.OrderPriority( self, xy, mi, underCursor ) )
// .Select( x => x.IssueOrder( self, xy, mi, underCursor ) )
// .FirstOrDefault( x => x != null );
//if( old != null )
// return old;
if( mi.Button == MouseButton.Right )
{
var uim = self.World.WorldActor.Trait<UnitInfluence>();
foreach( var o in self.TraitsImplementing<IIssueOrder>()
.SelectMany( trait => trait.Orders
.Select( x => new { Trait = trait, Order = x } ) )
.OrderByDescending( x => x.Order.OrderPriority ) )
{
var actorsAt = uim.GetUnitsAt( xy ).ToList();
string cursor = null;
if( underCursor != null )
if( o.Order.CanTargetUnit( self, underCursor, mi.Modifiers.HasModifier( Modifiers.Ctrl ), mi.Modifiers.HasModifier( Modifiers.Alt ), ref cursor ) )
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromActor( underCursor ) );
if( o.Order.CanTargetLocation( self, xy, actorsAt, mi.Modifiers.HasModifier( Modifiers.Ctrl ), mi.Modifiers.HasModifier( Modifiers.Alt ), ref cursor ) )
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromCell( xy ) );
}
}
return null;
}
static Order CheckSameOrder( IOrderTargeter iot, Order order )
{
if( order == null && iot.OrderID != null )
Game.Debug( "BUG: in order targeter - decided on {0} but then didn't order", iot.OrderID );
else if( iot.OrderID != order.OrderString )
Game.Debug( "BUG: in order targeter - decided on {0} but ordered {1}", iot.OrderID, order.OrderString );
return order;
}
class UnitOrderResult
{
public readonly Actor self;
public readonly IOrderTargeter iot;
public readonly IIssueOrder trait;
public readonly string cursor;
public readonly Target target;
public UnitOrderResult( Actor self, IOrderTargeter iot, IIssueOrder trait, string cursor, Target target )
{
this.self = self;
this.iot = iot;
this.trait = trait;
this.cursor = cursor;
this.target = target;
}
}
}
}

View File

@@ -207,11 +207,11 @@ namespace OpenRA
public struct CellInfo
{
public float MinCost;
public int MinCost;
public int2 Path;
public bool Seen;
public CellInfo( float minCost, int2 path, bool seen )
public CellInfo( int minCost, int2 path, bool seen )
{
MinCost = minCost;
Path = path;
@@ -221,10 +221,10 @@ namespace OpenRA
public struct PathDistance : IComparable<PathDistance>
{
public float EstTotal;
public int EstTotal;
public int2 Location;
public PathDistance(float estTotal, int2 location)
public PathDistance(int estTotal, int2 location)
{
EstTotal = estTotal;
Location = location;

View File

@@ -20,7 +20,7 @@ namespace OpenRA
World world;
public CellInfo[ , ] cellInfo;
public PriorityQueue<PathDistance> queue;
public Func<int2, float> heuristic;
public Func<int2, int> heuristic;
Func<int2, bool> customBlock;
public bool checkForBlocked;
public Actor ignoreBuilding;
@@ -58,7 +58,7 @@ namespace OpenRA
return this;
}
public PathSearch WithHeuristic(Func<int2, float> h)
public PathSearch WithHeuristic(Func<int2, int> h)
{
heuristic = h;
return this;
@@ -66,7 +66,7 @@ namespace OpenRA
public PathSearch WithoutLaneBias()
{
LaneBias = 0f;
LaneBias = 0;
return this;
}
@@ -76,7 +76,7 @@ namespace OpenRA
return this;
}
float LaneBias = .5f;
int LaneBias = 1;
public int2 Expand( World world )
{
@@ -91,7 +91,7 @@ namespace OpenRA
var thisCost = Mobile.MovementCostForCell(mobileInfo, world, p.Location);
if (thisCost == float.PositiveInfinity)
if (thisCost == int.MaxValue)
return p.Location;
foreach( int2 d in directions )
@@ -104,7 +104,7 @@ namespace OpenRA
var costHere = Mobile.MovementCostForCell(mobileInfo, world, newHere);
if (costHere == float.PositiveInfinity)
if (costHere == int.MaxValue)
continue;
if (!Mobile.CanEnterCell(mobileInfo, world, uim, bim, newHere, ignoreBuilding, checkForBlocked))
@@ -114,10 +114,11 @@ namespace OpenRA
continue;
var est = heuristic( newHere );
if( est == float.PositiveInfinity )
if( est == int.MaxValue )
continue;
float cellCost = ((d.X * d.Y != 0) ? 1.414213563f : 1.0f) * costHere;
int cellCost = costHere;
if( d.X * d.Y != 0 ) cellCost = ( cellCost * 34 ) / 24;
// directional bonuses for smoother flow!
var ux = (newHere.X + (inReverse ? 1 : 0) & 1);
@@ -128,7 +129,7 @@ namespace OpenRA
if (uy == 0 && d.X < 0) cellCost += LaneBias;
else if (uy == 1 && d.X > 0) cellCost += LaneBias;
float newCost = cellInfo[ p.Location.X, p.Location.Y ].MinCost + cellCost;
int newCost = cellInfo[ p.Location.X, p.Location.Y ].MinCost + cellCost;
if( newCost >= cellInfo[ newHere.X, newHere.Y ].MinCost )
continue;
@@ -199,18 +200,18 @@ namespace OpenRA
var cellInfo = new CellInfo[ world.Map.MapSize.X, world.Map.MapSize.Y ];
for( int x = 0 ; x < world.Map.MapSize.X ; x++ )
for( int y = 0 ; y < world.Map.MapSize.Y ; y++ )
cellInfo[ x, y ] = new CellInfo( float.PositiveInfinity, new int2( x, y ), false );
cellInfo[ x, y ] = new CellInfo( int.MaxValue, new int2( x, y ), false );
return cellInfo;
}
public static Func<int2, float> DefaultEstimator( int2 destination )
public static Func<int2, int> DefaultEstimator( int2 destination )
{
return here =>
{
int2 d = ( here - destination ).Abs();
int diag = Math.Min( d.X, d.Y );
int straight = Math.Abs( d.X - d.Y );
return 1.5f * diag + straight;
return (3400 * diag / 24) + (100 * straight);
};
}
}

View File

@@ -37,7 +37,8 @@ namespace OpenRA
public readonly int Index;
public readonly bool NonCombatant = false;
public readonly int ClientIndex;
public readonly PlayerReference PlayerRef;
public readonly PlayerReference PlayerRef;
public bool IsBot;
public ShroudRenderer Shroud;
public World World { get; private set; }
@@ -46,11 +47,10 @@ namespace OpenRA
{
World = world;
Shroud = new ShroudRenderer(this, world.Map);
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
Index = index;
Palette = "player"+index;
Color = pr.Color;
Color2 = pr.Color2;
ClientIndex = 0; /* it's a map player, "owned" by host */
@@ -63,15 +63,13 @@ namespace OpenRA
PlayerRef = pr;
RegisterPlayerColor(world, Palette);
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
}
public Player( World world, Session.Client client, PlayerReference pr, int index )
{
World = world;
Shroud = new ShroudRenderer(this, world.Map);
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
Index = index;
Palette = "player"+index;
@@ -86,15 +84,7 @@ namespace OpenRA
ClientIndex = client.Index;
PlayerRef = pr;
RegisterPlayerColor(world, Palette);
}
public void RegisterPlayerColor(World world, string palette)
{
var info = Rules.Info["world"].Traits.Get<PlayerColorPaletteInfo>();
var newpal = new Palette(world.WorldRenderer.GetPalette(info.BasePalette),
new PlayerColorRemap(Color, Color2, info.SplitRamp));
world.WorldRenderer.AddPalette(palette, newpal);
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
}
public void GiveAdvice(string advice)

View File

@@ -42,7 +42,7 @@ namespace OpenRA
else
actors = (isCombine ? oldSelection.Union(newSelection) : newSelection).ToList();
var voicedUnit = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.HasVoice());
var voicedUnit = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.IsInWorld && a.HasVoice());
if (voicedUnit != null)
Sound.PlayVoice("Select", voicedUnit, voicedUnit.Owner.Country.Race);
@@ -56,6 +56,10 @@ namespace OpenRA
public void Tick(World world)
{
actors.RemoveAll(a => !a.IsInWorld);
foreach (var cg in controlGroups.Values)
cg.RemoveAll(a => a.Destroyed); // note: NOT `!a.IsInWorld`, since that would remove things
// that are in transports.
}
Cache<int, List<Actor>> controlGroups = new Cache<int, List<Actor>>(_ => new List<Actor>());

1
OpenRA.Game/Server/Exts.cs Normal file → Executable file
View File

@@ -11,6 +11,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System;
namespace OpenRA.Server
{

60
OpenRA.Game/Server/MasterServerQuery.cs Normal file → Executable file
View File

@@ -14,15 +14,20 @@ using System.Net;
using System.Text;
using System.Threading;
using OpenRA.FileFormats;
using OpenRA.Widgets;
namespace OpenRA.Server
{
static class MasterServerQuery
{
public static event Action<GameServer[]> OnComplete = _ => { };
public static event Action<string> OnVersion = _ => { };
static GameServer[] Games = { };
public static string ClientVersion = "";
public static string ServerVersion = "";
static AutoResetEvent ev = new AutoResetEvent(false);
static AutoResetEvent ev2 = new AutoResetEvent(false);
public static void Refresh(string masterServerUrl)
{
@@ -30,9 +35,7 @@ namespace OpenRA.Server
{
try
{
var wc = new WebClient();
var data = wc.DownloadData(new Uri(masterServerUrl + "list.php"));
var str = Encoding.UTF8.GetString(data);
var str = GetData(new Uri(masterServerUrl + "list.php"));
var yaml = MiniYaml.FromString(str);
@@ -48,10 +51,61 @@ namespace OpenRA.Server
}).Start();
}
public static void GetMOTD(string masterServerUrl)
{
var motd = Widget.RootWidget.GetWidget<ScrollingTextWidget>("MOTD_SCROLLER");
// Runs in a separate thread to prevent dns lookup hitches
new Thread(() =>
{
if (motd != null)
{
try
{
motd.SetText(GetData(new Uri(masterServerUrl + "motd.php?v=" + ClientVersion)));
motd.ResetScroll();
}
catch
{
motd.SetText("Welcome to OpenRA. MOTD unable to be loaded from server.");
motd.ResetScroll();
}
}
ev.Set();
}).Start();
}
public static void Tick()
{
if (ev.WaitOne(TimeSpan.FromMilliseconds(0)))
OnComplete(Games);
if (ev2.WaitOne(TimeSpan.FromMilliseconds(0)))
OnVersion(ServerVersion);
}
static string GetData(Uri uri)
{
var wc = new WebClient();
var data = wc.DownloadData(uri);
return Encoding.UTF8.GetString(data);
}
public static void GetCurrentVersion(string masterServerUrl)
{
new Thread(() =>
{
try
{
ServerVersion = GetData(new Uri(masterServerUrl + "VERSION"));
}
catch
{
ServerVersion = "";
}
ev2.Set();
}).Start();
}
}

View File

@@ -60,11 +60,11 @@ namespace OpenRA.Server
randomSeed = (int)DateTime.Now.ToBinary();
ModData = modData;
lobbyInfo = new Session();
lobbyInfo.GlobalSettings.Mods = settings.Game.Mods;
lobbyInfo = new Session( settings.Game.Mods );
lobbyInfo.GlobalSettings.RandomSeed = randomSeed;
lobbyInfo.GlobalSettings.Map = map;
lobbyInfo.GlobalSettings.AllowCheats = settings.Server.AllowCheats;
lobbyInfo.GlobalSettings.ServerName = settings.Server.Name;
LoadMap(); // populates the Session's slots, too.
@@ -164,7 +164,8 @@ namespace OpenRA.Server
static int ChooseFreeSlot()
{
return lobbyInfo.Slots.First(s => !s.Closed && s.Bot == null).Index;
return lobbyInfo.Slots.First(s => !s.Closed && s.Bot == null
&& !lobbyInfo.Clients.Any( c => c.Slot == s.Index )).Index;
}
static void AcceptConnection()
@@ -588,8 +589,9 @@ namespace OpenRA.Server
static void SyncLobbyInfo()
{
DispatchOrders(null, 0,
new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize());
if (!GameStarted) /* don't do this while the game is running, it breaks things. */
DispatchOrders(null, 0,
new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize());
PingMasterServer();
}

View File

@@ -9,7 +9,6 @@
#endregion
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.Graphics;
namespace OpenRA
@@ -128,7 +127,7 @@ namespace OpenRA
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
}
internal void Draw()
internal void Draw( WorldRenderer wr )
{
if (disabled)
return;
@@ -145,71 +144,45 @@ namespace OpenRA
}
var clipRect = Bounds.HasValue ? Rectangle.Intersect(Bounds.Value, map.Bounds) : map.Bounds;
clipRect = Rectangle.Intersect(Game.viewport.ViewBounds(), clipRect);
var miny = clipRect.Top;
var maxy = clipRect.Bottom;
var minx = clipRect.Left;
var maxx = clipRect.Right;
var shroudPalette = "fog";
DrawShroud( wr, minx, miny, maxx, maxy, fogSprites, "fog" );
DrawShroud( wr, minx, miny, maxx, maxy, sprites, "shroud" );
}
void DrawShroud( WorldRenderer wr, int minx, int miny, int maxx, int maxy, Sprite[,] s, string pal )
{
var shroudPalette = wr.GetPaletteIndex(pal);
for (var j = miny; j < maxy; j++)
{
var starti = minx;
for (var i = minx; i < maxx; i++)
{
if (fogSprites[i, j] == shadowBits[0x0f])
if (s[i, j] == shadowBits[0x0f])
continue;
if (starti != i)
{
Game.Renderer.SpriteRenderer.DrawSprite(fogSprites[starti, j],
Game.CellSize * new float2(starti, j),
shroudPalette,
new float2(Game.CellSize * (i - starti), Game.CellSize));
starti = i+1;
}
Game.Renderer.SpriteRenderer.DrawSprite(fogSprites[i, j],
Game.CellSize * new float2(i, j),
shroudPalette);
starti = i+1;
}
if (starti < maxx)
Game.Renderer.SpriteRenderer.DrawSprite(fogSprites[starti, j],
Game.CellSize * new float2(starti, j),
shroudPalette,
new float2(Game.CellSize * (maxx - starti), Game.CellSize));
}
shroudPalette = "shroud";
for (var j = miny; j < maxy; j++)
{
var starti = minx;
for (var i = minx; i < maxx; i++)
{
if (sprites[i, j] == shadowBits[0x0f])
continue;
if (starti != i)
{
Game.Renderer.SpriteRenderer.DrawSprite(sprites[starti, j],
s[starti, j].DrawAt(
Game.CellSize * new float2(starti, j),
shroudPalette,
new float2(Game.CellSize * (i - starti), Game.CellSize));
starti = i + 1;
}
Game.Renderer.SpriteRenderer.DrawSprite(sprites[i, j],
s[i, j].DrawAt(
Game.CellSize * new float2(i, j),
shroudPalette);
starti = i + 1;
}
if (starti < maxx)
Game.Renderer.SpriteRenderer.DrawSprite(sprites[starti, j],
s[starti, j].DrawAt(
Game.CellSize * new float2(starti, j),
shroudPalette,
new float2(Game.CellSize * (maxx - starti), Game.CellSize));

View File

@@ -129,5 +129,36 @@ namespace OpenRA
return p.Index * 0x567;
return 0;
}
public static void CheckSyncUnchanged( World world, Action fn )
{
CheckSyncUnchanged( world, () => { fn(); return true; } );
}
static bool inUnsyncedCode = false;
public static T CheckSyncUnchanged<T>( World world, Func<T> fn )
{
if( world == null ) return fn();
int sync = world.SyncHash();
bool prevInUnsyncedCode = inUnsyncedCode;
inUnsyncedCode = true;
try
{
return fn();
}
finally
{
inUnsyncedCode = prevInUnsyncedCode;
if( sync != world.SyncHash() )
throw new InvalidOperationException( "CheckSyncUnchanged: sync-changing code may not run here" );
}
}
public static void AssertUnsynced( string message )
{
if( !inUnsyncedCode )
throw new InvalidOperationException( message );
}
}
}

View File

@@ -8,19 +8,19 @@
*/
#endregion
using OpenRA.Traits;
using System.Collections.Generic;
namespace OpenRA.Traits.Activities
{
public class Drag : IActivity
{
public IActivity NextActivity { get; set; }
IActivity NextActivity { get; set; }
float2 endLocation;
float2 startLocation;
int2 endLocation;
int2 startLocation;
int length;
public Drag(float2 start, float2 end, int length)
public Drag(int2 start, int2 end, int length)
{
startLocation = start;
endLocation = end;
@@ -29,15 +29,32 @@ namespace OpenRA.Traits.Activities
int ticks = 0;
public IActivity Tick( Actor self )
{
self.CenterLocation = float2.Lerp(startLocation, endLocation, (float)ticks/(length-1));
{
var mobile = self.Trait<Mobile>();
mobile.PxPosition = int2.Lerp(startLocation, endLocation, ticks, length - 1);
if (++ticks >= length)
return NextActivity;
{
mobile.IsMoving = false;
return NextActivity;
}
mobile.IsMoving = true;
return this;
}
public void Cancel(Actor self) { }
public void Queue( IActivity activity )
{
if( NextActivity != null )
NextActivity.Queue( activity );
else
NextActivity = activity;
}
public IEnumerable<float2> GetCurrentPath()
{
yield return endLocation;
}
}
}

View File

@@ -10,11 +10,8 @@
namespace OpenRA.Traits.Activities
{
class Idle : IActivity
public class Idle : CancelableActivity
{
public IActivity NextActivity { get; set; }
public IActivity Tick(Actor self) { return NextActivity; }
public void Cancel(Actor self) {}
public override IActivity Tick(Actor self) { return NextActivity; }
}
}

View File

@@ -15,33 +15,17 @@ using System.Linq;
namespace OpenRA.Traits.Activities
{
public class Move : IActivity
public class Move : CancelableActivity
{
public IActivity NextActivity { get; set; }
int2? destination;
int nearEnough;
public List<int2> path;
Func<Actor, Mobile, List<int2>> getPath;
public Actor ignoreBuilding;
bool cancellable = true;
MovePart move;
int ticksBeforePathing;
const int avgTicksBeforePathing = 5;
const int spreadTicksBeforePathing = 5;
Move()
{
ticksBeforePathing = avgTicksBeforePathing +
Game.world.SharedRandom.Next(-spreadTicksBeforePathing, spreadTicksBeforePathing);
}
// Scriptable move order
// Ignores lane bias and nearby units
public Move( int2 destination )
: this()
public Move( int2 destination )
{
this.getPath = (self,mobile) =>
self.World.PathFinder.FindPath(
@@ -49,11 +33,9 @@ namespace OpenRA.Traits.Activities
.WithoutLaneBias());
this.destination = destination;
this.nearEnough = 0;
this.cancellable = false;
}
public Move( int2 destination, int nearEnough )
: this()
{
this.getPath = (self,mobile) => self.World.PathFinder.FindUnitPath( mobile.toCell, destination, self );
this.destination = destination;
@@ -61,7 +43,6 @@ namespace OpenRA.Traits.Activities
}
public Move(int2 destination, Actor ignoreBuilding)
: this()
{
this.getPath = (self,mobile) =>
self.World.PathFinder.FindPath(
@@ -75,7 +56,6 @@ namespace OpenRA.Traits.Activities
}
public Move( Actor target, int range )
: this()
{
this.getPath = (self,mobile) => self.World.PathFinder.FindUnitPathToRange(
mobile.toCell, target.Location,
@@ -85,7 +65,6 @@ namespace OpenRA.Traits.Activities
}
public Move(Target target, int range)
: this()
{
this.getPath = (self,mobile) => self.World.PathFinder.FindUnitPathToRange(
mobile.toCell, Util.CellContaining(target.CenterLocation),
@@ -95,35 +74,47 @@ namespace OpenRA.Traits.Activities
}
public Move(Func<List<int2>> getPath)
: this()
{
this.getPath = (_1,_2) => getPath();
this.destination = null;
this.nearEnough = 0;
}
public IActivity Tick( Actor self )
static int HashList<T>(List<T> xs)
{
int hash = 0;
int n = 0;
foreach (var x in xs)
hash += n++ * x.GetHashCode();
return hash;
}
List<int2> EvalPath( Actor self, Mobile mobile )
{
var path = getPath(self, mobile).TakeWhile(a => a != mobile.toCell).ToList();
mobile.PathHash = HashList(path);
Log.Write("debug", "EvalPathHash #{0} {1}",
self.ActorID, mobile.PathHash);
return path;
}
public override IActivity Tick( Actor self )
{
var mobile = self.Trait<Mobile>();
if( move != null )
{
move.TickMove( self, mobile, this );
return this;
}
if (destination == mobile.toCell)
return NextActivity;
if( path == null )
{
if (ticksBeforePathing > 0)
if (mobile.ticksBeforePathing > 0)
{
--ticksBeforePathing;
--mobile.ticksBeforePathing;
return this;
}
path = getPath( self, mobile ).TakeWhile( a => a != mobile.toCell ).ToList();
path = EvalPath(self, mobile);
SanityCheckPath( mobile );
}
@@ -144,22 +135,20 @@ namespace OpenRA.Traits.Activities
if( firstFacing != mobile.Facing )
{
path.Add( nextCell.Value );
return new Turn( firstFacing ) { NextActivity = this };
return Util.SequenceActivities( new Turn( firstFacing ), this ).Tick( self );
}
else
{
mobile.toCell = nextCell.Value;
move = new MoveFirstHalf(
mobile.SetLocation( mobile.fromCell, nextCell.Value );
var move = new MoveFirstHalf(
this,
Util.CenterOfCell( mobile.fromCell ),
Util.BetweenCells( mobile.fromCell, mobile.toCell ),
mobile.Facing,
mobile.Facing,
0 );
move.TickMove( self, mobile, this );
return this;
return move.Tick( self );
}
}
@@ -182,6 +171,9 @@ namespace OpenRA.Traits.Activities
var blocker = self.World.WorldActor.Trait<UnitInfluence>().GetUnitsAt(nextCell).FirstOrDefault();
if (blocker == null) return;
Log.Write("debug", "NudgeBlocker #{0} nudges #{1} at {2} from {3}",
self.ActorID, blocker.ActorID, nextCell, self.Location);
var nudge = blocker.TraitOrDefault<INudge>();
if (nudge != null)
nudge.OnNudge(blocker, self);
@@ -215,8 +207,14 @@ namespace OpenRA.Traits.Activities
if (--waitTicksRemaining >= 0)
return null;
if (mobile.ticksBeforePathing > 0)
{
--mobile.ticksBeforePathing;
return null;
}
mobile.RemoveInfluence();
var newPath = getPath( self, mobile ).TakeWhile(a => a != mobile.toCell).ToList();
var newPath = EvalPath(self, mobile);
mobile.AddInfluence();
if (newPath.Count != 0)
@@ -230,64 +228,98 @@ namespace OpenRA.Traits.Activities
return nextCell;
}
public void Cancel( Actor self )
protected override bool OnCancel()
{
if (!cancellable) return;
path = new List<int2>();
NextActivity = null;
return true;
}
abstract class MovePart
public override IEnumerable<float2> GetCurrentPath()
{
public readonly float2 from, to;
if( path != null )
return Enumerable.Reverse(path).Select( c => (float2)Util.CenterOfCell(c) );
if( destination != null )
return new float2[] { destination.Value };
return new float2[ 0 ];
}
abstract class MovePart : IActivity
{
public readonly Move move;
public readonly int2 from, to;
public readonly int fromFacing, toFacing;
public int moveFraction;
public readonly int moveFractionTotal;
public MovePart( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
public MovePart( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction )
{
this.move = move;
this.from = from;
this.to = to;
this.fromFacing = fromFacing;
this.toFacing = toFacing;
this.moveFraction = startingFraction;
this.moveFractionTotal = (int)(( to - from ).Length*3);
this.moveFractionTotal = ( ( to - from ) * 3 ).Length;
}
public void TickMove( Actor self, Mobile mobile, Move parent )
public void Cancel( Actor self )
{
moveFraction += (int)mobile.MovementSpeedForCell(self, mobile.toCell);
if( moveFraction >= moveFractionTotal )
move.Cancel( self );
}
public void Queue( IActivity activity )
{
move.Queue( activity );
}
public IActivity Tick( Actor self )
{
var mobile = self.Trait<Mobile>();
var ret = InnerTick( self, mobile );
mobile.IsMoving = ( ret is MovePart );
if( moveFraction > moveFractionTotal )
moveFraction = moveFractionTotal;
UpdateCenterLocation( self, mobile );
if( moveFraction >= moveFractionTotal )
{
parent.move = OnComplete( self, mobile, parent );
if( parent.move == null )
UpdateCenterLocation( self, mobile );
}
return ret;
}
IActivity InnerTick( Actor self, Mobile mobile )
{
moveFraction += (int)mobile.MovementSpeedForCell(self, mobile.toCell);
if( moveFraction <= moveFractionTotal )
return this;
var next = OnComplete( self, mobile, move );
if( next != null )
return next;
return move;
}
void UpdateCenterLocation( Actor self, Mobile mobile )
{
var frac = (float)moveFraction / moveFractionTotal;
self.CenterLocation = float2.Lerp( from, to, frac );
mobile.PxPosition = int2.Lerp( from, to, moveFraction, moveFractionTotal );
if( moveFraction >= moveFractionTotal )
mobile.Facing = toFacing & 0xFF;
else
mobile.Facing = ( fromFacing + ( toFacing - fromFacing ) * moveFraction / moveFractionTotal ) & 0xFF;
mobile.Facing = int2.Lerp( fromFacing, toFacing, moveFraction, moveFractionTotal ) & 0xFF;
}
protected abstract MovePart OnComplete( Actor self, Mobile mobile, Move parent );
public IEnumerable<float2> GetCurrentPath()
{
return move.GetCurrentPath();
}
}
class MoveFirstHalf : MovePart
{
public MoveFirstHalf( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
: base( from, to, fromFacing, toFacing, startingFraction )
public MoveFirstHalf( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction )
: base( move, from, to, fromFacing, toFacing, startingFraction )
{
}
@@ -299,40 +331,41 @@ namespace OpenRA.Traits.Activities
if( ( nextCell - mobile.toCell ) != ( mobile.toCell - mobile.fromCell ) )
{
var ret = new MoveFirstHalf(
move,
Util.BetweenCells( mobile.fromCell, mobile.toCell ),
Util.BetweenCells( mobile.toCell, nextCell.Value ),
mobile.Facing,
Util.GetNearestFacing( mobile.Facing, Util.GetFacing( nextCell.Value - mobile.toCell, mobile.Facing ) ),
moveFraction - moveFractionTotal );
mobile.fromCell = mobile.toCell;
mobile.toCell = nextCell.Value;
mobile.SetLocation( mobile.toCell, nextCell.Value );
return ret;
}
else
parent.path.Add( nextCell.Value );
}
var ret2 = new MoveSecondHalf(
move,
Util.BetweenCells( mobile.fromCell, mobile.toCell ),
Util.CenterOfCell( mobile.toCell ),
mobile.Facing,
mobile.Facing,
moveFraction - moveFractionTotal );
mobile.fromCell = mobile.toCell;
mobile.SetLocation( mobile.toCell, mobile.toCell );
return ret2;
}
}
class MoveSecondHalf : MovePart
{
public MoveSecondHalf( float2 from, float2 to, int fromFacing, int toFacing, int startingFraction )
: base( from, to, fromFacing, toFacing, startingFraction )
public MoveSecondHalf( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction )
: base( move, from, to, fromFacing, toFacing, startingFraction )
{
}
protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent )
{
self.CenterLocation = Util.CenterOfCell( mobile.toCell );
mobile.fromCell = mobile.toCell;
mobile.PxPosition = Util.CenterOfCell( mobile.toCell );
mobile.SetLocation( mobile.toCell, mobile.toCell );
mobile.FinishedMoving(self);
return null;
}

View File

@@ -10,18 +10,13 @@
namespace OpenRA.Traits.Activities
{
public class RemoveSelf : IActivity
public class RemoveSelf : CancelableActivity
{
bool isCanceled;
public IActivity NextActivity { get; set; }
public IActivity Tick(Actor self)
public override IActivity Tick(Actor self)
{
if (isCanceled) return NextActivity;
if (IsCanceled) return NextActivity;
self.Destroy();
return null;
}
public void Cancel(Actor self) { isCanceled = true; NextActivity = null; }
}
}

View File

@@ -8,11 +8,13 @@
*/
#endregion
using System.Collections.Generic;
namespace OpenRA.Traits.Activities
{
class Sell : IActivity
{
public IActivity NextActivity { get; set; }
IActivity NextActivity { get; set; }
bool started;
@@ -55,5 +57,18 @@ namespace OpenRA.Traits.Activities
}
public void Cancel(Actor self) { /* never gonna give you up.. */ }
public void Queue( IActivity activity )
{
if( NextActivity != null )
NextActivity.Queue( activity );
else
NextActivity = activity;
}
public IEnumerable<float2> GetCurrentPath()
{
yield break;
}
}
}

View File

@@ -12,9 +12,8 @@ using System.Linq;
namespace OpenRA.Traits.Activities
{
public class Turn : IActivity
public class Turn : CancelableActivity
{
public IActivity NextActivity { get; set; }
int desiredFacing;
public Turn( int desiredFacing )
@@ -22,8 +21,9 @@ namespace OpenRA.Traits.Activities
this.desiredFacing = desiredFacing;
}
public IActivity Tick( Actor self )
public override IActivity Tick( Actor self )
{
if (IsCanceled) return NextActivity;
var facing = self.Trait<IFacing>();
if( desiredFacing == facing.Facing )
@@ -32,11 +32,5 @@ namespace OpenRA.Traits.Activities
return this;
}
public void Cancel( Actor self )
{
desiredFacing = self.Trait<IFacing>().Facing;
NextActivity = null;
}
}
}

View File

@@ -38,46 +38,41 @@ namespace OpenRA.Traits
public object Create(ActorInitializer init) { return new Building(init); }
}
public class Building : INotifyDamage, IResolveOrder, IRenderModifier, IOccupySpace
public class Building : INotifyDamage, IResolveOrder, IOccupySpace
{
readonly Actor self;
public readonly BuildingInfo Info;
[Sync]
readonly int2 topLeft;
public bool Disabled
{
get { return self.TraitsImplementing<IDisable>().Any(t => t.Disabled); }
}
readonly PowerManager PlayerPower;
public int2 PxPosition { get { return ( 2 * topLeft + Info.Dimensions ) * Game.CellSize / 2; } }
public Building(ActorInitializer init)
{
this.self = init.self;
this.topLeft = init.Get<LocationInit,int2>();
Info = self.Info.Traits.Get<BuildingInfo>();
self.CenterLocation = Game.CellSize
* ((float2)topLeft + .5f * (float2)Info.Dimensions);
PlayerPower = init.self.Owner.PlayerActor.Trait<PowerManager>();
}
public int GetPowerUsage()
{
var modifier = self
.TraitsImplementing<IPowerModifier>()
.Select(t => t.GetPowerModifier())
.Product();
if (Info.Power <= 0)
return Info.Power;
if (Info.Power > 0)
{
var health = self.TraitOrDefault<Health>();
var healthFraction = (health == null) ? 1f : health.HPFraction;
return (int)(modifier * healthFraction * Info.Power);
}
else
return (int)(modifier * Info.Power);
var health = self.TraitOrDefault<Health>();
return health != null ? (Info.Power * health.HP / health.MaxHP) : Info.Power;
}
public void Damaged(Actor self, AttackInfo e)
{
// Power plants lose power with damage
if (Info.Power > 0)
PlayerPower.UpdateActor(self, GetPowerUsage());
if (e.DamageState == DamageState.Dead)
{
self.World.WorldActor.Trait<ScreenShaker>().AddEffect(10, self.CenterLocation, 1);
@@ -94,16 +89,6 @@ namespace OpenRA.Traits
}
}
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
{
foreach (var a in r)
{
yield return a;
if (Disabled)
yield return a.WithPalette("disabled");
}
}
public int2 TopLeft
{
get { return topLeft; }

View File

@@ -8,8 +8,8 @@
*/
#endregion
using System.Drawing;
using OpenRA.Traits.Activities;
using System.Drawing;
using OpenRA.Graphics;
namespace OpenRA.Traits
{
@@ -45,7 +45,7 @@ namespace OpenRA.Traits
this.c = c;
}
public void RenderAfterWorld(Actor self)
public void RenderAfterWorld(WorldRenderer wr, Actor self)
{
if (self.IsIdle) return;
@@ -53,6 +53,9 @@ namespace OpenRA.Traits
if ((lifetime <= 0 || --lifetime <= 0) && !force)
return;
if (!target.IsValid)
return;
var p = target.CenterLocation;
Game.Renderer.LineRenderer.DrawLine(self.CenterLocation, p, c, c);

6
OpenRA.Game/Traits/Health.cs Normal file → Executable file
View File

@@ -140,6 +140,8 @@ namespace OpenRA.Traits
{
public static bool IsDead(this Actor self)
{
if (self.Destroyed) return true;
var health = self.TraitOrDefault<Health>();
return (health == null) ? true : health.IsDead;
}
@@ -161,7 +163,9 @@ namespace OpenRA.Traits
{
var health = self.TraitOrDefault<Health>();
if (health == null) return;
health.InflictDamage(self, attacker, health.HP, null);
/* hack. Fix for proper */
health.InflictDamage(self, attacker, int.MaxValue, null);
}
}
}

View File

@@ -15,6 +15,8 @@ using System.Linq;
using OpenRA.Effects;
using OpenRA.Traits.Activities;
using OpenRA.FileFormats;
using System.Diagnostics;
using OpenRA.Orders;
namespace OpenRA.Traits
{
@@ -38,7 +40,7 @@ namespace OpenRA.Traits
foreach (var t in y.NodesDict["TerrainSpeeds"].Nodes)
{
var speed = (float)FieldLoader.GetValue("speed", typeof(float),t.Value.Value);
var cost = t.Value.NodesDict.ContainsKey("PathingCost") ? (float)FieldLoader.GetValue("cost", typeof(float), t.Value.NodesDict["PathingCost"].Value) : 1f/speed;
var cost = t.Value.NodesDict.ContainsKey("PathingCost") ? (int)FieldLoader.GetValue("cost", typeof(int), t.Value.NodesDict["PathingCost"].Value) : (int)(10000/speed);
ret.Add(t.Key, new TerrainInfo{Speed = speed, Cost = cost});
}
@@ -47,39 +49,51 @@ namespace OpenRA.Traits
public class TerrainInfo
{
public float Cost = float.PositiveInfinity;
public int Cost = int.MaxValue;
public float Speed = 0;
}
}
public class Mobile : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice, IOccupySpace, IMove, IFacing, INudge
public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IOccupySpace, IMove, IFacing, INudge
{
public readonly Actor self;
public readonly MobileInfo Info;
public bool IsMoving { get; internal set; }
int __facing;
int2 __fromCell, __toCell;
int __altitude;
[Sync]
public int Facing
{
get { return __facing; }
set { __facing = value; }
}
[Sync]
public int Altitude
{
get { return __altitude; }
set { __altitude = value; }
}
[Sync]
public int Facing { get; set; }
[Sync]
public int Altitude { get; set; }
[Sync]
public int ROT { get { return Info.ROT; } }
public int InitialFacing { get { return Info.InitialFacing; } }
int2 __fromCell, __toCell;
public int2 fromCell
{
get { return __fromCell; }
set { SetLocation( value, __toCell ); }
}
[Sync]
public int2 toCell
public int2 PxPosition { get; set; }
[Sync]
public int2 fromCell { get { return __fromCell; } }
[Sync]
public int2 toCell { get { return __toCell; } }
[Sync]
public int PathHash; // written by Move.EvalPath, to temporarily debug this crap.
public void SetLocation(int2 from, int2 to)
{
get { return __toCell; }
set { SetLocation( __fromCell, value ); }
}
void SetLocation( int2 from, int2 to )
{
if( fromCell == from && toCell == to ) return;
if (fromCell == from && toCell == to) return;
RemoveInfluence();
__fromCell = from;
__toCell = to;
@@ -87,6 +101,10 @@ namespace OpenRA.Traits
}
UnitInfluence uim;
const int avgTicksBeforePathing = 5;
const int spreadTicksBeforePathing = 5;
internal int ticksBeforePathing = 0;
public Mobile(ActorInitializer init, MobileInfo info)
{
@@ -98,6 +116,7 @@ namespace OpenRA.Traits
if (init.Contains<LocationInit>())
{
this.__fromCell = this.__toCell = init.Get<LocationInit,int2>();
this.PxPosition = Util.CenterOfCell( fromCell );
AddInfluence();
}
@@ -108,24 +127,27 @@ namespace OpenRA.Traits
public void SetPosition(Actor self, int2 cell)
{
SetLocation( cell, cell );
self.CenterLocation = Util.CenterOfCell(fromCell);
PxPosition = Util.CenterOfCell(fromCell);
}
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
public void SetPxPosition( Actor self, int2 px )
{
// Force move takes precidence
return mi.Modifiers.HasModifier(Modifiers.Alt) ? int.MaxValue : 0;
var cell = Util.CellContaining( px );
SetLocation( cell, cell );
PxPosition = px;
}
public IEnumerable<IOrderTargeter> Orders { get { yield return new MoveOrderTargeter( Info ); } }
// Note: Returns a valid order even if the unit can't move to the target
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
{
if (Info.OnRails) return null;
if (mi.Button == MouseButton.Left) return null;
var type = (!self.World.LocalPlayer.Shroud.IsVisible(xy) || CanEnterCell(xy)) ? "Move" : "Move-Blocked";
return new Order(type, self, xy, mi.Modifiers.HasModifier(Modifiers.Shift));
if( order is MoveOrderTargeter )
{
if( Info.OnRails ) return null;
return new Order( "Move", self, Util.CellContaining( target.CenterLocation ), false );
}
return null;
}
public int2 NearestMoveableCell(int2 target)
@@ -150,15 +172,16 @@ namespace OpenRA.Traits
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Move" || order.OrderString == "Move-Blocked")
if (order.OrderString == "Move")
{
int2 currentLocation = NearestMoveableCell(order.TargetLocation);
if (!CanEnterCell(currentLocation))
return;
if( !order.Queued ) self.CancelActivity();
self.QueueActivity(new Activities.Move(currentLocation, 8));
if (self.Owner == self.World.LocalPlayer)
self.World.AddFrameEndTask(w =>
{
@@ -167,23 +190,14 @@ namespace OpenRA.Traits
if (line != null)
line.SetTarget(self, Target.FromCell(currentLocation), Color.Green);
});
ticksBeforePathing = avgTicksBeforePathing +
self.World.SharedRandom.Next( -spreadTicksBeforePathing, spreadTicksBeforePathing );
}
}
public string CursorForOrder(Actor self, Order order)
{
if (order.OrderString == "Move")
return "move";
if (order.OrderString == "Move-Blocked")
return "move-blocked";
return null;
}
public string VoicePhraseForOrder(Actor self, Order order)
{
if (order.OrderString == "Move" || order.OrderString == "Move-Blocked")
if (order.OrderString == "Move")
return "Move";
return null;
}
@@ -220,7 +234,7 @@ namespace OpenRA.Traits
public static bool CanEnterCell( MobileInfo mobileInfo, World world, UnitInfluence uim, BuildingInfluence bim, int2 cell, Actor ignoreActor, bool checkTransientActors )
{
if (MovementCostForCell(mobileInfo, world, cell) == float.PositiveInfinity)
if (MovementCostForCell(mobileInfo, world, cell) == int.MaxValue)
return false;
// Check for buildings
@@ -265,19 +279,14 @@ namespace OpenRA.Traits
}
}
public float MovementCostForCell( Actor self, int2 cell )
{
return MovementCostForCell( Info, self.World, cell );
}
public static float MovementCostForCell(MobileInfo info, World world, int2 cell)
public static int MovementCostForCell(MobileInfo info, World world, int2 cell)
{
if (!world.Map.IsInMap(cell.X,cell.Y))
return float.PositiveInfinity;
return int.MaxValue;
var type = world.GetTerrainType(cell);
if (!info.TerrainSpeeds.ContainsKey(type))
return float.PositiveInfinity;
return int.MaxValue;
return info.TerrainSpeeds[type].Cost;
}
@@ -293,15 +302,7 @@ namespace OpenRA.Traits
.TraitsImplementing<ISpeedModifier>()
.Select(t => t.GetSpeedModifier())
.Product();
return Info.Speed * Info.TerrainSpeeds[type].Speed * modifier;
}
public IEnumerable<float2> GetCurrentPath(Actor self)
{
var move = self.GetCurrentActivity() as Move;
if (move == null || move.path == null) return new float2[] { };
return Enumerable.Reverse(move.path).Select( c => Util.CenterOfCell(c) );
return Info.Speed * Info.TerrainSpeeds[type].Speed * modifier / 100f;
}
public void AddInfluence()
@@ -354,6 +355,38 @@ namespace OpenRA.Traits
line.SetTargetSilently(self, Target.FromCell(moveTo.Value), Color.Green);
});
self.QueueActivity(new Move(moveTo.Value, 0));
Log.Write("debug", "OnNudge #{0} from {1} to {2}",
self.ActorID, self.Location, moveTo.Value);
}
else
Log.Write("debug", "OnNudge #{0} refuses at {1}",
self.ActorID, self.Location);
}
class MoveOrderTargeter : IOrderTargeter
{
readonly MobileInfo unitType;
public MoveOrderTargeter( MobileInfo unitType )
{
this.unitType = unitType;
}
public string OrderID { get { return "Move"; } }
public int OrderPriority { get { return 4; } }
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
{
return false;
}
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
{
cursor = "move";
if( self.World.LocalPlayer.Shroud.IsVisible( location ) && !self.Trait<Mobile>().CanEnterCell( location ) )
cursor = "move-blocked";
return true;
}
}
}

View File

@@ -42,7 +42,7 @@ namespace OpenRA.Traits
public void ResolveOrder (Actor self, Order order)
{
if (!Game.LobbyInfo.GlobalSettings.AllowCheats) return;
if (!self.World.LobbyInfo.GlobalSettings.AllowCheats) return;
switch(order.OrderString)
{
@@ -68,17 +68,14 @@ namespace OpenRA.Traits
}
case "DevShroud":
{
DisableShroud ^= true;
if (self.World.LocalPlayer == self.Owner)
{
DisableShroud ^= true;
Game.world.LocalPlayer.Shroud.Disabled = DisableShroud;
}
self.World.LocalPlayer.Shroud.Disabled = DisableShroud;
break;
}
case "DevPathDebug":
{
if (self.World.LocalPlayer == self.Owner)
PathDebug ^= true;
PathDebug ^= true;
break;
}
case "DevUnitDebug":
@@ -86,14 +83,19 @@ namespace OpenRA.Traits
if (self.World.LocalPlayer == self.Owner)
Game.Settings.Debug.ShowCollisions ^= true;
break;
}
case "DevGiveExploration":
{
if (self.World.LocalPlayer == self.Owner)
self.World.WorldActor.Trait<Shroud>().ExploreAll(self.World);
break;
}
case "DevGiveExploration":
{
if (self.World.LocalPlayer == self.Owner)
self.World.WorldActor.Trait<Shroud>().ExploreAll(self.World);
break;
}
default:
return;
}
Game.Debug("Cheat used: {0} by {1}"
.F(order.OrderString, self.Owner.PlayerName));
}
}
}

View File

@@ -13,7 +13,7 @@ using System.Linq;
namespace OpenRA.Traits
{
class PlayerResourcesInfo : ITraitInfo
public class PlayerResourcesInfo : ITraitInfo
{
public readonly int InitialCash = 10000;
public readonly int InitialOre = 0;
@@ -45,17 +45,53 @@ namespace OpenRA.Traits
public int OreCapacity;
[Sync]
public int DisplayOre;
public float GetSiloFullness() { return (float)Ore / OreCapacity; }
public void GiveOre(int num)
{
Ore += num;
if (Ore > OreCapacity)
{
nextSiloAdviceTime = 0;
Ore = OreCapacity;
}
}
[Sync]
public int PowerProvided;
[Sync]
public int PowerDrained;
public bool TakeOre(int num)
{
if (Ore < num) return false;
Ore -= num;
return true;
}
public void GiveCash(int num)
{
Cash += num;
}
public bool TakeCash(int num)
{
if (Cash + Ore < num) return false;
// Spend ore before cash
Ore -= num;
if (Ore < 0)
{
Cash += Ore;
Ore = 0;
}
return true;
}
const float displayCashFracPerFrame = .07f;
const int displayCashDeltaPerFrame = 37;
int nextSiloAdviceTime = 0;
void TickOre(Actor self)
public void Tick(Actor self)
{
OreCapacity = self.World.Queries.OwnedBy[Owner].WithTrait<IStoreOre>()
.Sum(a => a.Trait.Capacity);
@@ -102,91 +138,5 @@ namespace OpenRA.Traits
Sound.PlayToPlayer(self.Owner, eva.CashTickDown);
}
}
int nextPowerAdviceTime = 0;
void TickPower()
{
var oldBalance = PowerProvided - PowerDrained;
PowerProvided = 0;
PowerDrained = 0;
var myBuildings = Owner.World.Queries.OwnedBy[Owner].WithTrait<Building>();
foreach (var a in myBuildings)
{
var q = a.Trait.GetPowerUsage();
if (q > 0)
PowerProvided += q;
else
PowerDrained -= q;
}
if (PowerProvided - PowerDrained < 0)
if (PowerProvided - PowerDrained != oldBalance)
nextPowerAdviceTime = 0;
if (--nextPowerAdviceTime <= 0)
{
if (PowerProvided - PowerDrained < 0)
Owner.GiveAdvice(Rules.Info["world"].Traits.Get<EvaAlertsInfo>().LowPower);
nextPowerAdviceTime = AdviceInterval;
}
}
public PowerState GetPowerState()
{
if (PowerProvided >= PowerDrained) return PowerState.Normal;
if (PowerProvided > PowerDrained / 2) return PowerState.Low;
return PowerState.Critical;
}
public float GetSiloFullness() { return (float)Ore / OreCapacity; }
public void GiveOre(int num)
{
Ore += num;
if (Ore > OreCapacity)
{
nextSiloAdviceTime = 0;
Ore = OreCapacity;
}
}
public bool TakeOre(int num)
{
if (Ore < num) return false;
Ore -= num;
return true;
}
public void GiveCash(int num)
{
Cash += num;
}
public bool TakeCash(int num)
{
if (Cash + Ore < num) return false;
// Spend ore before cash
Ore -= num;
if (Ore < 0)
{
Cash += Ore;
Ore = 0;
}
return true;
}
public void Tick(Actor self)
{
TickPower();
TickOre(self);
}
}
}

View File

@@ -0,0 +1,111 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Linq;
using System.Collections.Generic;
using OpenRA.FileFormats;
namespace OpenRA.Traits
{
public class PowerManagerInfo : ITraitInfo
{
public readonly int AdviceInterval = 250;
public object Create(ActorInitializer init) { return new PowerManager(init, this); }
}
public class PowerManager : ITick
{
PowerManagerInfo Info;
Player Player;
Dictionary<Actor, int> PowerDrain = new Dictionary<Actor, int>();
[Sync] int totalProvided;
public int PowerProvided { get { return totalProvided; } }
[Sync] int totalDrained;
public int PowerDrained { get { return totalDrained; } }
public PowerManager(ActorInitializer init, PowerManagerInfo info)
{
Info = info;
Player = init.self.Owner;
init.world.ActorAdded += ActorAdded;
init.world.ActorRemoved += ActorRemoved;
}
void ActorAdded(Actor a)
{
if (a.Owner != Player || !a.HasTrait<Building>())
return;
PowerDrain.Add(a, a.Trait<Building>().GetPowerUsage());
UpdateTotals();
}
void ActorRemoved(Actor a)
{
if (a.Owner != Player || !a.HasTrait<Building>())
return;
PowerDrain.Remove(a);
UpdateTotals();
}
void UpdateTotals()
{
totalProvided = 0;
totalDrained = 0;
foreach (var kv in PowerDrain)
{
var p = kv.Value;
if (p > 0)
totalProvided += p;
else
totalDrained -= p;
}
}
public void UpdateActor(Actor a, int newPower)
{
if (a.Owner != Player || !a.HasTrait<Building>())
return;
PowerDrain[a] = newPower;
UpdateTotals();
}
int nextPowerAdviceTime = 0;
bool wasLowPower = false;
public void Tick(Actor self)
{
var lowPower = totalProvided < totalDrained;
if (lowPower && !wasLowPower)
nextPowerAdviceTime = 0;
wasLowPower = lowPower;
if (--nextPowerAdviceTime <= 0)
{
if (lowPower)
Player.GiveAdvice(Rules.Info["world"].Traits.Get<EvaAlertsInfo>().LowPower);
nextPowerAdviceTime = Info.AdviceInterval;
}
}
public PowerState PowerState
{
get {
if (PowerProvided >= PowerDrained) return PowerState.Normal;
if (PowerProvided > PowerDrained / 2) return PowerState.Low;
return PowerState.Critical;
}
}
}
}

View File

@@ -0,0 +1,124 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Traits
{
public class TechTreeInfo : ITraitInfo
{
public object Create(ActorInitializer init) { return new TechTree(init);}
}
public class TechTree
{
readonly List<Watcher> watchers = new List<Watcher>();
readonly Player player;
public TechTree(ActorInitializer init)
{
player = init.self.Owner;
init.world.ActorAdded += ActorChanged;
init.world.ActorRemoved += ActorChanged;
}
public void ActorChanged(Actor a)
{
if (a.Owner == player && a.HasTrait<Building>())
Update();
}
public void Update()
{
var buildings = GatherBuildings(player);
foreach(var w in watchers)
w.Update(buildings);
}
public void Add(string key, List<string> prerequisites, ITechTreeElement tte)
{
Add(key, prerequisites, false, tte);
}
// set requiresPowered = true to discard buildings that have an IDisabled active (eg manually powered down)
public void Add(string key, List<string> prerequisites, bool requiresPowered, ITechTreeElement tte)
{
watchers.Add(new Watcher( key, prerequisites, requiresPowered, tte ));
}
public void Remove(string key)
{
watchers.RemoveAll(x => x.key == key);
}
static Cache<string, List<Actor>> GatherBuildings( Player player )
{
var ret = new Cache<string, List<Actor>>( x => new List<Actor>() );
if (player == null)
return ret;
foreach( var b in player.World.Queries.OwnedBy[player].Where( x=>x.Info.Traits.Contains<BuildingInfo>() ) )
{
ret[ b.Info.Name ].Add( b );
var tt = b.Info.Traits.GetOrDefault<TooltipInfo>();
if( tt != null )
foreach( var alt in tt.AlternateName )
ret[ alt ].Add( b );
}
return ret;
}
class Watcher
{
public readonly string key;
// strings may be either actor type, or "alternate name" key
public readonly List<string> prerequisites;
public readonly ITechTreeElement watcher;
bool hasPrerequisites;
bool requiresPowered;
public Watcher(string key, List<string> prerequisites, bool requiresPowered, ITechTreeElement watcher)
{
this.key = key;
this.prerequisites = prerequisites;
this.watcher = watcher;
this.hasPrerequisites = false;
this.requiresPowered = requiresPowered;
}
public void Update(Cache<string, List<Actor>> buildings)
{
var nowHasPrerequisites = true;
foreach (var p in prerequisites)
if (!buildings.Keys.Contains(p) ||
(requiresPowered && buildings[p].All(b => b.TraitsImplementing<IDisable>().Any(d => d.Disabled))))
{
nowHasPrerequisites = false;
break;
}
if( nowHasPrerequisites && !hasPrerequisites )
watcher.PrerequisitesAvailable(key);
if( !nowHasPrerequisites && hasPrerequisites )
watcher.PrerequisitesUnavailable(key);
hasPrerequisites = nowHasPrerequisites;
}
}
}
public interface ITechTreeElement
{
void PrerequisitesAvailable(string key);
void PrerequisitesUnavailable(string key);
}
}

View File

@@ -1,78 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.GameRules;
namespace OpenRA.Traits
{
class TechTreeCacheInfo : TraitInfo<TechTreeCache> { }
class TechTreeCache : ITick
{
class Watcher
{
public readonly string key;
// strings may be either actor type, or "alternate name" key
public readonly List<string> prerequisites;
public readonly ITechTreeElement watcher;
bool hasPrerequisites;
public Watcher(string key, List<string> prerequisites, ITechTreeElement watcher)
{
this.key = key;
this.prerequisites = prerequisites;
this.watcher = watcher;
this.hasPrerequisites = false;
}
public void Tick( Player owner, Cache<string, List<Actor>> buildings )
{
var nowHasPrerequisites = prerequisites.All( a => buildings[ a ].Any( b => !b.Trait<Building>().Disabled ) );
if( nowHasPrerequisites && !hasPrerequisites )
watcher.PrerequisitesAvailable(key);
if( !nowHasPrerequisites && hasPrerequisites )
watcher.PrerequisitesUnavailable(key);
hasPrerequisites = nowHasPrerequisites;
}
}
readonly List<Watcher> watchers = new List<Watcher>();
public void Tick( Actor self )
{
var buildings = Rules.TechTree.GatherBuildings( self.Owner );
foreach( var w in watchers )
w.Tick( self.Owner, buildings );
}
public void Add( string key, List<string> prerequisites, ITechTreeElement tte )
{
watchers.Add( new Watcher( key, prerequisites, tte ) );
}
public void Remove( string key )
{
watchers.RemoveAll( x => x.key == key );
}
}
interface ITechTreeElement
{
void PrerequisitesAvailable(string key);
void PrerequisitesUnavailable(string key);
}
}

12
OpenRA.Game/Traits/Render/RenderSimple.cs Normal file → Executable file
View File

@@ -62,16 +62,20 @@ namespace OpenRA.Traits
a.Animation.Tick();
}
protected virtual string GetPrefix(Actor self)
protected virtual string NormalizeSequence(Actor self, string baseSequence)
{
return self.GetDamageState() >= DamageState.Heavy ? "damaged-" : "";
string damageState = self.GetDamageState() >= DamageState.Heavy ? "damaged-" : "";
if (anim.HasSequence(damageState + baseSequence))
return damageState + baseSequence;
else
return baseSequence;
}
public void PlayCustomAnim(Actor self, string name)
{
if (anim.HasSequence(name))
anim.PlayThen(GetPrefix(self) + name,
() => anim.PlayRepeating(GetPrefix(self) + "idle"));
anim.PlayThen(NormalizeSequence(self, name),
() => anim.PlayRepeating(NormalizeSequence(self, "idle")));
}
public class AnimationWithOffset

View File

@@ -28,7 +28,7 @@ namespace OpenRA.Traits
public void Tick(Actor self)
{
if (!self.IsIdle && previousLocation != self.Location)
if (previousLocation != self.Location)
{
previousLocation = self.Location;
self.World.WorldActor.Trait<Shroud>().UpdateActor(self);

View File

@@ -10,7 +10,6 @@
using System.Drawing;
using OpenRA.Graphics;
using System.Linq;
namespace OpenRA.Traits
{
@@ -29,7 +28,7 @@ namespace OpenRA.Traits
static readonly string[] pipStrings = { "pip-empty", "pip-green", "pip-yellow", "pip-red", "pip-gray" };
static readonly string[] tagStrings = { "", "tag-fake", "tag-primary" };
public void RenderAfterWorld (Actor self)
public void RenderAfterWorld (WorldRenderer wr, Actor self)
{
var bounds = self.GetBounds(true);
@@ -40,9 +39,9 @@ namespace OpenRA.Traits
DrawSelectionBox(self, xy, Xy, xY, XY, Color.White);
DrawHealthBar(self, xy, Xy);
DrawControlGroup(self, xy);
DrawPips(self, xY);
DrawTags(self, new float2(.5f * (bounds.Left + bounds.Right), bounds.Top));
DrawControlGroup(wr, self, xy);
DrawPips(wr, self, xY);
DrawTags(wr, self, new float2(.5f * (bounds.Left + bounds.Right), bounds.Top));
DrawUnitPath(self);
}
@@ -61,9 +60,10 @@ namespace OpenRA.Traits
void DrawHealthBar(Actor self, float2 xy, float2 Xy)
{
if (!self.IsInWorld) return;
var health = self.TraitOrDefault<Health>();
if (self.IsDead() || health == null)
return;
if (health == null || health.IsDead) return;
var c = Color.Gray;
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), xy + new float2(0, -4), c, c);
@@ -88,7 +88,7 @@ namespace OpenRA.Traits
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -4), z + new float2(0, -4), healthColor2, healthColor2);
}
void DrawControlGroup(Actor self, float2 basePosition)
void DrawControlGroup(WorldRenderer wr, Actor self, float2 basePosition)
{
var group = self.World.Selection.GetControlGroupForActor(self);
if (group == null) return;
@@ -96,10 +96,10 @@ namespace OpenRA.Traits
var pipImages = new Animation("pips");
pipImages.PlayFetchIndex("groups", () => (int)group);
pipImages.Tick();
Game.Renderer.SpriteRenderer.DrawSprite(pipImages.Image, basePosition + new float2(-8, 1), "chrome");
pipImages.Image.DrawAt(wr, basePosition + new float2(-8, 1), "chrome");
}
void DrawPips(Actor self, float2 basePosition)
void DrawPips(WorldRenderer wr, Actor self, float2 basePosition)
{
if (self.Owner != self.World.LocalPlayer) return;
@@ -122,7 +122,7 @@ namespace OpenRA.Traits
}
var pipImages = new Animation("pips");
pipImages.PlayRepeating(pipStrings[(int)pip]);
Game.Renderer.SpriteRenderer.DrawSprite(pipImages.Image, pipxyBase + pipxyOffset, "chrome");
pipImages.Image.DrawAt(wr, pipxyBase + pipxyOffset, "chrome");
pipxyOffset += new float2(4, 0);
}
// Increment row
@@ -131,7 +131,7 @@ namespace OpenRA.Traits
}
}
void DrawTags(Actor self, float2 basePosition)
void DrawTags(WorldRenderer wr, Actor self, float2 basePosition)
{
if (self.Owner != self.World.LocalPlayer) return;
@@ -148,7 +148,7 @@ namespace OpenRA.Traits
var tagImages = new Animation("pips");
tagImages.PlayRepeating(tagStrings[(int)tag]);
Game.Renderer.SpriteRenderer.DrawSprite(tagImages.Image, tagxyBase + tagxyOffset, "chrome");
tagImages.Image.DrawAt(wr, tagxyBase + tagxyOffset, "chrome");
// Increment row
tagxyOffset.Y += 8;
@@ -158,13 +158,14 @@ namespace OpenRA.Traits
void DrawUnitPath(Actor self)
{
if (!Game.world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
if (!self.World.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
var activity = self.GetCurrentActivity();
var mobile = self.TraitOrDefault<IMove>();
if (mobile != null)
if (activity != null && mobile != null)
{
var alt = new float2(0, -mobile.Altitude);
var path = mobile.GetCurrentPath(self);
var path = activity.GetCurrentPath();
var start = self.CenterLocation + alt;
var c = Color.Green;

0
OpenRA.Game/Traits/SharesCell.cs Normal file → Executable file
View File

View File

@@ -17,7 +17,7 @@ namespace OpenRA.Traits
public class TargetableInfo : ITraitInfo
{
public readonly string[] TargetTypes = {};
public object Create( ActorInitializer init ) { return new Targetable(this); }
public virtual object Create( ActorInitializer init ) { return new Targetable(this); }
}
public class Targetable : ITargetable

View File

@@ -10,9 +10,9 @@
using System.Collections.Generic;
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.FileFormats;
namespace OpenRA.Traits
{
@@ -35,8 +35,15 @@ namespace OpenRA.Traits
public interface IRender { IEnumerable<Renderable> Render(Actor self); }
public interface IIssueOrder
{
Order IssueOrder( Actor self, int2 xy, MouseInput mi, Actor underCursor );
int OrderPriority( Actor self, int2 xy, MouseInput mi, Actor underCursor );
IEnumerable<IOrderTargeter> Orders { get; }
Order IssueOrder( Actor self, IOrderTargeter order, Target target );
}
public interface IOrderTargeter
{
string OrderID { get; }
int OrderPriority { get; }
bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor );
bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor );
}
public interface IResolveOrder { void ResolveOrder(Actor self, Order order); }
public interface IOrderCursor { string CursorForOrder(Actor self, Order order); }
@@ -49,7 +56,6 @@ namespace OpenRA.Traits
public interface INotifyProduction { void UnitProduced(Actor self, Actor other, int2 exit); }
public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); }
public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); }
public interface INotifyEnterCell { void OnEnterCell(Actor self, int2 cell); }
public interface IStoreOre { int Capacity { get; }}
public interface IDisable { bool Disabled { get; } }
@@ -64,18 +70,17 @@ namespace OpenRA.Traits
public interface IVisibilityModifier { bool IsVisible(Actor self, Player byPlayer); }
public interface IRadarColorModifier { Color RadarColorOverride(Actor self); }
public interface IOccupySpace
public interface IHasLocation
{
int2 PxPosition { get; }
}
public interface IOccupySpace : IHasLocation
{
int2 TopLeft { get; }
IEnumerable<int2> OccupiedCells();
}
public interface IOccupyAir
{
int2 TopLeft { get; }
IEnumerable<int2> OccupiedAirCells();
}
public static class IOccupySpaceExts
{
public static int2 NearestCellTo( this IOccupySpace ios, int2 other )
@@ -99,23 +104,21 @@ namespace OpenRA.Traits
public interface IRenderModifier { IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r); }
public interface IDamageModifier { float GetDamageModifier( WarheadInfo warhead ); }
public interface ISpeedModifier { float GetSpeedModifier(); }
public interface IPowerModifier { float GetPowerModifier(); }
public interface IFirepowerModifier { float GetFirepowerModifier(); }
public interface IPalette { void InitPalette( WorldRenderer wr ); }
public interface IPaletteModifier { void AdjustPalette(Dictionary<string,Palette> b); }
public interface IPips { IEnumerable<PipType> GetPips(Actor self); }
public interface ITags { IEnumerable<TagType> GetTags(); }
public interface ITeleportable /* crap name! */
public interface ITeleportable : IHasLocation /* crap name! */
{
bool CanEnterCell(int2 location);
void SetPosition(Actor self, int2 cell);
void SetPxPosition(Actor self, int2 px);
}
public interface IMove : ITeleportable
{
float MovementCostForCell(Actor self, int2 cell);
float MovementSpeedForCell(Actor self, int2 cell);
IEnumerable<float2> GetCurrentPath(Actor self);
int Altitude { get; set; }
}
@@ -138,22 +141,24 @@ namespace OpenRA.Traits
public readonly Sprite Sprite;
public readonly float2 Pos;
public readonly string Palette;
public readonly int Z;
public readonly int ZOffset;
public Renderable(Sprite sprite, float2 pos, string palette, int zOffset)
public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset)
{
Sprite = sprite;
Pos = pos;
Palette = palette;
Z = z;
ZOffset = zOffset;
}
public Renderable(Sprite sprite, float2 pos, string palette)
: this(sprite, pos, palette, 0) { }
public Renderable(Sprite sprite, float2 pos, string palette, int z)
: this(sprite, pos, palette, z, 0) { }
public Renderable WithPalette(string newPalette) { return new Renderable(Sprite, Pos, newPalette, ZOffset); }
public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, newOffset); }
public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, ZOffset); }
public Renderable WithPalette(string newPalette) { return new Renderable(Sprite, Pos, newPalette, Z, ZOffset); }
public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, Z, newOffset); }
public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, Z, ZOffset); }
}
public interface ITraitInfo { object Create(ActorInitializer init); }
@@ -170,18 +175,50 @@ namespace OpenRA.Traits
public interface IActivity
{
IActivity NextActivity { get; set; }
IActivity Tick(Actor self);
void Cancel(Actor self);
void Queue(IActivity activity);
IEnumerable<float2> GetCurrentPath();
}
public interface IRenderOverlay { void Render(); }
public abstract class CancelableActivity : IActivity
{
protected IActivity NextActivity { get; private set; }
protected bool IsCanceled { get; private set; }
public abstract IActivity Tick( Actor self );
protected virtual bool OnCancel() { return true; }
public void Cancel( Actor self )
{
IsCanceled = OnCancel();
if( IsCanceled )
NextActivity = null;
else if (NextActivity != null)
NextActivity.Cancel( self );
}
public void Queue( IActivity activity )
{
if( NextActivity != null )
NextActivity.Queue( activity );
else
NextActivity = activity;
}
public virtual IEnumerable<float2> GetCurrentPath()
{
yield break;
}
}
public interface IRenderOverlay { void Render( WorldRenderer wr ); }
public interface INotifyIdle { void Idle(Actor self); }
public interface IBlocksBullets { }
public interface IPostRenderSelection { void RenderAfterWorld(Actor self); }
public interface IPreRenderSelection { void RenderBeforeWorld(Actor self); }
public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr, Actor self); }
public interface IPreRenderSelection { void RenderBeforeWorld(WorldRenderer wr, Actor self); }
public struct Target // a target: either an actor, or a fixed location.
{
@@ -202,9 +239,10 @@ namespace OpenRA.Traits
public static readonly Target None = new Target();
public bool IsValid { get { return valid && (actor == null || actor.IsInWorld); } }
public float2 CenterLocation { get { return actor != null ? actor.CenterLocation : pos.ToInt2(); } }
public int2 PxPosition { get { return IsActor ? actor.Trait<IHasLocation>().PxPosition : pos.ToInt2(); } }
public float2 CenterLocation { get { return PxPosition; } }
public Actor Actor { get { return actor; } }
public bool IsActor { get { return actor != null; } }
public Actor Actor { get { return IsActor ? actor : null; } }
public bool IsActor { get { return actor != null && !actor.Destroyed; } }
}
}

View File

@@ -34,7 +34,7 @@ namespace OpenRA.Traits
public static int GetFacing( float2 d, int currentFacing )
{
if( float2.WithinEpsilon( d, float2.Zero, 0.001f ) )
if (float2.WithinEpsilon(d, float2.Zero, 0.001f))
return currentFacing;
int highest = -1;
@@ -82,14 +82,14 @@ namespace OpenRA.Traits
ecc * (cosAngle * v.Y - sinAngle * v.X));
}
public static float2 CenterOfCell(int2 loc)
public static int2 CenterOfCell(int2 loc)
{
return new float2(12, 12) + Game.CellSize * (float2)loc;
return new int2( Game.CellSize / 2, Game.CellSize / 2 ) + Game.CellSize * loc;
}
public static float2 BetweenCells(int2 from, int2 to)
public static int2 BetweenCells(int2 from, int2 to)
{
return 0.5f * (CenterOfCell(from) + CenterOfCell(to));
return int2.Lerp( CenterOfCell( from ), CenterOfCell( to ), 1, 2 );
}
public static int2 AsInt2(this int[] xs) { return new int2(xs[0], xs[1]); }
@@ -100,13 +100,13 @@ namespace OpenRA.Traits
{
var pal = self.Owner == null ? "player0" : self.Owner.Palette;
var loc = location - 0.5f * s.size;
return new Renderable(s, loc.Round(), pal);
return new Renderable(s, loc.Round(), pal, (int)self.CenterLocation.Y);
}
public static IActivity SequenceActivities(params IActivity[] acts)
{
return acts.Reverse().Aggregate(
(next, a) => { a.NextActivity = next; return a; });
(next, a) => { a.Queue( next ); return a; });
}
public static Color ArrayToColor(int[] x) { return Color.FromArgb(x[0], x[1], x[2]); }

23
OpenRA.Game/Traits/Valued.cs Executable file
View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRA.Traits
{
public class ValuedInfo : TraitInfo<Valued>
{
public readonly int Cost = 0;
}
public class TooltipInfo : TraitInfo<Tooltip>
{
public readonly string Description = "";
public readonly string Name = "";
public readonly string Icon = null;
public readonly string[] AlternateName = { };
}
public class Valued { }
public class Tooltip { }
}

27
OpenRA.Game/Traits/World/BibLayer.cs Normal file → Executable file
View File

@@ -6,14 +6,14 @@
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using System.Collections.Generic;
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
namespace OpenRA.Traits
{
@@ -71,11 +71,10 @@ namespace OpenRA.Traits
}
}
public void Render()
{
var cliprect = Game.viewport.ShroudBounds().HasValue
? Rectangle.Intersect(Game.viewport.ShroudBounds().Value, world.Map.Bounds) : world.Map.Bounds;
public void Render( WorldRenderer wr )
{
var cliprect = Game.viewport.ShroudBounds( world );
cliprect = Rectangle.Intersect(Game.viewport.ViewBounds(), cliprect);
foreach (var kv in tiles)
{
if (!cliprect.Contains(kv.Key.X, kv.Key.Y))
@@ -83,7 +82,7 @@ namespace OpenRA.Traits
if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.IsExplored(kv.Key))
continue;
Game.Renderer.SpriteRenderer.DrawSprite(bibSprites[kv.Value.type - 1][kv.Value.image],
bibSprites[kv.Value.type - 1][kv.Value.image].DrawAt( wr,
Game.CellSize * kv.Key, "terrain");
}
}

View File

@@ -8,13 +8,35 @@
*/
#endregion
using OpenRA.FileFormats;
using OpenRA.Graphics;
namespace OpenRA.Traits
{
public class PlayerColorPaletteInfo : TraitInfo<PlayerColorPalette>
{
public class PlayerColorPaletteInfo : ITraitInfo
{
public readonly string BasePalette = null;
public readonly bool SplitRamp = false;
public readonly string BaseName = "player";
public readonly PaletteFormat PaletteFormat = PaletteFormat.ra;
public object Create( ActorInitializer init ) { return new PlayerColorPalette( init.self.Owner, this ); }
}
public class PlayerColorPalette {}
public class PlayerColorPalette : IPalette
{
readonly Player owner;
readonly PlayerColorPaletteInfo info;
public PlayerColorPalette( Player owner, PlayerColorPaletteInfo info )
{
this.owner = owner;
this.info = info;
}
public void InitPalette( WorldRenderer wr )
{
var paletteName = "{0}{1}".F( info.BaseName, owner.Index );
var newpal = new Palette(wr.GetPalette(info.BasePalette),
new PlayerColorRemap(owner.Color, owner.Color2, info.PaletteFormat));
wr.AddPalette(paletteName, newpal);
}
}
}

View File

@@ -18,23 +18,26 @@ namespace OpenRA.Traits
public class ResourceLayerInfo : TraitInfo<ResourceLayer> { }
public class ResourceLayer: IRenderOverlay, IWorldLoaded
{
{
World world;
public ResourceType[] resourceTypes;
CellContents[,] content;
public void Render()
public void Render( WorldRenderer wr )
{
var cliprect = Game.viewport.ShroudBounds().HasValue
? Rectangle.Intersect(Game.viewport.ShroudBounds().Value, world.Map.Bounds) : world.Map.Bounds;
var cliprect = Game.viewport.ShroudBounds( world );
cliprect = Rectangle.Intersect(Game.viewport.ViewBounds(), cliprect);
var minx = cliprect.Left;
var maxx = cliprect.Right;
var miny = cliprect.Top;
var maxy = cliprect.Bottom;
foreach( var rt in world.WorldActor.TraitsImplementing<ResourceType>() )
rt.info.PaletteIndex = wr.GetPaletteIndex(rt.info.Palette);
for (int x = minx; x < maxx; x++)
for (int y = miny; y < maxy; y++)
{
@@ -44,9 +47,9 @@ namespace OpenRA.Traits
var c = content[x, y];
if (c.image != null)
Game.Renderer.SpriteRenderer.DrawSprite(c.image[c.density],
c.image[c.density].DrawAt(
Game.CellSize * new int2(x, y),
c.type.info.Palette);
c.type.info.PaletteIndex);
}
}
@@ -144,6 +147,7 @@ namespace OpenRA.Traits
content[p.X, p.Y].type = null;
content[p.X, p.Y].image = null;
content[p.X, p.Y].density = 0;
world.Map.CustomTerrain[p.X, p.Y] = null;
}
public ResourceType GetResource(int2 p) { return content[p.X, p.Y].type; }

View File

@@ -23,6 +23,7 @@ namespace OpenRA.Traits
public readonly string TerrainType = "Ore";
public Sprite[][] Sprites;
public int PaletteIndex;
public object Create(ActorInitializer init) { return new ResourceType(this); }
}

View File

@@ -51,7 +51,7 @@ namespace OpenRA.Traits
var cp = Game.viewport.Location
+ .5f * new float2(Game.viewport.Width, Game.viewport.Height);
var intensity = 24 * 24 * 100 * shakeEffects.Sum(
var intensity = Game.CellSize * Game.CellSize * 100 * shakeEffects.Sum(
e => e.Intensity / (e.Position - cp).LengthSquared);
return Math.Min(intensity, 10);

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