Compare commits

..

211 Commits

Author SHA1 Message Date
Chris Forbes
ae29941d52 fix bogus target lines being drawn to 0,0 2010-10-08 21:04:31 +13:00
Caleb Anderson
e224fadbeb bandage to fix dogs not killing infantry in certain cases 2010-10-08 19:56:27 +13:00
Bob
1cccef5434 use a getter for Aircraft.Location 2010-10-08 19:54:56 +13:00
Bob
319da4c5ae add IHasLocation 2010-10-08 19:54:52 +13:00
Bob
94fc260293 remove setters on Mobile.{from,to}Cell. use SetLocation instead 2010-10-08 19:54:49 +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
317 changed files with 6413 additions and 6211 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

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

@@ -11,15 +11,12 @@
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.Traits;
using OpenRA.Widgets;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Editor
{
@@ -349,9 +346,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 */
@@ -376,7 +375,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;
@@ -423,4 +422,4 @@ namespace OpenRA.Editor
catch { }
}
}
}
}

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),
};

View File

@@ -52,11 +52,13 @@
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
@@ -85,9 +87,9 @@
//
// MapIconsList
//
this.MapIconsList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("MapIconsList.ImageStream")));
this.MapIconsList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
this.MapIconsList.ImageSize = new System.Drawing.Size(24, 24);
this.MapIconsList.TransparentColor = System.Drawing.Color.Transparent;
this.MapIconsList.Images.SetKeyName(0, "mapicon");
//
// btnCancel
//
@@ -141,6 +143,7 @@
//
// 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);
@@ -301,6 +304,16 @@
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;
@@ -327,6 +340,7 @@
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.Panel2.PerformLayout();
this.splitContainer1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
@@ -356,5 +370,6 @@
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

@@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using OpenRA.FileFormats;
using System.Windows.Forms;
using System.IO;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Graphics;
namespace OpenRA.Editor
@@ -19,11 +13,11 @@ namespace OpenRA.Editor
public MapSelect()
{
InitializeComponent();
MapIconsList.Images.Add(pictureBox1.Image);
}
private void MapSelect_Load(object sender, EventArgs e)
void MapSelect_Load(object sender, EventArgs e)
{
DirectoryInfo directory = new DirectoryInfo(MapFolderPath);
DirectoryInfo[] directories = directory.GetDirectories();
MapList.Items.Clear();
@@ -33,20 +27,14 @@ namespace OpenRA.Editor
ListViewItem map1 = new ListViewItem(subDirectory.Name);
map1.ImageIndex = 0;
MapList.Items.Add(map1);
}
if (txtNew.Text == "unnamed")
{
//dumb indian code
}
else
{
// hack
if (txtNew.Text != "unnamed")
MapList.Items[0].Selected = true;
}
}
private void MapList_SelectedIndexChanged(object sender, EventArgs e)
void MapList_SelectedIndexChanged(object sender, EventArgs e)
{
if (MapList.SelectedItems.Count == 1)
{
@@ -69,7 +57,7 @@ namespace OpenRA.Editor
}
}
private void txtPathOut_TextChanged(object sender, EventArgs e)
void txtPathOut_TextChanged(object sender, EventArgs e)
{
MapFolderPath = txtPathOut.Text;
}

View File

@@ -120,73 +120,58 @@
<metadata name="MapIconsList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<data name="MapIconsList.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<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>
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABW
DgAAAk1TRnQBSQFMAwEBAAEoAQABKAEAARgBAAEYAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABYAMA
ARgDAAEBAQABIAYAASQhAAEBAx8BLAM/AW8DSQGJAzYBWQMYASIDAQECDAADHQEqA0gBhQNCAXYDDwEU
AwEBAgMNARIDMwFSA0MBdwNRAacDDwEU/wAwAAEBAwMBBAM0BFQBwgFlAVMBUgH0AV4CWAHYA0oBjQMW
AR4DAgEDAwABAQMCAQMDGgElA00BlAEIAQkBJgH9A1ABpAM1AVcDQQFzA1MBugJDAVMB4wJTAVQBsgMA
AQH/ADAAAQEDDAEQA0IBdAFVAVQBUQHYAZkBiAGBAf8BoAGMAYUB/wF8AXABZQH4AzoBYQMKAQ4DCgEN
Ax0BKgM/AW0DVAG7ARkCGgH5AQABBQG/Af8BFwEbAUcB+QE5AUYBSwHrAQABBQFEAf8CCAFOAf0DDQER
/wAxAAMDAQQDHQEpA1ABpAFdAVMBUQHtAZsBiwGDAf8BnAGMAYQB/wGWAYQBdwH/AVsBWgFYAdgDMwFT
AzQBVANPAZ0CUwFSAdMCTAFOAfMBMAGeAbsB/wEUAXMBqwH/ARQBdQG/Af8BEAFmAbYB/wEXAY0BwgH/
AUgBYQFpAeEDAQEC/wAwAAEBAwkBDAMwAUwBVgJVAcMBewFqAWAB+gGoAZkBjwH/AZMBhAF3Af8BjAF3
AXAB/wGHAXEBbAH/A1YBvgNTAbwBTAFIAUYB5QF2AVsBUgH6AYMBbQFlAf8BUQFIAUcB/wEOAUsBpAH/
AQMBGgG4Af8BDQFRAZUB/wEZAZUBwAH/AUABagGBAesDMwFSAw0BEgMCAQP/ACUAAwEBAgMYASEDSwGP
A1EB3AGbAY4BhQH9AaEBkQGJAf8BhwFzAWsB/wGBAW4BZQH/AXUBZwFgAf8BUwFKAUMB/QFHAT4BOwH8
AZYBhgF5Af8BowGSAYoB/wFTAUoBUwH/AQMBGAHzAf8BEgFgAaYB/wEVAXYBlQH/AS8B/QH+Af8BBwEy
AZQB/wEVAXoByAH/AgABVAH/A00BlAMZASP/ACUAAwYBCAMtAUYDUwG8AWoBZQFiAfQBqgGbAZEB/wGJ
AXQBbQH/AYwBdwFuAf8BmgGJAYEB/wGLAXcBbwH/AXUBZQFeAf8BhgFxAWkB/wGVAYYBegH/AUEBPAFK
Af8BEwEfAYgB/wEKAREBrgH/ARwBegGVAf8BKgHfAeIB/wEOAVMBdwH/AQkBOQG8Af8BGQGBAaoB/wEK
ARIBqQH/ASABJQFSAfcDUQGg/wAlAAMQARUDQQFyA08B1gGTAYQBcgH9AZoBiQGDAf8BjwGAAXMB/wGW
AYYBeAH/AZ8BjQGEAf8BlgGFAXkB/wGUAYQBdwH/AZQBgwF3Af8BlwGHAYAB/wFqAV8BXAH/AWMBVwFW
Af8BYAFVAVMB/wFTAVcBWAH/ASIBYwGaAf8BDQFLAZ0B/wEgAY4BsAH/AUwBnAGvAf8BaAGaAa4B/wE7
AUsBWgH+A1ABn/8AJQADGAEiA00BlQF8AXUBbwH8AagBmAGOAf8BkQGBAXUB/wGNAXcBcAH/AZoBiQGB
Af8BkwGDAXYB/wGZAYgBgQH/AZwBiwGDAf8BlQGGAXgB/wGWAYYBeQH/AaABjwGHAf8BlgGFAXgB/wF2
AW8BbAH/AUwBbQGBAf8BHgE7AV0B/wEdAZ4BhAH/AVMBlwGpAf8BhgHFAd8B/wGIAb4B1wH/AUUBXwFi
AfsDQQFz/wAlAAMYASIDTQGVAZ0BjwGGAf8BmwGLAYMB/wGGAXEBagH/AYUBbwFoAf8BiAFzAWwB/wGJ
AXQBbAH/AZABdwFvAf8BlQGEAXcB/wGWAYUBeAH/AZ8BjwGGAf8BmQGLAYQB/wFtAYABhgH/AVYBkwGw
Af8BWgGmAccB/wFMAYMBpAH/AQUBFgGgAf8BYwGaAbAB/wGCAb8B2QH/AXEBrQHIAf8BXQFpAXIB3gMq
AUD/ACEAAwMBBAMmATgDUAGjAZoBjAGEAf8BpwGWAY4B/wGXAYYBegH/AZQBggF2Af8BlAGDAXcB/wGW
AYUBeAH/AZIBeQFyAf8BjwF5AXIB/wGVAYQBeAH/AY8BdgFrAf8BcAGAAYcB/wFaAZcBswH/AU8BmgHC
Af8BZQG1AdQB/wFlAaQBvgH/AR4BKgE1Af8BeAG6AdMB/wGAAbsB1QH/AYEBvwHaAf8BVQFWAVkBtQMP
ART/ACEAAwoBDQNBAXMDUgHPAasBmgGRAf8BmgGJAYIB/wGOAXgBcQH/AZEBgQF1Af8BlQGEAXcB/wGY
AYgBgAH/AYsBdQFuAf8BkQF6AXMB/wF4AW4BagH/AW8BrwHIAf8BWQGoAc0B/wFZAasBzAH/AVUBpgHJ
Af8BdQHDAeAB/wF6AcIB3wH/AYMBwAHbAf8BggHBAd0B/wFvAa4ByAH/AYsBvwHbAf8DSAGGAwUBB/8A
IQADHgErA1EBoAFSAVABTQHtAYMBbwFoAf8BgwFuAWcB/wGBAWwBZQH/AYEBbQFmAf8BiAFzAWsB/wGH
AXIBawH/AZQBhAF4Af8BhQF2AXMB/wFUAWwBgwH/AU0BhAGmAf8BZgGwAdAB/wFdAaoBywH/AWEBsQHR
Af8BdgG/Ad0B/wGFAcgB4wH/AYEBxAHfAf8BiAHHAeIB/wF3AbYB0QH/AW0BngG2Af8DPgFrAwIBA/8A
IQADOAFcA1UByAFrAlwB+AGRAYABdAH/AZgBiAGAAf8BlQGEAXgB/wGNAXcBcAH/AZUBhAF4Af8BmAGH
AYAB/wGTAYMBdwH/AWgBgAGLAf8BVgGQAbEB/wE3AUoBagH/AWMBqQHKAf8BYAGuAc8B/wFhAawBzAH/
AXYBvwHcAf8BiQHMAecB/wGDAcYB4gH/AYUBxQHgAf8BhwHDAd4B/wFIAYMBmwH/AzwBaAMEAQX/ACEA
A0kBiQFXAVYBVQHiAaQBkwGKAf8BrAGcAZMB/wGlAZUBjAH/AZYBhgF5Af8BkAF5AXQB/wGZAYgBgQH/
AaIBkQGJAf8BbgFdAVUB/wFkAZUBqwH/AWgBtQHVAf8BcgHBAd0B/wF0AbsB2wH/AV4BrAHOAf8BXwGt
AcwB/wF4AcMB4AH/AYgBywHmAf8BhQHGAeQB/wGDAcYB4gH/AYcBvwHdAf8BQwFVAWkB7gMbASb/ACUA
A08BpQFiAlgB7wGjAZMBigH/AZgBhwGAAf8BnwGOAYYB/wGdAYwBhAH/AZABeQFzAf8BiAFyAWsB/wGI
AXYBbwH/AWoBhQGPAf8BaAGwAdAB/wFvAbwB2gH/AWYBtgHWAf8BXwGxAdAB/wFdAa8B0AH/AXEBvQHa
Af8BcAG7AdoB/wGAAcQB3wH/AY8BzQHpAf8BigHJAeUB/wFbAZcBrAH9A0QBeQMAAQH/ACUAA1MBsQFs
Al8B8wGjAZIBigH/AZUBgwF4Af8BlAGCAXcB/wGUAYUBdwH/AYQBiwGNAf8BWwFzAYYB/wFcAYcBnQH/
AWEBrwHSAf8BbwG7AdoB/wF3AcEB3gH/AWwBuQHXAf8BYQGzAdIB/wFpAbkB1gH/AYABxQHhAf8BeAHC
Ad8B/wGAAcUB4QH/AYUBxAHhAf8BiQHGAeIB/wFSAXMBhAHzAzEBTv8AKQADUQHHAXsBcQFnAfgBqwGb
AZIB/wGQAYABdQH/AYQBbwFmAf8BcgGaAasB/wFiAasBzwH/AWQBsgHTAf8BbQG8AdoB/wFrAbgB1QH/
AXEBvgHbAf8BdgG/Ad0B/wFwAb4B2wH/AWgBuQHWAf8BgAHHAeEB/wGJAcsB5AH/AYoBzAHnAf8BjQHR
AewB/wGFAckB5gH/AW0BswHUAf8DTgGYAzABTAMAAQEDAAEB/wAhAAM+AWwBYgFfAV4ByQGJAYIBfAH1
AaQBkwGLAf8BhgGeAakB/wFnAa8B0gH/AXgBxAHgAf8BdgHCAd4B/wF2AcIB3gH/AXEBvwHbAf8BcwG8
AdoB/wFyAbsB2AH/AXQBuwHZAf8BdAG/Ad0B/wFhAZ0BwwH/AUEBYwGUAf8BbQGnAcgB/wGHAcQB4AH/
AYgBzQHpAf8BXwFxAXkB4AMsAUQDBwEJAwQBBgMAAQH/ACEAAwQBBQMZASMDNAFUA0oBiQFYAlsBwQFh
AXIBeQHiAW4BlwGoAfUBfQG0Ac8B/gGAAcUB4gH/AXIBvAHaAf8BcQG8AdoB/wFwAbsB2AH/AXUBvAHZ
Af8BjgHPAesB/wFtAa8B0gH/AU8BdQGkAf8BbAGrAc0B/wFuAa8BzwH/AY8BygHnAf8BWAFjAWYB0QMi
ATH/AD0AAwEBAgMJAQwDGgElA0IBdgFSAVwBZQHqAYEBxAHgAf4BigHHAeQB/wF5AcAB3QH/AYoBxgHi
Af8BlgHUAe4B/wF5AbgB1wH/AWEBoQHIAf8BaQGmAcwB/wFZAZIBvwH/AX8BwwHdAf4CRgFHAYEDAwEE
/wBJAAMCAQMDEAEWAzIBUANKAY0DUAGdA1IBoQFmAXUBewHgAXIBrwHFAf0BYAGXAb4B/wFgAZQBwAH/
AW8BqAHOAf8BQAF5AaoB/wM1AVYDAAEB/wBVAAMCAQMDBgEIAwoBDQMoAT0DQAFxAU8CUQGcAVsBYgFo
AdYBZQF/AZMB8gFKAX0BoQH8AyABL/8AcAABAQMIAQsDJAE2A0YBgQMDAQT/ADEAAUIBTQE+BwABPgMA
ASgDAAFgAwABGAMAAQEBAAEBBQABIAEBFgAD/wEAAeABOAEBCQABwAEAAQEJAAHAAQABAwkAAcABAAED
CQABgAsAAYALAAGACwABgAsAAYALAAGAPQABAQsAAQELAAEDIwABBwkAAfABAAEHCQAB/gEAAQcJAAH/
AcABDwkAAf8B/gEPCQAL
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>

View File

@@ -1,4 +1,14 @@
using System.Drawing;
#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;

View File

@@ -439,10 +439,6 @@ namespace OpenRA.Editor
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);

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

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

@@ -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,17 +6,16 @@
* 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;
using OpenRA.Traits.Activities;
using OpenRA.Support;
#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
{
@@ -27,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;
@@ -53,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>();
@@ -100,8 +97,6 @@ namespace OpenRA
get { return currentActivity == null || currentActivity is Idle; }
}
public float2 CenterLocation;
OpenRA.FileFormats.Lazy<float2> Size;
public IEnumerable<Renderable> Render()
@@ -111,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>();
@@ -152,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

@@ -22,7 +22,7 @@ namespace OpenRA
public void Draw(int frame, float2 pos)
{
Game.Renderer.SpriteRenderer.DrawSprite(sequence.GetSprite(frame), pos - sequence.Hotspot, sequence.Palette);
sequence.GetSprite(frame).DrawAt(pos - sequence.Hotspot, sequence.Palette);
}
}
}

20
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 )
if (dt > time)
Log.Write("perf", text, x, dt * 1000, Game.LocalTick);
} );
});
}
}
}

View File

@@ -18,11 +18,9 @@ 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.Support;
using OpenRA.Widgets;
using XRandom = OpenRA.Thirdparty.Random;
namespace OpenRA
@@ -49,7 +47,6 @@ namespace OpenRA
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);
}
@@ -103,7 +100,7 @@ namespace OpenRA
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } }
static void Tick()
static void Tick( World world, OrderManager orderManager, Viewport viewPort )
{
if (orderManager.Connection.ConnectionState != lastConnectionState)
{
@@ -128,6 +125,8 @@ namespace OpenRA
{
++LocalTick;
Log.Write("debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local");
if (isNetTick) orderManager.Tick(world);
world.OrderGenerator.Tick(world);
@@ -159,7 +158,7 @@ namespace OpenRA
internal static event Action LobbyInfoChanged = () => { };
internal static void SyncLobbyInfo(string data)
internal static void SyncLobbyInfo( World world, string data)
{
LobbyInfo = Session.Deserialize(data);
@@ -179,17 +178,20 @@ namespace OpenRA
LobbyInfoChanged();
}
public static void IssueOrder(Order o) { orderManager.IssueOrder(o); } /* avoid exposing the OM to mod code */
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 BeforeGameStart = () => {};
internal static void StartGame(string map)
{
world = null;
BeforeGameStart();
LoadMap(map);
if (orderManager.GameStarted) return;
Widget.SelectedWidget = null;
Widget.SelectedWidget = null;
LocalTick = 0;
orderManager.StartGame();
viewport.RefreshPalette();
@@ -198,23 +200,20 @@ namespace OpenRA
public static void DispatchMouseInput(MouseInputEvent ev, MouseEventArgs e, Modifiers modifierKeys)
{
if (world == null)
return;
int sync = world.SyncHash();
var initialWorld = world;
var world = Game.world;
if (world == null) return;
var mi = new MouseInput
Sync.CheckSyncUnchanged( 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( world, mi );
} );
}
public static bool IsHost
@@ -229,16 +228,13 @@ namespace OpenRA
public static void HandleKeyEvent(KeyInput e)
{
if (world == null)
return;
int sync = world.SyncHash();
if (Widget.HandleKeyPress(e))
return;
var world = Game.world;
if( world == null ) return;
if (sync != Game.world.SyncHash())
throw new InvalidOperationException("Desync in OnKeyPress");
Sync.CheckSyncUnchanged( world, () =>
{
Widget.HandleKeyPress( e );
} );
}
static Modifiers modifiers;
@@ -265,7 +261,14 @@ namespace OpenRA
Renderer.SheetSize = Settings.Game.SheetSize;
Renderer = new Renderer();
LobbyInfo.GlobalSettings.Mods = Settings.Game.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
LobbyInfo.GlobalSettings.Mods = Settings.Game.Mods.Where(m => ModData.AllMods.ContainsKey(m)).ToArray();
Console.WriteLine("Loading mods: {0}",string.Join(",",LobbyInfo.GlobalSettings.Mods));
modData = new ModData( LobbyInfo.GlobalSettings.Mods );
Sound.Initialize();
@@ -277,6 +280,36 @@ namespace OpenRA
JoinLocal();
StartGame(modData.Manifest.ShellmapUid);
Game.BeforeGameStart += () => Widget.OpenWindow("INGAME_ROOT");
Game.ConnectionStateChanged += () =>
{
Widget.CloseWindow();
switch( Game.orderManager.Connection.ConnectionState )
{
case ConnectionState.PreConnecting:
Widget.OpenWindow("MAINMENU_BG");
break;
case ConnectionState.Connecting:
Widget.OpenWindow("CONNECTING_BG");
break;
case ConnectionState.NotConnected:
Widget.OpenWindow("CONNECTION_FAILED_BG");
break;
case ConnectionState.Connected:
var lobby = Widget.OpenWindow("SERVER_LOBBY");
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( Widget.RootWidget, "PERF_BG" );
Widget.OpenWindow("MAINMENU_BG");
ResetTimer();
}
@@ -285,7 +318,7 @@ namespace OpenRA
internal static void Run()
{
while (!quit)
{
{
Tick( world, orderManager, viewport );
Application.DoEvents();
}
@@ -294,9 +327,9 @@ namespace OpenRA
public static void Exit() { quit = true; }
public static Action<Color,string,string> AddChatLine = (c,n,s) => {};
public static void Debug(string s, params object[] args)
{
{
AddChatLine(Color.White, "Debug", String.Format(s,args));
}
@@ -308,8 +341,8 @@ namespace OpenRA
LobbyInfo.GlobalSettings.Mods = Settings.Game.Mods;
JoinLocal();
StartGame(shellmap);
Widget.RootWidget.CloseWindow();
Widget.CloseWindow();
Widget.OpenWindow("MAINMENU_BG");
}

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;
}
@@ -69,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;
@@ -133,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.Save(kv.Value) ) );
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

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

@@ -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,26 @@ namespace OpenRA.Graphics
{
return uvhax[ k ];
}
public void DrawAt( float2 location, string palette )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, palette, this.size );
}
public void DrawAt( float2 location, int paletteIndex )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, this.size );
}
public void DrawAt(float2 location, string palette, float2 size)
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, palette, 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,7 +51,6 @@ namespace OpenRA.Graphics
nv = 0; ni = 0;
currentSheet = null;
sprites = 0;
}
}
@@ -73,14 +66,19 @@ namespace OpenRA.Graphics
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

@@ -56,10 +56,10 @@ 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 )

View File

@@ -107,10 +107,6 @@ namespace OpenRA.Graphics
var c = new Cursor(cursorName);
c.Draw((int)cursorFrame, Viewport.LastMousePos + Location);
renderer.RgbaSpriteRenderer.Flush();
renderer.SpriteRenderer.Flush();
renderer.WorldSpriteRenderer.Flush();
renderer.EndFrame();
}
@@ -158,5 +154,13 @@ namespace OpenRA.Graphics
if (localPlayer.Shroud.Disabled) return null;
return localPlayer.Shroud.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

@@ -21,7 +21,7 @@ namespace OpenRA.Graphics
{
readonly World world;
internal readonly TerrainRenderer terrainRenderer;
internal readonly UiOverlay uiOverlay;
public readonly UiOverlay uiOverlay;
internal readonly HardwarePalette palette;
internal WorldRenderer(World world)
@@ -90,20 +90,16 @@ namespace OpenRA.Graphics
public void Draw()
{
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);
if (world.OrderGenerator != null)
world.OrderGenerator.RenderBeforeWorld(world);
Game.Renderer.SpriteRenderer.Flush();
Game.Renderer.LineRenderer.Flush();
foreach (var image in worldSprites)
Game.Renderer.SpriteRenderer.DrawSprite(image.Sprite, image.Pos, image.Palette);
foreach( var image in worldSprites )
image.Sprite.DrawAt( image.Pos, this.GetPaletteIndex( image.Palette ) );
uiOverlay.Draw(world);
Game.Renderer.SpriteRenderer.Flush();
if (world.OrderGenerator != null)
world.OrderGenerator.RenderAfterWorld(world);
@@ -111,11 +107,7 @@ namespace OpenRA.Graphics
if (world.LocalPlayer != null)
world.LocalPlayer.Shroud.Draw();
Game.Renderer.SpriteRenderer.Flush();
Game.Renderer.Device.DisableScissor();
Game.Renderer.LineRenderer.Flush();
Game.Renderer.DisableScissor();
}
void DrawBox(RectangleF r, Color color)

View File

@@ -19,15 +19,45 @@ 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 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 +69,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

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

@@ -3,61 +3,87 @@ 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>>();
const int numSyncReports = 5;
Report[] syncReports = new Report[numSyncReports];
int curIndex = 0;
public SyncReport()
{
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:");
report.Frame = Game.orderManager.FrameNumber;
report.SyncedRandom = Game.world.SharedRandom.Last;
report.Traits.Clear();
foreach (var a in Game.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

@@ -21,10 +21,10 @@ namespace OpenRA.Network
return Game.LobbyInfo.Clients.FirstOrDefault(c => c.Index == id);
}
static Player FindPlayerByClientId(int id)
static Player FindPlayerByClientId( this World world, int id)
{
/* todo: find the interactive player. */
return Game.world.players.Values.FirstOrDefault(p => p.ClientIndex == id);
return world.players.Values.FirstOrDefault(p => p.ClientIndex == id);
}
public static void ProcessOrder( World world, int clientId, Order order )
@@ -43,7 +43,7 @@ namespace OpenRA.Network
var client = FindClientById(clientId);
if (client != null)
{
var player = FindPlayerByClientId(clientId);
var player = world.FindPlayerByClientId(clientId);
if (player != null && player.WinState == WinState.Lost)
Game.AddChatLine(client.Color1, client.Name + " (Dead)", order.TargetString);
else
@@ -56,7 +56,7 @@ namespace OpenRA.Network
var client = FindClientById(clientId);
if (client != null)
{
var player = FindPlayerByClientId(clientId);
var player = world.FindPlayerByClientId(clientId);
var display = (world.GameHasStarted) ?
player != null && (world.LocalPlayer != null && player.Stances[world.LocalPlayer] == Stance.Ally
|| player.WinState == WinState.Lost) :
@@ -78,7 +78,7 @@ namespace OpenRA.Network
}
case "SyncInfo":
{
Game.SyncLobbyInfo(order.TargetString);
Game.SyncLobbyInfo( world, order.TargetString);
break;
}
case "SetStance":

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,61 @@ 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().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 ];
}
return ctor.Invoke( a );
}
[AttributeUsage( AttributeTargets.Parameter )]
public class ParamAttribute : Attribute
{
public string ParamName { get; private set; }
public ParamAttribute( string paramName )
{
ParamName = paramName;
}
}
[AttributeUsage( AttributeTargets.Constructor )]
public class UseCtorAttribute : Attribute
{
}
}
}

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{0DFB103F-2962-400F-8C6D-E2C28CCBA633}</ProjectGuid>
<OutputType>WinExe</OutputType>
@@ -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" />
@@ -135,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" />
@@ -155,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" />
@@ -191,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" />
@@ -200,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" />
@@ -215,18 +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\ClassicProductionQueue.cs" />
<Compile Include="Traits\Player\PowerManager.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
@@ -241,8 +226,11 @@
<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

@@ -35,8 +35,11 @@ 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);
if( mi.Button == MouseButton.Left && world.Map.IsInMap( xy ) )
{
world.CancelInputMode();
yield return new Order( order, subject, xy );
}
}
public virtual void Tick(World world) { }

View File

@@ -11,7 +11,8 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Traits;
using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Orders
{
@@ -25,17 +26,17 @@ 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 ) {}
@@ -45,39 +46,107 @@ namespace OpenRA.Orders
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
t.RenderBeforeWorld(a);
t.RenderBeforeWorld(a);
Game.Renderer.Flush();
}
public void RenderAfterWorld( 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(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

@@ -49,6 +49,7 @@ namespace OpenRA
Index = index;
Palette = "player"+index;
Color = pr.Color;
Color2 = pr.Color2;
ClientIndex = 0; /* it's a map player, "owned" by host */

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

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

@@ -145,71 +145,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( minx, miny, maxx, maxy, fogSprites, "fog" );
DrawShroud( minx, miny, maxx, maxy, sprites, "shroud" );
}
void DrawShroud( int minx, int miny, int maxx, int maxy, Sprite[,] s, string pal )
{
var shroudPalette = Game.world.WorldRenderer.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,34 @@ 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 )
{
int sync = world.SyncHash();
inUnsyncedCode = true;
try
{
return fn();
}
finally
{
inUnsyncedCode = false;
if( sync != world.SyncHash() )
throw new InvalidOperationException( "Desync in DispatchMouseInput" );
}
}
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,18 +15,14 @@ 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;
@@ -49,7 +45,6 @@ namespace OpenRA.Traits.Activities
.WithoutLaneBias());
this.destination = destination;
this.nearEnough = 0;
this.cancellable = false;
}
public Move( int2 destination, int nearEnough )
@@ -102,16 +97,29 @@ namespace OpenRA.Traits.Activities
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;
@@ -123,7 +131,7 @@ namespace OpenRA.Traits.Activities
return this;
}
path = getPath( self, mobile ).TakeWhile( a => a != mobile.toCell ).ToList();
path = EvalPath(self, mobile);
SanityCheckPath( mobile );
}
@@ -144,22 +152,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 +188,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);
@@ -216,7 +225,7 @@ namespace OpenRA.Traits.Activities
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 +239,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 +342,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

@@ -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;
@@ -98,6 +112,7 @@ namespace OpenRA.Traits
if (init.Contains<LocationInit>())
{
this.__fromCell = this.__toCell = init.Get<LocationInit,int2>();
this.PxPosition = Util.CenterOfCell( fromCell );
AddInfluence();
}
@@ -108,24 +123,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 precedence
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,7 +168,7 @@ 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))
@@ -170,20 +188,9 @@ namespace OpenRA.Traits
}
}
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 +227,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 +272,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 +295,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 +348,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

@@ -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,17 +83,17 @@ 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;
}
default:
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

@@ -11,16 +11,15 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.GameRules;
namespace OpenRA.Traits
{
class TechTreeInfo : ITraitInfo
public class TechTreeInfo : ITraitInfo
{
public object Create(ActorInitializer init) { return new TechTree(init);}
}
class TechTree
public class TechTree
{
readonly List<Watcher> watchers = new List<Watcher>();
readonly Player player;
@@ -43,10 +42,16 @@ namespace OpenRA.Traits
foreach(var w in watchers)
w.Update(buildings);
}
public void Add(string key, List<string> prerequisites, ITechTreeElement tte)
{
watchers.Add(new Watcher( key, prerequisites, 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)
@@ -54,7 +59,7 @@ namespace OpenRA.Traits
watchers.RemoveAll(x => x.key == key);
}
public static Cache<string, List<Actor>> GatherBuildings( Player player )
static Cache<string, List<Actor>> GatherBuildings( Player player )
{
var ret = new Cache<string, List<Actor>>( x => new List<Actor>() );
if (player == null)
@@ -78,25 +83,28 @@ namespace OpenRA.Traits
public readonly List<string> prerequisites;
public readonly ITechTreeElement watcher;
bool hasPrerequisites;
public Watcher(string key, List<string> prerequisites, ITechTreeElement watcher)
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))
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);
@@ -108,7 +116,7 @@ namespace OpenRA.Traits
}
}
interface ITechTreeElement
public 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

@@ -61,9 +61,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);
@@ -96,7 +97,7 @@ 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(basePosition + new float2(-8, 1), "chrome");
}
void DrawPips(Actor self, float2 basePosition)
@@ -122,7 +123,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(pipxyBase + pipxyOffset, "chrome");
pipxyOffset += new float2(4, 0);
}
// Increment row
@@ -148,7 +149,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(tagxyBase + tagxyOffset, "chrome");
// Increment row
tagxyOffset.Y += 8;
@@ -158,13 +159,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

@@ -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,20 @@ 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 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; }
}
@@ -172,9 +174,41 @@ 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 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
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(); }
@@ -204,9 +238,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]); }
@@ -106,7 +106,7 @@ namespace OpenRA.Traits
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 { }
}

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

@@ -75,7 +75,8 @@ namespace OpenRA.Traits
{
var cliprect = Game.viewport.ShroudBounds().HasValue
? Rectangle.Intersect(Game.viewport.ShroudBounds().Value, world.Map.Bounds) : world.Map.Bounds;
cliprect = Rectangle.Intersect(Game.viewport.ViewBounds(), cliprect);
foreach (var kv in tiles)
{
if (!cliprect.Contains(kv.Key.X, kv.Key.Y))
@@ -83,7 +84,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(
Game.CellSize * kv.Key, "terrain");
}
}

View File

@@ -18,7 +18,7 @@ namespace OpenRA.Traits
public class ResourceLayerInfo : TraitInfo<ResourceLayer> { }
public class ResourceLayer: IRenderOverlay, IWorldLoaded
{
{
World world;
public ResourceType[] resourceTypes;
@@ -29,12 +29,17 @@ namespace OpenRA.Traits
var cliprect = Game.viewport.ShroudBounds().HasValue
? Rectangle.Intersect(Game.viewport.ShroudBounds().Value, world.Map.Bounds) : world.Map.Bounds;
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 = world.WorldRenderer.GetPaletteIndex(rt.info.Palette);
for (int x = minx; x < maxx; x++)
for (int y = miny; y < maxy; y++)
{
@@ -44,9 +49,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 +149,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

@@ -45,9 +45,9 @@ namespace OpenRA.Traits
for (var i = 0; i <= bins.GetUpperBound(0); i++)
bins[i, j].Clear();
foreach (var a in self.World.Actors)
foreach (var a in self.World.Queries.WithTrait<IHasLocation>())
{
var bounds = a.GetBounds(true);
var bounds = a.Actor.GetBounds(true);
if (bounds.Right <= Game.CellSize * self.World.Map.XOffset) continue;
if (bounds.Bottom <= Game.CellSize * self.World.Map.YOffset) continue;
@@ -61,7 +61,7 @@ namespace OpenRA.Traits
for (var j = j1; j <= j2; j++)
for (var i = i1; i <= i2; i++)
bins[i, j].Add(a);
bins[i, j].Add(a.Actor);
}
}

View File

@@ -18,7 +18,7 @@ using OpenRA.Widgets;
namespace OpenRA
{
class UiOverlay
public class UiOverlay
{
Sprite buildOk, buildBlocked, unitDebug;
@@ -49,7 +49,7 @@ namespace OpenRA
for (var i = world.Map.Bounds.Left; i < world.Map.Bounds.Right; i++)
for (var j = world.Map.Bounds.Top; j < world.Map.Bounds.Bottom; j++)
if (uim.GetUnitsAt(new int2(i, j)).Any())
Game.Renderer.SpriteRenderer.DrawSprite(unitDebug, Game.CellSize * new float2(i, j), "terrain");
unitDebug.DrawAt(Game.CellSize * new float2(i, j), "terrain");
}
}
@@ -63,23 +63,21 @@ namespace OpenRA
if (Rules.Info[name].Traits.Contains<LineBuildInfo>())
{
foreach (var t in LineBuildUtils.GetLineBuildCells(world, topLeft, name, bi))
Game.Renderer.SpriteRenderer.DrawSprite(world.IsCloseEnoughToBase(world.LocalPlayer, name, bi, t)
? buildOk : buildBlocked, Game.CellSize * t, "terrain");
(world.IsCloseEnoughToBase(world.LocalPlayer, name, bi, t) ? buildOk : buildBlocked)
.DrawAt(Game.CellSize * t, "terrain");
}
else
{
var res = world.WorldActor.Trait<ResourceLayer>();
var isCloseEnough = world.IsCloseEnoughToBase(world.LocalPlayer, name, bi, topLeft);
foreach (var t in Footprint.Tiles(name, bi, topLeft))
Game.Renderer.SpriteRenderer.DrawSprite((isCloseEnough && world.IsCellBuildable(t, bi.WaterBound) && res.GetResource(t) == null)
? buildOk : buildBlocked, Game.CellSize * t, "terrain");
((isCloseEnough && world.IsCellBuildable(t, bi.WaterBound) && res.GetResource(t) == null) ? buildOk : buildBlocked)
.DrawAt(Game.CellSize * t, "terrain");
}
Game.Renderer.SpriteRenderer.Flush();
}
}
static class LineBuildUtils
public static class LineBuildUtils
{
public static IEnumerable<int2> GetLineBuildCells(World world, int2 location, string name, BuildingInfo bi)
{

View File

@@ -41,8 +41,7 @@ namespace OpenRA.Widgets
if (DrawBackground)
WidgetUtils.DrawPanel("dialog3", chatLogArea);
Game.Renderer.RgbaSpriteRenderer.Flush();
Game.Renderer.Device.EnableScissor(chatLogArea.Left, chatLogArea.Top, chatLogArea.Width, chatLogArea.Height);
Game.Renderer.EnableScissor(chatLogArea.Left, chatLogArea.Top, chatLogArea.Width, chatLogArea.Height);
foreach (var line in recentLines.AsEnumerable().Reverse())
{
chatpos.Y -= 20;
@@ -52,8 +51,7 @@ namespace OpenRA.Widgets
Game.Renderer.RegularFont.DrawText(line.Text, chatpos + new int2(inset, 0), Color.White);
}
Game.Renderer.RgbaSpriteRenderer.Flush();
Game.Renderer.Device.DisableScissor();
Game.Renderer.DisableScissor();
}
public void AddLine(Color c, string from, string text)

View File

@@ -33,8 +33,6 @@ namespace OpenRA.Widgets
Game.Renderer.BoldFont.DrawText(text, RenderOrigin + new float2(3, 7), Color.White);
Game.Renderer.RegularFont.DrawText(content, RenderOrigin + new float2(3 + w, 7), Color.White);
Game.Renderer.RgbaSpriteRenderer.Flush();
}
}

View File

@@ -37,7 +37,6 @@ namespace OpenRA.Widgets
public override void DrawInner(World world)
{
WidgetUtils.FillRectWithColor(RenderBounds, GetColor());
Game.Renderer.LineRenderer.Flush();
}
}
}

View File

@@ -14,56 +14,37 @@ namespace OpenRA.Widgets.Delegates
{
public class ConnectionDialogsDelegate : IWidgetDelegate
{
public ConnectionDialogsDelegate()
[ObjectCreator.UseCtor]
public ConnectionDialogsDelegate( [ObjectCreator.Param( "widget" )] Widget widget )
{
var r = Widget.RootWidget;
r.GetWidget("CONNECTION_BUTTON_ABORT").OnMouseUp = mi => {
r.GetWidget("CONNECTION_BUTTON_ABORT").Parent.Visible = false;
widget.GetWidget("CONNECTION_BUTTON_ABORT").OnMouseUp = mi => {
widget.GetWidget("CONNECTION_BUTTON_ABORT").Parent.Visible = false;
Game.Disconnect();
return true;
};
r.GetWidget("CONNECTION_BUTTON_CANCEL").OnMouseUp = mi => {
r.GetWidget("CONNECTION_BUTTON_CANCEL").Parent.Visible = false;
widget.GetWidget<LabelWidget>("CONNECTING_DESC").GetText = () =>
"Connecting to {0}:{1}...".F(Game.CurrentHost, Game.CurrentPort);
}
}
public class ConnectionFailedDelegate : IWidgetDelegate
{
[ObjectCreator.UseCtor]
public ConnectionFailedDelegate( [ObjectCreator.Param( "widget" )] Widget widget )
{
widget.GetWidget("CONNECTION_BUTTON_CANCEL").OnMouseUp = mi => {
widget.GetWidget("CONNECTION_BUTTON_CANCEL").Parent.Visible = false;
Game.Disconnect();
return true;
};
r.GetWidget("CONNECTION_BUTTON_RETRY").OnMouseUp = mi => {
widget.GetWidget("CONNECTION_BUTTON_RETRY").OnMouseUp = mi => {
Game.JoinServer(Game.CurrentHost, Game.CurrentPort);
return true;
};
r.GetWidget<LabelWidget>("CONNECTING_DESC").GetText = () =>
"Connecting to {0}:{1}...".F(Game.CurrentHost, Game.CurrentPort);
r.GetWidget<LabelWidget>("CONNECTION_FAILED_DESC").GetText = () =>
widget.GetWidget<LabelWidget>("CONNECTION_FAILED_DESC").GetText = () =>
"Could not connect to {0}:{1}".F(Game.CurrentHost, Game.CurrentPort);
Game.ConnectionStateChanged += () =>
{
r.CloseWindow();
switch( Game.orderManager.Connection.ConnectionState )
{
case ConnectionState.PreConnecting:
r.OpenWindow("MAINMENU_BG");
break;
case ConnectionState.Connecting:
r.OpenWindow("CONNECTING_BG");
break;
case ConnectionState.NotConnected:
r.OpenWindow("CONNECTION_FAILED_BG");
break;
case ConnectionState.Connected:
r.OpenWindow("SERVER_LOBBY");
var lobby = r.GetWidget("SERVER_LOBBY");
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;
}
};
}
}
}

View File

@@ -14,26 +14,18 @@ using System.Net;
namespace OpenRA.Widgets.Delegates
{
public class CreateServerMenuDelegate : IWidgetDelegate
{
public CreateServerMenuDelegate()
{
[ObjectCreator.UseCtor]
public CreateServerMenuDelegate( [ObjectCreator.Param( "widget" )] Widget cs )
{
var settings = Game.Settings;
var r = Widget.RootWidget;
var cs = r.GetWidget("CREATESERVER_BG");
r.GetWidget("MAINMENU_BUTTON_CREATE").OnMouseUp = mi => {
r.OpenWindow("CREATESERVER_BG");
return true;
};
cs.GetWidget("BUTTON_CANCEL").OnMouseUp = mi => {
r.CloseWindow();
Widget.CloseWindow();
return true;
};
cs.GetWidget("BUTTON_START").OnMouseUp = mi => {
r.OpenWindow("SERVER_LOBBY");
var map = Game.modData.AvailableMaps.FirstOrDefault(m => m.Value.Selectable).Key;
settings.Server.Name = cs.GetWidget<TextFieldWidget>("GAME_TITLE").Text;

219
OpenRA.Game/Widgets/Delegates/LobbyDelegate.cs Normal file → Executable file
View File

@@ -12,7 +12,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Network;
using OpenRA.Network;
namespace OpenRA.Widgets.Delegates
{
@@ -22,12 +22,13 @@ namespace OpenRA.Widgets.Delegates
Dictionary<string, string> CountryNames;
string MapUid;
MapStub Map;
MapStub Map;
public static Color CurrentColorPreview1;
public static Color CurrentColorPreview2;
public LobbyDelegate()
[ObjectCreator.UseCtor]
public LobbyDelegate( [ObjectCreator.Param( "widget" )] Widget lobby )
{
Game.LobbyInfoChanged += UpdateCurrentMap;
UpdateCurrentMap();
@@ -35,9 +36,7 @@ namespace OpenRA.Widgets.Delegates
CurrentColorPreview1 = Game.Settings.Player.Color1;
CurrentColorPreview2 = Game.Settings.Player.Color2;
var r = Widget.RootWidget;
var lobby = r.GetWidget("SERVER_LOBBY");
Players = Widget.RootWidget.GetWidget("SERVER_LOBBY").GetWidget("PLAYERS");
Players = lobby.GetWidget("PLAYERS");
LocalPlayerTemplate = Players.GetWidget("TEMPLATE_LOCAL");
RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE");
EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY");
@@ -74,8 +73,7 @@ namespace OpenRA.Widgets.Delegates
var mapButton = lobby.GetWidget("CHANGEMAP_BUTTON");
mapButton.OnMouseUp = mi =>
{
r.GetWidget("MAP_CHOOSER").SpecialOneArg(MapUid);
r.OpenWindow("MAP_CHOOSER");
Widget.OpenWindow("MAP_CHOOSER").SpecialOneArg(MapUid); // WTF
return true;
};
@@ -135,74 +133,74 @@ namespace OpenRA.Widgets.Delegates
teamChat ^= true;
chatLabel.Text = (teamChat) ? "Team:" : "Chat:";
return true;
};
var colorChooser = lobby.GetWidget("COLOR_CHOOSER");
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
var satSlider = colorChooser.GetWidget<SliderWidget>("SAT_SLIDER");
var lumSlider = colorChooser.GetWidget<SliderWidget>("LUM_SLIDER");
var rangeSlider = colorChooser.GetWidget<SliderWidget>("RANGE_SLIDER");
hueSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
satSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
lumSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
rangeSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
colorChooser.GetWidget<ButtonWidget>("BUTTON_OK").OnMouseUp = mi =>
{
colorChooser.IsVisible = () => false;
UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
UpdatePlayerColor(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
return true;
};
}
void UpdatePlayerColor(float hf, float sf, float lf, float r)
{
var c1 = ColorFromHSL(hf, sf, lf);
var c2 = ColorFromHSL(hf, sf, r*lf);
Game.Settings.Player.Color1 = c1;
Game.Settings.Player.Color2 = c2;
Game.Settings.Save();
Game.IssueOrder(Order.Command("color {0},{1},{2},{3},{4},{5}".F(c1.R,c1.G,c1.B,c2.R,c2.G,c2.B)));
}
void UpdateColorPreview(float hf, float sf, float lf, float r)
{
CurrentColorPreview1 = ColorFromHSL(hf, sf, lf);
CurrentColorPreview2 = ColorFromHSL(hf, sf, r*lf);
Game.viewport.RefreshPalette();
}
var colorChooser = lobby.GetWidget("COLOR_CHOOSER");
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
var satSlider = colorChooser.GetWidget<SliderWidget>("SAT_SLIDER");
var lumSlider = colorChooser.GetWidget<SliderWidget>("LUM_SLIDER");
var rangeSlider = colorChooser.GetWidget<SliderWidget>("RANGE_SLIDER");
hueSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
satSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
lumSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
rangeSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
colorChooser.GetWidget<ButtonWidget>("BUTTON_OK").OnMouseUp = mi =>
{
colorChooser.IsVisible = () => false;
UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
UpdatePlayerColor(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
return true;
};
}
// hk is hue in the range [0,1] instead of [0,360]
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));
}
void UpdatePlayerColor(float hf, float sf, float lf, float r)
{
var c1 = ColorFromHSL(hf, sf, lf);
var c2 = ColorFromHSL(hf, sf, r*lf);
Game.Settings.Player.Color1 = c1;
Game.Settings.Player.Color2 = c2;
Game.Settings.Save();
Game.IssueOrder(Order.Command("color {0},{1},{2},{3},{4},{5}".F(c1.R,c1.G,c1.B,c2.R,c2.G,c2.B)));
}
void UpdateColorPreview(float hf, float sf, float lf, float r)
{
CurrentColorPreview1 = ColorFromHSL(hf, sf, lf);
CurrentColorPreview2 = ColorFromHSL(hf, sf, r*lf);
Game.viewport.RefreshPalette();
}
// 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));
}
void UpdateCurrentMap()
@@ -211,23 +209,23 @@ namespace OpenRA.Widgets.Delegates
MapUid = Game.LobbyInfo.GlobalSettings.Map;
Map = Game.modData.AvailableMaps[MapUid];
}
bool hasJoined = false;
void JoinedServer()
{
if (hasJoined)
return;
hasJoined = true;
if (Game.LocalClient.Name != Game.Settings.Player.Name)
Game.IssueOrder(Order.Command("name " + Game.Settings.Player.Name));
bool hasJoined = false;
void JoinedServer()
{
if (hasJoined)
return;
hasJoined = true;
if (Game.LocalClient.Name != Game.Settings.Player.Name)
Game.IssueOrder(Order.Command("name " + Game.Settings.Player.Name));
var c1 = Game.Settings.Player.Color1;
var c2 = Game.Settings.Player.Color2;
if (Game.LocalClient.Color1 != c1 || Game.LocalClient.Color2 != c2)
Game.IssueOrder(Order.Command("color {0},{1},{2},{3},{4},{5}".F(c1.R,c1.G,c1.B,c2.R,c2.G,c2.B)));
if (Game.LocalClient.Color1 != c1 || Game.LocalClient.Color2 != c2)
Game.IssueOrder(Order.Command("color {0},{1},{2},{3},{4},{5}".F(c1.R,c1.G,c1.B,c2.R,c2.G,c2.B)));
}
void ResetConnectionState()
@@ -315,24 +313,24 @@ namespace OpenRA.Widgets.Delegates
name.OnLoseFocus = () => name.OnEnterKey();
var color = template.GetWidget<ButtonWidget>("COLOR");
color.OnMouseUp = mi =>
{
var colorChooser = Widget.RootWidget.GetWidget("SERVER_LOBBY").GetWidget("COLOR_CHOOSER");
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
hueSlider.Offset = Game.LocalClient.Color1.GetHue()/360f;
var satSlider = colorChooser.GetWidget<SliderWidget>("SAT_SLIDER");
satSlider.Offset = Game.LocalClient.Color1.GetSaturation();
var lumSlider = colorChooser.GetWidget<SliderWidget>("LUM_SLIDER");
lumSlider.Offset = Game.LocalClient.Color1.GetBrightness();
var rangeSlider = colorChooser.GetWidget<SliderWidget>("RANGE_SLIDER");
rangeSlider.Offset = Game.LocalClient.Color1.GetBrightness() == 0 ? 0 : Game.LocalClient.Color2.GetBrightness()/Game.LocalClient.Color1.GetBrightness();
UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
colorChooser.IsVisible = () => true;
return true;
color.OnMouseUp = mi =>
{
var colorChooser = Widget.RootWidget.GetWidget("SERVER_LOBBY").GetWidget("COLOR_CHOOSER");
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
hueSlider.SetOffset(Game.LocalClient.Color1.GetHue()/360f);
var satSlider = colorChooser.GetWidget<SliderWidget>("SAT_SLIDER");
satSlider.SetOffset(Game.LocalClient.Color1.GetSaturation());
var lumSlider = colorChooser.GetWidget<SliderWidget>("LUM_SLIDER");
lumSlider.SetOffset(Game.LocalClient.Color1.GetBrightness());
var rangeSlider = colorChooser.GetWidget<SliderWidget>("RANGE_SLIDER");
rangeSlider.SetOffset(Game.LocalClient.Color1.GetBrightness() == 0 ? 0 : Game.LocalClient.Color2.GetBrightness()/Game.LocalClient.Color1.GetBrightness());
UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
colorChooser.IsVisible = () => true;
return true;
};
var colorBlock = color.GetWidget<ColorBlockWidget>("COLORBLOCK");
@@ -416,13 +414,12 @@ namespace OpenRA.Widgets.Delegates
bool CycleTeam(MouseInput mi)
{
var d = (mi.Button == MouseButton.Left) ? +1 : Game.world.Map.PlayerCount;
var newIndex = (Game.LocalClient.Team + d) % (Game.world.Map.PlayerCount + 1);
var d = (mi.Button == MouseButton.Left) ? +1 : Map.PlayerCount;
var newIndex = (Game.LocalClient.Team + d) % (Map.PlayerCount + 1);
Game.IssueOrder(
Order.Command("team " + newIndex));
return true;
}
}
}
}

View File

@@ -9,25 +9,41 @@
#endregion
using OpenRA.FileFormats;
using OpenRA.Server;
using System.Net;
using System.IO;
namespace OpenRA.Widgets.Delegates
{
public class MainMenuButtonsDelegate : IWidgetDelegate
{
public MainMenuButtonsDelegate()
[ObjectCreator.UseCtor]
public MainMenuButtonsDelegate( [ObjectCreator.Param( "widget" )] Widget widget )
{
// Main menu is the default window
Widget.WindowList.Push("MAINMENU_BG");
Widget.RootWidget.GetWidget("MAINMENU_BUTTON_QUIT").OnMouseUp = mi => { Game.Exit(); return true; };
widget.GetWidget( "MAINMENU_BUTTON_JOIN" ).OnMouseUp = mi => { Widget.OpenWindow( "JOINSERVER_BG" ); return true; };
widget.GetWidget( "MAINMENU_BUTTON_CREATE" ).OnMouseUp = mi => { Widget.OpenWindow( "CREATESERVER_BG" ); return true; };
widget.GetWidget( "MAINMENU_BUTTON_SETTINGS" ).OnMouseUp = mi => { Widget.OpenWindow( "SETTINGS_MENU" ); return true; };
widget.GetWidget( "MAINMENU_BUTTON_MUSIC" ).OnMouseUp = mi => { Widget.OpenWindow( "MUSIC_MENU" ); return true; };
widget.GetWidget( "MAINMENU_BUTTON_QUIT" ).OnMouseUp = mi => { Game.Exit(); return true; };
var version = Widget.RootWidget.GetWidget("MAINMENU_BG").GetWidget<LabelWidget>("VERSION_STRING");
var version = widget.GetWidget<LabelWidget>("VERSION_STRING");
if (FileSystem.Exists("VERSION"))
{
var s = FileSystem.Open("VERSION");
version.Text = s.ReadAllText();
s.Close();
MasterServerQuery.OnVersion += v => { if (!string.IsNullOrEmpty(v)) version.Text += "\nLatest: " + v; };
MasterServerQuery.GetCurrentVersion(Game.Settings.Server.MasterServer);
}
else
{
version.Text = "Dev Build";
}
MasterServerQuery.ClientVersion = version.Text;
MasterServerQuery.GetMOTD(Game.Settings.Server.MasterServer);
}
}
}

View File

@@ -17,10 +17,10 @@ namespace OpenRA.Widgets.Delegates
public class MapChooserDelegate : IWidgetDelegate
{
MapStub Map = null;
public MapChooserDelegate()
[ObjectCreator.UseCtor]
public MapChooserDelegate( [ObjectCreator.Param( "widget" )] Widget bg )
{
var r = Widget.RootWidget;
var bg = r.GetWidget("MAP_CHOOSER");
bg.SpecialOneArg = (map) => RefreshMapList(map);
var ml = bg.GetWidget<ListBoxWidget>("MAP_LIST");
@@ -33,13 +33,13 @@ namespace OpenRA.Widgets.Delegates
bg.GetWidget("BUTTON_OK").OnMouseUp = mi =>
{
Game.IssueOrder(Order.Command("map " + Map.Uid));
r.CloseWindow();
Widget.CloseWindow();
return true;
};
bg.GetWidget("BUTTON_CANCEL").OnMouseUp = mi =>
{
r.CloseWindow();
Widget.CloseWindow();
return true;
};

View File

@@ -24,15 +24,10 @@ namespace OpenRA.Widgets.Delegates
bg.GetWidget("BUTTON_CLOSE").OnMouseUp = mi => {
Game.Settings.Save();
Widget.RootWidget.CloseWindow();
Widget.CloseWindow();
return true;
};
Widget.RootWidget.GetWidget("MAINMENU_BUTTON_MUSIC").OnMouseUp = mi => {
Widget.RootWidget.OpenWindow("MUSIC_MENU");
return true;
};
bg.GetWidget("BUTTON_PLAY").OnMouseUp = mi =>
{
if (CurrentSong == null)

View File

@@ -23,28 +23,20 @@ namespace OpenRA.Widgets.Delegates
GameServer currentServer = null;
Widget ServerTemplate;
public ServerBrowserDelegate()
[ObjectCreator.UseCtor]
public ServerBrowserDelegate( [ObjectCreator.Param( "widget" )] Widget widget )
{
var r = Widget.RootWidget;
var bg = r.GetWidget("JOINSERVER_BG");
var dc = r.GetWidget("DIRECTCONNECT_BG");
var bg = widget.GetWidget("JOINSERVER_BG");
MasterServerQuery.OnComplete += games => RefreshServerList(games);
r.GetWidget("MAINMENU_BUTTON_JOIN").OnMouseUp = mi =>
{
r.OpenWindow("JOINSERVER_BG");
bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
bg.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list...";
r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
r.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list...";
bg.Children.RemoveAll(a => GameButtons.Contains(a));
GameButtons.Clear();
bg.Children.RemoveAll(a => GameButtons.Contains(a));
GameButtons.Clear();
MasterServerQuery.Refresh(Game.Settings.Server.MasterServer);
return true;
};
MasterServerQuery.Refresh(Game.Settings.Server.MasterServer);
bg.GetWidget("SERVER_INFO").IsVisible = () => currentServer != null;
var preview = bg.GetWidget<MapPreviewWidget>("MAP_PREVIEW");
@@ -52,7 +44,7 @@ namespace OpenRA.Widgets.Delegates
preview.IsVisible = () => CurrentMap() != null;
bg.GetWidget<LabelWidget>("SERVER_IP").GetText = () => currentServer.Address;
bg.GetWidget<LabelWidget>("SERVER_MODS").GetText = () => string.Join(",", currentServer.Mods);
bg.GetWidget<LabelWidget>("SERVER_MODS").GetText = () => GenerateModsLabel();
bg.GetWidget<LabelWidget>("MAP_TITLE").GetText = () => (CurrentMap() != null) ? CurrentMap().Title : "Unknown";
bg.GetWidget<LabelWidget>("MAP_PLAYERS").GetText = () =>
{
@@ -70,8 +62,8 @@ namespace OpenRA.Widgets.Delegates
bg.GetWidget("REFRESH_BUTTON").OnMouseUp = mi =>
{
r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
r.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list...";
bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
bg.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list...";
bg.Children.RemoveAll(a => GameButtons.Contains(a));
GameButtons.Clear();
@@ -83,16 +75,14 @@ namespace OpenRA.Widgets.Delegates
bg.GetWidget("CANCEL_BUTTON").OnMouseUp = mi =>
{
r.CloseWindow();
Widget.CloseWindow();
return true;
};
bg.GetWidget("DIRECTCONNECT_BUTTON").OnMouseUp = mi =>
{
r.CloseWindow();
dc.GetWidget<TextFieldWidget>("SERVER_ADDRESS").Text = Game.Settings.Player.LastServer;
r.OpenWindow("DIRECTCONNECT_BG");
Widget.CloseWindow();
Widget.OpenWindow("DIRECTCONNECT_BG");
return true;
};
@@ -119,33 +109,10 @@ namespace OpenRA.Widgets.Delegates
return false;
}
r.CloseWindow();
Widget.CloseWindow();
Game.JoinServer(currentServer.Address.Split(':')[0], int.Parse(currentServer.Address.Split(':')[1]));
return true;
};
// Direct Connect
dc.GetWidget("JOIN_BUTTON").OnMouseUp = mi =>
{
var address = dc.GetWidget<TextFieldWidget>("SERVER_ADDRESS").Text;
var cpts = address.Split(':').ToArray();
if (cpts.Length != 2)
return true;
Game.Settings.Player.LastServer = address;
Game.Settings.Save();
r.CloseWindow();
Game.JoinServer(cpts[0], int.Parse(cpts[1]));
return true;
};
dc.GetWidget("CANCEL_BUTTON").OnMouseUp = mi =>
{
r.CloseWindow();
return r.GetWidget("MAINMENU_BUTTON_JOIN").OnMouseUp(mi);
};
}
MapStub CurrentMap()
@@ -153,11 +120,22 @@ namespace OpenRA.Widgets.Delegates
return (currentServer == null || !Game.modData.AvailableMaps.ContainsKey(currentServer.Map))
? null : Game.modData.AvailableMaps[currentServer.Map];
}
string GenerateModsLabel()
{
return string.Join("\n", currentServer.Mods.Select(m =>
ModData.AllMods.ContainsKey(m) ? string.Format("{0} ({1})", ModData.AllMods[m].Title, ModData.AllMods[m].Version)
: string.Format("Unknown Mod: {0}",m)).ToArray());
}
void RefreshServerList(IEnumerable<GameServer> games)
{
var r = Widget.RootWidget;
var bg = r.GetWidget("JOINSERVER_BG");
if (bg == null) // We got a MasterServer reply AFTER the browser is gone, just return to prevent crash - Gecko
return;
var sl = bg.GetWidget<ListBoxWidget>("SERVER_LIST");
sl.Children.Clear();
@@ -205,4 +183,37 @@ namespace OpenRA.Widgets.Delegates
}
}
}
public class DirectConnectDelegate : IWidgetDelegate
{
[ObjectCreator.UseCtor]
public DirectConnectDelegate( [ObjectCreator.Param( "widget" )] Widget widget )
{
var dc = widget.GetWidget("DIRECTCONNECT_BG");
dc.GetWidget<TextFieldWidget>("SERVER_ADDRESS").Text = Game.Settings.Player.LastServer;
dc.GetWidget("JOIN_BUTTON").OnMouseUp = mi =>
{
var address = dc.GetWidget<TextFieldWidget>("SERVER_ADDRESS").Text;
var cpts = address.Split(':').ToArray();
if (cpts.Length != 2)
return true;
Game.Settings.Player.LastServer = address;
Game.Settings.Save();
Widget.CloseWindow();
Game.JoinServer(cpts[0], int.Parse(cpts[1]));
return true;
};
dc.GetWidget("CANCEL_BUTTON").OnMouseUp = mi =>
{
Widget.CloseWindow();
Widget.OpenWindow("MAINMENU_BG");
return true;
};
}
}
}

View File

@@ -53,6 +53,15 @@ namespace OpenRA.Widgets.Delegates
Game.Settings.Game.ViewportEdgeScroll ^= true;
return true;
};
// Added scroll sensitivity - Gecko
var edgeScrollSlider = general.GetWidget<SliderWidget>("EDGE_SCROLL_AMOUNT");
if (edgeScrollSlider != null) // Backwards compatible - Gecko
{
edgeScrollSlider.SetOffset(Game.Settings.Game.ViewportEdgeScrollStep);
edgeScrollSlider.OnChange += _ => { Game.Settings.Game.ViewportEdgeScrollStep = edgeScrollSlider.GetOffset(); };
Game.Settings.Game.ViewportEdgeScrollStep = edgeScrollSlider.GetOffset();
}
var inverseScroll = general.GetWidget<CheckboxWidget>("INVERSE_SCROLL");
inverseScroll.Checked = () => Game.Settings.Game.InverseDragScroll;
@@ -68,10 +77,12 @@ namespace OpenRA.Widgets.Delegates
var soundslider = audio.GetWidget<SliderWidget>("SOUND_VOLUME");
soundslider.OnChange += x => { Sound.SoundVolume = x; };
soundslider.GetOffset = () => { return Sound.SoundVolume; };
soundslider.SetOffset(Sound.SoundVolume);
var musicslider = audio.GetWidget<SliderWidget>("MUSIC_VOLUME");
musicslider.OnChange += x => { Sound.MusicVolume = x; };
musicslider.GetOffset = () => { return Sound.MusicVolume; };
musicslider.SetOffset(Sound.MusicVolume);
// Display
@@ -150,17 +161,9 @@ namespace OpenRA.Widgets.Delegates
bg.GetWidget("BUTTON_CLOSE").OnMouseUp = mi => {
Game.Settings.Save();
Widget.RootWidget.CloseWindow();
Widget.CloseWindow();
return true;
};
// Menu Buttons
Widget.RootWidget.GetWidget("MAINMENU_BUTTON_SETTINGS").OnMouseUp = mi => {
Widget.RootWidget.OpenWindow("SETTINGS_MENU");
return true;
};
}
string open = null;

View File

@@ -44,13 +44,13 @@ namespace OpenRA.Widgets.Delegates
bg.GetWidget("BUTTON_CLOSE").OnMouseUp = mi => {
player.Stop();
Widget.RootWidget.CloseWindow();
Widget.CloseWindow();
return true;
};
// Menu Buttons
Widget.RootWidget.GetWidget("MAINMENU_BUTTON_VIDEOPLAYER").OnMouseUp = mi => {
Widget.RootWidget.OpenWindow("VIDEOPLAYER_MENU");
Widget.OpenWindow("VIDEOPLAYER_MENU");
return true;
};

View File

@@ -16,10 +16,12 @@ namespace OpenRA.Widgets
public class LabelWidget : Widget
{
public enum TextAlign { Left, Center, Right }
public enum TextVAlign { Top, Middle, Bottom }
public string Text = null;
public string Background = null;
public TextAlign Align = TextAlign.Left;
public TextVAlign VAlign = TextVAlign.Middle;
public bool Bold = false;
public Func<string> GetText;
public Func<string> GetBackground;
@@ -54,8 +56,14 @@ namespace OpenRA.Widgets
return;
int2 textSize = font.Measure(text);
int2 position = RenderOrigin + new int2(0, (Bounds.Height - textSize.Y)/2);
int2 position = RenderOrigin;
if (VAlign == TextVAlign.Middle)
position += new int2(0, (Bounds.Height - textSize.Y)/2);
if (VAlign == TextVAlign.Bottom)
position += new int2(0, Bounds.Height - textSize.Y);
if (Align == TextAlign.Center)
position += new int2((Bounds.Width - textSize.X)/2, 0);

View File

@@ -71,15 +71,12 @@ namespace OpenRA.Widgets
WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", "down_arrow"),
new float2(downButtonRect.Left + downOffset, downButtonRect.Top + downOffset));
Game.Renderer.RgbaSpriteRenderer.Flush();
Game.Renderer.Device.EnableScissor(backgroundRect.X, backgroundRect.Y + HeaderHeight, backgroundRect.Width, backgroundRect.Height - HeaderHeight);
Game.Renderer.EnableScissor(backgroundRect.X, backgroundRect.Y + HeaderHeight, backgroundRect.Width, backgroundRect.Height - HeaderHeight);
foreach (var child in Children)
child.Draw(world);
Game.Renderer.RgbaSpriteRenderer.Flush();
Game.Renderer.Device.DisableScissor();
Game.Renderer.DisableScissor();
}
public override int2 ChildOrigin { get { return RenderOrigin + new int2(0, (int)ListOffset); } }

View File

@@ -105,8 +105,6 @@ namespace OpenRA.Widgets
new float2(MapRect.Location),
new float2( MapRect.Size ) );
Game.Renderer.RgbaSpriteRenderer.Flush();
// Overlay spawnpoints
var colors = SpawnColors();
foreach (var p in map.SpawnPoints)
@@ -120,12 +118,9 @@ namespace OpenRA.Widgets
sprite = OwnedSpawn;
offset = new int2(-OwnedSpawn.bounds.Width/2, -OwnedSpawn.bounds.Height/2);
WidgetUtils.FillRectWithColor(new Rectangle(pos.X + offset.X + 2, pos.Y + offset.Y + 2, 12, 12), colors[p]);
Game.Renderer.LineRenderer.Flush();
}
Game.Renderer.RgbaSpriteRenderer.DrawSprite(sprite, pos + offset);
}
Game.Renderer.Flush();
}
}
}

View File

@@ -40,8 +40,6 @@ namespace OpenRA.Widgets
return b;
});
}
Game.Renderer.LineRenderer.Flush();
}
}
}

View File

@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace OpenRA.Widgets
{
class ScrollingTextWidget : Widget
{
public string Text = "";
private string ScrollingText = "";
public string Background = null;
public bool Bold = false;
public int ScrollLength = 200;
// ticks per single letter scroll
public int ScrollRate = 4;
private string ScrollBuffer = "";
private int ScrollLocation = 0;
private int ScrollTick = 0;
public Func<string> GetText;
public Func<string> GetBackground;
public ScrollingTextWidget()
: base()
{
GetText = () => Text;
GetBackground = () => Background;
}
protected ScrollingTextWidget(ScrollingTextWidget other)
: base(other)
{
Text = other.Text;
GetText = other.GetText;
Bold = other.Bold;
GetBackground = other.GetBackground;
}
public override void Tick(World world)
{
if (Text != "")
{
ScrollingText = Text;
Text = "";
}
UpdateScrollBuffer();
}
public void ResetScroll()
{
ScrollLocation = 0;
ScrollTick = 0;
}
private void UpdateScrollBuffer()
{
ScrollTick++;
if (ScrollTick < ScrollRate)
{
return;
}
ScrollTick = 0;
ScrollBuffer = "";
if (ScrollingText.Substring(ScrollingText.Length - 4, 3) != " ")
{
ScrollingText += " ";
}
int tempScrollLocation = ScrollLocation;
for (int i = 0; i < ScrollLength; ++i)
{
ScrollBuffer += ScrollingText.Substring(tempScrollLocation, 1);
tempScrollLocation = (tempScrollLocation + 1) % ScrollingText.Length;
}
ScrollLocation = (ScrollLocation + 1) % ScrollingText.Length;
}
public void SetText(string newText)
{
Text = newText.Replace("\n", " ");
Text = Text.Replace("\r", "");
}
public override void DrawInner(World world)
{
var bg = GetBackground();
if (bg != null)
WidgetUtils.DrawPanel(bg, RenderBounds);
var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont;
var text = GetText();
if (text == null)
return;
int2 textSize = font.Measure(text);
int2 position = RenderOrigin + new int2(0, (Bounds.Height - textSize.Y) / 2);
Game.Renderer.EnableScissor(position.X, position.Y, Bounds.Width, Bounds.Height);
font.DrawText(ScrollBuffer, position, Color.White);
Game.Renderer.DisableScissor();
}
public override Widget Clone() { return new ScrollingTextWidget(this); }
}
}

45
OpenRA.Game/Widgets/SliderWidget.cs Normal file → Executable file
View File

@@ -6,9 +6,9 @@
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
#endregion
using System;
using System.Drawing;
namespace OpenRA.Widgets
@@ -17,9 +17,11 @@ namespace OpenRA.Widgets
{
public event Action<float> OnChange;
public Func<float> GetOffset;
public float Offset = 0;
public int Ticks = 0;
public int TrackHeight = 5;
public float2 Range = new float2(0f, 1f);
private float Offset = 0;
int2 lastMouseLocation;
bool isMoving = false;
@@ -27,8 +29,15 @@ namespace OpenRA.Widgets
public SliderWidget()
: base()
{
GetOffset = () => Offset;
OnChange = x => Offset = x;
GetOffset = () =>
{
var Big = Math.Max(Range.X, Range.Y);
var Little = Math.Min(Range.X, Range.Y);
var Spread = Big - Little;
return Spread * Offset + Little;
};
OnChange = x => Offset = x.Clamp(0f, 1f);
}
public SliderWidget(SliderWidget other)
@@ -36,13 +45,23 @@ namespace OpenRA.Widgets
{
OnChange = other.OnChange;
GetOffset = other.GetOffset;
Offset = other.Offset;
Ticks = other.Ticks;
Range = other.Range;
Offset = GetOffset();
TrackHeight = other.TrackHeight;
lastMouseLocation = other.lastMouseLocation;
isMoving = other.isMoving;
}
public void SetOffset(float newOffset)
{
var Big = Math.Max(Range.X, Range.Y);
var Little = Math.Min(Range.X, Range.Y);
var Spread = Big - Little;
Offset = ((newOffset - Little) / Spread).Clamp(0f, 1f);
}
public override bool HandleInputInner(MouseInput mi)
{
if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi))
@@ -72,7 +91,7 @@ namespace OpenRA.Widgets
}
else if (Ticks != 0)
{
var pos = GetOffset();
var pos = Offset;
// Offset slightly the direction we want to move so we don't get stuck on a tick
var delta = 0.001;
@@ -92,7 +111,7 @@ namespace OpenRA.Widgets
var thumb = thumbRect;
var center = thumb.X + thumb.Width / 2;
var newOffset = OffsetBy((mi.Location.X - center) * 1f / (RenderBounds.Width - thumb.Width));
if (newOffset != GetOffset())
if (newOffset != Offset)
{
OnChange(newOffset);
@@ -127,7 +146,7 @@ namespace OpenRA.Widgets
float OffsetBy(float amount)
{
var centerPos = GetOffset() + amount;
var centerPos = Offset + amount;
if (centerPos < 0) centerPos = 0;
if (centerPos > 1) centerPos = 1;
return centerPos;
@@ -141,7 +160,7 @@ namespace OpenRA.Widgets
{
var width = RenderBounds.Height;
var height = RenderBounds.Height;
var origin = (int)((RenderBounds.X + width / 2) + GetOffset() * (RenderBounds.Width - width) - width / 2f);
var origin = (int)((RenderBounds.X + width / 2) + Offset * (RenderBounds.Width - width) - width / 2f);
return new Rectangle(origin, RenderBounds.Y, width, height);
}
}
@@ -169,5 +188,5 @@ namespace OpenRA.Widgets
WidgetUtils.DrawPanel("dialog2", thumbRect);
}
}
}
}

View File

@@ -127,16 +127,13 @@ namespace OpenRA.Widgets
if (Focused)
textPos += new int2(Bounds.Width - 2 * margin - textSize.X, 0);
Game.Renderer.Device.EnableScissor(pos.X + margin, pos.Y, Bounds.Width - 2 * margin, Bounds.Bottom);
Game.Renderer.EnableScissor(pos.X + margin, pos.Y, Bounds.Width - 2 * margin, Bounds.Bottom);
}
font.DrawText(Text + cursor, textPos, Color.White);
if (textSize.X > Bounds.Width - 2 * margin)
{
Game.Renderer.RgbaSpriteRenderer.Flush();
Game.Renderer.Device.DisableScissor();
}
Game.Renderer.DisableScissor();
}
public override Widget Clone() { return new TextFieldWidget(this); }

336
OpenRA.Game/Widgets/ViewportScrollControllerWidget.cs Normal file → Executable file
View File

@@ -1,172 +1,178 @@
#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
#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 OpenRA.Graphics;
namespace OpenRA.Widgets
{
[Flags]
public enum ScrollDirection
{
None = 0,
Up = 1,
Left = 2,
Down = 4,
Right = 8
}
class ViewportScrollControllerWidget : Widget
{
public int EdgeScrollThreshold = 15;
ScrollDirection Keyboard;
namespace OpenRA.Widgets
{
[Flags]
public enum ScrollDirection
{
None = 0,
Up = 1,
Left = 2,
Down = 4,
Right = 8
}
class ViewportScrollControllerWidget : Widget
{
public int EdgeScrollThreshold = 15;
ScrollDirection Keyboard;
ScrollDirection Edge;
public ViewportScrollControllerWidget() : base() { }
protected ViewportScrollControllerWidget(ViewportScrollControllerWidget widget) : base(widget) {}
public override void DrawInner( World world ) {}
public override bool HandleInputInner(MouseInput mi)
{
if (mi.Event == MouseInputEvent.Move &&
(mi.Button == MouseButton.Middle || mi.Button == (MouseButton.Left | MouseButton.Right)))
public ViewportScrollControllerWidget() : base() { }
protected ViewportScrollControllerWidget(ViewportScrollControllerWidget widget) : base(widget) {}
public override void DrawInner( World world ) {}
public override bool HandleInputInner(MouseInput mi)
{
if (mi.Event == MouseInputEvent.Move &&
(mi.Button == MouseButton.Middle || mi.Button == (MouseButton.Left | MouseButton.Right)))
{
int InverseScroll = Game.Settings.Game.InverseDragScroll ? -1 : 1;
Game.viewport.Scroll((Viewport.LastMousePos - mi.Location) * InverseScroll);
return true;
}
return false;
}
public override string GetCursor(int2 pos)
{
if (!Game.Settings.Game.ViewportEdgeScroll)
return null;
if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Left)){
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
if(BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Left))
return "scroll-tl-blocked";
else
return "scroll-tl";
}
if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Right)){
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
if (BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Right))
return "scroll-tr-blocked";
else
return "scroll-tr";
}
if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Left)){
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Left))
return "scroll-bl-blocked";
else
return "scroll-bl";
}
if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Right)){
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Right))
return "scroll-br-blocked";
else
return "scroll-br";
}
if (Edge.Includes(ScrollDirection.Up))
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Up))
return "scroll-t-blocked";
else
return "scroll-t";
if (Edge.Includes(ScrollDirection.Down))
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Down))
return "scroll-b-blocked";
else
return "scroll-b";
if (Edge.Includes(ScrollDirection.Left))
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Left))
return "scroll-l-blocked";
else
return "scroll-l";
if (Edge.Includes(ScrollDirection.Right))
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Right))
return "scroll-r-blocked";
else
return "scroll-r";
return null;
}
public override bool LoseFocus (MouseInput mi)
{
Keyboard = ScrollDirection.None;
return base.LoseFocus(mi);
}
public override bool HandleKeyPressInner(KeyInput e)
{
switch (e.KeyName)
{
case "up": Keyboard = Keyboard.Set(ScrollDirection.Up, (e.Event == KeyInputEvent.Down)); return true;
case "down": Keyboard = Keyboard.Set(ScrollDirection.Down, (e.Event == KeyInputEvent.Down)); return true;
case "left": Keyboard = Keyboard.Set(ScrollDirection.Left, (e.Event == KeyInputEvent.Down)); return true;
case "right": Keyboard = Keyboard.Set(ScrollDirection.Right, (e.Event == KeyInputEvent.Down)); return true;
}
return false;
}
public override void Tick(World world)
{
Edge = ScrollDirection.None;
if (Game.Settings.Game.ViewportEdgeScroll && Game.HasInputFocus)
{
// Check for edge-scroll
if (Viewport.LastMousePos.X < EdgeScrollThreshold)
Edge = Edge.Set(ScrollDirection.Left, true);
if (Viewport.LastMousePos.Y < EdgeScrollThreshold)
Edge = Edge.Set(ScrollDirection.Up, true);
if (Viewport.LastMousePos.X >= Game.viewport.Width - EdgeScrollThreshold)
Edge = Edge.Set(ScrollDirection.Right, true);
if (Viewport.LastMousePos.Y >= Game.viewport.Height - EdgeScrollThreshold)
Edge = Edge.Set(ScrollDirection.Down, true);
}
if(Keyboard != ScrollDirection.None || Edge != ScrollDirection.None)
{
var scroll = new float2(0,0);
if (Keyboard.Includes(ScrollDirection.Up) || Edge.Includes(ScrollDirection.Up))
scroll += new float2(0, -10);
if (Keyboard.Includes(ScrollDirection.Right) || Edge.Includes(ScrollDirection.Right))
scroll += new float2(10, 0);
if (Keyboard.Includes(ScrollDirection.Down) || Edge.Includes(ScrollDirection.Down))
scroll += new float2(0, 10);
if (Keyboard.Includes(ScrollDirection.Left) || Edge.Includes(ScrollDirection.Left))
scroll += new float2(-10, 0);
Game.viewport.Scroll(scroll);
}
}
public override Widget Clone() { return new ViewportScrollControllerWidget(this); }
}
public static class ViewportExts
{
public static bool Includes(this ScrollDirection d, ScrollDirection s)
{
return (d & s) == s;
}
public static ScrollDirection Set(this ScrollDirection d, ScrollDirection s, bool val)
{
return (d.Includes(s) != val) ? d ^ s : d;
}
}
}
Game.viewport.Scroll((Viewport.LastMousePos - mi.Location) * InverseScroll);
return true;
}
return false;
}
public override string GetCursor(int2 pos)
{
if (!Game.Settings.Game.ViewportEdgeScroll)
return null;
if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Left)){
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
if(BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Left))
return "scroll-tl-blocked";
else
return "scroll-tl";
}
if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Right)){
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
if (BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Right))
return "scroll-tr-blocked";
else
return "scroll-tr";
}
if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Left)){
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Left))
return "scroll-bl-blocked";
else
return "scroll-bl";
}
if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Right)){
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Right))
return "scroll-br-blocked";
else
return "scroll-br";
}
if (Edge.Includes(ScrollDirection.Up))
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Up))
return "scroll-t-blocked";
else
return "scroll-t";
if (Edge.Includes(ScrollDirection.Down))
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Down))
return "scroll-b-blocked";
else
return "scroll-b";
if (Edge.Includes(ScrollDirection.Left))
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Left))
return "scroll-l-blocked";
else
return "scroll-l";
if (Edge.Includes(ScrollDirection.Right))
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Right))
return "scroll-r-blocked";
else
return "scroll-r";
return null;
}
public override bool LoseFocus (MouseInput mi)
{
Keyboard = ScrollDirection.None;
return base.LoseFocus(mi);
}
public override bool HandleKeyPressInner(KeyInput e)
{
switch (e.KeyName)
{
case "up": Keyboard = Keyboard.Set(ScrollDirection.Up, (e.Event == KeyInputEvent.Down)); return true;
case "down": Keyboard = Keyboard.Set(ScrollDirection.Down, (e.Event == KeyInputEvent.Down)); return true;
case "left": Keyboard = Keyboard.Set(ScrollDirection.Left, (e.Event == KeyInputEvent.Down)); return true;
case "right": Keyboard = Keyboard.Set(ScrollDirection.Right, (e.Event == KeyInputEvent.Down)); return true;
}
return false;
}
public override void Tick(World world)
{
Edge = ScrollDirection.None;
if (Game.Settings.Game.ViewportEdgeScroll && Game.HasInputFocus)
{
// Check for edge-scroll
if (Viewport.LastMousePos.X < EdgeScrollThreshold)
Edge = Edge.Set(ScrollDirection.Left, true);
if (Viewport.LastMousePos.Y < EdgeScrollThreshold)
Edge = Edge.Set(ScrollDirection.Up, true);
if (Viewport.LastMousePos.X >= Game.viewport.Width - EdgeScrollThreshold)
Edge = Edge.Set(ScrollDirection.Right, true);
if (Viewport.LastMousePos.Y >= Game.viewport.Height - EdgeScrollThreshold)
Edge = Edge.Set(ScrollDirection.Down, true);
}
if(Keyboard != ScrollDirection.None || Edge != ScrollDirection.None)
{
var scroll = new float2(0, 0);
// Modified to use the ViewportEdgeScrollStep setting - Gecko
if (Keyboard.Includes(ScrollDirection.Up) || Edge.Includes(ScrollDirection.Up))
scroll += new float2(0, -1);
if (Keyboard.Includes(ScrollDirection.Right) || Edge.Includes(ScrollDirection.Right))
scroll += new float2(1, 0);
if (Keyboard.Includes(ScrollDirection.Down) || Edge.Includes(ScrollDirection.Down))
scroll += new float2(0, 1);
if (Keyboard.Includes(ScrollDirection.Left) || Edge.Includes(ScrollDirection.Left))
scroll += new float2(-1, 0);
float length = scroll.Length;
scroll.X = (scroll.X / length) * Game.Settings.Game.ViewportEdgeScrollStep;
scroll.Y = (scroll.Y / length) * Game.Settings.Game.ViewportEdgeScrollStep;
Game.viewport.Scroll(scroll);
}
}
public override Widget Clone() { return new ViewportScrollControllerWidget(this); }
}
public static class ViewportExts
{
public static bool Includes(this ScrollDirection d, ScrollDirection s)
{
return (d & s) == s;
}
public static ScrollDirection Set(this ScrollDirection d, ScrollDirection s, bool val)
{
return (d.Includes(s) != val) ? d ^ s : d;
}
}
}

View File

@@ -26,6 +26,7 @@ namespace OpenRA.Widgets
public string Width = "0";
public string Height = "0";
public string Delegate = null;
public string EventHandler = null;
public bool ClickThrough = true;
public bool Visible = true;
public readonly List<Widget> Children = new List<Widget>();
@@ -35,7 +36,7 @@ namespace OpenRA.Widgets
public Widget Parent = null;
static List<string> Delegates = new List<string>();
public static Stack<string> WindowList = new Stack<string>();
public static Stack<Widget> WindowList = new Stack<Widget>();
// Common Funcs that most widgets will want
public Action<object> SpecialOneArg = (arg) => {};
@@ -47,24 +48,13 @@ namespace OpenRA.Widgets
public Func<bool> IsVisible;
public Widget() { IsVisible = () => Visible; }
public static Widget RootWidget {
get
{
if (rootWidget == null)
{
rootWidget = new ContainerWidget();
foreach( var file in Game.modData.Manifest.ChromeLayout.Select( a => MiniYaml.FromFile( a ) ) )
foreach( var w in file )
rootWidget.AddChild( WidgetLoader.LoadWidget( w ) );
rootWidget.Initialize();
rootWidget.InitDelegates();
}
return rootWidget;
}
public static Widget RootWidget
{
get { return rootWidget; }
set { rootWidget = value; }
}
private static Widget rootWidget = null;
private static Widget rootWidget = new ContainerWidget();
public Widget(Widget widget)
{
@@ -132,14 +122,15 @@ namespace OpenRA.Widgets
Evaluator.Evaluate(Y, substitutions),
width,
height);
}
// Non-static func definitions
if (Delegate != null && !Delegates.Contains(Delegate))
Delegates.Add(Delegate);
foreach (var child in Children)
child.Initialize();
public void PostInit()
{
if( Delegate != null )
{
var createDict = new Dictionary<string, object> { { "widget", this } };
Game.modData.ObjectCreator.CreateObject<IWidgetDelegate>( Delegate, createDict );
}
}
public void InitDelegates()
@@ -322,20 +313,19 @@ namespace OpenRA.Widgets
return (widget != null)? (T) widget : null;
}
public void CloseWindow()
public static void CloseWindow()
{
RootWidget.GetWidget(WindowList.Pop()).Visible = false;
if (WindowList.Count > 0)
RootWidget.GetWidget(WindowList.Peek()).Visible = true;
RootWidget.Children.Remove( WindowList.Pop() );
if( WindowList.Count > 0 )
rootWidget.Children.Add( WindowList.Peek() );
}
public Widget OpenWindow(string id)
public static Widget OpenWindow(string id)
{
if (WindowList.Count > 0)
RootWidget.GetWidget(WindowList.Peek()).Visible = false;
WindowList.Push(id);
var window = RootWidget.GetWidget(id);
window.Visible = true;
var window = Game.modData.WidgetLoader.LoadWidget( rootWidget, id );
if( WindowList.Count > 0 )
rootWidget.Children.Remove( WindowList.Peek() );
WindowList.Push( window );
return window;
}

View File

@@ -8,29 +8,57 @@
*/
#endregion
using System.Linq;
using System.Collections.Generic;
using OpenRA.FileFormats;
using OpenRA.Widgets;
namespace OpenRA
{
class WidgetLoader
public class WidgetLoader
{
public static Widget LoadWidget(MiniYamlNode node)
// foreach( var file in Game.modData.Manifest.ChromeLayout.Select( a => MiniYaml.FromFile( a ) ) )
// foreach( var w in file )
// rootWidget.AddChild( WidgetLoader.LoadWidget( w ) );
// rootWidget.Initialize();
// rootWidget.InitDelegates();
Dictionary<string, MiniYamlNode> widgets = new Dictionary<string, MiniYamlNode>();
public WidgetLoader( ModData modData )
{
foreach( var file in modData.Manifest.ChromeLayout.Select( a => MiniYaml.FromFile( a ) ) )
foreach( var w in file )
widgets.Add( w.Key.Substring( w.Key.IndexOf( '@' ) + 1 ), w );
}
public Widget LoadWidget( Widget parent, string w )
{
return LoadWidget( parent, widgets[ w ] );
}
public Widget LoadWidget( Widget parent, MiniYamlNode node)
{
var widget = NewWidget(node.Key);
parent.AddChild( widget );
foreach (var child in node.Value.Nodes)
if (child.Key != "Children")
FieldLoader.LoadField(widget, child.Key, child.Value.Value);
widget.Initialize();
foreach (var child in node.Value.Nodes)
{
if (child.Key == "Children")
foreach (var c in child.Value.Nodes)
widget.AddChild(LoadWidget(c));
else
FieldLoader.LoadField(widget, child.Key, child.Value.Value);
}
LoadWidget( widget, c);
widget.PostInit();
return widget;
}
static Widget NewWidget(string widgetType)
Widget NewWidget(string widgetType)
{
widgetType = widgetType.Split('@')[0];
return Game.CreateObject<Widget>(widgetType + "Widget");

View File

@@ -127,8 +127,6 @@ namespace OpenRA.Widgets
DrawRGBA(ss[6], new float2(Bounds.Left, Bounds.Bottom - ss[6].size.Y));
if (ps.HasFlags(PanelSides.Right | PanelSides.Bottom))
DrawRGBA(ss[7], new float2(Bounds.Right - ss[7].size.X, Bounds.Bottom - ss[7].size.Y));
Game.Renderer.RgbaSpriteRenderer.Flush();
}
}

View File

@@ -6,14 +6,14 @@
* 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.Orders;
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Orders;
using OpenRA.Traits;
namespace OpenRA.Widgets
@@ -39,8 +39,6 @@ namespace OpenRA.Widgets
foreach (var u in SelectActorsInBox(world, selbox.Value.First, selbox.Value.Second))
world.WorldRenderer.DrawSelectionBox(u, Color.Yellow);
Game.Renderer.LineRenderer.Flush();
}
float2 dragStart, dragEnd;
@@ -111,9 +109,8 @@ namespace OpenRA.Widgets
public override string GetCursor(int2 pos)
{
var world = Game.world;
int sync = world.SyncHash();
try
{
return Sync.CheckSyncUnchanged( world, () =>
{
if (!world.GameHasStarted)
return "default";
@@ -124,29 +121,24 @@ namespace OpenRA.Widgets
Modifiers = Game.GetModifierKeys()
};
return Game.world.OrderGenerator.GetCursor( world, Game.viewport.ViewToWorld(mi).ToInt2(), mi );
}
finally
{
if( sync != world.SyncHash() )
throw new InvalidOperationException( "Desync in InputControllerWidget.GetCursor" );
}
return world.OrderGenerator.GetCursor( world, Game.viewport.ViewToWorld(mi).ToInt2(), mi );
} );
}
public override bool HandleKeyPressInner(KeyInput e)
{
if (e.Event == KeyInputEvent.Down)
{
if (e.KeyName.Length == 1 && char.IsDigit(e.KeyName[0]))
{
Game.world.Selection.DoControlGroup(Game.world, e.KeyName[0] - '0', e.Modifiers);
return true;
}
if (e.KeyChar == '\b')
{
GotoNextBase();
return true;
{
if (e.KeyName.Length == 1 && char.IsDigit(e.KeyName[0]))
{
Game.world.Selection.DoControlGroup(Game.world, e.KeyName[0] - '0', e.Modifiers);
return true;
}
if (e.KeyChar == '\b')
{
GotoNextBase();
return true;
}
}
return false;

View File

@@ -85,7 +85,6 @@ namespace OpenRA.Widgets
ChromeProvider.GetImage("flags", actor.Owner.Country.Race),
new float2(Viewport.LastMousePos.X + 30, Viewport.LastMousePos.Y + 50));
}
Game.Renderer.RgbaSpriteRenderer.Flush();
}
}
}

View File

@@ -10,13 +10,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Collections;
using OpenRA.Effects;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Orders;
using OpenRA.Support;
using OpenRA.Traits;
using XRandom = OpenRA.Thirdparty.Random;
@@ -56,8 +54,18 @@ namespace OpenRA
public readonly TileSet TileSet;
public readonly WorldRenderer WorldRenderer;
public IOrderGenerator OrderGenerator = new UnitOrderGenerator();
IOrderGenerator orderGenerator_;
public IOrderGenerator OrderGenerator
{
get { return orderGenerator_; }
set
{
Sync.AssertUnsynced( "The current order generator may not be changed from synced code" );
orderGenerator_ = value;
}
}
public Selection Selection = new Selection();
public void CancelInputMode() { OrderGenerator = new UnitOrderGenerator(); }
@@ -78,6 +86,7 @@ namespace OpenRA
public World(Manifest manifest, Map map)
{
orderGenerator_ = new UnitOrderGenerator();
Map = map;
TileSet = Rules.TileSets[Map.Tileset];
@@ -173,10 +182,20 @@ namespace OpenRA
{
//using (new PerfSample("synchash"))
{
int n = 0;
int ret = 0;
foreach (var a in Actors)
ret += (int)a.ActorID * Sync.CalculateSyncHash(a);
// hash all the actors
foreach (var a in Actors)
ret += n++ * (int)a.ActorID * Sync.CalculateSyncHash(a);
// hash all the traits that tick
foreach (var x in traitDict.ActorsWithTraitMultiple<object>(this))
ret += n++ * (int)x.Actor.ActorID * Sync.CalculateSyncHash(x.Trait);
// Hash the shared rng
ret += SharedRandom.Last;
return ret;
}
}
@@ -186,7 +205,6 @@ namespace OpenRA
readonly World world;
public readonly Cache<Player, OwnedByCachedView> OwnedBy;
readonly TypeDictionary hasTrait = new TypeDictionary();
public AllQueries( World world )
{

View File

@@ -22,13 +22,21 @@ namespace OpenRA.GlRenderer
{
Gl.glGenBuffers(1, out buffer);
GraphicsDevice.CheckGlError();
}
public void SetData(ushort[] data)
{
Bind();
Gl.glBufferData(Gl.GL_ELEMENT_ARRAY_BUFFER,
new IntPtr(2 * data.Length), data, Gl.GL_DYNAMIC_DRAW);
new IntPtr(2 * size),
new ushort[ size ],
Gl.GL_DYNAMIC_DRAW);
GraphicsDevice.CheckGlError();
}
public void SetData(ushort[] data, int length)
{
Bind();
Gl.glBufferSubData(Gl.GL_ELEMENT_ARRAY_BUFFER,
IntPtr.Zero,
new IntPtr(2 * length),
data);
GraphicsDevice.CheckGlError();
}

View File

@@ -24,13 +24,21 @@ namespace OpenRA.GlRenderer
{
Gl.glGenBuffers(1, out buffer);
GraphicsDevice.CheckGlError();
}
public void SetData(T[] data)
{
Bind();
Gl.glBufferData(Gl.GL_ARRAY_BUFFER,
new IntPtr(Marshal.SizeOf(typeof(T)) * data.Length), data, Gl.GL_DYNAMIC_DRAW);
new IntPtr(Marshal.SizeOf(typeof(T)) * size),
new T[ size ],
Gl.GL_DYNAMIC_DRAW);
GraphicsDevice.CheckGlError();
}
public void SetData(T[] data, int length)
{
Bind();
Gl.glBufferSubData(Gl.GL_ARRAY_BUFFER,
IntPtr.Zero,
new IntPtr(Marshal.SizeOf(typeof(T)) * length),
data);
GraphicsDevice.CheckGlError();
}

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