Compare commits

...

306 Commits

Author SHA1 Message Date
Matthew
db5920e83a Minor fixes to packaging. 2010-08-15 02:08:49 +12:00
Matthew
80555235d7 Fixes for Windows packaging. 2010-08-15 02:08:49 +12:00
Matthew
acd842f178 Windows support added to general packager. 2010-08-15 02:08:49 +12:00
Matthew
a5dacd52e8 OSX support added to general packager. 2010-08-15 02:08:49 +12:00
Matthew
6e045e864a Further RPM fixes 2010-08-15 02:08:49 +12:00
Matthew
0541b04c3a RPM packaging fixes. 2010-08-15 02:08:49 +12:00
Matthew
07b2bcbfdf RPM support in general packaging script. 2010-08-15 02:08:49 +12:00
Matthew
0e2b4bb721 General package script works for Arch-Linux packages. 2010-08-15 02:08:49 +12:00
Paul Chote
ab3c06cd04 Fail 2010-08-15 01:59:23 +12:00
Chris Forbes
299ee7f82c remove redundant devmode checkbox in settings -- 'enable cheats' does it 2010-08-15 01:44:38 +12:00
Paul Chote
ddd56e6f9b Reveal-map crate 2010-08-15 01:43:24 +12:00
Paul Chote
839043ea1b Disable music player until its finished 2010-08-15 01:13:49 +12:00
Paul Chote
1e8aea616b Hook up music seek 2010-08-15 01:07:05 +12:00
Paul Chote
727a88d82a Listbox content shouldn't steal clicks if they're clipped 2010-08-15 00:44:19 +12:00
alzeih
1f54ad3238 Oops 2010-08-15 00:38:31 +12:00
Paul Chote
694fd84188 Clean up custom color palette 2010-08-15 00:18:06 +12:00
alzeih
271be551b0 Add Voices and DisableVariants to VoiceInfo, remove the ".aud" for die sounds. 2010-08-15 00:07:27 +12:00
alzeih
fe481d7445 Fix #36
- add to ra
- add default variant
2010-08-15 00:07:27 +12:00
alzeih
7a10ae3dea Some of fixing #36 2010-08-15 00:07:27 +12:00
Chris Forbes
8c39e372e3 throttle mouse motion events to one per frame 2010-08-14 23:48:12 +12:00
Paul Chote
af6660d6ca Fix palette remaps 2010-08-14 23:36:41 +12:00
Paul Chote
d0da9d11bf Fix palettes and all palettemods. Remap palettes broken. 2010-08-14 23:29:01 +12:00
Paul Chote
0a2d39f15b More correct, still doesn't work. 2010-08-14 22:23:22 +12:00
Paul Chote
8118a17e3c foo 2010-08-14 21:53:24 +12:00
Paul Chote
0f6564f31a more or less fail 2010-08-14 21:36:13 +12:00
Paul Chote
dda6556e17 non-working palette fail 2010-08-14 21:07:19 +12:00
Paul Chote
5c1408d4d7 cnc water palette rotation 2010-08-14 17:52:59 +12:00
Chris Forbes
aa6e671d89 cnc tran unloadfacing=initialfacing 2010-08-14 17:44:36 +12:00
alzeih
e0de1427e9 Die sanely when a widget doesn't exist. 2010-08-14 17:39:50 +12:00
alzeih
db16ab4cdc Add VideoVolume 2010-08-14 17:39:50 +12:00
Bob
ae703d50b2 Actor.traits is implementation detail 2010-08-14 17:39:49 +12:00
Paul Chote
f6c6255f64 Custom tiberium pathing cost 2010-08-14 17:37:36 +12:00
Paul Chote
a569c712f0 Video pausing support; sync video to audio nicer. 2010-08-14 17:21:54 +12:00
Paul Chote
5c8c8d5e6e Support more video types. 2010-08-14 15:59:40 +12:00
alzeih
3f4f1ff75e MusicSeekPosition 2010-08-14 14:24:25 +12:00
Paul Chote
1aa4f57a68 Prototype new music player 2010-08-14 14:05:32 +12:00
Paul Chote
3f3ac377b2 Backend changes for new music player 2010-08-13 19:46:13 +12:00
Paul Chote
de12233edc cnc movie list 2010-08-13 00:30:46 +12:00
Paul Chote
b36b101392 Soviet movie definitions 2010-08-12 21:07:38 +12:00
Chris Forbes
726449b6fb fix it so it works when have no movies 2010-08-12 20:47:38 +12:00
Paul Chote
a0d7435550 Overlay with black lines for authentic ra feel 2010-08-12 20:47:38 +12:00
Paul Chote
11aed465a8 Populate the list from yaml; Define ra-allies movies; Additional polish. 2010-08-12 20:47:37 +12:00
Paul Chote
0f953226a6 Populate and use the listbox 2010-08-12 20:47:37 +12:00
Chris Forbes
ad181544cd give cnc towers significantly more hp 2010-08-12 20:44:03 +12:00
Chris Forbes
df19163ce5 fix #18 -- harvs built at weap choose a proc when trying to return now 2010-08-12 19:54:37 +12:00
Chris Forbes
4328fbc350 fix color picker again 2010-08-12 19:35:36 +12:00
Chris Forbes
7cd9afb6d2 remove some sillyness from the masterserver -- it shouldnt hold up the works. 2010-08-12 19:27:11 +12:00
Chris Forbes
1ad8b58f1b blah 2010-08-12 18:34:48 +12:00
Matthew
62e3d548c8 Makefile generated start-up script altered to allow command line switches to be passed to executable. 2010-08-12 18:11:06 +12:00
Matthew
ea7abcb585 Makefile install target fix. 2010-08-12 18:11:06 +12:00
Chris Forbes
441bffecfc fix #262 -- harv should move slower when full 2010-08-12 18:10:23 +12:00
Paul Chote
2c1ab33893 Add a "Video Player" menu with basic impl; kill the music player widget. 2010-08-12 18:06:12 +12:00
Paul Chote
74500c369c Stop video soundtrack when video stops 2010-08-12 00:44:53 +12:00
Paul Chote
6e0158039a Support uncompressed audio (ally1.vqa) 2010-08-12 00:37:19 +12:00
Paul Chote
c600239c54 Begin making video player widget useful; steal (othewise useless) musicplayer controls for now 2010-08-12 00:31:30 +12:00
Paul Chote
93a48c0cf1 Tweaks 2010-08-12 00:06:08 +12:00
Paul Chote
b88512df43 Keep video in sync with audio 2010-08-11 23:58:30 +12:00
Chris Forbes
ca6debde66 buffer up all the audio upfront 2010-08-11 22:56:32 +12:00
Chris Forbes
8dd9848636 preserve aud codec state across blocks, so the gain isnt completely bogus 2010-08-11 22:19:49 +12:00
Chris Forbes
ec9da154ad add crap broken sound support for vqa 2010-08-11 22:04:55 +12:00
Chris Forbes
46fc0ef563 add ignore for vqas; disable the vqaplayer in the mainmenu for now 2010-08-11 21:44:42 +12:00
Paul Chote
514c92a998 FAST vqa render 2010-08-11 19:54:24 +12:00
Paul Chote
96f9f33776 Tweaks 2010-08-11 19:04:03 +12:00
Paul Chote
20553a112d Don't hide the original crash if the master server is inaccessible 2010-08-11 18:20:50 +12:00
Paul Chote
9e49cad1c2 .vqp format doc 2010-08-11 14:56:16 +12:00
Paul Chote
5c6e2a5e42 Fix crash when cnc videos loop 2010-08-11 11:53:01 +12:00
Paul Chote
44d7aa14a4 Hacky ingame video widget 2010-08-11 11:45:37 +12:00
Paul Chote
bf8e3645cb cnc support (doesn't use format80) 2010-08-11 01:34:05 +12:00
Paul Chote
6ea8d4e6d3 Test a different video; fix a stupid crash. All works except for sound. 2010-08-11 00:57:49 +12:00
Paul Chote
16c3223f3e Fix 8-frame glitch 2010-08-11 00:57:49 +12:00
Paul Chote
b98e180361 Dump the animation to a set of bitmaps; glitches every 8 frames. 2010-08-11 00:57:49 +12:00
Paul Chote
80aade857e Start removing fail 2010-08-11 00:57:49 +12:00
Paul Chote
58700e4c07 Save the hax pixels too 2010-08-11 00:57:49 +12:00
Paul Chote
d364472862 Write the pixels that don't need further hax to a bitmap 2010-08-11 00:57:49 +12:00
Paul Chote
5d688a2e27 CBFZ, CBPZ, CPL0 chunks 2010-08-11 00:57:49 +12:00
Paul Chote
f4fa053a35 Add a null parser for VQFR chunk 2010-08-11 00:57:49 +12:00
Paul Chote
90373529b0 Parse FINF and (skip) SND2 2010-08-11 00:57:49 +12:00
Paul Chote
0416b6b429 Format docs 2010-08-11 00:57:48 +12:00
Paul Chote
bd991e33ca Begin vqa support; load and display FORM header 2010-08-11 00:57:48 +12:00
Chris Forbes
f162c5956e cleanup wtf 2010-08-10 21:51:06 +12:00
Chris Forbes
e6f717ff04 FAST 2010-08-10 21:26:50 +12:00
Chris Forbes
eb0c895e2c fix prev 2010-08-10 21:26:44 +12:00
Chris Forbes
3af0d2f6a4 noise reduction 2010-08-09 17:29:50 +12:00
Chris Forbes
8f6fe8344b split PrimaryBuilding from Production 2010-08-09 17:20:34 +12:00
Paul Chote
cb5307bb17 nerf e1 (stole ra damage stats) 2010-08-08 21:47:31 +12:00
Paul Chote
d9acf1a3e5 Don't teleport into transport's. 2010-08-08 19:30:49 +12:00
Paul Chote
6fc945ac91 Fix cargo/passenger interaction 2010-08-08 19:16:37 +12:00
Paul Chote
e5878e8207 Fix Color Picker 2010-08-08 18:45:05 +12:00
Paul Chote
b982a52086 stop .net clients taking out the server on drop 2010-08-08 18:26:55 +12:00
Matthew
f28ec846e7 WindowsBase.dll added to thirdparty DLLs to work around distributions with outdated versions of Mono. 2010-08-07 16:11:18 +12:00
Chris Forbes
551814fc32 fix crash when a bridge is destroyed, and has a husk on it. 2010-08-06 21:02:46 +12:00
Chris Forbes
f64a6e273e fix sub -> ground crash 2010-08-06 20:11:49 +12:00
Matthew
1a428186e9 Minor fix to arch-linux post install script. 2010-08-06 14:15:53 +12:00
Matthew
609abb7719 Fixes to include extra mod dirs in Makefile and correct paths in post install scripts. 2010-08-06 14:03:37 +12:00
Matthew
aee0728a73 SupportDir path fixed. 2010-08-06 12:37:21 +12:00
Matthew
120a5fa66b Packaging and Makefile fixes. 2010-08-06 12:28:09 +12:00
Chris Forbes
71792a8f09 fix crash on telling {sam,agun} to attack ground 2010-08-04 18:23:06 +12:00
Chris Forbes
0f20133af0 fix crash in retry 2010-08-03 20:40:27 +12:00
Paul Chote
40b16e33ba Fix and polish all ra production structures; remove some obsoleted Production subclasses 2010-08-03 18:29:32 +12:00
Paul Chote
8e82f6fa1a Fix a retarded crash with husks; remove some debug 2010-08-03 01:16:24 +12:00
Paul Chote
053f0f5c7f Refactoring + cnc weap 2010-08-03 01:03:31 +12:00
Paul Chote
7c562059c2 Fix cnc afld 2010-08-03 00:17:11 +12:00
Paul Chote
cf5cb80c61 Restore cnc helicopters (reservable etc changes deferred) 2010-08-02 23:57:19 +12:00
Paul Chote
711378d352 Polish cnc pyle & hand inf production; lays groundwork for future polish. Likely breaks every other production structure (untested). 2010-08-02 23:35:35 +12:00
Paul Chote
7d044a9e1b Remove custom cnc behavior 2010-08-02 20:43:56 +12:00
Paul Chote
bc93e8cac0 Health as an ActorInit 2010-08-02 20:12:04 +12:00
alzeih
578d42614b Convert all CreateActor calls to use TypeDictionary 2010-08-02 01:51:13 +12:00
alzeih
4ea66ea309 Added FacingInit and AltitudeInit. Used in Mobile/Aircraft/Husks. Refactored Production, SpyPlane, Paratroopers and LeavesHusk 2010-08-02 00:49:26 +12:00
alzeih
2cc6e197fa fix makefile 2010-08-02 00:36:18 +12:00
Chris Forbes
2ea0907d66 convert ra maps to format3 2010-08-01 23:46:16 +12:00
Chris Forbes
d50d26350e upgrade caffeinated as a test. 2010-08-01 21:02:12 +12:00
Chris Forbes
b77bddddbc fix maploader to be backwards compatible. InitDict-based format is now 3. Formats 1,2 are translated on load, and will be saved back as Format 3 if saved in the editor. 2010-08-01 21:00:17 +12:00
Chris Forbes
3521319095 editor compiles again 2010-08-01 20:40:23 +12:00
Bob
dfc24233f7 fix broken rebase 2010-08-01 19:38:44 +12:00
Bob
970eb4d6e1 use the new actorinit stuff when loading map yaml 2010-08-01 19:38:42 +12:00
Bob
10b7ece62e new mapactor init stuff 2010-08-01 19:38:39 +12:00
Bob
f789aef892 map format change: move mapactor Type onto header line 2010-08-01 19:38:37 +12:00
Bob
bceaecf031 change map format to remove redundant crap 2010-08-01 19:38:35 +12:00
Bob
74155812d0 don't merge yaml in chrome; just load sequentially 2010-08-01 19:38:32 +12:00
Bob
f49ec8d6b9 don't mention rootwidget in chrome yaml 2010-08-01 19:38:30 +12:00
Chris Forbes
fd5d441086 fix all the broken maps 2010-08-01 18:46:46 +12:00
Chris Forbes
eb85189c24 transparently upgrade maps produced by buggy converter 2010-08-01 18:42:48 +12:00
Chris Forbes
9bd808fcb8 generate a neutral player 2010-08-01 18:38:38 +12:00
Chris Forbes
968387eab2 converted all the cnc maps 2010-08-01 18:28:45 +12:00
Chris Forbes
f8f1e2a531 add warning on window close with modified map 2010-08-01 18:12:03 +12:00
Chris Forbes
8707bbd569 remove standalone MapConverter 2010-08-01 18:03:03 +12:00
Chris Forbes
724df5ad54 add central-conflict and marooned-ii via new importer 2010-08-01 18:02:02 +12:00
Chris Forbes
0f33913bf6 force x86 on MapConverter project 2010-08-01 17:15:51 +12:00
Chris Forbes
d856eb5905 move bits around in MapConverter 2010-08-01 17:10:05 +12:00
Chris Forbes
ab9e7ce672 replace editor toolbar with menus 2010-08-01 16:59:19 +12:00
Chris Forbes
741e43ab14 disable vshost for editor; move tabs back to top edge 2010-08-01 16:19:35 +12:00
Chris Forbes
4b0f66496c blah 2010-08-01 16:11:47 +12:00
Chris Forbes
260fe70e5f remove 'Middle of Hell' map, it's garbage 2010-08-01 16:07:55 +12:00
Chris Forbes
ae3d7bbe24 disable vshost 2010-08-01 16:02:32 +12:00
Chris Forbes
990eeb844a ChooseAirfield chooses closest, rather than first. 2010-08-01 15:49:52 +12:00
Chris Forbes
4567bad251 make Activities.Land work with Targets. 2010-08-01 14:57:07 +12:00
Chris Forbes
aafbeed703 ffs, doing it the hard way as usual 2010-08-01 14:36:53 +12:00
Chris Forbes
002bc20d50 some improvement to alfd/plane interaction 2010-08-01 14:32:59 +12:00
Chris Forbes
19c5c56ab2 ra.ss, ra.msub, cnc.stnk all spawn cloaked/submerged 2010-08-01 14:07:15 +12:00
Chris Forbes
718b0e7613 fix mslo nuke offset 2010-08-01 13:03:53 +12:00
Chris Forbes
5b5378ae6c make tmpl capturable 2010-08-01 12:54:39 +12:00
Chris Forbes
67418e0b9d fix capturing of neutral buildings 2010-08-01 12:23:45 +12:00
Chris Forbes
ca986688a1 fix primary building & building fallback when busy 2010-08-01 12:11:48 +12:00
Chris Forbes
97e43cfe40 add ReservableProduction, to start fixing afld behavior. 2010-08-01 11:57:33 +12:00
Chris Forbes
a0ca52491e add some debug to Reservable so we can see what retardage is happening 2010-08-01 11:49:55 +12:00
Chris Forbes
039a42cfef fix spyplane (it doesnt want Mobile) 2010-08-01 11:49:23 +12:00
Chris Forbes
e2ab99c0cc remove dead crap from Plane 2010-08-01 11:49:00 +12:00
Chris Forbes
5daaa99108 start cleaning up reservations 2010-08-01 11:35:26 +12:00
Chris Forbes
13244d17f1 format and clean up DrawLineToTarget 2010-08-01 11:32:09 +12:00
Chris Forbes
e8604d172c add levelup crates to cnc 2010-08-01 11:17:27 +12:00
Chris Forbes
9e0f0d2074 fix cloaking crate 2010-08-01 10:40:26 +12:00
Chris Forbes
3dae071f41 drop aftermath support from the installer 2010-08-01 09:59:53 +12:00
Paul Chote
d5dbd1b7da Fix Monodevelop build 2010-08-01 01:48:12 +12:00
Chris Forbes
b1736e5efd fix VS build 2010-08-01 01:40:37 +12:00
Paul Chote
bd979f65b8 Kill Unit trait; Radar signature tweaks 2010-08-01 01:26:59 +12:00
Paul Chote
d416f0be5c Shift "XXX Lost" notification onto a trait. Hook up "Structure Lost" (cnc) and "Airborne Unit Lost" (ra). 2010-08-01 01:01:31 +12:00
Paul Chote
45e54e1ca8 Kill some spurious references to Unit 2010-08-01 01:01:31 +12:00
Paul Chote
d29e3f3f0e Split facing into its own interface; fix husks 2010-08-01 01:01:31 +12:00
Paul Chote
207ee49da3 Move Facing and Altitude onto IMove impls, with associated pile of cleanups 2010-08-01 01:01:31 +12:00
Paul Chote
88cb942430 Cleaner access to InitialFacing and ROT 2010-08-01 01:01:31 +12:00
Chris Forbes
765bedb592 add cloak crate action to cnc 2010-08-01 00:21:20 +12:00
Chris Forbes
2c73d8a48d remove some dead files 2010-07-31 23:37:56 +12:00
Chris Forbes
750275d08f reduce crap a little more 2010-07-31 23:24:32 +12:00
Chris Forbes
491d38cafe move Weapon & friends into own file 2010-07-31 23:21:22 +12:00
Chris Forbes
6c6da12dd6 fix local offset -> screen space transform to work as advertised 2010-07-31 23:01:56 +12:00
Chris Forbes
0b20d1366a eliminate old form of GetTurretPosition 2010-07-31 22:33:54 +12:00
Chris Forbes
fa245aaa08 introduce collection of Turrets on AttackBase, too -- turret sharing w/ recoil works again 2010-07-31 22:19:29 +12:00
Chris Forbes
9a218f7b52 GetPrimaryWeapon() dies too. 2010-07-31 21:34:24 +12:00
Chris Forbes
d202e27f79 more tesla hax? 2010-07-31 21:34:24 +12:00
Chris Forbes
960dddc048 AttackTesla hax 2010-07-31 21:34:23 +12:00
Chris Forbes
9fcc739cd5 more... Combat.GetSecondaryWeapon() dies, etc 2010-07-31 21:34:23 +12:00
Chris Forbes
449cc4a42d remove old buff crates 2010-07-31 21:34:22 +12:00
Chris Forbes
b8421ba655 move more combat bits around 2010-07-31 21:34:22 +12:00
Chris Forbes
2ac261c15b remove other param spam from CheckFire 2010-07-31 21:34:22 +12:00
Chris Forbes
2bd9cd32f6 remove WeaponInfo param from CheckFire 2010-07-31 21:34:21 +12:00
Chris Forbes
693c8d96b1 introduce a Barrel object, unhacking the local offsets. 2010-07-31 21:34:21 +12:00
Chris Forbes
42683f5966 start refactoring AttackBase 2010-07-31 21:34:20 +12:00
Chris Forbes
2478b26a05 GetOrDefault can die. 2010-07-31 12:41:11 +12:00
Chris Forbes
2608ab3bf6 fix crash on building ttnk 2010-07-31 12:23:09 +12:00
Chris Forbes
9fc8b81362 disable speed/armor/firepower crates in favour of levelup crate 2010-07-31 12:23:09 +12:00
Chris Forbes
5093d531bc tweak unit crate shares 2010-07-31 12:23:08 +12:00
Chris Forbes
08d75cb55c add GiveMcvCrateAction, and wire unit crates / mcv crates / etc 2010-07-31 12:23:08 +12:00
Chris Forbes
4c24547c26 add GiveUnitCrateAction 2010-07-31 12:23:07 +12:00
Bob
53b9b63ae5 change Mobile, Move to use Mobile.toCell instead of Actor.Location 2010-07-31 12:23:07 +12:00
Chris Forbes
cd40b27357 fix bitrot in cnc and ra 2010-07-31 12:23:06 +12:00
Chris Forbes
3c10d14f60 add shok 2010-07-31 09:27:13 +12:00
Chris Forbes
035bc96b37 various bits 2010-07-31 09:27:09 +12:00
Chris Forbes
357e74573c fix .gitignore, which banned .aud by default for some reason 2010-07-31 09:25:41 +12:00
Chris Forbes
668c5c7bdd add missing sounds 2010-07-31 09:25:41 +12:00
Chris Forbes
7a0d898b1a integrate ttnk into ra; also art for shok; all am pieces are now in ra/extras 2010-07-31 09:25:40 +12:00
alzeih
33b6f590e9 move ROT, InitialFacing and Speed to Mobile and Aircraft. 2010-07-31 02:06:30 +12:00
Paul Chote
dd7008d7ee Make crates collectable; make cnc walls targetable. 2010-07-31 01:50:14 +12:00
Paul Chote
9b051a6624 Remove some bs from buildings with multiple damage states; cnc civilian structure rubble persists after death. 2010-07-31 01:50:09 +12:00
Paul Chote
62c2c3a1c6 Fix damage transition sounds 2010-07-30 22:24:43 +12:00
Paul Chote
8528c5d3a3 Correct the ordering on DamageState 2010-07-30 22:24:43 +12:00
Paul Chote
4cf0610fd9 Change DamageState names 2010-07-30 22:24:43 +12:00
Paul Chote
1459ec483c Rename ExtendedDamageState -> DamageState 2010-07-30 22:24:43 +12:00
Paul Chote
028c5b5201 Merge the two DamageState types 2010-07-30 22:24:43 +12:00
Chris Forbes
41c0d175bd fix paradrop being broken (again!) 2010-07-30 21:20:13 +12:00
Paul Chote
9280dd9f2f Add some polish 2010-07-30 21:00:23 +12:00
Paul Chote
bde16e4e15 Remove a pile of duplication on mcv undeploy 2010-07-30 21:00:23 +12:00
Paul Chote
119f85dbf4 Unfail mcv deploy 2010-07-30 21:00:23 +12:00
Bob
ede160f1b6 move some more (gameplay related) widgets into mods/ 2010-07-30 20:55:03 +12:00
Bob
b4c84a11f2 changes to allow widgets to be in mods/; moved BuildPaletteWidget into mods/ 2010-07-30 20:15:14 +12:00
Bob
2dd558a065 move LastMousePosition et al from Widget to Viewport 2010-07-30 20:07:39 +12:00
Chris Forbes
3cd9a1e0e4 fix player color blocks not showing up in MapPreviewWidget 2010-07-30 18:54:46 +12:00
Chris Forbes
ef92e004c0 set the correct template on destroying long bridges 2010-07-30 18:48:59 +12:00
Chris Forbes
290a44440c cnc should run 'ralint cnc' after build, not 'ralint ra'. ralint no longer allows exceptions to escape. 2010-07-30 18:41:09 +12:00
Chris Forbes
5d1ee145e1 make (some) RALint errors nonfatal 2010-07-30 18:41:08 +12:00
Chris Forbes
aba9942a85 selling should not cause the building to explode first. 2010-07-30 18:39:21 +12:00
Chris Forbes
3aa2bab99f crate needs Unit. 2010-07-30 18:39:03 +12:00
Chris Forbes
d6b8b327d9 fix Bridge init 2010-07-30 18:24:12 +12:00
alzeih
e1a0d40530 RA Yaml changes 2010-07-30 18:14:00 +12:00
Paul Chote
48c5803198 Zombie prevention 2010-07-30 10:21:19 +12:00
Paul Chote
0580dc4adf Fix damaged-building artwork and don't show healthbar for dead units (cnc critical-building state) 2010-07-30 10:11:33 +12:00
Paul Chote
98ac5a036f Add an `Undamaged' damagestate to simplify things related to healing. 2010-07-30 01:22:41 +12:00
Paul Chote
87d2071007 Fix health bar colors. Todo: Merge DamageState & ExtendedDamageState 2010-07-30 00:46:00 +12:00
Paul Chote
bce9791b56 Fix building repair; Kill GlobalDefaults. 2010-07-30 00:41:55 +12:00
Paul Chote
6fba888d45 Shift Actor.Health onto a trait.
Known regressions:
 - cnc only
 - health bar colors
 - can't repair buildings
2010-07-30 00:33:44 +12:00
Chris Forbes
1e08dc6301 fix crate weirdness 2010-07-29 19:31:05 +12:00
Chris Forbes
2d4efc7942 crate should only choose water/land type on landing, not every tick. 2010-07-29 18:49:41 +12:00
Chris Forbes
bb0531b80f convert Crate to use crushable support again 2010-07-29 18:48:25 +12:00
Chris Forbes
e325b5954c split ITeleportable off as a base interface from IMove; Crate no longer pretends to be moveable. 2010-07-29 18:16:26 +12:00
Paul Chote
2be6cf35ac Add extra spawnpoints to "Middle Mayhem" 2010-07-28 23:23:39 +12:00
Paul Chote
7a4fa93ce9 Introduce a Targetable trait; Subs can attack bridges; May introduce subtle bugs due to previous stupid assumption that !selectable == !attackable. 2010-07-28 22:57:14 +12:00
Paul Chote
f9f6720437 Hook up Building.Capturable and remove unused field 2010-07-28 22:28:52 +12:00
Paul Chote
cfee4405c7 ra too 2010-07-28 22:26:30 +12:00
Paul Chote
eaa80fab74 Shift Sight onto its own trait. Only cnc for now. 2010-07-28 21:37:43 +12:00
Paul Chote
8fab45ae39 Move Cloak, HiddenUnderFog, FrozenUnderFog into Mods.RA; Simplify a pile of related stuff. 2010-07-28 21:11:50 +12:00
Paul Chote
6854d9853b Kill Crewed and move WaterBound onto building 2010-07-28 20:48:50 +12:00
Chris Forbes
5ca7218eb6 integrate scrollbar and checkbox art. fixes #215. 2010-07-28 18:16:47 +12:00
Chris Forbes
72d6a211af disable vshost 2010-07-28 11:26:46 +12:00
Paul Chote
f10e3a4d2d Always update player info on server join 2010-07-27 21:52:21 +12:00
Paul Chote
cfd0e045cb Add Edge Scroll setting 2010-07-27 21:28:40 +12:00
Chris Forbes
4386970bd3 add standalone PNGs for checkbox & scrollbar use 2010-07-27 21:19:17 +12:00
Paul Chote
c6f0b792d3 Do the right thing when stances change 2010-07-27 21:19:17 +12:00
Paul Chote
966f607230 Only show the diplomacy window if its useful 2010-07-27 21:19:17 +12:00
Paul Chote
9a704e69b2 Shift RevealsShroud onto Unit; fix "vehicles don't update shroud" regression in last 2010-07-27 21:19:16 +12:00
Paul Chote
a91ebb4eda Allies share sight 2010-07-27 11:34:28 +12:00
Paul Chote
9fe6671ace Fix retarded crash on server create; redirect server console spam into a logfile. 2010-07-27 10:48:37 +12:00
Paul Chote
386211df8c Update correct download size for deps-v2. 2010-07-26 22:40:25 +12:00
alzeih
ce513ed61a oops 2010-07-26 22:23:25 +12:00
alzeih
3f75e655ce Set Allow Cheats on server creation 2010-07-26 22:23:25 +12:00
alzeih
d9a423b596 Smite Indexdebug, tidy up dev mode 2010-07-26 22:23:24 +12:00
alzeih
30241ddccc Locate devmode code largely in the trait, reduce exploitability. 2010-07-26 22:23:24 +12:00
alzeih
10c7674433 Add to cnc, tidy up ingame menus 2010-07-26 22:23:24 +12:00
alzeih
c749fcfce3 Nearly There 2010-07-26 22:23:24 +12:00
alzeih
fe527c1297 Some of DeveloperMode trait (not working yet) 2010-07-26 22:23:24 +12:00
alzeih
3b72af2e9b AllowCheats 2010-07-26 22:23:24 +12:00
alzeih
2d916e60d9 Remove Developer Settings from Settings > Debug. Adjust Widget layout in DeveloperMode. In preparation for DeveloperMode trait. 2010-07-26 22:23:23 +12:00
Paul Chote
d8d731b321 Don't draw target line when idle 2010-07-26 22:18:40 +12:00
Chris Forbes
4cc021adfe fix dumb crash in minimap -- actors outside the map accessed memory that wasnt part of the bitmap. 2010-07-26 22:16:23 +12:00
Chris Forbes
56e929014d slightly faster again (map.IsInMap isnt free) -- but be careful 2010-07-26 21:42:11 +12:00
Chris Forbes
e0a5350ed6 slightly faster again 2010-07-26 21:39:23 +12:00
Chris Forbes
d774817b0e remaining dumbness removed. 2010-07-26 21:35:00 +12:00
Chris Forbes
3526c05dc8 a bit more 2010-07-26 21:30:23 +12:00
Chris Forbes
69a74425d9 a free 40% or so. 2010-07-26 21:23:19 +12:00
Paul Chote
eb1e325fe2 More caching 2010-07-26 20:44:47 +12:00
Paul Chote
ffa0c16ab9 Ignore opendiff files 2010-07-26 20:36:48 +12:00
Paul Chote
30f16e1a7a Fix cnc 2010-07-26 20:36:48 +12:00
Chris Forbes
0d0353f8f3 a little faster -- don't look up the Mobile every expand either. 2010-07-26 20:33:42 +12:00
Paul Chote
637fae87cd Remove a bunch of unused stuff. May help pathfinder perf a little. 2010-07-26 20:27:56 +12:00
Paul Chote
c39116df84 DefaultInputController -> WorldInteractionController; Tooltip tweaks. 2010-07-26 20:14:36 +12:00
Paul Chote
dcef8770a7 Edge scrolling 2010-07-26 20:14:36 +12:00
Paul Chote
816722256b Split viewport scrolling into its own widget 2010-07-26 20:14:36 +12:00
Chris Forbes
2b890bdb2f make backspace 'cycle bases' binding more obvious. not all of us know the whole character set, or care to. 2010-07-26 20:14:36 +12:00
Chris Forbes
882d94a22a DefaultInputControllerWidget should not ever consume input it doesnt want 2010-07-26 20:14:36 +12:00
Paul Chote
43a488ed6d Rebase fixes 2010-07-26 20:14:35 +12:00
Paul Chote
305fa03355 Kill Controller 2010-07-26 20:14:35 +12:00
Paul Chote
e677be7908 Remove more cruft from Game.controller 2010-07-26 20:14:35 +12:00
Paul Chote
eac49ca641 Refactor existing hodgepodge of hardcoded mouse/keyboard events into DefaultInputController. 2010-07-26 20:14:35 +12:00
Paul Chote
2248320af7 Move Game.Controller.HandleInput into a widget; works but is hacky 2010-07-26 20:14:35 +12:00
Chris Forbes
f61421edd0 gain ~20% faster pathing perf 2010-07-26 19:14:54 +12:00
Chris Forbes
9bb5e49058 draw building grid under actors too 2010-07-26 18:32:29 +12:00
Chris Forbes
16c9f2b873 render range circle and detection circle under actors 2010-07-26 18:27:02 +12:00
Chris Forbes
69d30ac71b RenderBeforeWorld/RenderAfterWorld split. still need to sort out which behavior belongs where. 2010-07-26 18:19:39 +12:00
Chris Forbes
9cf8ac0c3d remove dead IVictoryConditions interface 2010-07-26 18:07:48 +12:00
Chris Forbes
f1a5998049 remove dead ChooseFreePalette crap 2010-07-26 17:54:18 +12:00
Chris Forbes
41b76144da force the socket closed so the client thread will die pretty fast. dirty hack, but teh read timeout is nuts otherwise. 2010-07-26 17:49:08 +12:00
Chris Forbes
e30e97037f squash warning 2010-07-26 17:40:36 +12:00
Chris Forbes
102f1dd858 blah 2010-07-26 17:33:56 +12:00
alzeih
925ca2bb73 SetTargetSilently for DrawLineToTarget 2010-07-26 13:57:53 +12:00
alzeih
526bb3e042 Use Targets 2010-07-26 12:33:54 +12:00
Paul Chote
e8adc357e9 Draw targeting lines for player-issued orders. Can force-display targets with [alt]. 2010-07-26 12:01:13 +12:00
alzeih
130b4d29b4 Move SelectedUnit drawing stuff out of WorldRenderer into Selectable with IRenderSelection 2010-07-26 02:25:52 +12:00
alzeih
5f357288ee layout tidyup - start game now forces game start, ready checkboxes behave as before. 2010-07-25 22:16:21 +12:00
alzeih
26b5fbe9bb startgame order and lobby changes 2010-07-25 21:31:17 +12:00
Paul Chote
4650642311 Keep selection on mcv deploy/undeploy. Bonus: build tab opens on mcv deploy 2010-07-25 20:02:23 +12:00
Chris Forbes
e850cb7ff8 assign a palette to the cursor for basemod 2010-07-25 16:36:29 +12:00
alzeih
9fcb0577a5 default mod (pchote: squashed + amended) 2010-07-25 16:10:35 +12:00
Chris Forbes
df7dad8aaa add ra_perf mod, which exposes the performance test maps 2010-07-25 15:57:54 +12:00
Chris Forbes
3080e19bf2 add visualization of minefields when MNLY is selected 2010-07-25 15:56:40 +12:00
Chris Forbes
f2bfa8e2ee reinstate range circles; IRenderSelection allows arb. plugging in of these things 2010-07-25 15:56:40 +12:00
alzeih
2254e48f65 little bit better threading [pchote: picked/amended] 2010-07-25 15:56:40 +12:00
Chris Forbes
443f2bb6b9 fix msbuild project files. thanks, monodevelop: what was there worked JUST FINE 2010-07-25 15:52:09 +12:00
Paul Chote
c82cc7b301 Update osx packaging script for WindowsBase.dll and mono 2.6.7 2010-07-25 15:34:13 +12:00
Paul Chote
63951ac134 Run ralint after building 2010-07-25 15:11:08 +12:00
Paul Chote
301007e225 Fix compile errors/warnings 2010-07-25 15:02:01 +12:00
Paul Chote
5776d351b4 Fix Monodevelop build; remove Aftermath project. 2010-07-25 14:55:44 +12:00
alzeih
484bea106b OpenRA works nicely with monodevelop 2010-07-24 16:19:54 +12:00
alzeih
4fd5d9e0c3 Cloak Changes: appear semitransparent to localplayer, not at all to others. Same for mines.
( Also fix compile warning in LimitedAmmo )
2010-07-24 15:17:29 +12:00
Chris Forbes
5375692f1f remove spam on planes doing stuff 2010-07-24 00:09:54 +12:00
Paul Chote
20c0419782 Don't leak information on the underlying terrain via the mouse cursor. Cursor and voice response always "move" for terrain under shroud.
Needs pathfinder changes before being mergeable
2010-07-23 22:53:38 +12:00
Paul Chote
c74fe87fc8 Fix voice on unpathable terrain 2010-07-23 22:45:11 +12:00
Paul Chote
d5c43c9fda Remove unused code 2010-07-23 22:44:59 +12:00
Paul Chote
5344e60e3d Forgot a file 2010-07-23 22:44:48 +12:00
521 changed files with 19642 additions and 10081 deletions

7
.gitignore vendored
View File

@@ -11,7 +11,6 @@ mods/*/*.dll
# Red Alert binary files
*.[mM][iI][xX]
*.[aA][uU][dD]
# Crap generated by OpenRa
sheet-*.png
@@ -23,12 +22,14 @@ log.txt
/*.dll
*.pdb
*.mdb
/*.exe
*.exe
OpenRA
OpenRA.app
*.vqa
# backup files by various editors
*~
*.orig
# dependency DLLs (different for every platform!)
cg.dll
cgGL.dll
@@ -53,4 +54,4 @@ temp.o
temp.s
*.config
*.resources
*.resources

View File

@@ -1,7 +1,7 @@
CSC = gmcs
CSFLAGS = -nologo -warn:4 -debug:+ -debug:full -optimize- -codepage:utf8 -unsafe
DEFINE = DEBUG;TRACE
PROGRAMS =fileformats gl game ra cnc aftermath seqed mapcvtr editor ralint filex tsbuild
PROGRAMS =fileformats gl game ra cnc seqed editor ralint filex tsbuild
prefix = /usr/local
datarootdir = $(prefix)/share
datadir = $(datarootdir)
@@ -16,7 +16,7 @@ COMMON_LIBS = System.dll System.Core.dll System.Drawing.dll System.Xml.dll
fileformats_SRCS = $(shell find OpenRA.FileFormats/ -iname '*.cs')
fileformats_TARGET = OpenRA.FileFormats.dll
fileformats_KIND = library
fileformats_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Sdl.dll WindowsBase.dll
fileformats_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Sdl.dll thirdparty/WindowsBase.dll
gl_SRCS = $(shell find OpenRA.Gl/ -iname '*.cs')
gl_TARGET = OpenRA.Gl.dll
@@ -46,12 +46,6 @@ cnc_KIND = library
cnc_DEPS = $(fileformats_TARGET) $(game_TARGET) $(ra_TARGET)
cnc_LIBS = $(COMMON_LIBS) $(cnc_DEPS)
aftermath_SRCS = $(shell find OpenRA.Mods.Aftermath/ -iname '*.cs')
aftermath_TARGET = mods/aftermath/OpenRA.Mods.Aftermath.dll
aftermath_KIND = library
aftermath_DEPS = $(fileformats_TARGET) $(game_TARGET) $(ra_TARGET)
aftermath_LIBS = $(COMMON_LIBS) $(aftermath_DEPS)
seqed_SRCS = $(shell find SequenceEditor/ -iname '*.cs')
seqed_TARGET = SequenceEditor.exe
seqed_KIND = winexe
@@ -66,12 +60,6 @@ editor_DEPS = $(fileformats_TARGET) $(game_TARGET)
editor_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll System.Data.dll $(editor_DEPS)
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources
mapcvtr_SRCS = $(shell find MapConverter/ -iname '*.cs')
mapcvtr_TARGET = MapConverter.exe
mapcvtr_KIND = winexe
mapcvtr_DEPS = $(fileformats_TARGET) $(game_TARGET)
mapcvtr_LIBS = $(COMMON_LIBS) $(mapcvtr_DEPS)
ralint_SRCS = $(shell find RALint/ -iname '*.cs')
ralint_TARGET = RALint.exe
ralint_KIND = winexe
@@ -94,45 +82,43 @@ tsbuild_EXTRA = -resource:OpenRA.TilesetBuilder.Form1.resources
# -platform:x86
.SUFFIXES:
.PHONY: clean all game tool default mods mod_ra mod_aftermath mod_cnc install uninstall editor_res editor tsbuild ralint seqed mapcvtr filex
.PHONY: clean all game tool default mods mod_ra mod_cnc install uninstall editor_res editor tsbuild ralint seqed filex
game: $(fileformats_TARGET) $(gl_TARGET) $(game_TARGET) $(ra_TARGET) $(cnc_TARGET) $(aftermath_TARGET)
game: $(fileformats_TARGET) $(gl_TARGET) $(game_TARGET) $(ra_TARGET) $(cnc_TARGET)
clean:
@-rm *.exe *.dll *.mdb mods/**/*.dll mods/**/*.mdb *.resources
distclean: clean
CORE = fileformats gl game seqed mapcvtr
CORE = fileformats gl game seqed
install: all
@-echo "Installing OpenRA to $(INSTALL_DIR)"
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)
@$(INSTALL_PROGRAM) $(foreach prog,$(CORE),$($(prog)_TARGET)) $(INSTALL_DIR)
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/aftermath
@$(INSTALL_PROGRAM) $(aftermath_TARGET) $(INSTALL_DIR)/mods/aftermath
@-cp $(foreach f,$(shell ls mods/aftermath --hide=*.dll),mods/aftermath/$(f)) $(INSTALL_DIR)/mods/aftermath
@cp -r mods/aftermath/packages $(INSTALL_DIR)/mods/aftermath
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/cnc
@$(INSTALL_PROGRAM) $(cnc_TARGET) $(INSTALL_DIR)/mods/cnc
@-cp $(foreach f,$(shell ls mods/cnc --hide=*.dll),mods/cnc/$(f)) $(INSTALL_DIR)/mods/cnc
@cp -r mods/cnc/maps $(INSTALL_DIR)/mods/cnc
@cp -r mods/cnc/chrome $(INSTALL_DIR)/mods/cnc
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/ra
@$(INSTALL_PROGRAM) $(ra_TARGET) $(INSTALL_DIR)/mods/ra
@-cp $(foreach f,$(shell ls mods/ra --hide=*.dll),mods/ra/$(f)) $(INSTALL_DIR)/mods/ra
@cp -r mods/ra/maps $(INSTALL_DIR)/mods/ra
@cp -r mods/ra/extras $(INSTALL_DIR)/mods/ra
@cp -r mods/ra/chrome $(INSTALL_DIR)/mods/ra
@cp -r shaders $(INSTALL_DIR)
@cp *.ttf $(INSTALL_DIR)
@-cp *.ini $(INSTALL_DIR)
@cp -r thirdparty $(INSTALL_DIR)
@cp --parents -r thirdparty/Tao $(INSTALL_DIR)
@$(INSTALL_PROGRAM) thirdparty/WindowsBase.dll $(INSTALL_DIR)
@echo "#!/bin/sh" > openra
@echo "cd "$(datadir)"/openra" >> openra
@echo "mono "$(datadir)"/openra/OpenRA.Game.exe" >> openra
@echo "mono "$(datadir)"/openra/OpenRA.Game.exe SupportDir=~/.openra \"$$""@\"" >> openra
@$(INSTALL_PROGRAM) -d $(BIN_INSTALL_DIR)
@$(INSTALL_PROGRAM) -m +rx openra $(BIN_INSTALL_DIR)
@@ -151,8 +137,6 @@ uninstall:
mod_ra: $(ra_TARGET) $(ralint_TARGET)
mono RALint.exe ra
mod_aftermath: $(aftermath_TARGET) $(ralint_TARGET)
mono RALint.exe ra aftermath
mod_cnc: $(cnc_TARGET) $(ralint_TARGET)
mono RALint.exe cnc
mods: mod_ra mod_cnc
@@ -164,12 +148,11 @@ ralint: $(ralint_TARGET)
seqed: SequenceEditor.Form1.resources $(seqed_TARGET)
SequenceEditor.Form1.resources:
resgen2 SequenceEditor/Form1.resx SequenceEditor.Form1.resources 1> /dev/null
mapcvtr: $(mapcvtr_TARGET)
filex: $(filex_TARGET)
tsbuild: OpenRA.TilesetBuilder.Form1.resources $(tsbuild_TARGET)
OpenRA.TilesetBuilder.Form1.resources:
resgen2 OpenRA.TilesetBuilder/Form1.resx OpenRA.TilesetBuilder.Form1.resources 1> /dev/null
tools: editor ralint seqed mapcvtr filex tsbuild
tools: editor ralint seqed filex tsbuild
all: game tools
define BUILD_ASSEMBLY

View File

@@ -1,51 +0,0 @@
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{BA2B4C61-D5EE-4C3E-9BA1-EB32C531FA36}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>MapConverter</RootNamespace>
<AssemblyName>MapConverter</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="MapConverter.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
<Project>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</Project>
<Name>OpenRA.FileFormats</Name>
</ProjectReference>
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">
<Project>{0DFB103F-2962-400F-8C6D-E2C28CCBA633}</Project>
<Name>OpenRA.Game</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@@ -39,14 +39,24 @@
this.actorPalette = new System.Windows.Forms.FlowLayoutPanel();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.resourcePalette = new System.Windows.Forms.FlowLayoutPanel();
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.toolStripButton3 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton5 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton4 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton1 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton6 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton7 = new System.Windows.Forms.ToolStripButton();
this.toolStripButton2 = new System.Windows.Forms.ToolStripButton();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.newToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.cCRedAlertMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.bitmapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
this.exotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.propertiesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.resizeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator();
this.spawnpointsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.tt = new System.Windows.Forms.ToolTip(this.components);
this.folderBrowser = new System.Windows.Forms.FolderBrowserDialog();
this.surface1 = new OpenRA.Editor.Surface();
@@ -60,7 +70,7 @@
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.tabPage3.SuspendLayout();
this.toolStrip1.SuspendLayout();
this.menuStrip1.SuspendLayout();
this.SuspendLayout();
//
// toolStripContainer1
@@ -69,7 +79,7 @@
// toolStripContainer1.ContentPanel
//
this.toolStripContainer1.ContentPanel.Controls.Add(this.splitContainer1);
this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(985, 680);
this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(985, 681);
this.toolStripContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.toolStripContainer1.Location = new System.Drawing.Point(0, 0);
this.toolStripContainer1.Name = "toolStripContainer1";
@@ -79,7 +89,7 @@
//
// toolStripContainer1.TopToolStripPanel
//
this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.toolStrip1);
this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.menuStrip1);
//
// splitContainer1
//
@@ -94,13 +104,12 @@
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.surface1);
this.splitContainer1.Size = new System.Drawing.Size(985, 680);
this.splitContainer1.Size = new System.Drawing.Size(985, 681);
this.splitContainer1.SplitterDistance = 198;
this.splitContainer1.TabIndex = 0;
//
// tabControl1
//
this.tabControl1.Alignment = System.Windows.Forms.TabAlignment.Left;
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Controls.Add(this.tabPage3);
@@ -109,16 +118,16 @@
this.tabControl1.Multiline = true;
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(198, 680);
this.tabControl1.Size = new System.Drawing.Size(198, 681);
this.tabControl1.TabIndex = 0;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.tilePalette);
this.tabPage1.Location = new System.Drawing.Point(23, 4);
this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(171, 672);
this.tabPage1.Size = new System.Drawing.Size(190, 655);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Templates";
this.tabPage1.UseVisualStyleBackColor = true;
@@ -130,16 +139,16 @@
this.tilePalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.tilePalette.Location = new System.Drawing.Point(3, 3);
this.tilePalette.Name = "tilePalette";
this.tilePalette.Size = new System.Drawing.Size(165, 666);
this.tilePalette.Size = new System.Drawing.Size(184, 649);
this.tilePalette.TabIndex = 1;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.actorPalette);
this.tabPage2.Location = new System.Drawing.Point(23, 4);
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(171, 672);
this.tabPage2.Size = new System.Drawing.Size(190, 655);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Actors";
this.tabPage2.UseVisualStyleBackColor = true;
@@ -151,15 +160,15 @@
this.actorPalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.actorPalette.Location = new System.Drawing.Point(3, 3);
this.actorPalette.Name = "actorPalette";
this.actorPalette.Size = new System.Drawing.Size(165, 666);
this.actorPalette.Size = new System.Drawing.Size(184, 649);
this.actorPalette.TabIndex = 2;
//
// tabPage3
//
this.tabPage3.Controls.Add(this.resourcePalette);
this.tabPage3.Location = new System.Drawing.Point(23, 4);
this.tabPage3.Location = new System.Drawing.Point(4, 22);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(171, 672);
this.tabPage3.Size = new System.Drawing.Size(190, 655);
this.tabPage3.TabIndex = 2;
this.tabPage3.Text = "Resources";
this.tabPage3.UseVisualStyleBackColor = true;
@@ -171,87 +180,154 @@
this.resourcePalette.Dock = System.Windows.Forms.DockStyle.Fill;
this.resourcePalette.Location = new System.Drawing.Point(0, 0);
this.resourcePalette.Name = "resourcePalette";
this.resourcePalette.Size = new System.Drawing.Size(171, 672);
this.resourcePalette.Size = new System.Drawing.Size(190, 655);
this.resourcePalette.TabIndex = 3;
//
// toolStrip1
// menuStrip1
//
this.toolStrip1.Dock = System.Windows.Forms.DockStyle.None;
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripButton3,
this.toolStripButton5,
this.toolStripButton4,
this.toolStripButton1,
this.toolStripButton6,
this.toolStripButton7,
this.toolStripButton2});
this.toolStrip1.Location = new System.Drawing.Point(3, 0);
this.toolStrip1.Name = "toolStrip1";
this.toolStrip1.Size = new System.Drawing.Size(480, 25);
this.toolStrip1.TabIndex = 0;
this.menuStrip1.Dock = System.Windows.Forms.DockStyle.None;
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.fileToolStripMenuItem,
this.mapToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(985, 24);
this.menuStrip1.TabIndex = 1;
this.menuStrip1.Text = "menuStrip1";
//
// toolStripButton3
// fileToolStripMenuItem
//
this.toolStripButton3.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton3.Image")));
this.toolStripButton3.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton3.Name = "toolStripButton3";
this.toolStripButton3.Size = new System.Drawing.Size(51, 22);
this.toolStripButton3.Text = "New";
this.toolStripButton3.Click += new System.EventHandler(this.NewClicked);
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.newToolStripMenuItem,
this.toolStripSeparator1,
this.openToolStripMenuItem,
this.saveToolStripMenuItem,
this.saveAsToolStripMenuItem,
this.toolStripSeparator2,
this.toolStripMenuItem1,
this.toolStripSeparator3,
this.exotToolStripMenuItem});
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
this.fileToolStripMenuItem.Text = "&File";
//
// toolStripButton5
// newToolStripMenuItem
//
this.toolStripButton5.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton5.Image")));
this.toolStripButton5.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton5.Name = "toolStripButton5";
this.toolStripButton5.Size = new System.Drawing.Size(56, 22);
this.toolStripButton5.Text = "Open";
this.toolStripButton5.Click += new System.EventHandler(this.OpenClicked);
this.newToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("newToolStripMenuItem.Image")));
this.newToolStripMenuItem.ImageTransparentColor = System.Drawing.Color.Fuchsia;
this.newToolStripMenuItem.Name = "newToolStripMenuItem";
this.newToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.newToolStripMenuItem.Text = "&New...";
this.newToolStripMenuItem.Click += new System.EventHandler(this.NewClicked);
//
// toolStripButton4
// toolStripSeparator1
//
this.toolStripButton4.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton4.Image")));
this.toolStripButton4.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton4.Name = "toolStripButton4";
this.toolStripButton4.Size = new System.Drawing.Size(51, 22);
this.toolStripButton4.Text = "Save";
this.toolStripButton4.Click += new System.EventHandler(this.SaveClicked);
this.toolStripSeparator1.Name = "toolStripSeparator1";
this.toolStripSeparator1.Size = new System.Drawing.Size(149, 6);
//
// toolStripButton1
// openToolStripMenuItem
//
this.toolStripButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton1.Image")));
this.toolStripButton1.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton1.Name = "toolStripButton1";
this.toolStripButton1.Size = new System.Drawing.Size(76, 22);
this.toolStripButton1.Text = "Save As...";
this.toolStripButton1.Click += new System.EventHandler(this.SaveAsClicked);
this.openToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("openToolStripMenuItem.Image")));
this.openToolStripMenuItem.Name = "openToolStripMenuItem";
this.openToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.openToolStripMenuItem.Text = "&Open...";
this.openToolStripMenuItem.Click += new System.EventHandler(this.OpenClicked);
//
// toolStripButton6
// saveToolStripMenuItem
//
this.toolStripButton6.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton6.Image")));
this.toolStripButton6.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton6.Name = "toolStripButton6";
this.toolStripButton6.Size = new System.Drawing.Size(59, 22);
this.toolStripButton6.Text = "Resize";
this.toolStripButton6.Click += new System.EventHandler(this.ResizeClicked);
this.saveToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image")));
this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
this.saveToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.saveToolStripMenuItem.Text = "&Save";
this.saveToolStripMenuItem.Click += new System.EventHandler(this.SaveClicked);
//
// toolStripButton7
// saveAsToolStripMenuItem
//
this.toolStripButton7.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton7.Image")));
this.toolStripButton7.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton7.Name = "toolStripButton7";
this.toolStripButton7.Size = new System.Drawing.Size(80, 22);
this.toolStripButton7.Text = "Properties";
this.toolStripButton7.Click += new System.EventHandler(this.PropertiesClicked);
this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.saveAsToolStripMenuItem.Text = "Save &As...";
this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.SaveAsClicked);
//
// toolStripButton2
// toolStripSeparator2
//
this.toolStripButton2.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton2.Image")));
this.toolStripButton2.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripButton2.Name = "toolStripButton2";
this.toolStripButton2.Size = new System.Drawing.Size(95, 22);
this.toolStripButton2.Text = "Spawnpoints";
this.toolStripButton2.Click += new System.EventHandler(this.SpawnPointsClicked);
this.toolStripSeparator2.Name = "toolStripSeparator2";
this.toolStripSeparator2.Size = new System.Drawing.Size(149, 6);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.cCRedAlertMapToolStripMenuItem,
this.bitmapToolStripMenuItem});
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(152, 22);
this.toolStripMenuItem1.Text = "&Import";
//
// cCRedAlertMapToolStripMenuItem
//
this.cCRedAlertMapToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("cCRedAlertMapToolStripMenuItem.Image")));
this.cCRedAlertMapToolStripMenuItem.Name = "cCRedAlertMapToolStripMenuItem";
this.cCRedAlertMapToolStripMenuItem.Size = new System.Drawing.Size(195, 22);
this.cCRedAlertMapToolStripMenuItem.Text = "&C&&C / Red Alert Map...";
this.cCRedAlertMapToolStripMenuItem.Click += new System.EventHandler(this.ImportLegacyMapClicked);
//
// bitmapToolStripMenuItem
//
this.bitmapToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("bitmapToolStripMenuItem.Image")));
this.bitmapToolStripMenuItem.Name = "bitmapToolStripMenuItem";
this.bitmapToolStripMenuItem.Size = new System.Drawing.Size(195, 22);
this.bitmapToolStripMenuItem.Text = "&Bitmap...";
//
// toolStripSeparator3
//
this.toolStripSeparator3.Name = "toolStripSeparator3";
this.toolStripSeparator3.Size = new System.Drawing.Size(149, 6);
//
// exotToolStripMenuItem
//
this.exotToolStripMenuItem.Name = "exotToolStripMenuItem";
this.exotToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.exotToolStripMenuItem.Text = "E&xit";
this.exotToolStripMenuItem.Click += new System.EventHandler(this.CloseClicked);
//
// mapToolStripMenuItem
//
this.mapToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.propertiesToolStripMenuItem,
this.resizeToolStripMenuItem,
this.toolStripSeparator4,
this.spawnpointsToolStripMenuItem});
this.mapToolStripMenuItem.Name = "mapToolStripMenuItem";
this.mapToolStripMenuItem.Size = new System.Drawing.Size(43, 20);
this.mapToolStripMenuItem.Text = "&Map";
//
// propertiesToolStripMenuItem
//
this.propertiesToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("propertiesToolStripMenuItem.Image")));
this.propertiesToolStripMenuItem.Name = "propertiesToolStripMenuItem";
this.propertiesToolStripMenuItem.Size = new System.Drawing.Size(142, 22);
this.propertiesToolStripMenuItem.Text = "&Properties...";
this.propertiesToolStripMenuItem.Click += new System.EventHandler(this.PropertiesClicked);
//
// resizeToolStripMenuItem
//
this.resizeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("resizeToolStripMenuItem.Image")));
this.resizeToolStripMenuItem.Name = "resizeToolStripMenuItem";
this.resizeToolStripMenuItem.Size = new System.Drawing.Size(142, 22);
this.resizeToolStripMenuItem.Text = "&Resize...";
this.resizeToolStripMenuItem.Click += new System.EventHandler(this.ResizeClicked);
//
// toolStripSeparator4
//
this.toolStripSeparator4.Name = "toolStripSeparator4";
this.toolStripSeparator4.Size = new System.Drawing.Size(139, 6);
//
// spawnpointsToolStripMenuItem
//
this.spawnpointsToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("spawnpointsToolStripMenuItem.Image")));
this.spawnpointsToolStripMenuItem.Name = "spawnpointsToolStripMenuItem";
this.spawnpointsToolStripMenuItem.Size = new System.Drawing.Size(142, 22);
this.spawnpointsToolStripMenuItem.Text = "&Spawnpoints";
this.spawnpointsToolStripMenuItem.Click += new System.EventHandler(this.SpawnPointsClicked);
//
// tt
//
@@ -263,7 +339,7 @@
this.surface1.Dock = System.Windows.Forms.DockStyle.Fill;
this.surface1.Location = new System.Drawing.Point(0, 0);
this.surface1.Name = "surface1";
this.surface1.Size = new System.Drawing.Size(783, 680);
this.surface1.Size = new System.Drawing.Size(783, 681);
this.surface1.TabIndex = 5;
this.surface1.Text = "surface1";
//
@@ -274,9 +350,11 @@
this.ClientSize = new System.Drawing.Size(985, 705);
this.Controls.Add(this.toolStripContainer1);
this.KeyPreview = true;
this.MainMenuStrip = this.menuStrip1;
this.Name = "Form1";
this.Text = "OpenRA Editor";
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OnFormClosing);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.toolStripContainer1.ContentPanel.ResumeLayout(false);
this.toolStripContainer1.TopToolStripPanel.ResumeLayout(false);
@@ -290,8 +368,8 @@
this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.ResumeLayout(false);
}
@@ -301,23 +379,33 @@
private System.Windows.Forms.ToolStripContainer toolStripContainer1;
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.ToolTip tt;
private System.Windows.Forms.ToolStrip toolStrip1;
private System.Windows.Forms.ToolStripButton toolStripButton1;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.FlowLayoutPanel tilePalette;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.ToolStripButton toolStripButton2;
private System.Windows.Forms.FlowLayoutPanel actorPalette;
private System.Windows.Forms.TabPage tabPage3;
private System.Windows.Forms.FlowLayoutPanel resourcePalette;
private System.Windows.Forms.ToolStripButton toolStripButton3;
private System.Windows.Forms.ToolStripButton toolStripButton5;
private System.Windows.Forms.ToolStripButton toolStripButton4;
private System.Windows.Forms.FolderBrowserDialog folderBrowser;
private System.Windows.Forms.ToolStripButton toolStripButton6;
private System.Windows.Forms.ToolStripButton toolStripButton7;
private Surface surface1;
private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem newToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem saveAsToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
private System.Windows.Forms.ToolStripMenuItem exotToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1;
private System.Windows.Forms.ToolStripMenuItem cCRedAlertMapToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem bitmapToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator3;
private System.Windows.Forms.ToolStripMenuItem mapToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem propertiesToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem resizeToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator4;
private System.Windows.Forms.ToolStripMenuItem spawnpointsToolStripMenuItem;
}
}

View File

@@ -43,11 +43,16 @@ namespace OpenRA.Editor
folderBrowser.SelectedPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
.Aggregate(Path.Combine);
surface1.AfterChange += MakeDirty;
}
void MakeDirty() { dirty = true; }
string loadedMapName;
string currentMod = "ra";
TileSet tileset;
bool dirty = false;
void LoadMap(string mapname)
{
@@ -67,7 +72,15 @@ namespace OpenRA.Editor
// load the map
var map = new Map(new Folder(mapname));
// upgrade maps that have no player definitions. editor doesnt care,
// but this breaks the game pretty badly.
if (map.Players.Count == 0)
map.Players.Add("Neutral", new PlayerReference("Neutral",
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
PrepareMapResources(manifest, map);
dirty = false;
}
void NewMap(Map map)
@@ -86,6 +99,8 @@ namespace OpenRA.Editor
foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg);
PrepareMapResources(manifest, map);
MakeDirty();
}
void PrepareMapResources(Manifest manifest, Map map)
@@ -137,6 +152,7 @@ namespace OpenRA.Editor
try
{
var info = Rules.Info[a];
if( !info.Traits.Contains<RenderSimpleInfo>() ) continue;
var template = RenderActor(info, tileset, palette);
var ibox = new PictureBox
{
@@ -328,6 +344,8 @@ namespace OpenRA.Editor
surface1.Map.PlayerCount = surface1.Map.Waypoints.Count;
surface1.Map.Package = new Folder(loadedMapName);
surface1.Map.Save(loadedMapName);
dirty = false;
}
}
@@ -337,7 +355,6 @@ namespace OpenRA.Editor
if (DialogResult.OK == folderBrowser.ShowDialog())
{
loadedMapName = folderBrowser.SelectedPath;
SaveClicked(sender, e);
}
@@ -396,5 +413,48 @@ namespace OpenRA.Editor
void SpawnPointsClicked(object sender, EventArgs e) { surface1.SetWaypoint(new WaypointTemplate()); }
void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = true; }
void Form1_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = false; }
void CloseClicked(object sender, EventArgs e)
{
Close();
}
void ImportLegacyMapClicked(object sender, EventArgs e)
{
using (var ofd = new OpenFileDialog { Filter = "Legacy maps (*.ini;*.mpr)|*.ini;*.mpr" })
if (DialogResult.OK == ofd.ShowDialog())
{
/* 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 */
var savePath = Path.Combine(Path.GetTempPath(), "OpenRA.Import");
Directory.CreateDirectory(savePath);
var map = LegacyMapImporter.Import(ofd.FileName);
map.Package = new Folder(savePath);
map.Players.Add("Neutral", new PlayerReference("Neutral",
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
map.Save(savePath);
LoadMap(savePath);
loadedMapName = null; /* editor needs to think this hasnt been saved */
Directory.Delete(savePath, true);
MakeDirty();
}
}
void OnFormClosing(object sender, FormClosingEventArgs e)
{
if (!dirty) return;
switch (MessageBox.Show("The map has been modified since it was last saved. Save changes now?",
"Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation))
{
case DialogResult.Yes: SaveClicked(null, EventArgs.Empty); break;
case DialogResult.No: break;
case DialogResult.Cancel: e.Cancel = true; break;
}
}
}
}

View File

@@ -117,113 +117,175 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>77, 17</value>
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>309, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="toolStripButton3.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="newToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHNSURBVDhPjZNdTxNREIb5LV54azSRxJ8gt95445XGa/8A
CU0MMVgIWNmgRSioGN0AapQaISAWrEaITQTkQyhL2WbbWtt1+7ll+7h7SDdBocskk3Mm58xzZt7JaWmx
bTdyk9/rPsz0fbYmz2JqfvSdHhJLPpxzTzMUid13F0D3k/h41V57iU+dI7/dfTqA8zKGBLUohjpurxER
7/24i/RkSnj/47csLsWOB27IZ1DmrlDQJrHIU8q8EbE63UrD7oVe09p243iIqEAPQGVOQJxKRJwfdgE9
gxO8X1wRkIWv/1Ri7A0QD5/HSrWT/HTNTgwIDapayAV0DTwXyQ0/IqwSvXU4hWQn6uwl4usPKCl9pGI+
F2DV6zwaX2BQjgjIiZPpHXrpJjU2di7lao2sXmLiwwYXL18/GeB/KP8HqJgH5Iwy++k/yDOrzQF3+p8d
AZi1A/RCleQvg81ElrHwt+aA232jLqBmWRjFKlq2wM/9HLGtFCOvPjcHdHQPCYBl1SmWTdK5IvFknu/b
GaIrKsEX880B7V1B6rZq5cqhaIqms7aT4cuqyuyygvR0xhvgiOao7Qjm9Byyyw7K80hj0wRGw94tOGPy
cs8fetoLfwGP5fd9L1vD4gAAAABJRU5ErkJggg==
</value>
</data>
<data name="toolStripButton5.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="openToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAACeklE
QVQ4T6WTWUiUURiG/4suurJIjUIwskQsEANDqosQpUVNKbdCSRPKrQVDMddmXEedGdcpFXNGnUYdrSzF
sEIoFInQcqHE1CwoKsXUUMnt6Z+RLMtA8OK5OZz3Oe/5OEcAhPWwpnBaodZZmqfjWmY5GSo98XJNwq9D
1yQIilLhFaYIMIQuxZaZJ4uy6FS1T2BUIUKdNsdPhL9pqpEp/ne18PiiE94RCjzDco0C+rs1zIzXGvkx
pmNuRI2+XEG9NjV5NYlXuBLP0DzcQwoQaiuUTI9VrQgvfC5irjeSqrJMKovTURcmU5KbxE15HAWyGNH5
e/BCtSab6a+a5ZMXxTD9cdAbsir/CG6Xyvj+qcRY2xBurss28lCfRYNOxr3KdPTqFHQlUspV17mVl0Cx
Mg5VdqyxjVBZks7k+3wMtYdaJdRXKVkYksJw6kreiWuD8dAXBa8j6Krx5UqwR4WgVqUwMZAJH+Tcr1bQ
/ki+tOnPK7wKhA5v5tvcmHnsxNsKOy6ePTohCvYKpXkSvr2RMtyWSL1OzuKgBHpClwRdwWLwNPPtHsy0
HGGy6RCjdfuQhllzxsUs1zBMoUiZyGh3LHe02XQ+E5v0RYqC89AZwOLzk8w+Pc5U82HG6h34Um1LR9pm
/N2scLAxsTEKVFlx9LQkcVebBQNJ8FKs+8KH2VZ3pp44Md7gyIjejo+a3fTKTZGE7MJ+j0Xj8lPOz4ih
tjyT3gfhdOQIy7TLN9Ai20hj8iZqEsxRx1hw4+oO/F13LjraW7ouC3JSo8mRXCAjNoj4y36GyXLO14VT
xw7gfNCO/XbW2FpZYLndjK1bTNhmarLyIa3nKxuyPwG9D9E7Fbto+QAAAABJRU5ErkJggg==
</value>
</data>
<data name="toolStripButton4.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="saveToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAACMklE
QVQ4T6WT3UuTcRTH9y90303QRbc1NYZrMRs86hzKsmFoIb09kqZpunxJUqxMxZYvkK1w6sTlahJOKvIF
TJEUMZaSlZkrWuJQU3QiGHz7nZ+wn0vrQh84Nw98Puc553wfBQDFXorDL18EQOXuXEGHaxlPHItoafbj
kXUW9XU/YLnnxd3yaZSWfEZR4Qfk5Y7japaHoVBwAYF9vUBd7Tq9/Oeztr4BfVIfTic95xUUuJ4tcUFl
xa//wv7FNRw3voJSKcN0yikEjrYFLigt+bmjgDoT/NW3hDCDG4UFMzhpbBUCW+McF1w3f9km2Aq/n/Lj
kORCTvYkEuJtQtDwwMcFmVfGQwR/w0MeH/ZrHZDlURgMViGorfnOBfKl0aBgJ7h35Bv2RTYj5cwbxMbW
C0FV5Qx6usFOCaSeH4bp7CDfNi2MZqbPps6bcD8STa8hSRYhuFU2hS43WAaAVvtvdvdVlN+Z50ulhdHM
GemeIByX0AmdrkIIbhRNwtkONNk2WHAC0Cdnh5TxnBnJl4t557h4Bsc4odWWCYE5b4LBQM39AO9MAgXL
WJhawtinOUxMz0POvY0T+g4Oq6Ps0GiKhYBiaX2I4GeTgOC0/Gp89C7AO7uMazctCNfaGdyC8GOPoY7M
F4KM9Hds7hU+80GdEweOSHjaNQB39xB6+kcw+HYM0QYTlJpGRDD4sKoBKlVOiCDx4oUBHk9KGIWE7kyn
om3Twmhm6kpF8NGITCGgn2K39QfkKu4LIHJHnwAAAABJRU5ErkJggg==
</value>
</data>
<data name="toolStripButton1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="cCRedAlertMapToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH
DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2Zp
bGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZE
sRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTs
AIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4
JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR
3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQd
li7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtF
ehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGX
wzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNF
hImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH55
4SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJ
VgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB
5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyC
qbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiE
j6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I
1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9
rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhG
fDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFp
B+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJ
yeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJC
YVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQln
yfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48v
vacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0Cvp
vfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15L
Wytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AA
bWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0z
llmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHW
ztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5s
xybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6
eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPw
YyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmR
XVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNm
WS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wl
xqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2
dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8
V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33za
Eb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2v
Tqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqb
PhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/
0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h
/HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavr
XTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxS
fNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+
tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/
6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAALDAAACwwBP0AiyAAAAN5JREFUOE+FUwEOAyEI
8+k+7X7GoFBWmZdtISYgtS3csrXsFtvzf2Mv8/8d4Hkec2SLM+IHzJsjdwVAcxQrtl8OsDgBxPMGgKJG
SQkwMlI2zSCS+cuL0YCceHEDAcBbM6gTQOhDDpnBxHqVOsmgdYvmfCxk7q+JpDZN4yQOJhOAOtmslGna
MYE3AN2HeBEmyvhYZ44mL5rRXkijgoAZAA3nCVBzbzM5vuE8x8xmbGIzqE1LkNwHOO2RZmZOjQYTjoWF
g/YYr+qn2QBQSl2ofL8oC6Wb2hIOM8WD+bXOex/mMAFDkP1eQgAAAABJRU5ErkJggg==
</value>
</data>
<data name="toolStripButton6.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="bitmapToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAACR0lE
QVQ4T6WTXUiTARSGdxkRRBdB0IUREV1EKRFEYYuQAklL8sKQfphUoJSUWJbLxAVZWqyBio5WajorM1PL
xExUlLQfbU5n0lygRerMP/qxOZ92vpjfCKLAi3P5Puc957xHA2gWUoo49147gWUqbSPrdjOXChrQm56S
lFVFvKEcXaqV2OQiohMt7Esw+6Ro5gGeWfhbff0BY9NzDI3N0f/JS6fLy7rd6f8HcNsdOI6EYD8cjK3V
roiLawdYu+vivwHSWcQM1THz/DQv96+ixeHlVvU71oQFAGTmP+37bdsPBf8WZ4fRFhVEXdcsBQ9srN6Z
pjqQhQUCAmcW29JZxA8fvaWyY5YcawdBOy6oANm2H9A3MMypDLNS7b1flJnFtnQWcVmrB2NhMytD9SpA
TiUA5+CYInQOjWPrH2V7RBzmijdo9x5VKr+yj6ImD9nmelZsS1UBcme/+OPIJIOfv/Gi201ZXQ/hMfFU
Peuktqnbd3QN+U/cXM6tYfmW8ypAQiKdh91TTE7PYHNOYKl6z916F3m+eSNjT1B4vxHjzWoFYrhRwbLN
51SAJOynx8vo5Ay9rimKHzu5XtJDpuU1WZY2Eg1WgrXRJOpNxKdcUyBLN6WoAInnyPh3XvW6KW/4MC9O
z2ki+Wo1CWklROkMCiT8wEm0kXEsCTmrAiTbDtcEpTVdZOS1oDfWk5xZ6RPeQZeUR8zxK0Qe1BO65xjr
t0YotXhjAEAeQ7It8ZSESUjkznIq2bYsTGYW29JZxIs2nFEdLOSdfwFwpvLxRKIY2AAAAABJRU5ErkJg
gg==
</value>
</data>
<data name="toolStripButton7.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="propertiesToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAACCklE
QVQ4T6WT30tTUQDHz39QD0UQSpAPIkgPyR60AiUiyoGBL4qZjOyt0tZP9tBDk1AsXIhj93ILdd27DPPH
3VwrUrdK2ioJHAgVOdoPaQsarBg43L6ec+akuRsEPnw5D4fP5/vlXg4BQHaSf8LjjwdqaTA2cg+y1Ith
qxmi5Tas/SYWk+QRoPgmtNsLcPq7GYX8+XoTqaUL+KR2cAmDxeBgqeBv2NhWzwUFOBk4g5/zRxB3V8Es
38AtbzuIw/0RLMrMeyhTs2CzGdRtaOTn1dajvLkAR9VKLNvLcHmoExddzSDKzAfkcjkkEtEiOLxoQpdB
z+Er7ScQUg/DL5TD2bsfl5oPoKWnCZ3jehDZGeAC1hwL3uXNs55Jep7Gis/AJWxyTeVe1FXvhq5qH6oP
7nlw/NoxGByNIKPT77CezSEeD6Pn+jlEIiGk6X8N+F9zyfLYIZzUVUCwT0J36jy9yX83KjDq7zSADE8t
cGB7kpksFt76YDzbgMWVFLzBX0WCTcku8mjiTSm8lkUslcHnH2kK/+aw6k+UCJiESE+9XCApz2Gzu5Gk
sEVy4r6got82vRV5blVbIDyZ21rAZrPmL7w5P5s1KxQWXRFtgU15lV8ge2AbdXPY8pAuEIsXWJ6FtAVW
+SWSmXWssuZ4vnl+s5nNFl1hMLjP8U1bMGR/wS/+N9tf7o6eMpNtADko6xybtEXLAAAAAElFTkSuQmCC
</value>
</data>
<data name="toolStripButton2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<data name="resizeToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI
ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9
HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN
rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K
TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx
oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8
7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI
xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX
LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd
KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAADLklE
QVQ4T3WS60/ScRjFf39CL3rR1ovurduWbbU2t7ZqdlkXt7Lrym6O1VoXcdYqQ54wKlGxABE1CzWF0nIm
lZcoTbyUNJFIzDJSJK+E0qy8wInvz+i2erazfd+cz3m+zw4nTS+FLOeZNim3Vp6UU5sqvf5MSZqnyjhV
pfKUvEx54kqp8rCkWHVQVKSJPHtbs+tUgSYiOicVAMfEqfR1dVFCGSqrX94cHQeN/aXhbyD3Zz91uf3U
9tFHTQ4fzVtH9BOQVdKcW2F6/eKkWA1zcxu6vUAQMmCzk/3AErLtDyFrrY035z16T3PXin8B5LfqZE6P
HyZzKw5FX+Yh4XtjwZKZGV3lNPIkhhojplON3Uc3S9/Q7LDfADKtKYklMsgTkwV7joixKHQr2Nq2fSET
5uQwqtsyjcot45R510ozV8f/2iAhsyolCNh9WIyFoRGYHbIGfYN+SVd7Nznzk8ll0FLzKxdZO3xkaOjG
GYUxcIIfRxSlPU4N/rn1fS8JJVlU1WCT3npggVLfAIWuHjJtNRIyjIhTPEKM7D6OSop4RcXpwZ2Wl11l
gHanmze/c36ioc8jyRlFjSzljxl2daI9Pwuv1Cnw9PRjZeQ1cCcSS68Fza6+IXL2fCG7w0ssmc3o2IR8
gbc1PQU9NUp48sNRcUyAkPBL4AIlUbLk3gEvS6YXrW6p0dx9UZ5n4gHjzBmYAAPPYwRwazeiMXYWqjcs
wLSVInAHRYWq0TEf9Q+NUEsg+fr9t2nF1U71leyqn+u3vPuIl2298HZ2wnxkO5q2LYOtxoKpK86D23tW
r+7zfCVzywAVGT/QVV2LvNDo0Eo0j3mAtbUTiRnFOJ94Axp9LfIKK5Ctq0RDmw9TQuPAsW7bHYNUYLCQ
JL2GRAqjtMDYwV+8wzUAWeY9eIfHYW0fxNodxyGWZeOSPBvzl27C5OXnwG0T5irmr79wgdWTNYyVJFL8
kAeo8wyBA/rx2jGErBIH0nXPsWmPEHcM9YgURGPS0jMTZfiXGKDfM4Y0fVOgA/UgRQWECTpExaqxUyDF
wuUbJjb4H0AQfxtrDqiweLMUc8LEmLEqnv9zUMzM9B1/cM83lepxTAAAAABJRU5ErkJggg==
</value>
</data>
<data name="spawnpointsToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAABrUlE
QVQ4T6WTWyhDcRzHl8g1D/IkxZ4mjcgDB0U5ubbVbJLkkubJSt7w6M1eENHUENrktmzJ3HKEiSh7US5l
QiK5JUXpy/9f/9O2zhY59at//c/n87uc35EBkP0nAsL6Bi33E9CpeBINJElHthIkvBNKChh8YVPi1Cpn
Eo7ANSnJwQUMfnLEobVejZbaCnis8VRiyFSgXJ4QWOAPO5fXYJ2xo1HD48QcRSV5CfHSAn94fV0gL9Jn
eVWAtjgXRwPhrJ18Ngc6g2AwkzhXBJTmZ+GgN8xHwgRgPXtnZvDH5xde3j6x6BTAcxk47JFRCUnOBAWF
2WkQhC2xbH/49uEd59evGLfYoJAnEkGjKCCHyjqDDzw72YOpUSMmTF0w93VS2H32iLmlXSSlcuIgxT1Q
VTf7CAj87IjFgy2Gfk4Cu9x3sNhd0oIyXZMoID2TzPez0biyREKvK6bw6t4NxuYDCEo0ZFsBNjBStmci
Asb2Kmj4HAovbF5ieHpHugJeXUfhja19rGzsYai7DcemULj7Q1DEpWNkzgXTDzxo3ZYWFKlq6cVvw2eR
vP+uv56/AehVvkSccelEAAAAAElFTkSuQmCC
</value>
</data>
<metadata name="tt.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">

View File

@@ -1,4 +1,4 @@
#region Copyright & License Information
#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
@@ -16,9 +16,9 @@ using System.Text;
using OpenRA;
using OpenRA.FileFormats;
namespace MapConverter
namespace OpenRA.Editor
{
public class MapConverter
public class LegacyMapImporter
{
// Mapping from ra overlay index to type string
static string[] raOverlayNames =
@@ -29,8 +29,8 @@ namespace MapConverter
"v12", "v13", "v14", "v15", "v16", "v17", "v18",
"fpls", "wcrate", "scrate", "barb", "sbag",
};
static Dictionary< string, Pair<byte,byte> > overlayResourceMapping = new Dictionary<string, Pair<byte, byte>>()
static Dictionary<string, Pair<byte, byte>> overlayResourceMapping = new Dictionary<string, Pair<byte, byte>>()
{
// RA Gems, Gold
{ "gold01", new Pair<byte,byte>(1,0) },
@@ -57,8 +57,8 @@ namespace MapConverter
{ "ti11", new Pair<byte,byte>(1,10) },
{ "ti12", new Pair<byte,byte>(1,11) },
};
static Dictionary<string, string> overlayActorMapping = new Dictionary<string,string>() {
static Dictionary<string, string> overlayActorMapping = new Dictionary<string, string>() {
// Fences
{"sbag","sbag"},
{"cycl","cycl"},
@@ -76,29 +76,27 @@ namespace MapConverter
{"v18","v18"},
// Crates
{"wcrate","crate"},
{"scrate","crate"},
// {"wcrate","crate"},
// {"scrate","crate"},
};
int MapSize;
int ActorCount = 0;
int ActorCount = 0;
Map Map = new Map();
public MapConverter(string[] args)
LegacyMapImporter(string filename)
{
if (args.Length != 3)
{
Console.WriteLine("usage: MapConverter mod[,mod]* input-map.ini output-map.yaml");
return;
}
ConvertIniMap(filename);
}
Game.InitializeEngineWithMods(args[0].Split(','));
ConvertIniMap(args[1]);
Save(args[2]);
public static Map Import(string filename)
{
var converter = new LegacyMapImporter(filename);
return converter.Map;
}
enum IniMapFormat { RedAlert = 3, /* otherwise, cnc (2 variants exist, we don't care to differentiate) */ };
public void ConvertIniMap(string iniFile)
{
var file = new IniFile(FileSystem.Open(iniFile));
@@ -110,14 +108,14 @@ namespace MapConverter
var Width = int.Parse(map.GetValue("Width", "0"));
var Height = int.Parse(map.GetValue("Height", "0"));
MapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64;
Map.Title = basic.GetValue("Name", "(null)");
Map.Author = "Westwood Studios";
Map.Tileset = Truncate(map.GetValue("Theater", "TEMPERAT"), 8);
Map.MapSize.X = MapSize;
Map.MapSize.Y = MapSize;
Map.TopLeft = new int2 (XOffset, YOffset);
Map.BottomRight = new int2(XOffset+Width,YOffset+Height);
Map.TopLeft = new int2(XOffset, YOffset);
Map.BottomRight = new int2(XOffset + Width, YOffset + Height);
Map.Selectable = true;
if (legacyMapFormat == IniMapFormat.RedAlert)
@@ -130,37 +128,37 @@ namespace MapConverter
}
else // CNC
{
UnpackCncTileData(FileSystem.Open(iniFile.Substring(0,iniFile.Length-4)+".bin"));
UnpackCncTileData(FileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin"));
ReadCncOverlay(file);
ReadCncTrees(file);
// TODO: Fixme
//tileset = new TileSet("tileSet.til","templates.ini",fileMapping[Pair.New("cnc",Map.Tileset)].First);
}
LoadActors(file, "STRUCTURES");
LoadActors(file, "UNITS");
LoadActors(file, "INFANTRY");
LoadSmudges(file, "SMUDGE");
var wp = file.GetSection("Waypoints")
.Where(kv => int.Parse(kv.Value) > 0)
.Select(kv => Pair.New(int.Parse(kv.Key),
LocationFromMapOffset( int.Parse( kv.Value ), MapSize )))
.Select(kv => Pair.New(int.Parse(kv.Key),
LocationFromMapOffset(int.Parse(kv.Value), MapSize)))
.Where(a => a.First < 8)
.ToArray();
Map.PlayerCount = wp.Count();
foreach (var kv in wp)
Map.Waypoints.Add("spawn"+kv.First, kv.Second);
Map.Waypoints.Add("spawn" + kv.First, kv.Second);
}
static int2 LocationFromMapOffset(int offset, int mapSize)
{
return new int2(offset % mapSize, offset / mapSize);
}
static MemoryStream ReadPackedSection(IniSection mapPackSection)
{
StringBuilder sb = new StringBuilder();
@@ -185,7 +183,8 @@ namespace MapConverter
byte[] dest = new byte[8192];
byte[] src = reader.ReadBytes((int)length);
/*int actualLength =*/ Format80.DecodeInto(src, dest);
/*int actualLength =*/
Format80.DecodeInto(src, dest);
chunks.Add(dest);
}
@@ -201,10 +200,10 @@ namespace MapConverter
return ms;
}
static byte ReadByte( Stream s )
static byte ReadByte(Stream s)
{
int ret = s.ReadByte();
if( ret == -1 )
if (ret == -1)
throw new NotImplementedException();
return (byte)ret;
}
@@ -217,147 +216,164 @@ namespace MapConverter
return ret;
}
void UnpackRATileData( MemoryStream ms )
void UnpackRATileData(MemoryStream ms)
{
Map.MapTiles = new TileReference<ushort, byte>[ MapSize, MapSize ];
for( int i = 0 ; i < MapSize ; i++ )
for( int j = 0 ; j < MapSize ; j++ )
Map.MapTiles[i,j] = new TileReference<ushort,byte>();
for( int j = 0 ; j < MapSize ; j++ )
for( int i = 0 ; i < MapSize ; i++ )
Map.MapTiles[i,j].type = ReadWord(ms);
Map.MapTiles = new TileReference<ushort, byte>[MapSize, MapSize];
for (int i = 0; i < MapSize; i++)
for (int j = 0; j < MapSize; j++)
Map.MapTiles[i, j] = new TileReference<ushort, byte>();
for( int j = 0 ; j < MapSize ; j++ )
for( int i = 0 ; i < MapSize ; i++ )
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
Map.MapTiles[i, j].type = ReadWord(ms);
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
{
Map.MapTiles[i,j].index = ReadByte(ms);
if( Map.MapTiles[i,j].type == 0xff || Map.MapTiles[i,j].type == 0xffff )
Map.MapTiles[i,j].index = byte.MaxValue;
Map.MapTiles[i, j].index = ReadByte(ms);
if (Map.MapTiles[i, j].type == 0xff || Map.MapTiles[i, j].type == 0xffff)
Map.MapTiles[i, j].index = byte.MaxValue;
}
}
void UnpackRAOverlayData( MemoryStream ms )
void UnpackRAOverlayData(MemoryStream ms)
{
Map.MapResources = new TileReference<byte, byte>[ MapSize, MapSize ];
for( int j = 0 ; j < MapSize ; j++ )
for( int i = 0 ; i < MapSize ; i++ )
Map.MapResources = new TileReference<byte, byte>[MapSize, MapSize];
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
{
byte o = ReadByte( ms );
var res = Pair.New((byte)0,(byte)0);
byte o = ReadByte(ms);
var res = Pair.New((byte)0, (byte)0);
if (o != 255 && overlayResourceMapping.ContainsKey(raOverlayNames[o]))
res = overlayResourceMapping[raOverlayNames[o]];
Map.MapResources[i,j] = new TileReference<byte,byte>(res.First, res.Second);
Map.MapResources[i, j] = new TileReference<byte, byte>(res.First, res.Second);
if (o != 255 && overlayActorMapping.ContainsKey(raOverlayNames[o]))
Map.Actors.Add("Actor"+ActorCount, new ActorReference("Actor"+ActorCount++, overlayActorMapping[raOverlayNames[o]], new int2(i,j), "Neutral"));
Map.Actors.Add("Actor" + ActorCount,
new ActorReference(overlayActorMapping[raOverlayNames[o]])
{
new LocationInit( new int2(i, j) ),
new OwnerInit( "Neutral" )
});
}
}
void ReadRATrees( IniFile file )
void ReadRATrees(IniFile file)
{
IniSection terrain = file.GetSection( "TERRAIN", true );
if( terrain == null )
return;
foreach( KeyValuePair<string, string> kv in terrain )
{
var loc = int.Parse( kv.Key );
Map.Actors.Add("Actor"+ActorCount, new ActorReference("Actor"+ActorCount++,kv.Value.ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), "Neutral" ) );
}
}
void UnpackCncTileData( Stream ms )
{
Map.MapTiles = new TileReference<ushort, byte>[ MapSize, MapSize ];
for( int i = 0 ; i < MapSize ; i++ )
for( int j = 0 ; j < MapSize ; j++ )
Map.MapTiles[i,j] = new TileReference<ushort,byte>();
for( int j = 0 ; j < MapSize ; j++ )
for( int i = 0 ; i < MapSize ; i++ )
{
Map.MapTiles[i,j].type = ReadByte(ms);
Map.MapTiles[i,j].index = ReadByte(ms);
if( Map.MapTiles[i,j].type == 0xff )
Map.MapTiles[i,j].index = byte.MaxValue;
}
}
void ReadCncOverlay( IniFile file )
{
IniSection overlay = file.GetSection( "OVERLAY", true );
if( overlay == null )
return;
Map.MapResources = new TileReference<byte, byte>[ MapSize, MapSize ];
foreach( KeyValuePair<string, string> kv in overlay )
{
var loc = int.Parse( kv.Key );
int2 cell = new int2(loc % MapSize, loc / MapSize);
var res = Pair.New((byte)0,(byte)0);
if (overlayResourceMapping.ContainsKey(kv.Value.ToLower()))
res = overlayResourceMapping[kv.Value.ToLower()];
Map.MapResources[ cell.X, cell.Y ] = new TileReference<byte,byte>(res.First, res.Second);
if (overlayActorMapping.ContainsKey(kv.Value.ToLower()))
Map.Actors.Add("Actor"+ActorCount, new ActorReference("Actor"+ActorCount++, overlayActorMapping[kv.Value.ToLower()], new int2(cell.X,cell.Y), "Neutral"));
}
}
void ReadCncTrees( IniFile file )
{
IniSection terrain = file.GetSection( "TERRAIN", true );
if( terrain == null )
IniSection terrain = file.GetSection("TERRAIN", true);
if (terrain == null)
return;
foreach( KeyValuePair<string, string> kv in terrain )
foreach (KeyValuePair<string, string> kv in terrain)
{
var loc = int.Parse( kv.Key );
Map.Actors.Add("Actor"+ActorCount, new ActorReference("Actor"+ActorCount++, kv.Value.Split(',')[0].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize),"Neutral"));
var loc = int.Parse(kv.Key);
Map.Actors.Add("Actor" + ActorCount,
new ActorReference(kv.Value.ToLowerInvariant())
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit("Neutral")
});
}
}
void UnpackCncTileData(Stream ms)
{
Map.MapTiles = new TileReference<ushort, byte>[MapSize, MapSize];
for (int i = 0; i < MapSize; i++)
for (int j = 0; j < MapSize; j++)
Map.MapTiles[i, j] = new TileReference<ushort, byte>();
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
{
Map.MapTiles[i, j].type = ReadByte(ms);
Map.MapTiles[i, j].index = ReadByte(ms);
if (Map.MapTiles[i, j].type == 0xff)
Map.MapTiles[i, j].index = byte.MaxValue;
}
}
void ReadCncOverlay(IniFile file)
{
IniSection overlay = file.GetSection("OVERLAY", true);
if (overlay == null)
return;
Map.MapResources = new TileReference<byte, byte>[MapSize, MapSize];
foreach (KeyValuePair<string, string> kv in overlay)
{
var loc = int.Parse(kv.Key);
int2 cell = new int2(loc % MapSize, loc / MapSize);
var res = Pair.New((byte)0, (byte)0);
if (overlayResourceMapping.ContainsKey(kv.Value.ToLower()))
res = overlayResourceMapping[kv.Value.ToLower()];
Map.MapResources[cell.X, cell.Y] = new TileReference<byte, byte>(res.First, res.Second);
if (overlayActorMapping.ContainsKey(kv.Value.ToLower()))
Map.Actors.Add("Actor" + ActorCount,
new ActorReference(overlayActorMapping[kv.Value.ToLower()])
{
new LocationInit(cell),
new OwnerInit("Neutral")
});
}
}
void ReadCncTrees(IniFile file)
{
IniSection terrain = file.GetSection("TERRAIN", true);
if (terrain == null)
return;
foreach (KeyValuePair<string, string> kv in terrain)
{
var loc = int.Parse(kv.Key);
Map.Actors.Add("Actor" + ActorCount,
new ActorReference(kv.Value.Split(',')[0].ToLowerInvariant())
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit("Neutral")
});
}
}
void LoadActors(IniFile file, string section)
{
foreach (var s in file.GetSection(section, true))
{
//num=owner,type,health,location,facing,...
var parts = s.Value.Split( ',' );
var parts = s.Value.Split(',');
var loc = int.Parse(parts[3]);
if (parts[0] == "")
parts[0] = "Neutral";
Map.Actors.Add("Actor"+ActorCount, new ActorReference("Actor"+ActorCount++, parts[1].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), parts[0]));
Map.Actors.Add("Actor" + ActorCount,
new ActorReference(parts[1].ToLowerInvariant())
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit(parts[0])
});
}
}
void LoadSmudges(IniFile file, string section)
{
foreach (var s in file.GetSection(section, true))
{
//loc=type,loc,depth
var parts = s.Value.Split( ',' );
var parts = s.Value.Split(',');
var loc = int.Parse(parts[1]);
Map.Smudges.Add(new SmudgeReference(parts[0].ToLowerInvariant(),new int2(loc % MapSize, loc / MapSize),int.Parse(parts[2])));
Map.Smudges.Add(new SmudgeReference(parts[0].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), int.Parse(parts[2])));
}
}
static string Truncate( string s, int maxLength )
static string Truncate(string s, int maxLength)
{
return s.Length <= maxLength ? s : s.Substring(0,maxLength );
}
public void Save(string filepath)
{
Directory.CreateDirectory(filepath);
Map.Package = new Folder(filepath);
Map.Save(filepath);
return s.Length <= maxLength ? s : s.Substring(0, maxLength);
}
}
}

View File

@@ -23,6 +23,7 @@
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -31,6 +32,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@@ -44,7 +46,6 @@
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
@@ -57,6 +58,7 @@
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="LegacyMapImporter.cs" />
<Compile Include="NewMapDialog.cs">
<SubType>Form</SubType>
</Compile>
@@ -121,7 +123,7 @@
<Name>OpenRA.Game</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@@ -22,6 +22,7 @@ namespace OpenRA.Editor
Application.CurrentCulture = CultureInfo.InvariantCulture;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args));
}
}

View File

@@ -8,13 +8,13 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Thirdparty;
namespace OpenRA.Editor
{
@@ -31,6 +31,7 @@ namespace OpenRA.Editor
WaypointTemplate Waypoint;
public bool IsPanning;
public event Action AfterChange = () => { };
Dictionary<string, ActorTemplate> ActorTemplates = new Dictionary<string, ActorTemplate>();
Dictionary<int, ResourceTemplate> ResourceTemplates = new Dictionary<int, ResourceTemplate>();
@@ -129,6 +130,8 @@ namespace OpenRA.Editor
/* todo: optimize */
foreach (var ch in Chunks.Values) ch.Dispose();
Chunks.Clear();
AfterChange();
}
int2 FindEdge(int2 p, int2 d, TileReference<ushort, byte> replace)
@@ -178,6 +181,8 @@ namespace OpenRA.Editor
}
}
}
AfterChange();
}
int wpid;
@@ -197,6 +202,8 @@ namespace OpenRA.Editor
if (k.Key != null) Map.Waypoints.Remove(k.Key);
Map.Waypoints.Add(NextWpid(), GetBrushLocation());
AfterChange();
}
void Erase()
@@ -206,7 +213,7 @@ namespace OpenRA.Editor
Resource = null;
Waypoint = null;
var key = Map.Actors.FirstOrDefault(a => a.Value.Location == GetBrushLocation());
var key = Map.Actors.FirstOrDefault(a => a.Value.Location() == GetBrushLocation());
if (key.Key != null) Map.Actors.Remove(key.Key);
if (Map.MapResources[GetBrushLocation().X, GetBrushLocation().Y].type != 0)
@@ -222,6 +229,8 @@ namespace OpenRA.Editor
var k = Map.Waypoints.FirstOrDefault(a => a.Value == GetBrushLocation());
if (k.Key != null) Map.Waypoints.Remove(k.Key);
AfterChange();
}
void Draw()
@@ -230,6 +239,8 @@ namespace OpenRA.Editor
if (Actor != null) DrawWithActor();
if (Resource != null) DrawWithResource();
if (Waypoint != null) DrawWithWaypoint();
AfterChange();
}
int id;
@@ -244,15 +255,21 @@ namespace OpenRA.Editor
void DrawWithActor()
{
if (Map.Actors.Any(a => a.Value.Location == GetBrushLocation()))
if (Map.Actors.Any(a => a.Value.Location() == GetBrushLocation()))
return;
var owner = "Neutral";
var id = NextActorName();
Map.Actors[id] = new ActorReference(id,Actor.Info.Name.ToLowerInvariant(), GetBrushLocation(), owner);
Map.Actors[id] = new ActorReference(Actor.Info.Name.ToLowerInvariant())
{
new LocationInit( GetBrushLocation() ),
new OwnerInit( owner)
};
AfterChange();
}
Random r = new Random();
System.Random r = new System.Random();
void DrawWithResource()
{
Map.MapResources[GetBrushLocation().X, GetBrushLocation().Y]
@@ -269,6 +286,8 @@ namespace OpenRA.Editor
Chunks[ch].Dispose();
Chunks.Remove(ch);
}
AfterChange();
}
protected override void OnMouseDown(MouseEventArgs e)
@@ -288,10 +307,11 @@ namespace OpenRA.Editor
Bitmap RenderChunk(int u, int v)
{
var bitmap = new Bitmap(ChunkSize * 24, ChunkSize * 24);
bitmap.SetPixel(0, 0, Color.Green);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
@@ -308,7 +328,7 @@ namespace OpenRA.Editor
var rawImage = tile.TileBitmapBytes[index];
for (var x = 0; x < 24; x++)
for (var y = 0; y < 24; y++)
p[ (j * 24 + y) * stride + i * 24 + x ] = Palette.GetColor(rawImage[x + 24 * y]).ToArgb();
p[(j * 24 + y) * stride + i * 24 + x] = Palette.GetColor(rawImage[x + 24 * y]).ToArgb();
if (Map.MapResources[u * ChunkSize + i, v * ChunkSize + j].type != 0)
{
@@ -379,7 +399,7 @@ namespace OpenRA.Editor
new Rectangle(Map.XOffset * 24 + Offset.X, Map.YOffset * 24 + Offset.Y, Map.Width * 24, Map.Height * 24));
foreach (var ar in Map.Actors)
DrawActor(e.Graphics, ar.Value.Location, ActorTemplates[ar.Value.Type]);
DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type]);
foreach (var wp in Map.Waypoints)
e.Graphics.DrawRectangle(Pens.LimeGreen, new Rectangle(
@@ -406,10 +426,18 @@ namespace OpenRA.Editor
if (Brush == null && Actor == null && Resource == null)
{
var x = Map.Actors.FirstOrDefault(a => a.Value.Location == GetBrushLocation());
var x = Map.Actors.FirstOrDefault(a => a.Value.Location() == GetBrushLocation());
if (x.Key != null)
DrawActorBorder(e.Graphics, x.Value.Location, ActorTemplates[x.Value.Type]);
DrawActorBorder(e.Graphics, x.Value.Location(), ActorTemplates[x.Value.Type]);
}
}
}
static class ActorReferenceExts
{
public static int2 Location(this ActorReference ar)
{
return ar.InitDict.Get<LocationInit>().value;
}
}
}

View File

@@ -28,13 +28,15 @@ namespace OpenRA.FileFormats
throw new NotImplementedException( "FieldLoader: Missing field `{0}` on `{1}`".F( s, f.Name ) );
};
public static void Load(object self, MiniYaml my) { Load(self, my.Nodes); }
public static void Load(object self, Dictionary<string, MiniYaml> my)
public static void Load( object self, MiniYaml my )
{
foreach (var x in my)
foreach( var x in my.Nodes )
if (!x.Key.StartsWith("-"))
LoadField(self, x.Key, x.Value.Value);
foreach( var field in self.GetType().GetFields())
if( field.HasAttribute<FieldFromYamlKeyAttribute>() )
field.SetValue( self, GetValue( field.Name, field.FieldType, my.Value ) );
}
public static T Load<T>(MiniYaml y) where T : new()
@@ -58,7 +60,9 @@ namespace OpenRA.FileFormats
var field = self.GetType().GetField( key.Trim() );
if( field == null )
UnknownFieldAction(key.Trim(), self.GetType());
UnknownFieldAction( key.Trim(), self.GetType() );
else if( field.HasAttribute<FieldFromYamlKeyAttribute>() )
return;
else
field.SetValue( self, GetValue( field.Name, field.FieldType, value ) );
}
@@ -150,10 +154,18 @@ namespace OpenRA.FileFormats
{
public static MiniYaml Save(object o)
{
return new MiniYaml(null, o.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)
.ToDictionary(
f => f.Name,
f => new MiniYaml(FormatValue(o, f))));
var dict = new Dictionary<string, MiniYaml>();
string root = null;
foreach( var f in o.GetType().GetFields( BindingFlags.Public | BindingFlags.Instance ) )
{
if( f.HasAttribute<FieldFromYamlKeyAttribute>() )
root = FormatValue( o, f );
else
dict.Add( f.Name, new MiniYaml( FormatValue( o, f ) ) );
}
return new MiniYaml( root, dict );
}
public static MiniYaml SaveDifferences(object o, object from)
@@ -187,4 +199,6 @@ namespace OpenRA.FileFormats
: v.ToString();
}
}
public class FieldFromYamlKeyAttribute : Attribute { }
}

View File

@@ -76,6 +76,32 @@ namespace OpenRA.FileFormats
return (short)current;
}
public static byte[] LoadSound(byte[] raw, ref int index)
{
var br = new BinaryReader(new MemoryStream(raw));
var dataSize = raw.Length;
var outputSize = raw.Length * 4;
var output = new byte[outputSize];
var offset = 0;
var currentSample = 0;
while (dataSize-- > 0)
{
var b = br.ReadByte();
var t = DecodeSample(b, ref index, ref currentSample);
output[offset++] = (byte)t;
output[offset++] = (byte)(t >> 8);
t = DecodeSample((byte)(b >> 4), ref index, ref currentSample);
output[offset++] = (byte)t;
output[offset++] = (byte)(t >> 8);
}
return output;
}
public static byte[] LoadSound(Stream s)
{
var br = new BinaryReader(s);

View File

@@ -32,6 +32,7 @@ namespace OpenRA.FileFormats.Graphics
IVertexBuffer<Vertex> CreateVertexBuffer( int length );
IIndexBuffer CreateIndexBuffer( int length );
ITexture CreateTexture( Bitmap bitmap );
ITexture CreateTexture();
IShader CreateShader( Stream stream );
Size WindowSize { get; }
@@ -71,6 +72,7 @@ namespace OpenRA.FileFormats.Graphics
public interface ITexture
{
void SetData( Bitmap bitmap );
void SetData(uint[,] colors);
}
public interface IFont

View File

@@ -0,0 +1,295 @@
#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.IO;
namespace OpenRA.FileFormats
{
public class VqaReader
{
public readonly ushort Frames;
public readonly byte Framerate;
public readonly ushort Width;
public readonly ushort Height;
Stream stream;
int currentFrame;
ushort flags;
ushort numColors;
ushort blockWidth;
ushort blockHeight;
byte cbParts;
int2 blocks;
UInt32[] offsets;
uint[] palette;
// Stores a list of subpixels, referenced by the VPTZ chunk
byte[] cbf;
byte[] cbp;
int cbChunk = 0;
int cbOffset = 0;
// Top half contains block info, bottom half contains references to cbf array
byte[] origData;
// Final frame output
uint[,] frameData;
byte[] audioData; // audio for this frame: 22050Hz 16bit mono pcm, uncompressed.
public byte[] AudioData { get { return audioData; } }
public int CurrentFrame { get { return currentFrame; } }
public VqaReader( Stream stream )
{
this.stream = stream;
BinaryReader reader = new BinaryReader( stream );
// Decode FORM chunk
if (new String(reader.ReadChars(4)) != "FORM")
throw new InvalidDataException("Invalid vqa (invalid FORM section)");
/*var length = */ reader.ReadUInt32();
if (new String(reader.ReadChars(8)) != "WVQAVQHD")
throw new InvalidDataException("Invalid vqa (not WVQAVQHD)");
/* var length = */reader.ReadUInt32();
/*var version = */reader.ReadUInt16();
flags = reader.ReadUInt16();
Frames = reader.ReadUInt16();
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
blockWidth = reader.ReadByte();
blockHeight = reader.ReadByte();
Framerate = reader.ReadByte();
cbParts = reader.ReadByte();
blocks = new int2(Width / blockWidth, Height / blockHeight);
numColors = reader.ReadUInt16();
/*var maxBlocks = */reader.ReadUInt16();
/*var unknown1 = */reader.ReadUInt16();
/*var unknown2 = */reader.ReadUInt32();
// Audio
/*var freq = */reader.ReadUInt16();
/*var channels = */reader.ReadByte();
/*var bits = */reader.ReadByte();
var unknown3 = reader.ReadChars(14);
var frameSize = NextPowerOf2(Math.Max(Width,Height));
cbf = new byte[Width*Height];
cbp = new byte[Width*Height];
palette = new uint[numColors];
origData = new byte[2*blocks.X*blocks.Y];
frameData = new uint[frameSize,frameSize];
var type = new String(reader.ReadChars(4));
if (type != "FINF")
{
reader.ReadBytes(27);
type = new String(reader.ReadChars(4));
}
/*var length = */reader.ReadUInt16();
/*var unknown4 = */reader.ReadUInt16();
// Frame offsets
offsets = new UInt32[Frames];
for (int i = 0; i < Frames; i++)
{
offsets[i] = reader.ReadUInt32();
if (offsets[i] > 0x40000000) offsets[i] -= 0x40000000;
offsets[i] <<= 1;
}
CollectAudioData();
Reset();
}
public void Reset()
{
currentFrame = cbOffset = cbChunk = 0;
LoadFrame();
}
void CollectAudioData()
{
var ms = new MemoryStream();
var adpcmIndex = 0;
bool compressed = false;
for (var i = 0; i < Frames; i++)
{
stream.Seek(offsets[i], SeekOrigin.Begin);
BinaryReader reader = new BinaryReader(stream);
var end = (i < Frames - 1) ? offsets[i + 1] : stream.Length;
while (reader.BaseStream.Position < end)
{
var type = new String(reader.ReadChars(4));
var length = int2.Swap(reader.ReadUInt32());
switch (type)
{
case "SND0":
case "SND2":
var rawAudio = reader.ReadBytes((int)length);
ms.Write(rawAudio);
compressed = (type == "SND2");
break;
default:
reader.ReadBytes((int)length);
break;
}
if (reader.PeekChar() == 0) reader.ReadByte();
}
}
audioData = (compressed) ? AudLoader.LoadSound(ms.ToArray(), ref adpcmIndex) : ms.ToArray();
}
public void AdvanceFrame()
{
currentFrame++;
LoadFrame();
}
void LoadFrame()
{
if (currentFrame >= Frames)
return;
// Seek to the start of the frame
stream.Seek(offsets[currentFrame], SeekOrigin.Begin);
BinaryReader reader = new BinaryReader(stream);
var end = (currentFrame < Frames - 1) ? offsets[currentFrame+1] : stream.Length;
while(reader.BaseStream.Position < end)
{
var type = new String(reader.ReadChars(4));
var length = int2.Swap(reader.ReadUInt32());
switch(type)
{
case "VQFR":
DecodeVQFR(reader);
break;
default:
// Don't parse sound here.
reader.ReadBytes((int)length);
break;
}
// Chunks are aligned on even bytes; advance by a byte if the next one is null
if (reader.PeekChar() == 0) reader.ReadByte();
}
}
// VQA Frame
public void DecodeVQFR(BinaryReader reader)
{
while(true)
{
// Chunks are aligned on even bytes; may be padded with a single null
if (reader.PeekChar() == 0) reader.ReadByte();
var type = new String(reader.ReadChars(4));
int subchunkLength = (int)int2.Swap(reader.ReadUInt32());
switch(type)
{
// Full frame-modifier
case "CBFZ":
Format80.DecodeInto( reader.ReadBytes(subchunkLength), cbf );
break;
case "CBF0":
cbf = reader.ReadBytes(subchunkLength);
break;
// frame-modifier chunk
case "CBP0":
case "CBPZ":
// Partial buffer is full; dump and recreate
if (cbChunk == cbParts)
{
if (type == "CBP0")
cbf = (byte[])cbp.Clone();
else
Format80.DecodeInto( cbp, cbf );
cbOffset = cbChunk = 0;
}
var bytes = reader.ReadBytes(subchunkLength);
bytes.CopyTo(cbp,cbOffset);
cbOffset += subchunkLength;
cbChunk++;
break;
// Palette
case "CPL0":
for (int i = 0; i < numColors; i++)
{
byte r = (byte)(reader.ReadByte() << 2);
byte g = (byte)(reader.ReadByte() << 2);
byte b = (byte)(reader.ReadByte() << 2);
palette[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b);
}
break;
// Frame data
case "VPTZ":
Format80.DecodeInto( reader.ReadBytes(subchunkLength), origData );
// This is the last subchunk
return;
default:
throw new InvalidDataException("Unknown sub-chunk {0}".F(type));
}
}
}
int cachedFrame = -1;
public uint[,] FrameData { get
{
if (cachedFrame != currentFrame)
{
cachedFrame = currentFrame;
for (var y = 0; y < blocks.Y; y++)
for (var x = 0; x < blocks.X; x++)
{
var px = origData[x + y*blocks.X];
var mod = origData[x + (y + blocks.Y)*blocks.X];
for (var j = 0; j < blockHeight; j++)
for (var i = 0; i < blockWidth; i++)
{
var cbfi = (mod*256 + px)*8 + j*blockWidth + i;
byte color = (mod == 0x0f) ? px : cbf[cbfi];
frameData[y*blockHeight + j, x*blockWidth + i] = palette[color];
}
}
}
return frameData;
}}
int NextPowerOf2(int v)
{
--v;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
++v;
return v;
}
}
}

View File

@@ -1,34 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
namespace OpenRA.FileFormats
{
public class ActorReference
{
public readonly string Id;
public readonly string Type;
public readonly int2 Location;
public readonly string Owner;
public ActorReference(MiniYaml my)
{
FieldLoader.Load(this, my);
}
// Legacy construtor for old format maps
public ActorReference(string id, string type, int2 location, string owner )
{
Id = id;
Type = type;
Location = location;
Owner = owner;
}
}
}

View File

@@ -17,10 +17,10 @@ namespace OpenRA.FileFormats
{
public class MapStub
{
public IFolder Package;
public readonly IFolder Package;
// Yaml map data
public string Uid;
public readonly string Uid;
public bool Selectable;
public string Title;
@@ -35,7 +35,6 @@ namespace OpenRA.FileFormats
public int2 BottomRight;
public int Width { get { return BottomRight.X - TopLeft.X; } }
public int Height { get { return BottomRight.Y - TopLeft.Y; } }
public Map Map { get { return new Map(Package); }}
static List<string> Fields = new List<string>() {
"Selectable", "Title", "Description", "Author", "PlayerCount", "Tileset", "TopLeft", "BottomRight"

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -76,8 +76,6 @@
<Compile Include="Support\Stopwatch.cs" />
<Compile Include="Support\Timer.cs" />
<Compile Include="TypeDictionary.cs" />
<Compile Include="Map\ActorReference.cs" />
<Compile Include="Map\Map.cs" />
<Compile Include="Map\TileReference.cs" />
<Compile Include="Map\Terrain.cs" />
<Compile Include="Primitives\Cache.cs" />
@@ -101,6 +99,7 @@
<Compile Include="Map\SmudgeReference.cs" />
<Compile Include="Map\PlayerReference.cs" />
<Compile Include="CompressedPackage.cs" />
<Compile Include="Graphics\VqaReader.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -11,20 +11,38 @@
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System;
namespace OpenRA.FileFormats
{
public class Palette
{
List<Color> colors = new List<Color>();
uint[] colors;
public Color GetColor(int index)
{
return colors[index];
return Color.FromArgb((int)colors[index]);
}
public void SetColor(int index, Color color)
{
colors[index] = (uint)color.ToArgb();
}
public void SetColor(int index, uint color)
{
colors[index] = (uint)color;
}
public uint[] Values
{
get { return colors; }
}
public Palette(Stream s, bool remapTransparent)
{
colors = new uint[256];
using (BinaryReader reader = new BinaryReader(s))
{
for (int i = 0; i < 256; i++)
@@ -32,24 +50,28 @@ namespace OpenRA.FileFormats
byte r = (byte)(reader.ReadByte() << 2);
byte g = (byte)(reader.ReadByte() << 2);
byte b = (byte)(reader.ReadByte() << 2);
colors.Add(Color.FromArgb(r, g, b));
colors[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b);
}
}
colors[0] = Color.FromArgb(0, 0, 0, 0);
colors[0] = 0;
if (remapTransparent)
{
colors[3] = Color.FromArgb(178, 0, 0, 0);
colors[4] = Color.FromArgb(140, 0, 0, 0);
colors[3] = 178u << 24;
colors[4] = 140u << 24;
}
}
public Palette(Palette p, IPaletteRemap r)
{
for (int i = 0; i < 256; i++)
colors.Add(r.GetRemappedColor(p.GetColor(i), i));
colors = new uint[256];
for(int i = 0; i < 256; i++)
colors[i] = (uint)r.GetRemappedColor(Color.FromArgb((int)p.colors[i]),i).ToArgb();
}
public Palette(Palette p)
{
colors = (uint[])p.colors.Clone();
}
}

View File

@@ -53,5 +53,11 @@ namespace OpenRA
public float2 ToFloat2() { return new float2(X, Y); }
public override string ToString() { return string.Format("{0},{1}", X, Y); }
// Change endianness of a uint32
public static uint Swap(uint orig)
{
return (uint)((orig & 0xff000000) >> 24) | ((orig & 0x00ff0000) >> 8) | ((orig & 0x0000ff00) << 8) | ((orig & 0x000000ff) << 24);
}
}
}

View File

@@ -47,6 +47,7 @@ namespace OpenRA.FileFormats
public int OrderLatency = 3;
public int RandomSeed = 0;
public bool LockTeams = false; // don't allow team changes after game start.
public bool AllowCheats = false;
}
}
@@ -55,7 +56,7 @@ namespace OpenRA.FileFormats
public readonly string[]
Folders, Packages, Rules,
Sequences, Chrome, Assemblies, ChromeLayout,
Weapons, Voices, Music, TileSets;
Weapons, Voices, Music, Movies, TileSets;
public readonly string ShellmapUid;
@@ -75,6 +76,7 @@ namespace OpenRA.FileFormats
Weapons = YamlList(yaml, "Weapons");
Voices = YamlList(yaml, "Voices");
Music = YamlList(yaml, "Music");
Movies = YamlList(yaml, "Movies");
TileSets = YamlList(yaml, "TileSets");
ShellmapUid = yaml["ShellmapUid"].Value;

View File

@@ -96,10 +96,12 @@ namespace OpenRA
request.Headers.Add("Channel", kvp.Key);
// request.Headers.Add("Diff", kvp.Value.Diff ? "1" : "0");
using (var requestStream = request.GetRequestStream())
requestStream.Write(buffer, 0, buffer.Length);
//var response = (HttpWebResponse)request.GetResponse();
try
{
using (var requestStream = request.GetRequestStream())
requestStream.Write(buffer, 0, buffer.Length);
}
catch (Exception){}
}
}
}

View File

@@ -9,12 +9,13 @@
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.FileFormats
{
public class TypeDictionary
public class TypeDictionary : IEnumerable
{
Dictionary<Type, object> dataSingular = new Dictionary<Type, object>();
Dictionary<Type, List<object>> dataMultiple = new Dictionary<Type, List<object>>();
@@ -85,7 +86,7 @@ namespace OpenRA.FileFormats
return new T[ 0 ];
}
public IEnumerator<object> GetEnumerator()
public IEnumerator GetEnumerator()
{
return WithInterface<object>().GetEnumerator();
}

View File

@@ -22,28 +22,27 @@ namespace OpenRA
public class Actor
{
[Sync]
public readonly TypeDictionary traits = new TypeDictionary();
readonly TypeDictionary traits = new TypeDictionary();
public readonly ActorInfo Info;
public readonly World World;
public readonly uint ActorID;
public int2 Location { get { return traits.Get<IOccupySpace>().TopLeft; } }
public int2 Location { get { return Trait<IOccupySpace>().TopLeft; } }
[Sync]
public Player Owner;
[Sync]
public int Health;
IActivity currentActivity;
public Group Group;
public Actor(World world, string name, int2 location, Player owner)
internal Actor(World world, string name, TypeDictionary initDict )
{
World = world;
ActorID = world.NextAID();
Owner = owner;
var init = new ActorInitializer( this, initDict );
var init = new ActorInitializer( this, location );
World = world;
ActorID = world.NextAID();
if( initDict.Contains<OwnerInit>() )
Owner = init.Get<OwnerInit,Player>();
if (name != null)
{
@@ -51,13 +50,11 @@ namespace OpenRA
throw new NotImplementedException("No rules definition for unit {0}".F(name.ToLowerInvariant()));
Info = Rules.Info[name.ToLowerInvariant()];
Health = this.GetMaxHP();
foreach (var trait in Info.TraitsInConstructOrder())
traits.Add(trait.Create(init));
AddTrait(trait.Create(init));
}
if( CenterLocation == float2.Zero && traits.Contains<IOccupySpace>() )
if( CenterLocation == float2.Zero && HasTrait<IOccupySpace>() )
CenterLocation = Traits.Util.CenterOfCell(Location);
Size = Lazy.New(() =>
@@ -67,7 +64,7 @@ namespace OpenRA
return new float2(si.Bounds[0], si.Bounds[1]);
// auto size from render
var firstSprite = traits.WithInterface<IRender>().SelectMany(x => x.Render(this)).FirstOrDefault();
var firstSprite = TraitsImplementing<IRender>().SelectMany(x => x.Render(this)).FirstOrDefault();
if (firstSprite.Sprite == null) return float2.Zero;
return firstSprite.Sprite.size;
});
@@ -86,7 +83,7 @@ namespace OpenRA
if (currentActivity is Idle)
{
if (!wasIdle)
foreach (var ni in traits.WithInterface<INotifyIdle>())
foreach (var ni in TraitsImplementing<INotifyIdle>())
ni.Idle(this);
break;
@@ -105,8 +102,8 @@ namespace OpenRA
public IEnumerable<Renderable> Render()
{
var mods = traits.WithInterface<IRenderModifier>();
var sprites = traits.WithInterface<IRender>().SelectMany(x => x.Render(this));
var mods = TraitsImplementing<IRenderModifier>();
var sprites = TraitsImplementing<IRender>().SelectMany(x => x.Render(this));
return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
}
@@ -119,11 +116,11 @@ namespace OpenRA
return null;
var underCursor = World.FindUnitsAtMouse(mi.Location)
.Where(a => a.Info.Traits.Contains<SelectableInfo>())
.OrderByDescending(a => a.Info.Traits.Get<SelectableInfo>().Priority)
//.Where(a => a.Info.Traits.Contains<SelectableInfo>())
.OrderByDescending(a => a.Info.Traits.Contains<SelectableInfo>() ? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
.FirstOrDefault();
return traits.WithInterface<IIssueOrder>()
return TraitsImplementing<IIssueOrder>()
.Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
.FirstOrDefault( x => x != null );
}
@@ -140,73 +137,14 @@ namespace OpenRA
if (useAltitude)
{
var unit = traits.GetOrDefault<Unit>();
if (unit != null) loc -= new float2(0, unit.Altitude);
var move = TraitOrDefault<IMove>();
if (move != null) loc -= new float2(0, move.Altitude);
}
return new RectangleF(loc.X, loc.Y, size.X, size.Y);
}
public bool IsDead { get { return Health <= 0; } }
public bool IsInWorld { get; set; }
public bool RemoveOnDeath = true;
public DamageState GetDamageState()
{
if (Health <= 0)
return DamageState.Dead;
if (Health < this.GetMaxHP() * World.Defaults.ConditionYellow)
return DamageState.Half;
return DamageState.Normal;
}
public void InflictDamage(Actor attacker, int damage, WarheadInfo warhead)
{
if (IsDead) return; /* overkill! don't count extra hits as more kills! */
var oldState = GetDamageState();
/* apply the damage modifiers, if we have any. */
var modifier = (float)traits.WithInterface<IDamageModifier>()
.Select(t => t.GetDamageModifier(warhead)).Product();
damage = (int)(damage * modifier);
Health -= damage;
if (Health <= 0)
{
Health = 0;
attacker.Owner.Kills++;
Owner.Deaths++;
if (RemoveOnDeath)
World.AddFrameEndTask(w => w.Remove(this));
Log.Write("debug", "{0} #{1} killed by {2} #{3}", Info.Name, ActorID, attacker.Info.Name, attacker.ActorID);
}
var maxHP = this.GetMaxHP();
if (Health > maxHP) Health = maxHP;
// Log.Write("debug", "InflictDamage: {0} #{1} -> {2} #{3} raw={4} adj={5} hp={6} mod={7}",
// attacker.Info.Name, attacker.ActorID, Info.Name, ActorID, rawDamage, damage, Health, modifier);
var newState = GetDamageState();
foreach (var nd in traits.WithInterface<INotifyDamage>())
nd.Damaged(this, new AttackInfo
{
Attacker = attacker,
Damage = damage,
DamageState = newState,
DamageStateChanged = newState != oldState,
Warhead = warhead
});
}
public void QueueActivity( IActivity nextActivity )
{
@@ -245,18 +183,35 @@ namespace OpenRA
var o = obj as Actor;
return ( o != null && o.ActorID == ActorID );
}
}
public class ActorInitializer
{
public readonly Actor self;
public World world { get { return self.World; } }
public readonly int2 location;
public ActorInitializer( Actor actor, int2 location )
public override string ToString()
{
this.self = actor;
this.location = location;
return "{0} {1}{2}".F( Info.Name, ActorID, IsInWorld ? "" : " (not in world)" );
}
public T Trait<T>()
{
return traits.Get<T>();
}
}
public T TraitOrDefault<T>()
{
return traits.GetOrDefault<T>();
}
public IEnumerable<T> TraitsImplementing<T>()
{
return traits.WithInterface<T>();
}
public bool HasTrait<T>()
{
return traits.Contains<T>();
}
public void AddTrait( object t )
{
traits.Add( t );
}
}
}

134
OpenRA.Game/ActorInitializer.cs Executable file
View File

@@ -0,0 +1,134 @@
#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.Linq;
using OpenRA.FileFormats;
namespace OpenRA
{
public class ActorInitializer
{
public readonly Actor self;
public World world { get { return self.World; } }
internal TypeDictionary dict;
public ActorInitializer( Actor actor, TypeDictionary dict )
{
this.self = actor;
this.dict = dict;
}
public T Get<T>()
where T : IActorInit
{
return dict.Get<T>();
}
public U Get<T,U>()
where T : IActorInit<U>
{
return dict.Get<T>().Value( world );
}
public bool Contains<T>()
where T : IActorInit
{
return dict.Contains<T>();
}
}
public interface IActorInit {}
public interface IActorInit<T> : IActorInit
{
T Value( World world );
}
public class FacingInit : IActorInit<int>
{
[FieldFromYamlKey]
public readonly int value = 128;
public FacingInit() { }
public FacingInit( int init )
{
value = init;
}
public int Value( World world )
{
return value;
}
}
public class AltitudeInit : IActorInit<int>
{
[FieldFromYamlKey]
public readonly int value = 0;
public AltitudeInit() { }
public AltitudeInit( int init )
{
value = init;
}
public int Value( World world )
{
return value;
}
}
public class LocationInit : IActorInit<int2>
{
[FieldFromYamlKey]
public readonly int2 value = int2.Zero;
public LocationInit() { }
public LocationInit( int2 init )
{
value = init;
}
public int2 Value( World world )
{
return value;
}
}
public class OwnerInit : IActorInit<Player>
{
[FieldFromYamlKey]
public readonly string PlayerName = "Neutral";
Player player;
public OwnerInit() { }
public OwnerInit( string playerName )
{
this.PlayerName = playerName;
}
public OwnerInit( Player player )
{
this.player = player;
this.PlayerName = player.InternalName;
}
public Player Value( World world )
{
if( player != null )
return player;
return world.players.First( x => x.Value.InternalName == PlayerName ).Value;
}
}
}

53
OpenRA.Game/ActorReference.cs Executable file
View File

@@ -0,0 +1,53 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Collections;
namespace OpenRA.FileFormats
{
public class ActorReference : IEnumerable
{
public readonly string Type;
public readonly TypeDictionary InitDict;
public ActorReference( string type ) : this( type, new Dictionary<string, MiniYaml>() ) { }
public ActorReference( string type, Dictionary<string, MiniYaml> inits )
{
Type = type;
InitDict = new TypeDictionary();
foreach( var i in inits )
InitDict.Add( LoadInit( i.Key, i.Value ) );
}
static IActorInit LoadInit(string traitName, MiniYaml my)
{
var info = Game.CreateObject<IActorInit>(traitName + "Init");
FieldLoader.Load(info, my);
return info;
}
public MiniYaml Save()
{
var ret = new MiniYaml( Type );
foreach( var init in InitDict )
{
var initName = init.GetType().Name;
ret.Nodes.Add( initName.Substring( 0, initName.Length - 4 ), FieldSaver.Save( init ) );
}
return ret;
}
// for initialization syntax
public void Add( object o ) { InitDict.Add( o ); }
public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); }
}
}

View File

@@ -1,156 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Orders;
using OpenRA.Traits;
namespace OpenRA
{
public class Controller : IHandleInput
{
public IOrderGenerator orderGenerator = new UnitOrderGenerator();
public Selection selection = new Selection();
public void CancelInputMode() { orderGenerator = new UnitOrderGenerator(); }
public bool ToggleInputMode<T>() where T : IOrderGenerator, new()
{
if (orderGenerator is T)
{
CancelInputMode();
return false;
}
else
{
orderGenerator = new T();
return true;
}
}
void ApplyOrders(World world, float2 xy, MouseInput mi)
{
if (orderGenerator == null) return;
var orders = orderGenerator.Order(world, xy.ToInt2(), mi).ToArray();
Game.orderManager.IssueOrders( orders );
// Find an actor with a phrase to say
var done = false;
foreach (var o in orders)
{
foreach (var v in o.Subject.traits.WithInterface<IOrderVoice>())
{
if (Sound.PlayVoice(v.VoicePhraseForOrder(o.Subject, o), o.Subject))
{
done = true;
break;
}
}
if (done) break;
}
}
float2 dragStart, dragEnd;
public bool HandleInput(World world, MouseInput mi)
{
var xy = Game.viewport.ViewToWorld(mi);
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down)
{
dragStart = dragEnd = xy;
ApplyOrders(world, xy, mi);
}
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Move)
dragEnd = xy;
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Up)
{
if (orderGenerator is UnitOrderGenerator)
{
var newSelection = world.SelectActorsInBox(Game.CellSize * dragStart, Game.CellSize * xy);
selection.Combine(world, newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == xy);
}
dragStart = dragEnd = xy;
}
if (mi.Button == MouseButton.None && mi.Event == MouseInputEvent.Move)
dragStart = dragEnd = xy;
if (mi.Button == MouseButton.Right && mi.Event == MouseInputEvent.Down)
ApplyOrders(world, xy, mi);
return true;
}
public Pair<float2, float2>? SelectionBox
{
get
{
if (dragStart == dragEnd) return null;
return Pair.New(Game.CellSize * dragStart, Game.CellSize * dragEnd);
}
}
public float2 MousePosition { get { return dragEnd; } }
Modifiers modifiers;
public string ChooseCursor( World world )
{
int sync = world.SyncHash();
try
{
if (!world.GameHasStarted)
return "default";
var mi = new MouseInput
{
Location = ( Game.CellSize * MousePosition - Game.viewport.Location ).ToInt2(),
Button = MouseButton.Right,
Modifiers = modifiers
};
return orderGenerator.GetCursor( world, MousePosition.ToInt2(), mi );
}
finally
{
if( sync != world.SyncHash() )
throw new InvalidOperationException( "Desync in Controller.ChooseCursor" );
}
}
public void SetModifiers(Modifiers mods) { modifiers = mods; }
public Modifiers GetModifiers() { return modifiers; }
public void GotoNextBase()
{
var bases = Game.world.Queries.OwnedBy[Game.world.LocalPlayer].WithTrait<BaseBuilding>().ToArray();
if (!bases.Any()) return;
var next = bases
.Select( b => b.Actor )
.SkipWhile(b => Game.controller.selection.Actors.Contains(b))
.Skip(1)
.FirstOrDefault();
if (next == null)
next = bases.Select(b => b.Actor).First();
Game.controller.selection.Combine(Game.world, new Actor[] { next }, false, true);
Game.viewport.Center(Game.controller.selection.Actors);
}
}
}

View File

@@ -23,12 +23,12 @@ namespace OpenRA.Effects
public RepairIndicator(Actor a)
{
this.a = a; anim.PlayRepeating("repair");
framesLeft = (int)(a.World.Defaults.RepairRate * 25 * 60 / 2);
framesLeft = (int)(a.Info.Traits.Get<RepairableBuildingInfo>().RepairRate * 25 * 60 / 2);
}
public void Tick( World world )
{
if (--framesLeft == 0 || a.IsDead)
if (--framesLeft == 0 || a.IsDead())
world.AddFrameEndTask(w => w.Remove(this));
}

View File

@@ -34,13 +34,6 @@ namespace OpenRA
return xs.Aggregate(1f, (a, x) => a * x);
}
public static int GetMaxHP(this Actor self)
{
var oai = self.Info.Traits.GetOrDefault<OwnedActorInfo>();
if (oai == null) return 0;
return oai.HP;
}
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k )
where V : new()
{

View File

@@ -36,9 +36,8 @@ namespace OpenRA
public static readonly int CellSize = 24;
public static World world;
internal static Viewport viewport;
public static Controller controller;
internal static UserSettings Settings;
public static Viewport viewport;
public static UserSettings Settings;
internal static OrderManager orderManager;
@@ -53,11 +52,6 @@ namespace OpenRA
static bool packageChangePending;
static bool mapChangePending;
static Pair<Assembly, string>[] ModAssemblies;
static internal bool scrollUp = false;
static internal bool scrollDown = false;
static internal bool scrollLeft = false;
static internal bool scrollRight = false;
static void LoadModPackages()
{
@@ -87,6 +81,9 @@ namespace OpenRA
ModAssemblies = asms.ToArray();
}
public static Action<string> MissingTypeAction =
s => { throw new InvalidOperationException("Cannot locate type: {0}".F(s)); };
public static T CreateObject<T>(string classname)
{
foreach (var mod in ModAssemblies)
@@ -97,7 +94,8 @@ namespace OpenRA
return (T)obj;
}
throw new InvalidOperationException("Cannot locate type: {0}".F(classname));
MissingTypeAction(classname);
return default(T);
}
public static Dictionary<string, MapStub> AvailableMaps;
@@ -167,6 +165,9 @@ namespace OpenRA
CurrentHost = host;
CurrentPort = port;
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged();
orderManager = new OrderManager(new NetworkConnection(host, port), ChooseReplayFilename());
}
@@ -177,6 +178,9 @@ namespace OpenRA
static void JoinLocal()
{
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged();
if (orderManager != null) orderManager.Dispose();
orderManager = new OrderManager(new EchoConnection());
}
@@ -291,9 +295,8 @@ namespace OpenRA
if (isNetTick) orderManager.Tick(world);
controller.orderGenerator.Tick(world);
controller.selection.Tick(world);
world.OrderGenerator.Tick(world);
world.Selection.Tick(world);
world.Tick();
PerfHistory.Tick();
@@ -304,15 +307,6 @@ namespace OpenRA
}
}
if (scrollUp == true)
viewport.Scroll(new float2(0, -10));
if (scrollRight == true)
viewport.Scroll(new float2(10, 0));
if (scrollDown == true)
viewport.Scroll(new float2(0, 10));
if (scrollLeft == true)
viewport.Scroll(new float2(-10, 0));
using (new PerfSample("render"))
{
++RenderFrame;
@@ -390,7 +384,7 @@ namespace OpenRA
LoadMap(map);
world.Queries = new World.AllQueries(world);
foreach (var gs in world.WorldActor.traits.WithInterface<IGameStarted>())
foreach (var gs in world.WorldActor.TraitsImplementing<IGameStarted>())
gs.GameStarted(world);
orderManager.StartGame();
}
@@ -404,7 +398,7 @@ namespace OpenRA
world.Queries = new World.AllQueries(world);
foreach (var gs in world.WorldActor.traits.WithInterface<IGameStarted>())
foreach (var gs in world.WorldActor.TraitsImplementing<IGameStarted>())
gs.GameStarted(world);
viewport.GoToStartLocation(world.LocalPlayer);
@@ -431,33 +425,20 @@ namespace OpenRA
return LobbyInfo.Clients.Single(c => c.Index == p.Index);
}
static int2 lastPos;
public static void DispatchMouseInput(MouseInputEvent ev, MouseEventArgs e, Modifiers modifierKeys)
{
int sync = world.SyncHash();
var initialWorld = world;
if (ev == MouseInputEvent.Down)
lastPos = new int2(e.Location);
if (ev == MouseInputEvent.Move &&
(e.Button == MouseButtons.Middle ||
e.Button == (MouseButtons.Left | MouseButtons.Right)))
var mi = new MouseInput
{
var p = new int2(e.Location);
viewport.Scroll(lastPos - p);
lastPos = p;
}
viewport.DispatchMouseInput(world,
new MouseInput
{
Button = (MouseButton)(int)e.Button,
Event = ev,
Location = new int2(e.Location),
Modifiers = modifierKeys,
});
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");
}
@@ -472,66 +453,20 @@ namespace OpenRA
get { return LobbyInfo.Clients.FirstOrDefault(c => c.Index == orderManager.Connection.LocalClientId); }
}
public static void HandleKeyDown(KeyInput e)
public static void HandleKeyEvent(KeyInput e)
{
int sync = world.SyncHash();
if (Widget.HandleKeyPress(e))
return;
switch (e.KeyName)
{
case "up": scrollUp = true; break;
case "down": scrollDown = true; break;
case "left": scrollLeft = true; break;
case "right": scrollRight = true; break;
}
if (e.KeyName.Length == 1 && char.IsDigit(e.KeyName[0]))
Game.controller.selection.DoControlGroup(world, e.KeyName[0] - '0', e.Modifiers);
if (e.KeyChar == 08)
Game.controller.GotoNextBase();
if (sync != Game.world.SyncHash())
throw new InvalidOperationException("Desync in OnKeyPress");
}
public static void HandleKeyUp(KeyInput e)
{
switch (e.KeyName)
{
case "up": scrollUp = false; break;
case "down": scrollDown = false; break;
case "left": scrollLeft = false; break;
case "right": scrollRight = false; break;
}
}
public static void HandleArrowKeyScroll(String k, Boolean pressed)
{
if (k == "up")
{
scrollUp = pressed;
}
if (k == "left")
{
scrollLeft = pressed;
}
if (k == "down")
{
scrollDown = pressed;
}
if (k == "right")
{
scrollRight = pressed;
}
}
public static void HandleModifierKeys(Modifiers mods)
{
controller.SetModifiers(mods);
}
static Modifiers modifiers;
public static Modifiers GetModifierKeys() { return modifiers; }
public static void HandleModifierKeys(Modifiers mods) { modifiers = mods; }
static Size GetResolution(Settings settings, WindowMode windowmode)
{
@@ -568,14 +503,12 @@ namespace OpenRA
// Load the default mod to access required files
LoadModPackages();
Renderer.SheetSize = Settings.SheetSize;
var resolution = GetResolution(settings, Game.Settings.WindowMode);
Renderer = new Renderer(resolution, Game.Settings.WindowMode);
resolution = Renderer.Resolution;
controller = new Controller();
clientSize = new int2(resolution);
Sound.Initialize();

View File

@@ -14,7 +14,7 @@ using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.GameRules
namespace OpenRA
{
public class ActorInfo
{

View File

@@ -13,38 +13,16 @@ using OpenRA.FileFormats;
namespace OpenRA.GameRules
{
public class MusicInfo
{
public readonly MusicPool Pool;
public readonly string[] Music = { };
{
public readonly string Filename = null;
public readonly string Title = null;
public readonly int Length = 0; // seconds
public MusicInfo( MiniYaml y )
public MusicInfo( string key, MiniYaml value )
{
FieldLoader.Load(this, y);
Pool = new MusicPool(Music);
FieldLoader.Load(this, value);
if (Filename == null)
Filename = key+".aud";
}
}
public class MusicPool
{
readonly string[] clips;
int playing = 0;
public MusicPool(params string[] clips)
{
this.clips = clips;
}
public string GetNext()
{
playing = (playing + 1) % clips.Length;
return clips[playing];
}
public string GetPrev()
{
playing = (playing + clips.Length - 1) % clips.Length;
return clips[playing];
}
public string GetCurrent(){ return clips[playing];}
}
}

View File

@@ -24,6 +24,7 @@ namespace OpenRA
public static Dictionary<string, WeaponInfo> Weapons;
public static Dictionary<string, VoiceInfo> Voices;
public static Dictionary<string, MusicInfo> Music;
public static Dictionary<string, string> Movies;
public static Dictionary<string, TileSet> TileSets;
public static void LoadRules(Manifest m, Map map)
@@ -31,7 +32,8 @@ namespace OpenRA
Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
Weapons = LoadYamlRules(m.Weapons, map.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new VoiceInfo(k.Value));
Music = LoadYamlRules(m.Music, map.Music, (k, _) => new MusicInfo(k.Value));
Music = LoadYamlRules(m.Music, map.Music, (k, _) => new MusicInfo(k.Key, k.Value));
Movies = LoadYamlRules(m.Movies, new Dictionary<string,MiniYaml>(), (k, v) => k.Value.Value);
TileSets = new Dictionary<string, TileSet>();
foreach (var file in m.TileSets)

View File

@@ -19,14 +19,15 @@ namespace OpenRA.GameRules
{
public class UserSettings
{
// Behaviour settings
public bool ViewportEdgeScroll = true;
// Debug settings
public bool UnitDebug = false;
public bool PathDebug = false;
public bool PerfDebug = false;
public bool IndexDebug = false;
public bool RecordSyncReports = true;
public bool ShowGameTimer = true;
public bool DeveloperMode = false;
public bool UnitDebug = false;
// Window settings
public WindowMode WindowMode = WindowMode.PseudoFullscreen;
@@ -37,6 +38,7 @@ namespace OpenRA.GameRules
//Sound Settings
public float SoundVolume = 0.5f;
public float MusicVolume = 0.5f;
public float VideoVolume = 0.5f;
public bool MusicPlayer = false;
// Internal game settings
@@ -58,6 +60,7 @@ namespace OpenRA.GameRules
public int ExternalPort = 1234;
public bool AdvertiseOnline = true;
public string MasterServer = "http://open-ra.org/master/";
public bool AllowCheats = false;
string SettingsFile;
UserSettings defaults;

View File

@@ -9,35 +9,35 @@
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using System;
namespace OpenRA.GameRules
{
public class VoiceInfo
{
public readonly string[] SovietVariants = { ".aud" };
public readonly string[] AlliedVariants = { ".aud" };
public readonly string[] Select = { };
public readonly string[] Move = { };
public readonly string[] Attack = null;
public readonly string[] Die = { };
public readonly string[] Lost = { };
public readonly Dictionary<string,string[]> Variants;
public readonly Dictionary<string,string[]> Voices;
public readonly string DefaultVariant = ".aud" ;
public readonly string[] DisableVariants = { };
Func<MiniYaml, string, Dictionary<string, string[]>> Load = (y,name) => (y.Nodes.ContainsKey(name))? y.Nodes[name].Nodes.ToDictionary(a => a.Key,
a => (string[])FieldLoader.GetValue( "(value)", typeof(string[]), a.Value.Value ))
: new Dictionary<string, string[]>();
public readonly Lazy<Dictionary<string, VoicePool>> Pools;
public VoiceInfo( MiniYaml y )
{
FieldLoader.Load(this, y);
Pools = Lazy.New(() =>
new Dictionary<string, VoicePool>
{
{ "Select", new VoicePool(Select) },
{ "Move", new VoicePool(Move) },
{ "Attack", new VoicePool( Attack ?? Move ) },
{ "Die", new VoicePool(Die) },
{ "Lost", new VoicePool(Lost) },
});
FieldLoader.LoadFields(this, y.Nodes, new string[] { "DisableVariants" });
Variants = Load(y, "Variants");
Voices = Load(y, "Voices");
if (!Voices.ContainsKey("Attack"))
Voices.Add("Attack", Voices["Move"]);
Pools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new VoicePool(a.Value) ));
}
}

View File

@@ -31,7 +31,13 @@ namespace OpenRA.GameRules
public readonly int Delay = 0; // delay in ticks before dealing the damage. 0=instant (old model)
public readonly DamageModel DamageModel = DamageModel.Normal; // which damage model to use
public float EffectivenessAgainst(ArmorType at) { return Verses[(int)at]; }
public float EffectivenessAgainst(Actor self)
{
var health = self.Info.Traits.GetOrDefault<HealthInfo>();
if (health == null) return 0f;
return Verses[(int)(health.Armor)];
}
}
public enum ArmorType

View File

@@ -16,7 +16,7 @@ using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
static class ChromeProvider
public static class ChromeProvider
{
static Dictionary<string, Dictionary<string, MappedImage>> collections;
static Dictionary<string, Sheet> cachedSheets;

View File

@@ -13,75 +13,68 @@ using System.Collections.Generic;
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.Traits;
using OpenRA.FileFormats.Graphics;
using System.Linq;
namespace OpenRA.Graphics
{
class HardwarePalette : Sheet
class HardwarePalette
{
public const int MaxPalettes = 64;
int allocated = 0;
// We need to store the Palettes themselves for the remap palettes to work
// We should probably try to fix this somehow
static Dictionary<string, Palette> palettes;
static Dictionary<string, int> indices;
ITexture texture;
Dictionary<string, Palette> palettes;
Dictionary<string, int> indices;
public HardwarePalette(Map map)
: base(new Size(256, MaxPalettes))
{
palettes = new Dictionary<string, Palette>();
indices = new Dictionary<string, int>();
texture = Game.Renderer.Device.CreateTexture();
}
public Palette GetPalette(string name)
{
try { return palettes[name]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException(
"Palette `{0}` does not exist".F(name));
}
Palette ret;
if (!palettes.TryGetValue(name,out ret))
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return ret;
}
public int GetPaletteIndex(string name)
{
try { return indices[name]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException(
"Palette `{0}` does not exist".F(name));
}
int ret;
if (!indices.TryGetValue(name,out ret))
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return ret;
}
public int AddPalette(string name, Palette p)
public void AddPalette(string name, Palette p)
{
palettes.Add(name, p);
indices.Add(name, allocated);
for (int i = 0; i < 256; i++)
{
this[new Point(i, allocated)] = p.GetColor(i);
}
return allocated++;
}
public void UpdatePalette(string name, Palette p)
{
palettes[name] = p;
var j = indices[name];
for (int i = 0; i < 256; i++)
{
this[new Point(i, j)] = p.GetColor(i);
}
indices.Add(name, allocated++);
}
public void Update(IEnumerable<IPaletteModifier> paletteMods)
{
var b = new Bitmap(Bitmap);
var copy = palettes.ToDictionary(p => p.Key, p => new Palette(p.Value));
foreach (var mod in paletteMods)
mod.AdjustPalette(b);
Texture.SetData(b);
Game.Renderer.PaletteTexture = Texture;
mod.AdjustPalette(copy);
var data = new uint[MaxPalettes,256];
foreach (var pal in copy)
{
var j = indices[pal.Key];
var c = pal.Value.Values;
for (var i = 0; i < 256; i++)
data[j,i] = c[i];
}
// Doesn't work
texture.SetData(data);
Game.Renderer.PaletteTexture = texture;
}
}
}

View File

@@ -17,7 +17,7 @@ using OpenRA.Traits;
namespace OpenRA.Graphics
{
class Minimap
public class Minimap
{
public static Bitmap TerrainBitmap(Map map)
{
@@ -119,12 +119,16 @@ namespace OpenRA.Graphics
unsafe
{
int* c = (int*)bitmapData.Scan0;
foreach (var t in world.Queries.WithTraitMultiple<IRadarSignature>())
{
if (!t.Actor.IsVisible())
continue;
var color = t.Trait.RadarSignatureColor(t.Actor);
foreach( var cell in t.Trait.RadarSignatureCells(t.Actor))
*(c + ((cell.Y - world.Map.TopLeft.Y)* bitmapData.Stride >> 2) + cell.X - world.Map.TopLeft.X) = color.ToArgb();
foreach (var cell in t.Trait.RadarSignatureCells(t.Actor))
if (world.Map.IsInMap(cell))
*(c + ((cell.Y - world.Map.TopLeft.Y) * bitmapData.Stride >> 2) + cell.X - world.Map.TopLeft.X) = color.ToArgb();
}
}

View File

@@ -20,7 +20,7 @@ namespace OpenRA.Graphics
ITexture texture;
bool dirty;
internal Sheet(Size size)
public Sheet(Size size)
{
this.bitmap = new Bitmap(size.Width, size.Height);
}

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Graphics
readonly float2[] uvhax;
internal Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel)
public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel)
{
this.bounds = bounds;
this.sheet = sheet;

View File

@@ -13,7 +13,7 @@ using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
static class SpriteSheetBuilder
public static class SpriteSheetBuilder
{
public static void Initialize( TileSet tileset )
{

View File

@@ -98,7 +98,7 @@ namespace OpenRA.Graphics
new Range<int>(indicesPerRow * firstRow, indicesPerRow * lastRow),
PrimitiveType.TriangleList, Game.Renderer.SpriteShader));
foreach (var r in world.WorldActor.traits.WithInterface<IRenderOverlay>())
foreach (var r in world.WorldActor.TraitsImplementing<IRenderOverlay>())
r.Render();
}
}

View File

@@ -17,12 +17,7 @@ using OpenRA.Widgets;
namespace OpenRA.Graphics
{
interface IHandleInput
{
bool HandleInput(World world, MouseInput mi);
}
class Viewport
public class Viewport
{
readonly float2 screenSize;
float2 scrollPosition;
@@ -33,16 +28,16 @@ namespace OpenRA.Graphics
public int Width { get { return (int)screenSize.X; } }
public int Height { get { return (int)screenSize.Y; } }
int2 mousePos;
float cursorFrame = 0f;
public static int TicksSinceLastMove = 0;
public static int2 LastMousePos;
public void Scroll(float2 delta)
{
scrollPosition = scrollPosition + delta;
}
public IEnumerable<IHandleInput> regions { get { return new IHandleInput[] { Widget.RootWidget, Game.controller }; } }
public Viewport(float2 screenSize, int2 mapStart, int2 mapEnd, Renderer renderer)
{
this.screenSize = screenSize;
@@ -55,9 +50,6 @@ namespace OpenRA.Graphics
{
Timer.Time( "DrawRegions start" );
world.WorldRenderer.palette.Update(
world.WorldActor.traits.WithInterface<IPaletteModifier>());
float2 r1 = new float2(2, -2) / screenSize;
float2 r2 = new float2(-1, 1);
@@ -68,9 +60,9 @@ namespace OpenRA.Graphics
Widget.DoDraw(world);
Timer.Time( "widgets: {0}" );
var cursorName = Widget.RootWidget.GetCursorOuter(mousePos) ?? Game.controller.ChooseCursor( world );
var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default";
var c = new Cursor(cursorName);
c.Draw((int)cursorFrame, mousePos + Location);
c.Draw((int)cursorFrame, Viewport.LastMousePos + Location);
Timer.Time( "cursors: {0}" );
renderer.RgbaSpriteRenderer.Flush();
@@ -81,31 +73,25 @@ namespace OpenRA.Graphics
Timer.Time( "endFrame: {0}" );
}
public void RefreshPalette()
{
Game.world.WorldRenderer.palette.Update(
Game.world.WorldActor.TraitsImplementing<IPaletteModifier>());
}
public void Tick()
{
cursorFrame += 0.5f;
RefreshPalette();
}
IHandleInput dragRegion = null;
public void DispatchMouseInput(World world, MouseInput mi)
public float2 ViewToWorld(int2 loc)
{
if (mi.Event == MouseInputEvent.Move)
mousePos = mi.Location;
if (dragRegion != null) {
dragRegion.HandleInput( world, mi );
if (mi.Event == MouseInputEvent.Up) dragRegion = null;
return;
}
dragRegion = regions.FirstOrDefault(r => r.HandleInput(world, mi));
if (mi.Event != MouseInputEvent.Down)
dragRegion = null;
return (1f / Game.CellSize) * (loc.ToFloat2() + Location);
}
public float2 ViewToWorld(MouseInput mi)
{
return (1f / Game.CellSize) * (new float2(mi.Location.X, mi.Location.Y) + Location);
return ViewToWorld(mi.Location);
}
public void Center(int2 loc)

View File

@@ -33,37 +33,10 @@ namespace OpenRA.Graphics
palette = new HardwarePalette(world.Map);
}
public void DrawLine(float2 start, float2 end, Color startColor, Color endColor)
{
Game.Renderer.LineRenderer.DrawLine(start,end,startColor,endColor);
}
public int GetPaletteIndex(string name) { return palette.GetPaletteIndex(name); }
public Palette GetPalette(string name) { return palette.GetPalette(name); }
public void AddPalette(string name, Palette pal) { palette.AddPalette(name, pal); }
public int GetPaletteIndex(string name)
{
return palette.GetPaletteIndex(name);
}
public Palette GetPalette(string name)
{
return palette.GetPalette(name);
}
public void AddPalette(string name, Palette pal)
{
palette.AddPalette(name, pal);
}
public void UpdatePalette(string name, Palette pal)
{
palette.UpdatePalette(name, pal);
}
void DrawSpriteList(IEnumerable<Renderable> images)
{
foreach (var image in images)
Game.Renderer.SpriteRenderer.DrawSprite(image.Sprite, image.Pos, image.Palette);
}
class SpriteComparer : IComparer<Renderable>
{
public int Compare(Renderable x, Renderable y)
@@ -125,13 +98,19 @@ namespace OpenRA.Graphics
terrainRenderer.Draw(Game.viewport);
DrawSpriteList(worldSprites);
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);
uiOverlay.Draw(world);
Game.Renderer.SpriteRenderer.Flush();
DrawBandBox();
if (Game.controller.orderGenerator != null)
Game.controller.orderGenerator.Render(world);
if (world.OrderGenerator != null)
world.OrderGenerator.RenderAfterWorld(world);
if (world.LocalPlayer != null)
world.LocalPlayer.Shroud.Draw();
@@ -140,12 +119,6 @@ namespace OpenRA.Graphics
Game.Renderer.Device.DisableScissor();
if (Game.Settings.IndexDebug)
{
bounds.Offset((int)Game.viewport.Location.X, (int)Game.viewport.Location.Y);
DrawBins(bounds);
}
Game.Renderer.LineRenderer.Flush();
}
@@ -174,25 +147,7 @@ namespace OpenRA.Graphics
}
}
void DrawBandBox()
{
var selbox = Game.controller.SelectionBox;
if (selbox == null) return;
var a = selbox.Value.First;
var b = new float2(selbox.Value.Second.X - a.X, 0);
var c = new float2(0, selbox.Value.Second.Y - a.Y);
Game.Renderer.LineRenderer.DrawLine(a, a + b, Color.White, Color.White);
Game.Renderer.LineRenderer.DrawLine(a + b, a + b + c, Color.White, Color.White);
Game.Renderer.LineRenderer.DrawLine(a + b + c, a + c, Color.White, Color.White);
Game.Renderer.LineRenderer.DrawLine(a, a + c, Color.White, Color.White);
foreach (var u in world.SelectActorsInBox(selbox.Value.First, selbox.Value.Second))
DrawSelectionBox(u, Color.Yellow, false);
}
public void DrawSelectionBox(Actor selectedUnit, Color c, bool drawHealthBar)
public void DrawSelectionBox(Actor selectedUnit, Color c)
{
var bounds = selectedUnit.GetBounds(true);
@@ -210,139 +165,7 @@ namespace OpenRA.Graphics
Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(0, -4), c, c);
Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(-4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c);
if (drawHealthBar)
{
DrawHealthBar(selectedUnit, xy, Xy);
DrawControlGroup(selectedUnit, xy);
// Only display pips and tags to the owner
if (selectedUnit.Owner == world.LocalPlayer)
{
DrawPips(selectedUnit, xY);
DrawTags(selectedUnit, new float2(.5f * (bounds.Left + bounds.Right ), xy.Y));
}
}
if (Game.Settings.PathDebug)
DrawUnitPath(selectedUnit);
}
void DrawUnitPath(Actor selectedUnit)
{
var mobile = selectedUnit.traits.WithInterface<IMove>().FirstOrDefault();
if (mobile != null)
{
var unit = selectedUnit.traits.Get<Unit>();
var alt = (unit != null)? new float2(0, -unit.Altitude) : float2.Zero;
var path = mobile.GetCurrentPath(selectedUnit);
var start = selectedUnit.CenterLocation + alt;
var c = Color.Green;
foreach (var step in path)
{
var stp = step + alt;
DrawLine(stp + new float2(-1, -1), stp + new float2(-1, 1), c, c);
DrawLine(stp + new float2(-1, 1), stp + new float2(1, 1), c, c);
DrawLine(stp + new float2(1, 1), stp + new float2(1, -1), c, c);
DrawLine(stp + new float2(1, -1), stp + new float2(-1, -1), c, c);
DrawLine(start, stp, c, c);
start = stp;
}
}
}
void DrawHealthBar(Actor selectedUnit, float2 xy, float2 Xy)
{
var c = Color.Gray;
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), xy + new float2(0, -4), c, c);
Game.Renderer.LineRenderer.DrawLine(Xy + new float2(0, -2), Xy + new float2(0, -4), c, c);
var healthAmount = (float)selectedUnit.Health / selectedUnit.Info.Traits.Get<OwnedActorInfo>().HP;
var healthColor = (healthAmount < selectedUnit.World.Defaults.ConditionRed) ? Color.Red
: (healthAmount < selectedUnit.World.Defaults.ConditionYellow) ? Color.Yellow
: Color.LimeGreen;
var healthColor2 = Color.FromArgb(
255,
healthColor.R / 2,
healthColor.G / 2,
healthColor.B / 2);
var z = float2.Lerp(xy, Xy, healthAmount);
Game.Renderer.LineRenderer.DrawLine(z + new float2(0, -4), Xy + new float2(0, -4), c, c);
Game.Renderer.LineRenderer.DrawLine(z + new float2(0, -2), Xy + new float2(0, -2), c, c);
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -3), z + new float2(0, -3), healthColor, healthColor);
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), z + new float2(0, -2), healthColor2, healthColor2);
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -4), z + new float2(0, -4), healthColor2, healthColor2);
}
// depends on the order of pips in TraitsInterfaces.cs!
static readonly string[] pipStrings = { "pip-empty", "pip-green", "pip-yellow", "pip-red", "pip-gray" };
static readonly string[] tagStrings = { "", "tag-fake", "tag-primary" };
void DrawControlGroup(Actor selectedUnit, float2 basePosition)
{
var group = Game.controller.selection.GetControlGroupForActor(selectedUnit);
if (group == null) return;
var pipImages = new Animation("pips");
pipImages.PlayFetchIndex("groups", () => (int)group);
pipImages.Tick();
Game.Renderer.SpriteRenderer.DrawSprite(pipImages.Image, basePosition + new float2(-8, 1), "chrome");
}
void DrawPips(Actor selectedUnit, float2 basePosition)
{
// If a mod wants to implement a unit with multiple pip sources, then they are placed on multiple rows
var pipxyBase = basePosition + new float2(-12, -7); // Correct for the offset in the shp file
var pipxyOffset = new float2(0, 0); // Correct for offset due to multiple columns/rows
foreach (var pips in selectedUnit.traits.WithInterface<IPips>())
{
foreach (var pip in pips.GetPips(selectedUnit))
{
if (pipxyOffset.X+5 > selectedUnit.GetBounds(false).Width)
{
pipxyOffset.X = 0;
pipxyOffset.Y -= 4;
}
var pipImages = new Animation("pips");
pipImages.PlayRepeating(pipStrings[(int)pip]);
Game.Renderer.SpriteRenderer.DrawSprite(pipImages.Image, pipxyBase + pipxyOffset, "chrome");
pipxyOffset += new float2(4, 0);
}
// Increment row
pipxyOffset.X = 0;
pipxyOffset.Y -= 5;
}
}
void DrawTags(Actor selectedUnit, float2 basePosition)
{
// If a mod wants to implement a unit with multiple tags, then they are placed on multiple rows
var tagxyBase = basePosition + new float2(-16, 2); // Correct for the offset in the shp file
var tagxyOffset = new float2(0, 0); // Correct for offset due to multiple rows
foreach (var tags in selectedUnit.traits.WithInterface<ITags>())
{
foreach (var tag in tags.GetTags())
{
if (tag == TagType.None)
continue;
var tagImages = new Animation("pips");
tagImages.PlayRepeating(tagStrings[(int)tag]);
Game.Renderer.SpriteRenderer.DrawSprite(tagImages.Image, tagxyBase + tagxyOffset, "chrome");
// Increment row
tagxyOffset.Y += 8;
}
}
}
public void DrawLocus(Color c, int2[] cells)
{
@@ -369,7 +192,7 @@ namespace OpenRA.Graphics
var prev = location + Game.CellSize * range * float2.FromAngle(0);
for (var i = 1; i <= 32; i++)
{
var pos = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * i) / 8);
var pos = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * i) / 16);
Game.Renderer.LineRenderer.DrawLine(prev, pos, c, c);
prev = pos;
}

View File

@@ -41,8 +41,10 @@ namespace OpenRA
Ctrl = (int)Keys.Control,
}
public enum KeyInputEvent { Down, Up };
public struct KeyInput
{
public KeyInputEvent Event;
public char KeyChar;
public string KeyName;
public Modifiers Modifiers;

120
OpenRA.FileFormats/Map/Map.cs → OpenRA.Game/Map.cs Normal file → Executable file
View File

@@ -15,8 +15,9 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using OpenRA.FileFormats;
namespace OpenRA.FileFormats
namespace OpenRA
{
public class Map
{
@@ -87,6 +88,14 @@ namespace OpenRA.FileFormats
Author = "Your name here";
}
class Format2ActorReference
{
public string Id;
public string Type;
public int2 Location;
public string Owner;
}
public Map(IFolder package)
{
Package = package;
@@ -100,41 +109,66 @@ namespace OpenRA.FileFormats
{
string[] loc = wp.Value.Value.Split(',');
Waypoints.Add(wp.Key, new int2(int.Parse(loc[0]), int.Parse(loc[1])));
}
// Players
if (MapFormat == 1)
{
Players.Add("Neutral", new PlayerReference("Neutral", "allies", true, true));
}
else
{
foreach (var kv in yaml["Players"].Nodes)
{
var player = new PlayerReference(kv.Value);
Players.Add(player.Name, player);
}
}
// Actors
if (MapFormat == 1)
{
int actors = 0;
foreach (var kv in yaml["Actors"].Nodes)
{
string[] vals = kv.Value.Value.Split(' ');
string[] loc = vals[2].Split(',');
var a = new ActorReference("Actor"+actors++, vals[0], new int2(int.Parse(loc[0]), int.Parse(loc[1])), "Neutral");
Actors.Add(a.Id, a);
}
}
else
{
foreach (var kv in yaml["Actors"].Nodes)
{
var a = new ActorReference(kv.Value);
Actors.Add(a.Id, a);
}
}
// Players & Actors -- this has changed several times.
// - Be backwards compatible wherever possible.
// - Loading a map then saving it out upgrades to latest.
// Minimum criteria for dropping a format:
// - There are no maps of this format left in tree
switch (MapFormat)
{
case 1:
{
Players.Add("Neutral", new PlayerReference("Neutral", "allies", true, true));
int actors = 0;
foreach (var kv in yaml["Actors"].Nodes)
{
string[] vals = kv.Value.Value.Split(' ');
string[] loc = vals[2].Split(',');
Actors.Add("Actor" + actors++, new ActorReference(vals[0])
{
new LocationInit( new int2( int.Parse( loc[ 0 ] ), int.Parse( loc[ 1 ] ) ) ),
new OwnerInit( "Neutral" ),
});
}
} break;
case 2:
{
foreach (var kv in yaml["Players"].Nodes)
{
var player = new PlayerReference(kv.Value);
Players.Add(player.Name, player);
}
foreach (var kv in yaml["Actors"].Nodes)
{
var oldActorReference = FieldLoader.Load<Format2ActorReference>(kv.Value);
Actors.Add(oldActorReference.Id, new ActorReference(oldActorReference.Type)
{
new LocationInit( oldActorReference.Location ),
new OwnerInit( oldActorReference.Owner )
});
}
} break;
case 3:
{
foreach (var kv in yaml["Players"].Nodes)
{
var player = new PlayerReference(kv.Value);
Players.Add(player.Name, player);
}
foreach (var kv in yaml["Actors"].Nodes)
Actors.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.Nodes));
} break;
default:
throw new InvalidDataException("Map format {0} is not supported.".F(MapFormat));
}
// Smudges
@@ -155,7 +189,7 @@ namespace OpenRA.FileFormats
public void Save(string filepath)
{
MapFormat = 2;
MapFormat = 3;
var root = new Dictionary<string, MiniYaml>();
foreach (var field in SimpleFields)
@@ -171,10 +205,10 @@ namespace OpenRA.FileFormats
p => FieldSaver.Save(p.Value))));
root.Add("Actors",
new MiniYaml(null, Actors.ToDictionary(
a => "ActorReference@{0}".F(a.Key),
a => FieldSaver.Save(a.Value))));
new MiniYaml( null, Actors.ToDictionary(
x => x.Key,
x => x.Value.Save() ) ) );
root.Add("Waypoints", MiniYaml.FromDictionary<string, int2>(Waypoints));
root.Add("Smudges", MiniYaml.FromList<SmudgeReference>(Smudges));
root.Add("Rules", new MiniYaml(null, Rules));
@@ -273,8 +307,8 @@ namespace OpenRA.FileFormats
{
// UID is calculated by taking an SHA1 of the yaml and binary data
// Read the relevant data into a buffer
var data = Exts.ReadAllBytes(Package.GetContent("map.yaml"))
.Concat(Exts.ReadAllBytes(Package.GetContent("map.bin"))).ToArray();
var data = Package.GetContent("map.yaml").ReadAllBytes()
.Concat(Package.GetContent("map.bin").ReadAllBytes()).ToArray();
// Take the SHA1
using (var csp = SHA1.Create())

View File

@@ -14,6 +14,7 @@ using System.IO;
using System.Net.Sockets;
using System.Threading;
using OpenRA.Server;
using OpenRA.Support;
namespace OpenRA.Network
{
@@ -115,6 +116,8 @@ namespace OpenRA.Network
{
connectionState = ConnectionState.NotConnected;
}
catch ( IOException ) { socket.Close(); }
catch (ThreadAbortException ) { socket.Close(); }
}
) { IsBackground = true };
t.Start();
@@ -145,8 +148,11 @@ namespace OpenRA.Network
disposed = true;
GC.SuppressFinalize( this );
socket.Close();
t.Abort();
if (socket != null)
socket.Client.Close();
using( new PerfSample( "Thread.Join" ))
t.Join();
}
~NetworkConnection() { Dispose(); }

View File

@@ -66,15 +66,20 @@ namespace OpenRA.Network
case "SetStance":
{
var targetPlayer = order.Player.World.players[order.TargetLocation.X];
var oldStance = order.Player.Stances[targetPlayer];
order.Player.Stances[targetPlayer] = (Stance)order.TargetLocation.Y;
if (targetPlayer == world.LocalPlayer)
world.WorldActor.Trait<Shroud>().UpdatePlayerStance(world, order.Player, oldStance, order.Player.Stances[targetPlayer]);
Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F(
order.Player.PlayerName, targetPlayer.PlayerName, (Stance)order.TargetLocation.Y));
order.Player.PlayerName, targetPlayer.PlayerName, order.Player.Stances[targetPlayer]));
break;
}
default:
{
if( !order.IsImmediate )
foreach (var t in order.Subject.traits.WithInterface<IResolveOrder>())
foreach (var t in order.Subject.TraitsImplementing<IResolveOrder>())
t.ResolveOrder(order.Subject, order);
break;
}

View File

@@ -81,22 +81,17 @@
<Compile Include="Orders\GenericSelectTarget.cs" />
<Compile Include="Server\ProtocolVersion.cs" />
<Compile Include="Traits\BaseBuilding.cs" />
<Compile Include="Traits\DetectCloaked.cs" />
<Compile Include="Traits\LintAttributes.cs" />
<Compile Include="Traits\Modifiers\FrozenUnderFog.cs" />
<Compile Include="Traits\Player\PlayerResources.cs" />
<Compile Include="Traits\Player\TechTreeCache.cs" />
<Compile Include="Traits\Modifiers\HiddenUnderFog.cs" />
<Compile Include="Traits\World\Shroud.cs" />
<Compile Include="Widgets\ChatEntryWidget.cs" />
<Compile Include="Widgets\Delegates\ConnectionDialogsDelegate.cs" />
<Compile Include="Widgets\Delegates\CreateServerMenuDelegate.cs" />
<Compile Include="Widgets\Delegates\DiplomacyDelegate.cs" />
<Compile Include="Widgets\Delegates\MainMenuButtonsDelegate.cs" />
<Compile Include="Widgets\RadarBinWidget.cs" />
<Compile Include="Widgets\Delegates\ServerBrowserDelegate.cs" />
<Compile Include="Widgets\Delegates\SettingsMenuDelegate.cs" />
<Compile Include="Widgets\MoneyBinWidget.cs" />
<Compile Include="Widgets\MapPreviewWidget.cs" />
<Compile Include="Widgets\WidgetUtils.cs" />
<Compile Include="Effects\DelayedAction.cs" />
@@ -128,10 +123,8 @@
<Compile Include="Sync.cs" />
<Compile Include="Traits\CustomSellValue.cs" />
<Compile Include="Traits\World\SpatialBins.cs" />
<Compile Include="Traits\World\ChoosePaletteOnSelect.cs" />
<Compile Include="Traits\World\Country.cs" />
<Compile Include="Actor.cs" />
<Compile Include="Controller.cs" />
<Compile Include="Cursor.cs" />
<Compile Include="GameRules\Footprint.cs" />
<Compile Include="GameRules\Rules.cs" />
@@ -181,10 +174,8 @@
<Compile Include="Traits\Production.cs" />
<Compile Include="Traits\RallyPoint.cs" />
<Compile Include="Traits\Render\RenderSimple.cs" />
<Compile Include="Traits\Cloak.cs" />
<Compile Include="Traits\TraitsInterfaces.cs" />
<Compile Include="Traits\Turreted.cs" />
<Compile Include="Traits\Unit.cs" />
<Compile Include="Traits\World\UnitInfluence.cs" />
<Compile Include="Network\UnitOrders.cs" />
<Compile Include="Traits\Util.cs" />
@@ -204,23 +195,16 @@
<Compile Include="Widgets\BackgroundWidget.cs" />
<Compile Include="Widgets\LabelWidget.cs" />
<Compile Include="Widgets\CheckboxWidget.cs" />
<Compile Include="Traits\World\GlobalDefaults.cs" />
<Compile Include="Traits\World\BibLayer.cs" />
<Compile Include="Traits\World\SmudgeLayer.cs" />
<Compile Include="Widgets\Delegates\IngameChromeDelegate.cs" />
<Compile Include="Widgets\SpecialPowerBinWidget.cs" />
<Compile Include="Widgets\Delegates\MusicPlayerDelegate.cs" />
<Compile Include="Widgets\PerfGraphWidget.cs" />
<Compile Include="Widgets\Delegates\PerfDebugDelegate.cs" />
<Compile Include="Widgets\BuildPaletteWidget.cs" />
<Compile Include="Widgets\Delegates\LobbyDelegate.cs" />
<Compile Include="Widgets\ColorBlockWidget.cs" />
<Compile Include="GameRules\MusicInfo.cs" />
<Compile Include="Widgets\PowerBinWidget.cs" />
<Compile Include="Widgets\ImageWidget.cs" />
<Compile Include="Traits\SharesCell.cs" />
<Compile Include="Traits\World\AircraftInfluence.cs" />
<Compile Include="Traits\World\HazardLayer.cs" />
<Compile Include="Widgets\TextFieldWidget.cs" />
<Compile Include="Widgets\ChatDisplayWidget.cs" />
<Compile Include="Widgets\Delegates\MapChooserDelegate.cs" />
@@ -228,13 +212,27 @@
<Compile Include="Widgets\SliderWidget.cs" />
<Compile Include="Widgets\TimerWidget.cs" />
<Compile Include="Widgets\ShpImageWidget.cs" />
<Compile Include="Widgets\OrderButtonWidget.cs" />
<Compile Include="Traits\DrawLineToTarget.cs" />
<Compile Include="Widgets\WorldInteractionControllerWidget.cs" />
<Compile Include="Widgets\ViewportScrollControllerWidget.cs" />
<Compile Include="Traits\Player\DeveloperMode.cs" />
<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" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
<Project>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</Project>
<Name>OpenRA.FileFormats</Name>
</ProjectReference>
<Compile Include="ActorInitializer.cs" />
<Compile Include="ActorReference.cs" />
<Compile Include="Map.cs" />
<Compile Include="Traits\PrimaryBuilding.cs" />
<Compile Include="Widgets\Delegates\DeveloperModeDelegate.cs" />
</ItemGroup>
<ItemGroup>

View File

@@ -29,7 +29,7 @@ namespace OpenRA.Orders
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Right)
Game.controller.CancelInputMode();
world.CancelInputMode();
return OrderInner(world, xy, mi);
}
@@ -40,7 +40,8 @@ namespace OpenRA.Orders
}
public virtual void Tick(World world) { }
public void Render(World world) { }
public void RenderAfterWorld(World world) { }
public void RenderBeforeWorld(World world) { }
public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
}
@@ -59,7 +60,7 @@ namespace OpenRA.Orders
.Any();
if (!hasStructure)
Game.controller.CancelInputMode();
world.CancelInputMode();
}
}

View File

@@ -14,9 +14,10 @@ namespace OpenRA
{
public interface IOrderGenerator
{
IEnumerable<Order> Order( World world, int2 xy, MouseInput mi );
void Tick( World world );
void Render( World world );
string GetCursor( World world, int2 xy, MouseInput mi );
IEnumerable<Order> Order(World world, int2 xy, MouseInput mi);
void Tick(World world);
void RenderBeforeWorld(World world);
void RenderAfterWorld(World world);
string GetCursor(World world, int2 xy, MouseInput mi);
}
}

View File

@@ -14,7 +14,7 @@ using OpenRA.Traits;
namespace OpenRA.Orders
{
class PlaceBuildingOrderGenerator : IOrderGenerator
public class PlaceBuildingOrderGenerator : IOrderGenerator
{
readonly Actor Producer;
readonly string Building;
@@ -29,7 +29,7 @@ namespace OpenRA.Orders
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Right)
Game.controller.CancelInputMode();
world.CancelInputMode();
return InnerOrder(world, xy, mi);
}
@@ -56,14 +56,16 @@ namespace OpenRA.Orders
public void Tick( World world )
{
var producing = Producer.traits.Get<Traits.ProductionQueue>().CurrentItem( Rules.Info[ Building ].Category );
var producing = Producer.Trait<Traits.ProductionQueue>().CurrentItem( Rules.Info[ Building ].Category );
if (producing == null || producing.Item != Building || producing.RemainingTime != 0)
Game.controller.CancelInputMode();
world.CancelInputMode();
}
public void Render( World world )
public void RenderAfterWorld( World world ) {}
public void RenderBeforeWorld(World world)
{
world.WorldRenderer.uiOverlay.DrawBuildingGrid( world, Building, BuildingInfo );
world.WorldRenderer.uiOverlay.DrawBuildingGrid(world, Building, BuildingInfo);
}
public string GetCursor(World world, int2 xy, MouseInput mi) { return "default"; }

View File

@@ -1,69 +1,65 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Orders
{
class UnitOrderGenerator : IOrderGenerator
{
public IEnumerable<Order> Order( World world, int2 xy, MouseInput mi )
{
var orders = Game.controller.selection.Actors
.Select(a => a.Order(xy, mi))
.Where(o => o != null)
.ToArray();
var actorsInvolved = orders.Select(o => o.Subject).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;
}
public void Tick( World world ) {}
public void Render( World world )
{
foreach (var a in Game.controller.selection.Actors)
{
world.WorldRenderer.DrawSelectionBox(a, Color.White, true);
if (a.Owner == world.LocalPlayer)
{
//if (a.traits.Contains<RenderRangeCircle>())
// world.WorldRenderer.DrawRangeCircle(Color.FromArgb(128, Color.Yellow),
// a.CenterLocation, (int)a.GetPrimaryWeapon().Range);
if (a.traits.Contains<DetectCloaked>())
world.WorldRenderer.DrawRangeCircle(Color.FromArgb(128, Color.LimeGreen),
a.CenterLocation, a.Info.Traits.Get<DetectCloakedInfo>().Range);
}
}
}
public string GetCursor( World world, int2 xy, MouseInput mi )
{
var c = Order(world, xy, mi)
.Select(o => o.Subject.traits.WithInterface<IOrderCursor>()
.Select(pc => pc.CursorForOrder(o.Subject, o)).FirstOrDefault(a => a != null))
.FirstOrDefault(a => a != null);
return c ??
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Orders
{
class UnitOrderGenerator : IOrderGenerator
{
public IEnumerable<Order> Order( World world, int2 xy, MouseInput mi )
{
var orders = world.Selection.Actors
.Select(a => a.Order(xy, mi))
.Where(o => o != null)
.ToArray();
var actorsInvolved = orders.Select(o => o.Subject).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;
}
public void Tick( World world ) {}
public void RenderBeforeWorld(World world)
{
foreach (var a in world.Selection.Actors)
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
t.RenderBeforeWorld(a);
}
public void RenderAfterWorld( World world )
{
foreach (var a in world.Selection.Actors)
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
t.RenderAfterWorld(a);
}
public string GetCursor( World world, int2 xy, MouseInput mi )
{
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 ??
(world.FindUnitsAtMouse(mi.Location)
.Any(a => a.Info.Traits.Contains<SelectableInfo>())
? "select" : "default");
}
}
}
.Any(a => a.Info.Traits.Contains<SelectableInfo>())
? "select" : "default");
}
}
}

View File

@@ -69,7 +69,7 @@ namespace OpenRA
{
using( new PerfSample( "find_unit_path_multiple_src" ) )
{
var mobile = self.traits.Get<Mobile>();
var mobile = self.Trait<Mobile>();
var tilesInRange = world.FindTilesInCircle(target, range)
.Where( t => mobile.CanEnterCell(t));
@@ -86,7 +86,7 @@ namespace OpenRA
return q =>
p != q &&
((p - q).LengthSquared < dist * dist) &&
(world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(q).Any(a => a.Group != self.Group));
(world.WorldActor.Trait<UnitInfluence>().GetUnitsAt(q).Any(a => a.Group != self.Group));
}
public List<int2> FindPath( PathSearch search )

View File

@@ -26,12 +26,14 @@ namespace OpenRA
public Actor ignoreBuilding;
Actor self;
public bool inReverse;
Mobile mobile;
public PathSearch(Actor self)
{
this.self = self;
world = self.World;
cellInfo = InitCellInfo();
mobile = self.Trait<Mobile>();
queue = new PriorityQueue<PathDistance>();
}
@@ -70,9 +72,14 @@ namespace OpenRA
public int2 Expand( World world )
{
var p = queue.Pop();
cellInfo[ p.Location.X, p.Location.Y ].Seen = true;
while (cellInfo[p.Location.X, p.Location.Y].Seen)
if (queue.Empty)
return p.Location;
else
p = queue.Pop();
cellInfo[p.Location.X, p.Location.Y].Seen = true;
var mobile = self.traits.Get<Mobile>();
var thisCost = mobile.MovementCostForCell(self, p.Location);
if (thisCost == float.PositiveInfinity)

View File

@@ -44,7 +44,7 @@ namespace OpenRA
World = world;
Shroud = new ShroudRenderer(this, world.Map);
PlayerActor = world.CreateActor("Player", new int2(int.MaxValue, int.MaxValue), this);
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
Index = index;
Palette = "player"+index;
@@ -64,7 +64,7 @@ namespace OpenRA
World = world;
Shroud = new ShroudRenderer(this, world.Map);
PlayerActor = world.CreateActor("Player", new int2(int.MaxValue, int.MaxValue), this);
PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
Index = client.Index;
Palette = "player"+client.Index;
@@ -89,8 +89,6 @@ namespace OpenRA
public void GiveAdvice(string advice)
{
// todo: store the condition or something.
// repeat after World.Defaults.SpeakDelay, as long as the condition holds.
Sound.PlayToPlayer(this, advice);
}

View File

@@ -18,7 +18,17 @@ namespace OpenRA
public class Selection
{
List<Actor> actors = new List<Actor>();
public void Add(World w, Actor a)
{
actors.Add(a);
foreach (var ns in w.WorldActor.TraitsImplementing<INotifySelection>())
ns.SelectionChanged();
}
public bool Contains(Actor a)
{
return actors.AsEnumerable().Contains(a);
}
public void Combine(World world, IEnumerable<Actor> newSelection, bool isCombine, bool isClick)
{
var oldSelection = actors.AsEnumerable();
@@ -32,9 +42,10 @@ namespace OpenRA
actors = (isCombine ? oldSelection.Union(newSelection) : newSelection).ToList();
var voicedUnit = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.HasVoice());
Sound.PlayVoice("Select", voicedUnit);
if (voicedUnit != null)
Sound.PlayVoice("Select", voicedUnit, voicedUnit.Owner.Country.Race);
foreach (var ns in world.WorldActor.traits.WithInterface<INotifySelection>())
foreach (var ns in world.WorldActor.TraitsImplementing<INotifySelection>())
ns.SelectionChanged();
}

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
@@ -44,8 +45,11 @@ namespace OpenRA.Server
static string masterServerUrl;
static bool isInitialPing;
public static void ServerMain(bool internetServer, string masterServerUrl, string name, int port, int extport, string[] mods, string map)
public static void ServerMain(bool internetServer, string masterServerUrl, string name, int port, int extport,
string[] mods, string map, bool cheats)
{
Log.AddChannel("server", "server.log", false, false);
isInitialPing = true;
Server.masterServerUrl = masterServerUrl;
isInternetServer = internetServer;
@@ -58,12 +62,13 @@ namespace OpenRA.Server
lobbyInfo.GlobalSettings.Mods = mods;
lobbyInfo.GlobalSettings.RandomSeed = randomSeed;
lobbyInfo.GlobalSettings.Map = map;
lobbyInfo.GlobalSettings.AllowCheats = cheats;
Console.WriteLine("Initial mods: ");
Log.Write("server", "Initial mods: ");
foreach( var m in lobbyInfo.GlobalSettings.Mods )
Console.WriteLine("- {0}", m);
Log.Write("server","- {0}", m);
Console.WriteLine("Initial map: {0}",lobbyInfo.GlobalSettings.Map);
Log.Write("server", "Initial map: {0}",lobbyInfo.GlobalSettings.Map);
try
{
@@ -82,7 +87,7 @@ namespace OpenRA.Server
checkRead.Add( listener.Server );
foreach( var c in conns ) checkRead.Add( c.socket );
Socket.Select( checkRead, null, null, MasterPingInterval * 1000000 );
Socket.Select( checkRead, null, null, MasterPingInterval * 10000 );
foreach( Socket s in checkRead )
if( s == listener.Server ) AcceptConnection();
@@ -90,6 +95,10 @@ namespace OpenRA.Server
if (Environment.TickCount - lastPing > MasterPingInterval * 1000)
PingMasterServer();
else
lock (masterServerMessages)
while (masterServerMessages.Count > 0)
SendChat(null, masterServerMessages.Dequeue());
if (conns.Count() == 0)
{
@@ -110,12 +119,6 @@ namespace OpenRA.Server
throw new InvalidOperationException("Already got 8 players");
}
static int ChooseFreePalette()
{
// TODO: Query the list of palettes from somewhere, and pick one
return 0;
}
static void AcceptConnection()
{
var newConn = new Connection { socket = listener.AcceptSocket() };
@@ -123,7 +126,7 @@ namespace OpenRA.Server
{
if (GameStarted)
{
Console.WriteLine("Rejected connection from {0}; game is already started.",
Log.Write("server", "Rejected connection from {0}; game is already started.",
newConn.socket.RemoteEndPoint);
newConn.socket.Close();
return;
@@ -138,20 +141,21 @@ namespace OpenRA.Server
newConn.socket.Send(BitConverter.GetBytes(newConn.PlayerIndex));
conns.Add(newConn);
var defaults = new GameRules.UserSettings();
lobbyInfo.Clients.Add(
new Session.Client()
{
Index = newConn.PlayerIndex,
Color1 = System.Drawing.Color.FromArgb(246,214,121),
Color2 = System.Drawing.Color.FromArgb(40,32,8),
Name = "Player {0}".F(1 + newConn.PlayerIndex),
Color1 = defaults.PlayerColor1,
Color2 = defaults.PlayerColor2,
Name = defaults.PlayerName,
Country = "random",
State = Session.ClientState.NotReady,
SpawnPoint = 0,
Team = 0,
});
Console.WriteLine("Client {0}: Accepted connection from {1}",
Log.Write("server", "Client {0}: Accepted connection from {1}",
newConn.PlayerIndex, newConn.socket.RemoteEndPoint);
SendChat(newConn, "has joined the game.");
@@ -236,32 +240,34 @@ namespace OpenRA.Server
else if (client.State == Session.ClientState.Ready)
client.State = Session.ClientState.NotReady;
Console.WriteLine("Player @{0} is {1}",
Log.Write("server", "Player @{0} is {1}",
conn.socket.RemoteEndPoint, client.State);
SyncLobbyInfo();
// start the game if everyone is ready.
if (conns.Count > 0 && conns.All(c => GetClient(c).State == Session.ClientState.Ready))
{
Console.WriteLine("All players are ready. Starting the game!");
GameStarted = true;
foreach( var c in conns )
foreach( var d in conns )
DispatchOrdersToClient( c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF } );
InterpretCommand(conn, "startgame");
return true;
}},
{ "startgame",
s =>
{
GameStarted = true;
foreach( var c in conns )
foreach( var d in conns )
DispatchOrdersToClient( c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF } );
DispatchOrders(null, 0,
new ServerOrder("StartGame", "").Serialize());
PingMasterServer();
}
DispatchOrders(null, 0,
new ServerOrder("StartGame", "").Serialize());
PingMasterServer();
return true;
}},
{ "name",
s =>
{
Console.WriteLine("Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s);
Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s);
GetClient(conn).Name = s;
SyncLobbyInfo();
return true;
@@ -270,9 +276,9 @@ namespace OpenRA.Server
s =>
{
int lag;
if (!int.TryParse(s, out lag)) { Console.WriteLine("Invalid order lag: {0}", s); return false; }
if (!int.TryParse(s, out lag)) { Log.Write("server", "Invalid order lag: {0}", s); return false; }
Console.WriteLine("Order lag is now {0} frames.", lag);
Log.Write("server", "Order lag is now {0} frames.", lag);
lobbyInfo.GlobalSettings.OrderLatency = lag;
SyncLobbyInfo();
@@ -289,7 +295,7 @@ namespace OpenRA.Server
s =>
{
int team;
if (!int.TryParse(s, out team)) { Console.WriteLine("Invalid team: {0}", s ); return false; }
if (!int.TryParse(s, out team)) { Log.Write("server", "Invalid team: {0}", s ); return false; }
GetClient(conn).Team = team;
SyncLobbyInfo();
@@ -301,7 +307,7 @@ namespace OpenRA.Server
int spawnPoint;
if (!int.TryParse(s, out spawnPoint) || spawnPoint < 0 || spawnPoint > 8) //TODO: SET properly!
{
Console.WriteLine("Invalid spawn point: {0}", s);
Log.Write("server", "Invalid spawn point: {0}", s);
return false;
}
@@ -319,8 +325,8 @@ namespace OpenRA.Server
s =>
{
var c = s.Split(',').Select(cc => int.Parse(cc)).ToArray();
GetClient(conn).Color1 = System.Drawing.Color.FromArgb(c[0],c[1],c[2]);
GetClient(conn).Color2 = System.Drawing.Color.FromArgb(c[3],c[4],c[5]);
GetClient(conn).Color1 = Color.FromArgb(c[0],c[1],c[2]);
GetClient(conn).Color2 = Color.FromArgb(c[3],c[4],c[5]);
SyncLobbyInfo();
return true;
}},
@@ -373,7 +379,7 @@ namespace OpenRA.Server
if (!dict.TryGetValue(cmdName, out a))
return false;
Console.WriteLine( "Client {0} sent server command: {1}", conn.PlayerIndex, cmd );
Log.Write("server", "Client {0} sent server command: {1}", conn.PlayerIndex, cmd );
return a(cmdValue);
}
@@ -396,11 +402,11 @@ namespace OpenRA.Server
{
if(GameStarted)
SendChatTo(conn, "Cannot change state when game started.");
else if (GetClient(conn).State == Session.ClientState.Ready && so.Data != "ready")
else if (GetClient(conn).State == Session.ClientState.Ready && !(so.Data == "ready" || so.Data == "startgame") )
SendChatTo(conn, "Cannot change state when marked as ready.");
else if (!InterpretCommand(conn, so.Data))
{
Console.WriteLine("Bad server command: {0}", so.Data);
Log.Write("server", "Bad server command: {0}", so.Data);
SendChatTo(conn, "Bad server command.");
};
}
@@ -419,8 +425,6 @@ namespace OpenRA.Server
public static void DropClient(Connection toDrop, Exception e)
{
Console.WriteLine("Client dropped: {0}.", toDrop.socket.RemoteEndPoint);
conns.Remove(toDrop);
SendChat(toDrop, "Connection Dropped");
@@ -446,38 +450,57 @@ namespace OpenRA.Server
PingMasterServer();
}
static volatile bool isBusy;
static Queue<string> masterServerMessages = new Queue<string>();
static void PingMasterServer()
{
if (wc.IsBusy || !isInternetServer) return;
var url = "ping.php?port={0}&name={1}&state={2}&players={3}&mods={4}&map={5}";
wc.DownloadDataCompleted += PingMasterServerResponse;
if (isInitialPing)
{
url += "&new=1";
isInitialPing = false;
}
else
wc.DownloadDataCompleted -= PingMasterServerResponse;
wc.DownloadDataAsync(new Uri(
masterServerUrl + url.F(
ExternalPort, Uri.EscapeUriString(Name),
GameStarted ? 2 : 1, // todo: post-game states, etc.
lobbyInfo.Clients.Count,
string.Join(",", lobbyInfo.GlobalSettings.Mods),
lobbyInfo.GlobalSettings.Map)));
if (isBusy || !isInternetServer) return;
lastPing = Environment.TickCount;
}
isBusy = true;
static void PingMasterServerResponse(object sender, DownloadDataCompletedEventArgs e)
{
string s = Encoding.UTF8.GetString(e.Result);
int gameId;
if (int.TryParse(s.Trim(), out gameId))
Game.SetGameId(gameId);
Log.Write("debug", "Game ID: {0}", gameId);
Action a = () =>
{
try
{
var url = "ping.php?port={0}&name={1}&state={2}&players={3}&mods={4}&map={5}";
if (isInitialPing) url += "&new=1";
using (var wc = new WebClient())
{
var result = wc.DownloadData(
masterServerUrl + url.F(
ExternalPort, Uri.EscapeUriString(Name),
GameStarted ? 2 : 1, // todo: post-game states, etc.
lobbyInfo.Clients.Count,
string.Join(",", lobbyInfo.GlobalSettings.Mods),
lobbyInfo.GlobalSettings.Map));
if (isInitialPing)
{
isInitialPing = false;
var s = Encoding.UTF8.GetString(result);
int gameId;
if (int.TryParse(s.Trim(), out gameId))
Game.SetGameId(gameId);
lock (masterServerMessages)
masterServerMessages.Enqueue("Master server communication established. Game ID = {0}".F(gameId));
}
}
}
catch(Exception ex)
{
Log.Write("server", ex.ToString());
lock( masterServerMessages )
masterServerMessages.Enqueue( "Master server communication failed." );
}
isBusy = false;
};
a.BeginInvoke(null, null);
}
}
}

View File

@@ -28,7 +28,7 @@ namespace OpenRA
public ShroudRenderer(Player owner, Map map)
{
this.shroud = owner.World.WorldActor.traits.Get<Traits.Shroud>();
this.shroud = owner.World.WorldActor.Trait<Traits.Shroud>();
this.map = map;
sprites = new Sprite[map.MapSize.X, map.MapSize.Y];

View File

@@ -21,10 +21,10 @@ namespace OpenRA
{
static ISoundEngine soundEngine;
static Cache<string, ISoundSource> sounds;
static ISoundSource rawSource;
static ISound music;
static bool paused;
static bool stopped;
static ISound video;
static string currentMusic;
static ISoundSource LoadSound(string filename)
{
@@ -32,13 +32,18 @@ namespace OpenRA
return soundEngine.AddSoundSourceFromMemory(data, 1, 16, 22050);
}
static ISoundSource LoadSoundRaw(byte[] rawData)
{
return soundEngine.AddSoundSourceFromMemory(rawData, 1, 16, 22050);
}
public static void Initialize()
{
soundEngine = new OpenAlSoundEngine();
sounds = new Cache<string, ISoundSource>(LoadSound);
music = null;
paused = false;
stopped = false;
currentMusic = null;
video = null;
}
public static void SetListenerPosition(float2 position) { soundEngine.SetListenerPosition(position); }
@@ -73,36 +78,59 @@ namespace OpenRA
Play(name, pos);
}
public static void PlayVideo(byte[] raw)
{
rawSource = LoadSoundRaw(raw);
video = soundEngine.Play2D(rawSource, false, true, float2.Zero, SoundVolume);
}
public static void PlayVideo()
{
if (video != null)
soundEngine.PauseSound(video, false);
}
public static void PauseVideo()
{
if (video != null)
soundEngine.PauseSound(video, true);
}
public static void StopVideo()
{
if (video != null)
soundEngine.StopSound(video);
}
public static void PlayMusic(string name)
{
if (name == "" || name == null)
return;
if (music != null)
soundEngine.StopSound(music);
if (name == currentMusic && music != null)
{
soundEngine.PauseSound(music, false);
return;
}
StopMusic();
currentMusic = name;
var sound = sounds[name];
music = soundEngine.Play2D(sound, true, true, float2.Zero, MusicVolume);
}
public static bool MusicPaused
public static void StopMusic()
{
get { return paused; }
set {
paused = value;
if (music != null)
soundEngine.PauseSound(music, paused);
}
if (music != null)
soundEngine.StopSound(music);
currentMusic = null;
}
public static bool MusicStopped
public static void PauseMusic()
{
get { return stopped; }
set {
stopped = value;
if (music != null && stopped)
soundEngine.StopSound(music);
}
if (music != null)
soundEngine.PauseSound(music, true);
}
public static float GlobalVolume
@@ -117,7 +145,7 @@ namespace OpenRA
set
{
Game.Settings.SoundVolume = value;
soundEngine.SetSoundVolume(value, music);
soundEngine.SetSoundVolume(value, music, video);
}
}
@@ -132,8 +160,29 @@ namespace OpenRA
}
}
public static float VideoVolume
{
get { return Game.Settings.VideoVolume; }
set
{
Game.Settings.VideoVolume = value;
if (video != null)
video.Volume = value;
}
}
public static float MusicSeekPosition
{
get { return (music != null)? music.SeekPosition : 0; }
}
public static float VideoSeekPosition
{
get { return (video != null)? video.SeekPosition : 0; }
}
// Returns true if it played a phrase
public static bool PlayVoice(string phrase, Actor voicedUnit)
public static bool PlayVoice(string phrase, Actor voicedUnit, string variant)
{
if (voicedUnit == null) return false;
if (phrase == null) return false;
@@ -147,20 +196,10 @@ namespace OpenRA
var clip = vi.Pools.Value[phrase].GetNext();
if (clip == null)
return false;
if (clip.Contains(".")) /* no variants! */
{
Play(clip);
return true;
}
// todo: fix this
var variants = (voicedUnit.Owner.Country.Race == "allies")
? vi.AlliedVariants : vi.SovietVariants;
var variant = variants[voicedUnit.ActorID % variants.Length];
Play(clip + variant);
var variantext = (vi.Variants.ContainsKey(variant) && !vi.DisableVariants.Contains(phrase))?
vi.Variants[variant][voicedUnit.ActorID % vi.Variants.Count] : vi.DefaultVariant;
Play(clip + variantext);
return true;
}
}
@@ -175,13 +214,14 @@ namespace OpenRA
void SetAllSoundsPaused(bool paused);
void StopAllSounds();
void SetListenerPosition(float2 position);
void SetSoundVolume(float volume, ISound music);
void SetSoundVolume(float volume, ISound music, ISound video);
}
interface ISoundSource {}
interface ISound
{
float Volume { get; set; }
float SeekPosition { get; }
}
class OpenAlSoundEngine : ISoundEngine
@@ -288,14 +328,15 @@ namespace OpenRA
}
}
public void SetSoundVolume(float volume, ISound music)
public void SetSoundVolume(float volume, ISound music, ISound video)
{
var sounds = sourcePool.Select(s => s.Key).Where( b =>
{
int state;
Al.alGetSourcei(b, Al.AL_SOURCE_STATE, out state);
return ((state == Al.AL_PLAYING || state == Al.AL_PAUSED) &&
((music != null)? b != ((OpenAlSound) music).source : true));
((music != null)? b != ((OpenAlSound) music).source : true) &&
((video != null)? b != ((OpenAlSound) video).source : true));
}).ToList();
foreach (var s in sounds)
{
@@ -371,7 +412,6 @@ namespace OpenRA
Al.alSourcef(source, Al.AL_REFERENCE_DISTANCE, 200);
Al.alSourcef(source, Al.AL_MAX_DISTANCE, 1500);
Volume = volume;
Al.alSourcePlay(source);
}
@@ -384,5 +424,15 @@ namespace OpenRA
Al.alSourcef(source, Al.AL_GAIN, volume = value);
}
}
public float SeekPosition
{
get
{
float pos;
Al.alGetSourcef(source, Al.AL_SAMPLE_OFFSET, out pos);
return pos/22050f;
}
}
}
}

View File

@@ -10,7 +10,7 @@
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Activities
namespace OpenRA.Traits.Activities
{
public class Drag : IActivity
{

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Traits.Activities
int2? destination;
int nearEnough;
public List<int2> path;
Func<Actor, List<int2>> getPath;
Func<Actor, Mobile, List<int2>> getPath;
public Actor ignoreBuilding;
MovePart move;
@@ -40,8 +40,8 @@ namespace OpenRA.Traits.Activities
public Move( int2 destination, int nearEnough )
: this()
{
this.getPath = self => self.World.PathFinder.FindUnitPath(
self.Location, destination, self );
this.getPath = (self,mobile) => self.World.PathFinder.FindUnitPath(
mobile.toCell, destination, self );
this.destination = destination;
this.nearEnough = nearEnough;
}
@@ -49,10 +49,10 @@ namespace OpenRA.Traits.Activities
public Move(int2 destination, Actor ignoreBuilding)
: this()
{
this.getPath = self =>
this.getPath = (self,mobile) =>
self.World.PathFinder.FindPath(
PathSearch.FromPoint( self, self.Location, destination, false )
.WithCustomBlocker( self.World.PathFinder.AvoidUnitsNear( self.Location, 4, self ))
PathSearch.FromPoint( self, mobile.toCell, destination, false )
.WithCustomBlocker( self.World.PathFinder.AvoidUnitsNear( mobile.toCell, 4, self ))
.WithIgnoredBuilding( ignoreBuilding ));
this.destination = destination;
@@ -63,8 +63,8 @@ namespace OpenRA.Traits.Activities
public Move( Actor target, int range )
: this()
{
this.getPath = self => self.World.PathFinder.FindUnitPathToRange(
self.Location, target.Location,
this.getPath = (self,mobile) => self.World.PathFinder.FindUnitPathToRange(
mobile.toCell, target.Location,
range, self );
this.destination = null;
this.nearEnough = range;
@@ -73,8 +73,8 @@ namespace OpenRA.Traits.Activities
public Move(Target target, int range)
: this()
{
this.getPath = self => self.World.PathFinder.FindUnitPathToRange(
self.Location, Util.CellContaining(target.CenterLocation),
this.getPath = (self,mobile) => self.World.PathFinder.FindUnitPathToRange(
mobile.toCell, Util.CellContaining(target.CenterLocation),
range, self);
this.destination = null;
this.nearEnough = range;
@@ -83,15 +83,14 @@ namespace OpenRA.Traits.Activities
public Move(Func<List<int2>> getPath)
: this()
{
this.getPath = _ => getPath();
this.getPath = (_1,_2) => getPath();
this.destination = null;
this.nearEnough = 0;
}
public IActivity Tick( Actor self )
{
var unit = self.traits.Get<Unit>();
var mobile = self.traits.Get<Mobile>();
var mobile = self.Trait<Mobile>();
if( move != null )
{
@@ -99,7 +98,7 @@ namespace OpenRA.Traits.Activities
return this;
}
if (destination == self.Location)
if (destination == mobile.toCell)
return NextActivity;
if( path == null )
@@ -110,7 +109,7 @@ namespace OpenRA.Traits.Activities
return this;
}
path = getPath( self ).TakeWhile( a => a != self.Location ).ToList();
path = getPath( self, mobile ).TakeWhile( a => a != mobile.toCell ).ToList();
SanityCheckPath( mobile );
}
@@ -127,8 +126,8 @@ namespace OpenRA.Traits.Activities
return this;
int2 dir = nextCell.Value - mobile.fromCell;
var firstFacing = Util.GetFacing( dir, unit.Facing );
if( firstFacing != unit.Facing )
var firstFacing = Util.GetFacing( dir, mobile.Facing );
if( firstFacing != mobile.Facing )
{
path.Add( nextCell.Value );
@@ -140,8 +139,8 @@ namespace OpenRA.Traits.Activities
move = new MoveFirstHalf(
Util.CenterOfCell( mobile.fromCell ),
Util.BetweenCells( mobile.fromCell, mobile.toCell ),
unit.Facing,
unit.Facing,
mobile.Facing,
mobile.Facing,
0 );
move.TickMove( self, mobile, this );
@@ -166,10 +165,10 @@ namespace OpenRA.Traits.Activities
void NudgeBlocker(Actor self, int2 nextCell)
{
var blocker = self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(nextCell).FirstOrDefault();
var blocker = self.World.WorldActor.Trait<UnitInfluence>().GetUnitsAt(nextCell).FirstOrDefault();
if (blocker == null) return;
var nudge = blocker.traits.GetOrDefault<INudge>();
var nudge = blocker.TraitOrDefault<INudge>();
if (nudge != null)
nudge.OnNudge(blocker, self);
}
@@ -202,13 +201,10 @@ namespace OpenRA.Traits.Activities
if (--waitTicksRemaining >= 0)
return null;
//self.World.WorldActor.traits.Get<UnitInfluence>().Remove( self, mobile );
mobile.RemoveInfluence();
var newPath = getPath(self).TakeWhile(a => a != self.Location).ToList();
//self.World.WorldActor.traits.Get<UnitInfluence>().Add( self, mobile );
var newPath = getPath( self, mobile ).TakeWhile(a => a != mobile.toCell).ToList();
mobile.AddInfluence();
if (newPath.Count != 0)
path = newPath;
@@ -245,7 +241,7 @@ namespace OpenRA.Traits.Activities
public void TickMove( Actor self, Mobile mobile, Move parent )
{
moveFraction += (int)mobile.MovementSpeedForCell(self, self.Location);
moveFraction += (int)mobile.MovementSpeedForCell(self, mobile.toCell);
if( moveFraction >= moveFractionTotal )
moveFraction = moveFractionTotal;
UpdateCenterLocation( self, mobile );
@@ -259,15 +255,14 @@ namespace OpenRA.Traits.Activities
void UpdateCenterLocation( Actor self, Mobile mobile )
{
var unit = self.traits.Get<Unit>();
var frac = (float)moveFraction / moveFractionTotal;
self.CenterLocation = float2.Lerp( from, to, frac );
if( moveFraction >= moveFractionTotal )
unit.Facing = toFacing & 0xFF;
mobile.Facing = toFacing & 0xFF;
else
unit.Facing = ( fromFacing + ( toFacing - fromFacing ) * moveFraction / moveFractionTotal ) & 0xFF;
mobile.Facing = ( fromFacing + ( toFacing - fromFacing ) * moveFraction / moveFractionTotal ) & 0xFF;
}
protected abstract MovePart OnComplete( Actor self, Mobile mobile, Move parent );
@@ -282,8 +277,6 @@ namespace OpenRA.Traits.Activities
protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent )
{
var unit = self.traits.Get<Unit>();
var nextCell = parent.PopPath( self, mobile );
if( nextCell != null )
{
@@ -292,8 +285,8 @@ namespace OpenRA.Traits.Activities
var ret = new MoveFirstHalf(
Util.BetweenCells( mobile.fromCell, mobile.toCell ),
Util.BetweenCells( mobile.toCell, nextCell.Value ),
unit.Facing,
Util.GetNearestFacing( unit.Facing, Util.GetFacing( nextCell.Value - mobile.toCell, unit.Facing ) ),
mobile.Facing,
Util.GetNearestFacing( mobile.Facing, Util.GetFacing( nextCell.Value - mobile.toCell, mobile.Facing ) ),
moveFraction - moveFractionTotal );
mobile.fromCell = mobile.toCell;
mobile.toCell = nextCell.Value;
@@ -305,8 +298,8 @@ namespace OpenRA.Traits.Activities
var ret2 = new MoveSecondHalf(
Util.BetweenCells( mobile.fromCell, mobile.toCell ),
Util.CenterOfCell( mobile.toCell ),
unit.Facing,
unit.Facing,
mobile.Facing,
mobile.Facing,
moveFraction - moveFractionTotal );
mobile.fromCell = mobile.toCell;
return ret2;

View File

@@ -22,12 +22,13 @@ namespace OpenRA.Traits.Activities
{
var csv = self.Info.Traits.GetOrDefault<CustomSellValueInfo>();
var cost = csv != null ? csv.Value : self.Info.Traits.Get<ValuedInfo>().Cost;
var hp = self.Info.Traits.Get<OwnedActorInfo>().HP;
var refund = self.World.Defaults.RefundPercent * self.Health * cost / hp;
var health = self.TraitOrDefault<Health>();
var refundFraction = self.Info.Traits.Get<BuildingInfo>().RefundPercent * (health == null ? 1f : health.HPFraction);
self.Owner.PlayerActor.traits.Get<PlayerResources>().GiveCash((int)refund);
self.Health = 0;
foreach (var ns in self.traits.WithInterface<INotifySold>())
self.Owner.PlayerActor.Trait<PlayerResources>().GiveCash((int)(refundFraction * cost));
foreach (var ns in self.TraitsImplementing<INotifySold>())
ns.Sold(self);
self.World.AddFrameEndTask( _ => self.World.Remove( self ) );
}
@@ -36,10 +37,10 @@ namespace OpenRA.Traits.Activities
{
if( !started )
{
framesRemaining = self.traits.Get<RenderSimple>().anim.HasSequence("make")
? self.traits.Get<RenderSimple>().anim.GetSequence( "make" ).Length : 0;
framesRemaining = self.Trait<RenderSimple>().anim.HasSequence("make")
? self.Trait<RenderSimple>().anim.GetSequence( "make" ).Length : 0;
foreach( var ns in self.traits.WithInterface<INotifySold>() )
foreach( var ns in self.TraitsImplementing<INotifySold>() )
ns.Selling( self );
started = true;

View File

@@ -8,12 +8,13 @@
*/
#endregion
using System.Linq;
namespace OpenRA.Traits.Activities
{
public class Turn : IActivity
{
public IActivity NextActivity { get; set; }
int desiredFacing;
public Turn( int desiredFacing )
@@ -23,20 +24,18 @@ namespace OpenRA.Traits.Activities
public IActivity Tick( Actor self )
{
var unit = self.traits.Get<Unit>();
var facing = self.Trait<IFacing>();
if( desiredFacing == unit.Facing )
if( desiredFacing == facing.Facing )
return NextActivity;
facing.Facing = Util.TickFacing(facing.Facing, desiredFacing, facing.ROT);
Util.TickFacing( ref unit.Facing, desiredFacing, self.Info.Traits.Get<UnitInfo>().ROT );
return this;
}
public void Cancel( Actor self )
{
var unit = self.traits.Get<Unit>();
desiredFacing = unit.Facing;
desiredFacing = self.Trait<IFacing>().Facing;
NextActivity = null;
}
}

View File

@@ -11,6 +11,6 @@
namespace OpenRA.Traits
{
/* tag trait for "bases": mcv/fact */
class BaseBuildingInfo : TraitInfo<BaseBuilding> { }
class BaseBuilding { }
public class BaseBuildingInfo : TraitInfo<BaseBuilding> { }
public class BaseBuilding { }
}

View File

@@ -18,28 +18,18 @@ using OpenRA.Traits.Activities;
namespace OpenRA.Traits
{
public class OwnedActorInfo
{
public readonly int HP = 0;
public readonly ArmorType Armor = ArmorType.none;
public readonly bool Crewed = false; // replace with trait?
public readonly int Sight = 0;
public readonly bool WaterBound = false;
public readonly string TargetType = "Ground";
}
public class BuildingInfo : OwnedActorInfo, ITraitInfo
public class BuildingInfo : ITraitInfo
{
public readonly int Power = 0;
public readonly bool BaseNormal = true;
public readonly bool WaterBound = false;
public readonly int Adjacent = 2;
public readonly bool Capturable = false;
public readonly bool Repairable = true;
public readonly string Footprint = "x";
public readonly string[] Produces = { }; // does this go somewhere else?
public readonly int2 Dimensions = new int2(1, 1);
public readonly bool Unsellable = false;
public readonly float RefundPercent = 0.5f;
public readonly string[] BuildSounds = {"placbldg.aud", "build5.aud"};
public readonly string[] SellSounds = {"cashturn.aud"};
public readonly string DamagedSound = "kaboom1.aud";
@@ -48,24 +38,22 @@ namespace OpenRA.Traits
public object Create(ActorInitializer init) { return new Building(init); }
}
public class Building : INotifyDamage, IResolveOrder, ITick, IRenderModifier, IOccupySpace, IRadarSignature
public class Building : INotifyDamage, IResolveOrder, IRenderModifier, IOccupySpace
{
readonly Actor self;
public readonly BuildingInfo Info;
[Sync]
readonly int2 topLeft;
[Sync]
bool isRepairing = false;
public bool Disabled
{
get { return self.traits.WithInterface<IDisable>().Any(t => t.Disabled); }
get { return self.TraitsImplementing<IDisable>().Any(t => t.Disabled); }
}
public Building(ActorInitializer init)
{
this.self = init.self;
this.topLeft = init.location;
this.topLeft = init.Get<LocationInit,int2>();
Info = self.Info.Traits.Get<BuildingInfo>();
self.CenterLocation = Game.CellSize
* ((float2)topLeft + .5f * (float2)Info.Dimensions);
@@ -73,15 +61,17 @@ namespace OpenRA.Traits
public int GetPowerUsage()
{
var modifier = self.traits
.WithInterface<IPowerModifier>()
var modifier = self
.TraitsImplementing<IPowerModifier>()
.Select(t => t.GetPowerModifier())
.Product();
var maxHP = self.Info.Traits.Get<BuildingInfo>().HP;
if (Info.Power > 0)
return (int)(modifier*(self.Health * Info.Power) / maxHP);
{
var health = self.TraitOrDefault<Health>();
var healthFraction = (health == null) ? 1f : health.HPFraction;
return (int)(modifier * healthFraction * Info.Power);
}
else
return (int)(modifier * Info.Power);
}
@@ -90,7 +80,7 @@ namespace OpenRA.Traits
{
if (e.DamageState == DamageState.Dead)
{
self.World.WorldActor.traits.Get<ScreenShaker>().AddEffect(10, self.CenterLocation, 1);
self.World.WorldActor.Trait<ScreenShaker>().AddEffect(10, self.CenterLocation, 1);
Sound.Play(Info.DestroyedSound, self.CenterLocation);
}
}
@@ -102,44 +92,6 @@ namespace OpenRA.Traits
self.CancelActivity();
self.QueueActivity(new Sell());
}
if (order.OrderString == "Repair")
{
isRepairing = !isRepairing;
}
}
int remainingTicks;
public void Tick(Actor self)
{
if (!isRepairing) return;
if (remainingTicks == 0)
{
var csv = self.Info.Traits.GetOrDefault<CustomSellValueInfo>();
var buildingValue = csv != null ? csv.Value : self.Info.Traits.Get<ValuedInfo>().Cost;
var maxHP = self.Info.Traits.Get<BuildingInfo>().HP;
var costPerHp = (self.World.Defaults.RepairPercent * buildingValue) / maxHP;
var hpToRepair = Math.Min(self.World.Defaults.RepairStep, maxHP - self.Health);
var cost = (int)Math.Ceiling(costPerHp * hpToRepair);
if (!self.Owner.PlayerActor.traits.Get<PlayerResources>().TakeCash(cost))
{
remainingTicks = 1;
return;
}
self.World.AddFrameEndTask(w => w.Add(new RepairIndicator(self)));
self.InflictDamage(self, -hpToRepair, null);
if (self.Health == maxHP)
{
isRepairing = false;
return;
}
remainingTicks = (int)(self.World.Defaults.RepairRate * 60 * 25);
}
else
--remainingTicks;
}
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
@@ -161,23 +113,5 @@ namespace OpenRA.Traits
{
return Footprint.UnpathableTiles( self.Info.Name, Info, TopLeft );
}
public IEnumerable<int2> RadarSignatureCells(Actor self)
{
foreach (var mod in self.traits.WithInterface<IRadarVisibilityModifier>())
if (!mod.VisibleOnRadar(self))
return new int2[] {};
return Footprint.Tiles(self);
}
public Color RadarSignatureColor(Actor self)
{
var mod = self.traits.WithInterface<IRadarColorModifier>().FirstOrDefault();
if (mod != null)
return mod.RadarColorOverride(self);
return self.Owner.Color;
}
}
}

View File

@@ -0,0 +1,70 @@
#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 OpenRA.Traits.Activities;
namespace OpenRA.Traits
{
public class DrawLineToTargetInfo : ITraitInfo
{
public readonly int Ticks = 60;
public virtual object Create(ActorInitializer init) { return new DrawLineToTarget(this); }
}
public class DrawLineToTarget : IPostRenderSelection
{
DrawLineToTargetInfo Info;
public DrawLineToTarget(DrawLineToTargetInfo info)
{
this.Info = info;
}
Target target;
int lifetime;
Color c;
public void SetTarget(Actor self, Target target, Color c)
{
this.target = target;
lifetime = Info.Ticks;
this.c = c;
}
public void SetTargetSilently(Actor self, Target target, Color c)
{
this.target = target;
this.c = c;
}
public void RenderAfterWorld(Actor self)
{
if (self.IsIdle) return;
var force = Game.GetModifierKeys().HasModifier(Modifiers.Alt);
if ((lifetime <= 0 || --lifetime <= 0) && !force)
return;
var p = target.CenterLocation;
Game.Renderer.LineRenderer.DrawLine(self.CenterLocation, p, c, c);
for (bool b = false; !b; p = self.CenterLocation, b = true)
{
Game.Renderer.LineRenderer.DrawLine(p + new float2(-1, -1), p + new float2(-1, 1), c, c);
Game.Renderer.LineRenderer.DrawLine(p + new float2(-1, 1), p + new float2(1, 1), c, c);
Game.Renderer.LineRenderer.DrawLine(p + new float2(1, 1), p + new float2(1, -1), c, c);
Game.Renderer.LineRenderer.DrawLine(p + new float2(1, -1), p + new float2(-1, -1), c, c);
}
Game.Renderer.LineRenderer.Flush();
}
}
}

View File

@@ -0,0 +1,167 @@
#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.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Traits.Activities;
using OpenRA.GameRules;
using OpenRA.FileFormats;
namespace OpenRA.Traits
{
public class HealthInfo : ITraitInfo
{
public readonly int HP = 0;
public readonly ArmorType Armor = ArmorType.none;
public virtual object Create(ActorInitializer init) { return new Health(init, this); }
}
public enum DamageState { Undamaged, Light, Medium, Heavy, Critical, Dead };
public class Health
{
public readonly HealthInfo Info;
[Sync]
int hp;
public Health(ActorInitializer init, HealthInfo info)
{
Info = info;
MaxHP = info.HP;
hp = init.Contains<HealthInit>() ? (int)(init.Get<HealthInit, float>()*MaxHP) : MaxHP;
}
public int HP { get { return hp; } }
public readonly int MaxHP;
public float HPFraction
{
get { return hp * 1f / MaxHP; }
}
public bool IsDead { get { return hp <= 0; } }
public bool RemoveOnDeath = true;
public DamageState DamageState
{
get
{
if (hp <= 0)
return DamageState.Dead;
if (hp < MaxHP * 0.25f)
return DamageState.Critical;
if (hp < MaxHP * 0.5f)
return DamageState.Heavy;
if (hp < MaxHP * 0.75f)
return DamageState.Medium;
if (hp == MaxHP)
return DamageState.Undamaged;
return DamageState.Light;
}
}
public void InflictDamage(Actor self, Actor attacker, int damage, WarheadInfo warhead)
{
if (IsDead) return; /* overkill! don't count extra hits as more kills! */
var oldState = this.DamageState;
/* apply the damage modifiers, if we have any. */
var modifier = (float)self.TraitsImplementing<IDamageModifier>()
.Select(t => t.GetDamageModifier(warhead)).Product();
damage = (int)(damage * modifier);
hp -= damage;
if (hp <= 0)
{
hp = 0;
attacker.Owner.Kills++;
self.Owner.Deaths++;
if (RemoveOnDeath)
self.World.AddFrameEndTask(w => w.Remove(self));
Log.Write("debug", "{0} #{1} killed by {2} #{3}", self.Info.Name, self.ActorID, attacker.Info.Name, attacker.ActorID);
}
if (hp > MaxHP) hp = MaxHP;
foreach (var nd in self.TraitsImplementing<INotifyDamage>())
nd.Damaged(self, new AttackInfo
{
Attacker = attacker,
Damage = damage,
DamageState = this.DamageState,
PreviousDamageState = oldState,
DamageStateChanged = this.DamageState != oldState,
Warhead = warhead
});
}
}
public class HealthInit : IActorInit<float>
{
[FieldFromYamlKey]
public readonly float value = 1f;
public HealthInit() { }
public HealthInit( float init )
{
value = init;
}
public float Value( World world )
{
return value;
}
}
public static class HealthExts
{
public static bool IsDead(this Actor self)
{
var health = self.TraitOrDefault<Health>();
return (health == null) ? true : health.IsDead;
}
public static DamageState GetDamageState(this Actor self)
{
var health = self.TraitOrDefault<Health>();
return (health == null) ? DamageState.Undamaged : health.DamageState;
}
public static void InflictDamage(this Actor self, Actor attacker, int damage, WarheadInfo warhead)
{
var health = self.TraitOrDefault<Health>();
if (health == null) return;
health.InflictDamage(self, attacker, damage, warhead);
}
public static void Kill(this Actor self, Actor attacker)
{
var health = self.TraitOrDefault<Health>();
if (health == null) return;
health.InflictDamage(self, attacker, health.HP, null);
}
}
}

View File

@@ -10,25 +10,30 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Traits.Activities;
using OpenRA.FileFormats;
namespace OpenRA.Traits
{
public class MobileInfo : ITraitInfo, ITraitPrerequisite<UnitInfo>
public class MobileInfo : ITraitInfo
{
public readonly string[] TerrainTypes;
public readonly float[] TerrainSpeeds;
public readonly string[] TerrainCostOverrides;
public readonly float[] TerrainCosts;
public readonly string[] Crushes;
public readonly int WaitAverage = 60;
public readonly int WaitSpread = 20;
public readonly int InitialFacing = 128;
public readonly int ROT = 255;
public readonly int Speed = 1;
public virtual object Create(ActorInitializer init) { return new Mobile(init, this); }
}
public class Mobile : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice, IOccupySpace, IMove, INudge
public class Mobile : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice, IOccupySpace, IMove, IFacing, INudge
{
public readonly Actor self;
public readonly MobileInfo Info;
@@ -36,6 +41,13 @@ namespace OpenRA.Traits
public readonly Dictionary<string,float> TerrainSpeed;
[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
{
@@ -57,22 +69,47 @@ namespace OpenRA.Traits
AddInfluence();
}
Shroud shroud;
UnitInfluence uim;
BuildingInfluence bim;
bool canShareCell;
public Mobile(ActorInitializer init, MobileInfo info)
{
this.self = init.self;
this.Info = info;
this.__fromCell = this.__toCell = init.location;
AddInfluence();
shroud = self.World.WorldActor.Trait<Shroud>();
uim = self.World.WorldActor.Trait<UnitInfluence>();
bim = self.World.WorldActor.Trait<BuildingInfluence>();
canShareCell = self.HasTrait<SharesCell>();
if (init.Contains<LocationInit>())
{
this.__fromCell = this.__toCell = init.Get<LocationInit,int2>();
AddInfluence();
}
this.Facing = init.Contains<FacingInit>() ? init.Get<FacingInit,int>() : info.InitialFacing;
this.Altitude = init.Contains<AltitudeInit>() ? init.Get<AltitudeInit,int>() : 0;
TerrainCost = new Dictionary<string, float>();
TerrainSpeed = new Dictionary<string, float>();
if (info.TerrainTypes.Count() != info.TerrainSpeeds.Count())
throw new InvalidOperationException("Mobile TerrainType/TerrainSpeed length missmatch");
throw new InvalidOperationException("Mobile TerrainType/TerrainSpeed length mismatch");
if (info.TerrainCostOverrides != null)
for (int i = 0; i < info.TerrainCostOverrides.Count(); i++)
{
TerrainCost.Add(info.TerrainCostOverrides[i], info.TerrainCosts[i]);
}
for (int i = 0; i < info.TerrainTypes.Count(); i++)
{
TerrainCost.Add(info.TerrainTypes[i], 1f/info.TerrainSpeeds[i]);
{
if (!TerrainCost.ContainsKey(info.TerrainTypes[i]))
TerrainCost.Add(info.TerrainTypes[i], 1f/info.TerrainSpeeds[i]);
TerrainSpeed.Add(info.TerrainTypes[i], info.TerrainSpeeds[i]);
}
}
@@ -96,7 +133,7 @@ namespace OpenRA.Traits
if (!mi.Modifiers.HasModifier(Modifiers.Alt)) return null;
if (!CanEnterCell(underCursor.Location, null, true)) return null;
}
if (MovementSpeedForCell(self, self.Location) == 0) return null; /* allow disabling move orders from modifiers */
if (MovementSpeedForCell(self, toCell) == 0) return null; /* allow disabling move orders from modifiers */
if (xy == toCell) return null;
return new Order("Move", self, xy, mi.Modifiers.HasModifier(Modifiers.Shift));
@@ -106,10 +143,16 @@ namespace OpenRA.Traits
{
if (order.OrderString == "Move")
{
if (self.traits.GetOrDefault<IMove>().CanEnterCell(order.TargetLocation))
if (CanEnterCell(order.TargetLocation))
{
if (self.Owner == self.World.LocalPlayer)
self.World.AddFrameEndTask(w => w.Add(new MoveFlash(self.World, order.TargetLocation)));
self.World.AddFrameEndTask(w =>
{
w.Add(new MoveFlash(self.World, order.TargetLocation));
var line = self.TraitOrDefault<DrawLineToTarget>();
if (line != null)
line.SetTarget(self, Target.FromOrder(order), Color.Green);
});
if( !order.Queued ) self.CancelActivity();
self.QueueActivity(new Activities.Move(order.TargetLocation, 8));
@@ -122,12 +165,14 @@ namespace OpenRA.Traits
if (order.OrderString != "Move")
return null;
return (CanEnterCell(order.TargetLocation)) ? "move" : "move-blocked";
var xy = order.TargetLocation;
return (!shroud.exploredCells[xy.X, xy.Y] || CanEnterCell(xy)) ? "move" : "move-blocked";
}
public string VoicePhraseForOrder(Actor self, Order order)
{
return (order.OrderString == "Move") ? "Move" : null;
var xy = order.TargetLocation;
return (order.OrderString == "Move" && (!shroud.exploredCells[xy.X, xy.Y] || CanEnterCell(xy))) ? "Move" : null;
}
public int2 TopLeft { get { return toCell; } }
@@ -145,84 +190,84 @@ namespace OpenRA.Traits
{
return CanEnterCell(p, null, true);
}
public virtual bool CanEnterCell(int2 cell, Actor ignoreActor, bool checkTransientActors)
{
if (MovementCostForCell(self, cell) == float.PositiveInfinity)
return false;
// Check for buildings
var building = self.World.WorldActor.traits.Get<BuildingInfluence>().GetBuildingBlocking(cell);
var building = bim.GetBuildingBlocking(cell);
if (building != null && building != ignoreActor)
{
if (Info.Crushes == null)
return false;
var crushable = building.traits.WithInterface<ICrushable>();
var crushable = building.TraitsImplementing<ICrushable>();
if (crushable.Count() == 0)
return false;
if (!crushable.Any(b => b.CrushClasses.Intersect(Info.Crushes).Any()))
return false;
}
// Check mobile actors
if (checkTransientActors)
if (checkTransientActors && uim.AnyUnitsAt(cell))
{
var canShare = self.traits.Contains<SharesCell>();
var actors = self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(cell).Where(a => a != self && a != ignoreActor);
var nonshareable = actors.Where(a => !(canShare && a.traits.Contains<SharesCell>()));
var shareable = actors.Where(a => canShare && a.traits.Contains<SharesCell>());
// only allow 5 in a cell
if (shareable.Count() >= 5)
return false;
var actors = uim.GetUnitsAt(cell).Where(a => a != self && a != ignoreActor).ToArray();
var nonshareable = canShareCell ? actors : actors.Where(a => !a.HasTrait<SharesCell>()).ToArray();
if (canShareCell)
{
var shareable = actors.Where(a => a.HasTrait<SharesCell>());
// only allow 5 in a cell
if (shareable.Count() >= 5)
return false;
}
// We can enter a cell with nonshareable units only if we can crush all of them
if (Info.Crushes == null && nonshareable.Count() > 0)
if (Info.Crushes == null && nonshareable.Length > 0)
return false;
if (nonshareable.Any(a => !(a.traits.Contains<ICrushable>() &&
a.traits.WithInterface<ICrushable>().Any(b => b.CrushClasses.Intersect(Info.Crushes).Any()))))
if (nonshareable.Length > 0 && nonshareable.Any(a => !(a.HasTrait<ICrushable>() &&
a.TraitsImplementing<ICrushable>().Any(b => b.CrushClasses.Intersect(Info.Crushes).Any()))))
return false;
}
return MovementCostForCell(self, cell) < float.PositiveInfinity;
return true;
}
public virtual void FinishedMoving(Actor self)
{
var crushable = self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(self.Location).Where(a => a != self && a.traits.Contains<ICrushable>());
var crushable = uim.GetUnitsAt(toCell).Where(a => a != self && a.HasTrait<ICrushable>());
foreach (var a in crushable)
{
var crushActions = a.traits.WithInterface<ICrushable>().Where(b => b.CrushClasses.Intersect(Info.Crushes).Any());
var crushActions = a.TraitsImplementing<ICrushable>().Where(b => b.CrushClasses.Intersect(Info.Crushes).Any());
foreach (var b in crushActions)
b.OnCrush(self);
}
}
public virtual float MovementCostForCell(Actor self, int2 cell)
{
if (!self.World.Map.IsInMap(cell.X,cell.Y))
return float.PositiveInfinity;
var type = self.World.GetTerrainType(cell);
var additionalCost = self.World.WorldActor.traits.WithInterface<ITerrainCost>()
.Select( t => t.GetTerrainCost(cell, self) ).Sum();
return TerrainCost[type] + additionalCost;
return TerrainCost[type];
}
public virtual float MovementSpeedForCell(Actor self, int2 cell)
{
var unitInfo = self.Info.Traits.GetOrDefault<UnitInfo>();
if( unitInfo == null )
return 0f;
{
var type = self.World.GetTerrainType(cell);
var modifier = self.traits
.WithInterface<ISpeedModifier>()
var modifier = self
.TraitsImplementing<ISpeedModifier>()
.Select(t => t.GetSpeedModifier())
.Product();
return unitInfo.Speed * TerrainSpeed[type] * modifier;
return Info.Speed * TerrainSpeed[type] * modifier;
}
public IEnumerable<float2> GetCurrentPath(Actor self)
@@ -235,12 +280,12 @@ namespace OpenRA.Traits
public virtual void AddInfluence()
{
self.World.WorldActor.traits.Get<UnitInfluence>().Add( self, this );
uim.Add( self, this );
}
public virtual void RemoveInfluence()
{
self.World.WorldActor.traits.Get<UnitInfluence>().Remove( self, this );
uim.Remove( self, this );
}
public void OnNudge(Actor self, Actor nudger)
@@ -261,11 +306,11 @@ namespace OpenRA.Traits
for( var i = -1; i < 2; i++ )
for (var j = -1; j < 2; j++)
{
var p = self.Location + new int2(i, j);
var p = toCell + new int2(i, j);
if (CanEnterCell(p))
availCells.Add(p);
else
if (p != nudger.Location && p != self.Location)
if (p != nudger.Location && p != toCell)
notStupidCells.Add(p);
}
@@ -275,6 +320,13 @@ namespace OpenRA.Traits
if (moveTo.HasValue)
{
self.CancelActivity();
if (self.Owner == self.World.LocalPlayer)
self.World.AddFrameEndTask(w =>
{
var line = self.TraitOrDefault<DrawLineToTarget>();
if (line != null)
line.SetTargetSilently(self, Target.FromCell(moveTo.Value), Color.Green);
});
self.QueueActivity(new Move(moveTo.Value, 0));
}
}

View File

@@ -0,0 +1,89 @@
#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;
namespace OpenRA.Traits
{
public class DeveloperModeInfo : ITraitInfo
{
public int Cash = 20000;
public bool FastBuild = false;
public bool FastCharge = false;
public bool DisableShroud = false;
public bool PathDebug = false;
public object Create (ActorInitializer init) { return new DeveloperMode(this); }
}
public class DeveloperMode : IResolveOrder
{
DeveloperModeInfo Info;
[Sync]
public bool FastCharge;
public bool FastBuild;
public bool DisableShroud;
public bool PathDebug;
public DeveloperMode(DeveloperModeInfo info)
{
Info = info;
FastBuild = Info.FastBuild;
FastCharge = Info.FastCharge;
DisableShroud = Info.DisableShroud;
PathDebug = Info.PathDebug;
}
public void ResolveOrder (Actor self, Order order)
{
if (!Game.LobbyInfo.GlobalSettings.AllowCheats) return;
switch(order.OrderString)
{
case "DevFastCharge":
{
FastCharge ^= true;
break;
}
case "DevFastBuild":
{
FastBuild ^= true;
break;
}
case "DevGiveCash":
{
self.Trait<PlayerResources>().GiveCash(Info.Cash);
break;
}
case "DevShroud":
{
if (self.World.LocalPlayer == self.Owner)
{
DisableShroud ^= true;
Game.world.LocalPlayer.Shroud.Disabled = DisableShroud;
}
break;
}
case "DevPathDebug":
{
if (self.World.LocalPlayer == self.Owner)
PathDebug ^= true;
break;
}
case "DevUnitDebug":
{
if (self.World.LocalPlayer == self.Owner)
Game.Settings.UnitDebug ^= true;
break;
}
}
}
}
}

View File

@@ -11,6 +11,7 @@
using System.Linq;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.FileFormats;
namespace OpenRA.Traits
{
@@ -26,7 +27,7 @@ namespace OpenRA.Traits
{
var prevItems = GetNumBuildables(self.Owner);
var queue = self.traits.Get<ProductionQueue>();
var queue = self.Trait<ProductionQueue>();
var unit = Rules.Info[order.TargetString];
var producing = queue.CurrentItem(unit.Category);
@@ -40,7 +41,12 @@ namespace OpenRA.Traits
bool playSounds = true;
foreach (var t in LineBuildUtils.GetLineBuildCells(w, order.TargetLocation, order.TargetString, buildingInfo))
{
var building = w.CreateActor(order.TargetString, t, order.Player);
var building = w.CreateActor(order.TargetString, new TypeDictionary
{
new LocationInit( t ),
new OwnerInit( order.Player ),
});
if (playSounds)
foreach (var s in buildingInfo.BuildSounds)
Sound.PlayToPlayer(order.Player, s, building.CenterLocation);
@@ -49,7 +55,11 @@ namespace OpenRA.Traits
}
else
{
var building = w.CreateActor(order.TargetString, order.TargetLocation, order.Player);
var building = w.CreateActor(order.TargetString, new TypeDictionary
{
new LocationInit( order.TargetLocation ),
new OwnerInit( order.Player ),
});
foreach (var s in buildingInfo.BuildSounds)
Sound.PlayToPlayer(order.Player, s, building.CenterLocation);
}
@@ -72,11 +82,11 @@ namespace OpenRA.Traits
var producers = self.World.Queries.OwnedBy[ self.Owner ].WithTrait<Production>()
.Where( x => x.Actor.Info.Traits.Get<ProductionInfo>().Produces.Contains( unit.Category ) )
.ToList();
var producer = producers.Where( x => x.Trait.IsPrimary ).Concat( producers )
var producer = producers.Where( x => x.Actor.IsPrimaryBuilding() ).Concat( producers )
.FirstOrDefault();
if( producer.Actor != null )
producer.Actor.traits.WithInterface<RenderSimple>().First().PlayCustomAnim( producer.Actor, "build" );
producer.Actor.TraitsImplementing<RenderSimple>().First().PlayCustomAnim( producer.Actor, "build" );
}
static int GetNumBuildables(Player p)

View File

@@ -57,7 +57,7 @@ namespace OpenRA.Traits
void TickOre(Actor self)
{
OreCapacity = self.World.Queries.OwnedBy[Owner].WithTrait<IStoreOre>()
.Sum(a => a.Actor.traits.WithInterface<IStoreOre>().Sum(b => b.Capacity));
.Sum(a => a.Actor.TraitsImplementing<IStoreOre>().Sum(b => b.Capacity));
if (Ore > OreCapacity)
Ore = OreCapacity;
@@ -186,6 +186,6 @@ namespace OpenRA.Traits
{
TickPower();
TickOre(self);
}
}
}
}

View File

@@ -15,14 +15,14 @@ using OpenRA.FileFormats;
namespace OpenRA.Traits
{
class ProductionQueueInfo : ITraitInfo
public class ProductionQueueInfo : ITraitInfo
{
public float BuildSpeed = 0.4f;
public readonly int LowPowerSlowdown = 3;
public object Create(ActorInitializer init) { return new ProductionQueue(init.self); }
}
class ProductionQueue : IResolveOrder, ITick
public class ProductionQueue : IResolveOrder, ITick
{
Actor self;
@@ -37,7 +37,7 @@ namespace OpenRA.Traits
{
while( p.Value.Count > 0 && !Rules.TechTree.BuildableItems( self.Owner, p.Key ).Contains( p.Value[ 0 ].Item ) )
{
self.Owner.PlayerActor.traits.Get<PlayerResources>().GiveCash(p.Value[0].TotalCost - p.Value[0].RemainingCost); // refund what's been paid so far.
self.Owner.PlayerActor.Trait<PlayerResources>().GiveCash(p.Value[0].TotalCost - p.Value[0].RemainingCost); // refund what's been paid so far.
FinishProduction(p.Key);
}
if( p.Value.Count > 0 )
@@ -101,6 +101,7 @@ namespace OpenRA.Traits
if (unit == null || ! unit.Traits.Contains<BuildableInfo>())
return 0;
if (Game.LobbyInfo.GlobalSettings.AllowCheats && self.Trait<DeveloperMode>().FastBuild) return 0;
var ui = unit.Traits.Get<BuildableInfo>();
var time = ui.Cost
* self.Owner.PlayerActor.Info.Traits.Get<ProductionQueueInfo>().BuildSpeed /* todo: country-specific build speed bonus */
@@ -138,7 +139,7 @@ namespace OpenRA.Traits
else if( lastIndex == 0 )
{
var item = queue[0];
self.Owner.PlayerActor.traits.Get<PlayerResources>().GiveCash(item.TotalCost - item.RemainingCost); // refund what's been paid so far.
self.Owner.PlayerActor.Trait<PlayerResources>().GiveCash(item.TotalCost - item.RemainingCost); // refund what's been paid so far.
FinishProduction(category);
}
}
@@ -155,51 +156,43 @@ namespace OpenRA.Traits
production[group].Add(item);
}
static bool IsDisabledBuilding(Actor a)
{
var building = a.TraitOrDefault<Building>();
return building != null && building.Disabled;
}
void BuildUnit( string name )
{
var newUnitType = Rules.Info[ name ];
var producerTypes = Rules.TechTree.UnitBuiltAt( newUnitType );
Actor producer = null;
// Prioritise primary structure in build order
var primaryProducers = self.World.Queries.OwnedBy[self.Owner]
var producers = self.World.Queries.OwnedBy[self.Owner]
.WithTrait<Production>()
.Where(x => producerTypes.Contains(x.Actor.Info)
&& x.Trait.IsPrimary);
foreach (var p in primaryProducers)
.Where(x => producerTypes.Contains(x.Actor.Info))
.OrderByDescending(x => x.Actor.IsPrimaryBuilding() ? 1 : 0 ) // prioritize the primary.
.ToArray();
if (producers.Length == 0)
{
// Ignore buildings that are disabled
if (p.Actor.traits.Contains<Building>() && p.Actor.traits.Get<Building>().Disabled)
continue;
producer = p.Actor;
break;
}
// TODO: Be smart about disabled buildings. Units in progress should be paused(?)
// Ignore this for now
// Pick the first available producer
if (producer == null)
{
producer = self.World.Queries.OwnedBy[self.Owner]
.Where( x => producerTypes.Contains( x.Info ) )
.FirstOrDefault();
}
// Something went wrong somewhere...
if( producer == null )
{
CancelProduction( name );
CancelProduction(name);
return;
}
foreach (var p in producers)
{
if (IsDisabledBuilding(p.Actor)) continue;
if( producer.traits.WithInterface<Production>().Any( p => p.Produce( producer, newUnitType ) ) )
FinishProduction( newUnitType.Category );
if (p.Trait.Produce(p.Actor, newUnitType))
{
FinishProduction(newUnitType.Category);
break;
}
}
}
}
class ProductionItem
public class ProductionItem
{
public readonly string Item;
@@ -234,7 +227,7 @@ namespace OpenRA.Traits
if (Paused) return;
if (player.PlayerActor.traits.Get<PlayerResources>().GetPowerState() != PowerState.Normal)
if (player.PlayerActor.Trait<PlayerResources>().GetPowerState() != PowerState.Normal)
{
if (--slowdown <= 0)
slowdown = player.PlayerActor.Info.Traits.Get<ProductionQueueInfo>().LowPowerSlowdown;
@@ -243,7 +236,7 @@ namespace OpenRA.Traits
}
var costThisFrame = RemainingCost / RemainingTime;
if (costThisFrame != 0 && !player.PlayerActor.traits.Get<PlayerResources>().TakeCash(costThisFrame)) return;
if (costThisFrame != 0 && !player.PlayerActor.Trait<PlayerResources>().TakeCash(costThisFrame)) return;
RemainingCost -= costThisFrame;
RemainingTime -= 1;
if (RemainingTime > 0) return;

View File

@@ -36,7 +36,7 @@ namespace OpenRA.Traits
{
var effectivePrereq = prerequisites.Where( a => a.Traits.Get<BuildableInfo>().Owner.Contains( owner.Country.Race ) );
var nowHasPrerequisites = effectivePrereq.Any() &&
effectivePrereq.All( a => buildings[ a.Name ].Any( b => !b.traits.Get<Building>().Disabled ) );
effectivePrereq.All( a => buildings[ a.Name ].Any( b => !b.Trait<Building>().Disabled ) );
if( nowHasPrerequisites && !hasPrerequisites )
watcher.Available();

View File

@@ -0,0 +1,77 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.Traits
{
class PrimaryBuildingInfo : TraitInfo<PrimaryBuilding> { }
class PrimaryBuilding : IIssueOrder, IResolveOrder, IOrderCursor, ITags
{
bool isPrimary = false;
public bool IsPrimary { get { return isPrimary; } }
public IEnumerable<TagType> GetTags()
{
yield return (isPrimary) ? TagType.Primary : TagType.None;
}
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (mi.Button == MouseButton.Right && underCursor == self)
return new Order("PrimaryProducer", self);
return null;
}
public string CursorForOrder(Actor self, Order order)
{
return (order.OrderString == "PrimaryProducer") ? "deploy" : null;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "PrimaryProducer")
SetPrimaryProducer(self, !isPrimary);
}
public void SetPrimaryProducer(Actor self, bool state)
{
if (state == false)
{
isPrimary = false;
return;
}
// Cancel existing primaries
foreach (var p in self.Info.Traits.Get<ProductionInfo>().Produces)
foreach (var b in self.World.Queries.OwnedBy[self.Owner]
.WithTrait<PrimaryBuilding>()
.Where(x => x.Trait.IsPrimary
&& (x.Actor.Info.Traits.Get<ProductionInfo>().Produces.Contains(p))))
b.Trait.SetPrimaryProducer(b.Actor, false);
isPrimary = true;
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.PlayToPlayer(self.Owner, eva.PrimaryBuildingSelected);
}
}
static class PrimaryExts
{
public static bool IsPrimaryBuilding(this Actor a)
{
var pb = a.TraitOrDefault<PrimaryBuilding>();
return pb != null && pb.IsPrimary;
}
}
}

View File

@@ -9,130 +9,105 @@
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.GameRules;
using System.Drawing;
using OpenRA.FileFormats;
namespace OpenRA.Traits
{
public class ProductionInfo : TraitInfo<Production>
public class ProductionInfo : ITraitInfo
{
public readonly int[] SpawnOffset = null;
public readonly int[] ProductionOffset = null;
public readonly int[] ExitOffset = null;
public readonly float[] SpawnOffsets; // in px relative to CenterLocation
public readonly int[] ExitCells; // in cells relative to TopLeft, supports a list for multiple exits
public readonly string[] Produces = { };
public virtual object Create(ActorInitializer init) { return new Production(this); }
}
public class Production : IIssueOrder, IResolveOrder, ITags, IOrderCursor
public class Production
{
public virtual int2? CreationLocation( Actor self, ActorInfo producee )
public readonly List<Pair<float2, int2>> Spawns = new List<Pair<float2, int2>>();
public Production(ProductionInfo info)
{
var pos = Util.CellContaining(self.CenterLocation);
var pi = self.Info.Traits.Get<ProductionInfo>();
if (pi.ProductionOffset != null)
pos += pi.ProductionOffset.AsInt2();
return pos;
}
public virtual int2? ExitLocation(Actor self, ActorInfo producee)
{
var pos = Util.CellContaining(self.CenterLocation);
var pi = self.Info.Traits.Get<ProductionInfo>();
if (pi.ExitOffset != null)
pos += pi.ExitOffset.AsInt2();
return pos;
if (info.SpawnOffsets == null || info.ExitCells == null)
return;
if (info.SpawnOffsets.Length != info.ExitCells.Length)
throw new System.InvalidOperationException("SpawnOffset, ExitCells length mismatch");
for (int i = 0; i < info.ExitCells.Length; i+=2)
Spawns.Add(Pair.New(new float2(info.SpawnOffsets[i],info.SpawnOffsets[i+1]), new int2(info.ExitCells[i], info.ExitCells[i+1])));
}
public virtual int CreationFacing( Actor self, Actor newUnit )
public void DoProduction(Actor self, Actor newUnit, int2 exit, float2 spawn)
{
return newUnit.Info.Traits.GetOrDefault<UnitInfo>().InitialFacing;
}
var move = newUnit.Trait<IMove>();
var facing = newUnit.TraitOrDefault<IFacing>();
// Set the physical position of the unit as the exit cell
move.SetPosition(newUnit,exit);
var to = Util.CenterOfCell(exit);
newUnit.CenterLocation = spawn;
if (facing != null)
facing.Facing = Util.GetFacing(to - spawn, facing.Facing);
self.World.Add(newUnit);
public virtual bool Produce( Actor self, ActorInfo producee )
{
var location = CreationLocation( self, producee );
if( location == null || self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt( location.Value ).Any() )
return false;
var newUnit = self.World.CreateActor( producee.Name, location.Value, self.Owner );
newUnit.traits.Get<Unit>().Facing = CreationFacing( self, newUnit ); ;
var pi = self.Info.Traits.Get<ProductionInfo>();
var rp = self.traits.GetOrDefault<RallyPoint>();
if (rp != null || pi.ExitOffset != null)
// Animate the spawn -> exit transition
var speed = move.MovementSpeedForCell(self, exit);
var length = speed > 0 ? (int)( ( to - spawn ).Length*3 / speed ) : 0;
newUnit.QueueActivity(new Activities.Drag(spawn, to, length));
// For the target line
var target = exit;
var rp = self.TraitOrDefault<RallyPoint>();
if (rp != null)
{
var mobile = newUnit.traits.GetOrDefault<Mobile>();
if (mobile != null)
target = rp.rallyPoint;
// Todo: Move implies unit has Mobile
newUnit.QueueActivity(new Activities.Move(target, 1));
}
if (newUnit.Owner == self.World.LocalPlayer)
{
self.World.AddFrameEndTask(w =>
{
if (pi.ExitOffset != null)
newUnit.QueueActivity(new Activities.Move(ExitLocation(self, producee).Value, 1));
if (rp != null)
newUnit.QueueActivity(new Activities.Move(rp.rallyPoint, 1));
}
var line = newUnit.TraitOrDefault<DrawLineToTarget>();
if (line != null)
line.SetTargetSilently(newUnit, Target.FromCell(target), Color.Green);
});
}
if (pi != null && pi.SpawnOffset != null)
newUnit.CenterLocation = self.CenterLocation + pi.SpawnOffset.AsInt2();
foreach (var t in self.traits.WithInterface<INotifyProduction>())
t.UnitProduced(self, newUnit);
foreach (var t in self.TraitsImplementing<INotifyProduction>())
t.UnitProduced(self, newUnit, exit);
Log.Write("debug", "{0} #{1} produced by {2} #{3}", newUnit.Info.Name, newUnit.ActorID, self.Info.Name, self.ActorID);
return true;
}
// "primary building" crap - perhaps this should be split?
bool isPrimary = false;
public bool IsPrimary { get { return isPrimary; } }
public IEnumerable<TagType> GetTags()
{
yield return (isPrimary) ? TagType.Primary : TagType.None;
}
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (mi.Button == MouseButton.Right && underCursor == self)
return new Order("Deploy", self);
return null;
}
public string CursorForOrder(Actor self, Order order)
{
return (order.OrderString == "Deploy") ? "deploy" : null;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Deploy")
SetPrimaryProducer(self, !isPrimary);
}
public void SetPrimaryProducer(Actor self, bool state)
{
if (state == false)
public virtual bool Produce( Actor self, ActorInfo producee )
{
var newUnit = self.World.CreateActor(false, producee.Name, new TypeDictionary
{
isPrimary = false;
return;
}
new OwnerInit( self.Owner ),
});
// Cancel existing primaries
foreach (var p in self.Info.Traits.Get<ProductionInfo>().Produces)
// Todo: remove assumption on Mobile;
// required for 3-arg CanEnterCell
var mobile = newUnit.Trait<Mobile>();
// Pick a spawn/exit point pair
// Todo: Reorder in a synced random way
foreach (var s in Spawns)
{
foreach (var b in self.World.Queries.OwnedBy[self.Owner]
.WithTrait<Production>()
.Where(x => x.Trait.IsPrimary
&& (x.Actor.Info.Traits.Get<ProductionInfo>().Produces.Contains(p))))
var exit = self.Location + s.Second;
var spawn = self.CenterLocation + s.First;
if (mobile.CanEnterCell(exit,self,true))
{
b.Trait.SetPrimaryProducer(b.Actor, false);
DoProduction(self, newUnit, exit, spawn);
return true;
}
}
isPrimary = true;
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.PlayToPlayer(self.Owner,eva.PrimaryBuildingSelected);
return false;
}
}
}

View File

@@ -12,9 +12,9 @@ using System.Linq;
namespace OpenRA.Traits
{
class ProvidesRadarInfo : TraitInfo<ProvidesRadar> { }
public class ProvidesRadarInfo : TraitInfo<ProvidesRadar> { }
class ProvidesRadar : ITick
public class ProvidesRadar : ITick
{
public bool IsActive { get; private set; }
@@ -23,7 +23,7 @@ namespace OpenRA.Traits
bool UpdateActive(Actor self)
{
// Check if powered
var b = self.traits.Get<Building>();
var b = self.Trait<Building>();
if (b.Disabled) return false;
var isJammed = self.World.Queries.WithTrait<JamsRadar>().Any(a => self.Owner != a.Actor.Owner

View File

@@ -37,7 +37,7 @@ namespace OpenRA.Traits
public IEnumerable<Renderable> Render(Actor self)
{
if (self.Owner == self.World.LocalPlayer && Game.controller.selection.Actors.Contains(self))
if (self.Owner == self.World.LocalPlayer && self.World.Selection.Actors.Contains(self))
yield return Util.Centered(self,
anim.Image, Util.CenterOfCell(rallyPoint));
}

View File

@@ -64,7 +64,7 @@ namespace OpenRA.Traits
protected virtual string GetPrefix(Actor self)
{
return self.GetDamageState() == DamageState.Half ? "damaged-" : "";
return self.GetDamageState() >= DamageState.Heavy ? "damaged-" : "";
}
public void PlayCustomAnim(Actor self, string name)

View File

@@ -0,0 +1,85 @@
#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.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Traits.Activities;
namespace OpenRA.Traits
{
public class RepairableBuildingInfo : ITraitInfo, ITraitPrerequisite<HealthInfo>
{
public readonly float RepairPercent = 0.2f;
public readonly float RepairRate = 0.016f;
public readonly int RepairStep = 7;
public object Create(ActorInitializer init) { return new RepairableBuilding(init.self, this); }
}
public class RepairableBuilding : ITick, IResolveOrder
{
[Sync]
bool isRepairing = false;
Health Health;
RepairableBuildingInfo Info;
public RepairableBuilding(Actor self, RepairableBuildingInfo info)
{
Health = self.Trait<Health>();
Info = info;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Repair")
{
isRepairing = !isRepairing;
}
}
int remainingTicks;
public void Tick(Actor self)
{
if (!isRepairing) return;
if (remainingTicks == 0)
{
var csv = self.Info.Traits.GetOrDefault<CustomSellValueInfo>();
var buildingValue = csv != null ? csv.Value : self.Info.Traits.Get<ValuedInfo>().Cost;
var costPerHp = (Info.RepairPercent * buildingValue) / Health.MaxHP;
var hpToRepair = Math.Min(Info.RepairStep, Health.MaxHP - Health.HP);
var cost = (int)Math.Ceiling(costPerHp * hpToRepair);
if (!self.Owner.PlayerActor.Trait<PlayerResources>().TakeCash(cost))
{
remainingTicks = 1;
return;
}
self.World.AddFrameEndTask(w => w.Add(new RepairIndicator(self)));
self.InflictDamage(self, -hpToRepair, null);
if (Health.DamageState == DamageState.Undamaged)
{
isRepairing = false;
return;
}
remainingTicks = (int)(Info.RepairRate * 60 * 25);
}
else
--remainingTicks;
}
}
public class AllowsBuildingRepairInfo : TraitInfo<AllowsBuildingRepair> {}
public class AllowsBuildingRepair {}
}

View File

@@ -1,30 +1,40 @@
#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 OpenRA.Traits;
namespace OpenRA.Mods.RA
{
class RevealsShroudInfo : TraitInfo<RevealsShroud> { }
class RevealsShroud : ITick
{
int2 previousLocation;
public void Tick(Actor self)
{
if (!self.IsIdle && previousLocation != self.Location)
{
previousLocation = self.Location;
self.World.WorldActor.traits.Get<Shroud>().UpdateActor(self);
}
}
}
}
#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
namespace OpenRA.Traits
{
class RevealsShroudInfo : ITraitInfo
{
public readonly int Range = 0;
public object Create(ActorInitializer init) { return new RevealsShroud(this); }
}
class RevealsShroud : ITick
{
RevealsShroudInfo Info;
int2 previousLocation;
public RevealsShroud(RevealsShroudInfo info)
{
Info = info;
}
public void Tick(Actor self)
{
if (!self.IsIdle && previousLocation != self.Location)
{
previousLocation = self.Location;
self.World.WorldActor.Trait<Shroud>().UpdateActor(self);
}
}
public int RevealRange { get { return Info.Range; } }
}
}

161
OpenRA.Game/Traits/Selectable.cs Executable file → Normal file
View File

@@ -8,6 +8,10 @@
*/
#endregion
using System.Drawing;
using OpenRA.Graphics;
using System.Linq;
namespace OpenRA.Traits
{
public class SelectableInfo : TraitInfo<Selectable>
@@ -19,5 +23,160 @@ namespace OpenRA.Traits
public readonly float Radius = 10;
}
public class Selectable {}
public class Selectable : IPostRenderSelection
{
// depends on the order of pips in TraitsInterfaces.cs!
static readonly string[] pipStrings = { "pip-empty", "pip-green", "pip-yellow", "pip-red", "pip-gray" };
static readonly string[] tagStrings = { "", "tag-fake", "tag-primary" };
public void RenderAfterWorld (Actor self)
{
var bounds = self.GetBounds(true);
var xy = new float2(bounds.Left, bounds.Top);
var Xy = new float2(bounds.Right, bounds.Top);
var xY = new float2(bounds.Left, bounds.Bottom);
var XY = new float2(bounds.Right, bounds.Bottom);
DrawSelectionBox(self, xy, Xy, xY, XY, Color.White);
DrawHealthBar(self, xy, Xy);
DrawControlGroup(self, xy);
DrawPips(self, xY);
DrawTags(self, new float2(.5f * (bounds.Left + bounds.Right), bounds.Top));
DrawUnitPath(self);
}
void DrawSelectionBox(Actor self, float2 xy, float2 Xy, float2 xY, float2 XY, Color c)
{
Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(0, 4), c, c);
Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(-4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(0, 4), c, c);
Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(0, -4), c, c);
Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(-4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c);
}
void DrawHealthBar(Actor self, float2 xy, float2 Xy)
{
var health = self.TraitOrDefault<Health>();
if (self.IsDead() || health == null)
return;
var c = Color.Gray;
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), xy + new float2(0, -4), c, c);
Game.Renderer.LineRenderer.DrawLine(Xy + new float2(0, -2), Xy + new float2(0, -4), c, c);
var healthColor = (health.DamageState == DamageState.Critical) ? Color.Red :
(health.DamageState == DamageState.Heavy) ? Color.Yellow : Color.LimeGreen;
var healthColor2 = Color.FromArgb(
255,
healthColor.R / 2,
healthColor.G / 2,
healthColor.B / 2);
var z = float2.Lerp(xy, Xy, health.HPFraction);
Game.Renderer.LineRenderer.DrawLine(z + new float2(0, -4), Xy + new float2(0, -4), c, c);
Game.Renderer.LineRenderer.DrawLine(z + new float2(0, -2), Xy + new float2(0, -2), c, c);
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -3), z + new float2(0, -3), healthColor, healthColor);
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), z + new float2(0, -2), healthColor2, healthColor2);
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -4), z + new float2(0, -4), healthColor2, healthColor2);
}
void DrawControlGroup(Actor self, float2 basePosition)
{
var group = self.World.Selection.GetControlGroupForActor(self);
if (group == null) return;
var pipImages = new Animation("pips");
pipImages.PlayFetchIndex("groups", () => (int)group);
pipImages.Tick();
Game.Renderer.SpriteRenderer.DrawSprite(pipImages.Image, basePosition + new float2(-8, 1), "chrome");
}
void DrawPips(Actor self, float2 basePosition)
{
if (self.Owner != self.World.LocalPlayer) return;
// If a mod wants to implement a unit with multiple pip sources, then they are placed on multiple rows
var pipxyBase = basePosition + new float2(-12, -7); // Correct for the offset in the shp file
var pipxyOffset = new float2(0, 0); // Correct for offset due to multiple columns/rows
foreach (var pips in self.TraitsImplementing<IPips>())
{
foreach (var pip in pips.GetPips(self))
{
if (pipxyOffset.X+5 > self.GetBounds(false).Width)
{
pipxyOffset.X = 0;
pipxyOffset.Y -= 4;
}
var pipImages = new Animation("pips");
pipImages.PlayRepeating(pipStrings[(int)pip]);
Game.Renderer.SpriteRenderer.DrawSprite(pipImages.Image, pipxyBase + pipxyOffset, "chrome");
pipxyOffset += new float2(4, 0);
}
// Increment row
pipxyOffset.X = 0;
pipxyOffset.Y -= 5;
}
}
void DrawTags(Actor self, float2 basePosition)
{
if (self.Owner != self.World.LocalPlayer) return;
// If a mod wants to implement a unit with multiple tags, then they are placed on multiple rows
var tagxyBase = basePosition + new float2(-16, 2); // Correct for the offset in the shp file
var tagxyOffset = new float2(0, 0); // Correct for offset due to multiple rows
foreach (var tags in self.TraitsImplementing<ITags>())
{
foreach (var tag in tags.GetTags())
{
if (tag == TagType.None)
continue;
var tagImages = new Animation("pips");
tagImages.PlayRepeating(tagStrings[(int)tag]);
Game.Renderer.SpriteRenderer.DrawSprite(tagImages.Image, tagxyBase + tagxyOffset, "chrome");
// Increment row
tagxyOffset.Y += 8;
}
}
}
void DrawUnitPath(Actor self)
{
if (!Game.world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
var mobile = self.TraitOrDefault<IMove>();
if (mobile != null)
{
var alt = new float2(0, -mobile.Altitude);
var path = mobile.GetCurrentPath(self);
var start = self.CenterLocation + alt;
var c = Color.Green;
foreach (var step in path)
{
var stp = step + alt;
Game.Renderer.LineRenderer.DrawLine(stp + new float2(-1, -1), stp + new float2(-1, 1), c, c);
Game.Renderer.LineRenderer.DrawLine(stp + new float2(-1, 1), stp + new float2(1, 1), c, c);
Game.Renderer.LineRenderer.DrawLine(stp + new float2(1, 1), stp + new float2(1, -1), c, c);
Game.Renderer.LineRenderer.DrawLine(stp + new float2(1, -1), stp + new float2(-1, -1), c, c);
Game.Renderer.LineRenderer.DrawLine(start, stp, c, c);
start = stp;
}
}
}
}
}

View File

@@ -56,7 +56,7 @@ namespace OpenRA.Traits
RemainingTime = TotalTime;
Owner = self.Owner;
self.traits.Get<TechTreeCache>().Add( Info.Prerequisites.Select( a => Rules.Info[ a.ToLowerInvariant() ] ).ToList(), this );
self.Trait<TechTreeCache>().Add( Info.Prerequisites.Select( a => Rules.Info[ a.ToLowerInvariant() ] ).ToList(), this );
}
public void Tick(Actor self)
@@ -69,6 +69,7 @@ namespace OpenRA.Traits
if (IsAvailable && (!Info.RequiresPower || IsPowered()))
{
if (Game.LobbyInfo.GlobalSettings.AllowCheats && self.Trait<DeveloperMode>().FastCharge) RemainingTime = 0;
if (RemainingTime > 0) --RemainingTime;
if (!notifiedCharging)
{
@@ -95,10 +96,10 @@ namespace OpenRA.Traits
.Where(a => Rules.Info[a].Traits.Get<ValuedInfo>().Owner.Contains(Owner.Country.Race));
if (Info.Prerequisites.Count() == 0)
return Owner.PlayerActor.traits.Get<PlayerResources>().GetPowerState() == PowerState.Normal;
return Owner.PlayerActor.Trait<PlayerResources>().GetPowerState() == PowerState.Normal;
return effectivePrereq.Any() &&
effectivePrereq.All(a => buildings[a].Any(b => !b.traits.Get<Building>().Disabled));
effectivePrereq.All(a => buildings[a].Any(b => !b.Trait<Building>().Disabled));
}
public void FinishActivate()

View File

@@ -1,23 +1,26 @@
#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.
*/
#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.FileFormats;
using System.Drawing;
using OpenRA.Graphics;
using System.Linq;
namespace MapConverter
namespace OpenRA.Traits
{
class MainClass
public class TargetableInfo : TraitInfo<Targetable>
{
public static void Main (string[] args)
{
new MapConverter(args);
}
public readonly string[] TargetTypes = {};
}
public class Targetable
{
}
}

View File

@@ -12,11 +12,10 @@ using System.Collections.Generic;
using System.Drawing;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.FileFormats;
namespace OpenRA.Traits
{
public enum DamageState { Normal, Half, Dead };
// depends on the order of pips in WorldRenderer.cs!
public enum PipType { Transparent, Green, Yellow, Red, Gray };
public enum TagType { None, Fake, Primary };
@@ -28,6 +27,7 @@ namespace OpenRA.Traits
public WarheadInfo Warhead;
public int Damage;
public DamageState DamageState;
public DamageState PreviousDamageState;
public bool DamageStateChanged;
}
@@ -41,16 +41,12 @@ namespace OpenRA.Traits
public interface INotifySold { void Selling( Actor self ); void Sold( Actor self ); }
public interface INotifyDamage { void Damaged(Actor self, AttackInfo e); }
public interface INotifyBuildComplete { void BuildingComplete(Actor self); }
public interface INotifyProduction { void UnitProduced(Actor self, Actor other); }
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 IProvideHazard { IEnumerable<HazardLayer.Hazard> HazardCells(Actor self); }
public interface IAvoidHazard { string Type { get; } }
public interface IStoreOre { int Capacity { get; }}
public interface ITerrainCost { float GetTerrainCost(int2 cell, Actor forActor); }
public interface IDisable { bool Disabled { get; } }
public interface IExplodeModifier { bool ShouldExplode(Actor self); }
public interface INudge { void OnNudge(Actor self, Actor nudger); }
@@ -61,9 +57,8 @@ namespace OpenRA.Traits
Color RadarSignatureColor(Actor self);
}
public interface IRadarVisibilityModifier { bool VisibleOnRadar(Actor self); }
public interface IVisibilityModifier { bool IsVisible(Actor self); }
public interface IRadarColorModifier { Color RadarColorOverride(Actor self); }
public interface IOccupySpace
{
int2 TopLeft { get; }
@@ -101,16 +96,29 @@ namespace OpenRA.Traits
public interface ISpeedModifier { float GetSpeedModifier(); }
public interface IPowerModifier { float GetPowerModifier(); }
public interface IFirepowerModifier { float GetFirepowerModifier(); }
public interface IPaletteModifier { void AdjustPalette(Bitmap b); }
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 IMove
public interface ITeleportable /* crap name! */
{
bool CanEnterCell(int2 location);
void SetPosition(Actor self, int2 cell);
}
public interface IMove : ITeleportable
{
float MovementCostForCell(Actor self, int2 cell);
float MovementSpeedForCell(Actor self, int2 cell);
IEnumerable<float2> GetCurrentPath(Actor self);
void SetPosition(Actor self, int2 cell);
int Altitude { get; set; }
}
public interface IFacing
{
int ROT { get; }
int Facing { get; set; }
int InitialFacing { get; }
}
public interface IOffsetCenterLocation { float2 CenterOffset { get; } }
@@ -163,9 +171,11 @@ namespace OpenRA.Traits
public interface IRenderOverlay { void Render(); }
public interface INotifyIdle { void Idle(Actor self); }
public interface IVictoryConditions { }
public interface IBlocksBullets { }
public interface IPostRenderSelection { void RenderAfterWorld(Actor self); }
public interface IPreRenderSelection { void RenderBeforeWorld(Actor self); }
public struct Target // a target: either an actor, or a fixed location.
{
Actor actor;

View File

@@ -10,12 +10,12 @@
namespace OpenRA.Traits
{
class TurretedInfo : ITraitInfo
public class TurretedInfo : ITraitInfo
{
public readonly int ROT = 255;
public readonly int InitialFacing = 128;
public object Create(ActorInitializer init) { return new Turreted(init.self); }
public object Create(ActorInitializer init) { return new Turreted(init.self, this); }
}
public class Turreted : ITick
@@ -23,16 +23,20 @@ namespace OpenRA.Traits
[Sync]
public int turretFacing = 0;
public int? desiredFacing;
public Turreted(Actor self)
TurretedInfo info;
IFacing facing;
public Turreted(Actor self, TurretedInfo info)
{
turretFacing = self.Info.Traits.Get<TurretedInfo>().InitialFacing;
this.info = info;
turretFacing = info.InitialFacing;
facing = self.TraitOrDefault<IFacing>();
}
public void Tick( Actor self )
{
var df = desiredFacing ?? ( self.traits.Contains<Unit>() ? self.traits.Get<Unit>().Facing : turretFacing );
Util.TickFacing(ref turretFacing, df, self.Info.Traits.Get<TurretedInfo>().ROT);
var df = desiredFacing ?? ( facing != null ? facing.Facing : turretFacing );
turretFacing = Util.TickFacing(turretFacing, df, info.ROT);
}
}
}

View File

@@ -1,58 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace OpenRA.Traits
{
public class UnitInfo : OwnedActorInfo, ITraitInfo
{
public readonly int InitialFacing = 128;
public readonly int ROT = 255;
public readonly int Speed = 1;
public object Create( ActorInitializer init ) { return new Unit(); }
}
public class Unit : INotifyDamage, IRadarSignature
{
[Sync]
public int Facing;
[Sync]
public int Altitude;
public void Damaged(Actor self, AttackInfo e)
{
if (e.DamageState == DamageState.Dead)
if (self.Owner == self.World.LocalPlayer)
Sound.PlayVoice("Lost", self);
}
public IEnumerable<int2> RadarSignatureCells(Actor self)
{
foreach (var mod in self.traits.WithInterface<IRadarVisibilityModifier>())
if (!mod.VisibleOnRadar(self))
yield break;
yield return self.Location;
}
public Color RadarSignatureColor(Actor self)
{
var mod = self.traits.WithInterface<IRadarColorModifier>().FirstOrDefault();
if (mod != null)
return mod.RadarColorOverride(self);
return self.Owner.Color;
}
}
}

View File

@@ -17,16 +17,16 @@ namespace OpenRA.Traits
{
public static class Util
{
public static void TickFacing( ref int facing, int desiredFacing, int rot )
public static int TickFacing( int facing, int desiredFacing, int rot )
{
var leftTurn = ( facing - desiredFacing ) & 0xFF;
var rightTurn = ( desiredFacing - facing ) & 0xFF;
if( Math.Min( leftTurn, rightTurn ) < rot )
facing = desiredFacing & 0xFF;
return desiredFacing & 0xFF;
else if( rightTurn < leftTurn )
facing = ( facing + rot ) & 0xFF;
return ( facing + rot ) & 0xFF;
else
facing = ( facing - rot ) & 0xFF;
return ( facing - rot ) & 0xFF;
}
static float2[] fvecs = Graphics.Util.MakeArray<float2>( 32,

View File

@@ -1,87 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Traits
{
public class AircraftInfluenceInfo : ITraitInfo
{
public object Create( ActorInitializer init ) { return new AircraftInfluence( init.world ); }
}
public class AircraftInfluence : ITick
{
List<Actor>[,] influence;
Map map;
public AircraftInfluence( World world )
{
map = world.Map;
influence = new List<Actor>[world.Map.MapSize.X, world.Map.MapSize.Y];
for (int i = 0; i < world.Map.MapSize.X; i++)
for (int j = 0; j < world.Map.MapSize.Y; j++)
influence[ i, j ] = new List<Actor>();
world.ActorRemoved += a => Remove( a, a.traits.GetOrDefault<IOccupyAir>() );
}
public void Tick( Actor self )
{
SanityCheck( self );
}
[Conditional( "SANITY_CHECKS" )]
void SanityCheck( Actor self )
{
for( int x = 0 ; x < self.World.Map.MapSize.X ; x++ )
for( int y = 0 ; y < self.World.Map.MapSize.Y ; y++ )
if( influence[ x, y ] != null )
foreach (var a in influence[ x, y ])
if (!a.traits.Get<IOccupyAir>().OccupiedAirCells().Contains( new int2( x, y ) ) )
throw new InvalidOperationException( "AIM: Sanity check failed A" );
foreach( var t in self.World.Queries.WithTraitMultiple<IOccupyAir>() )
foreach( var cell in t.Trait.OccupiedAirCells() )
if (!influence[cell.X, cell.Y].Contains(t.Actor))
throw new InvalidOperationException( "AIM: Sanity check failed B" );
}
Actor[] noActors = { };
public IEnumerable<Actor> GetUnitsAt( int2 a )
{
if (!map.IsInMap(a)) return noActors;
return influence[ a.X, a.Y ];
}
public void Add( Actor self, IOccupyAir unit )
{
foreach( var c in unit.OccupiedAirCells() )
influence[c.X, c.Y].Add(self);
}
public void Remove( Actor self, IOccupyAir unit )
{
if (unit != null)
foreach (var c in unit.OccupiedAirCells())
influence[c.X, c.Y].Remove(self);
}
public void Update(Actor self, IOccupyAir unit)
{
Remove(self, unit);
if (!self.IsDead) Add(self, unit);
}
}
}

View File

@@ -1,17 +1,17 @@
#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.Drawing;
using System.Linq;
using OpenRA.FileFormats;
#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.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
namespace OpenRA.Traits
@@ -37,9 +37,9 @@ namespace OpenRA.Traits
bibSprites = info.BibTypes.Select(x => SpriteSheetBuilder.LoadAllSprites(x)).ToArray();
self.World.ActorAdded +=
a => { if (a.traits.Contains<Bib>()) DoBib(a,true); };
a => { if (a.HasTrait<Bib>()) DoBib(a,true); };
self.World.ActorRemoved +=
a => { if (a.traits.Contains<Bib>()) DoBib(a,false); };
a => { if (a.HasTrait<Bib>()) DoBib(a,false); };
}
public void WorldLoaded(World w)
@@ -56,7 +56,7 @@ namespace OpenRA.Traits
int bib = Array.IndexOf(info.BibWidths,size);
if (bib < 0)
{
{
Log.Write("debug", "Cannot bib {0}-wide building {1}", size, b.Info.Name);
return;
}
@@ -72,23 +72,23 @@ namespace OpenRA.Traits
}
public void Render()
{
var cliprect = Game.viewport.ShroudBounds().HasValue
? Rectangle.Intersect(Game.viewport.ShroudBounds().Value, world.Map.Bounds) : world.Map.Bounds;
var minx = cliprect.Left;
var maxx = cliprect.Right;
var miny = cliprect.Top;
var maxy = cliprect.Bottom;
for (int x = minx; x < maxx; x++)
{
var cliprect = Game.viewport.ShroudBounds().HasValue
? Rectangle.Intersect(Game.viewport.ShroudBounds().Value, world.Map.Bounds) : world.Map.Bounds;
var minx = cliprect.Left;
var maxx = cliprect.Right;
var miny = cliprect.Top;
var maxy = cliprect.Bottom;
for (int x = minx; x < maxx; x++)
for (int y = miny; y < maxy; y++)
{
var t = new int2(x, y);
if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.IsExplored(t) || tiles[x,y].type == 0) continue;
Game.Renderer.SpriteRenderer.DrawSprite(bibSprites[tiles[x, y].type - 1][tiles[x, y].image],
if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.IsExplored(t) || tiles[x,y].type == 0) continue;
Game.Renderer.SpriteRenderer.DrawSprite(bibSprites[tiles[x, y].type - 1][tiles[x, y].image],
Game.CellSize * t, "terrain");
}
}

View File

@@ -32,11 +32,11 @@ namespace OpenRA.Traits
influence = new Actor[map.MapSize.X, map.MapSize.Y];
world.ActorAdded +=
a => { if (a.traits.Contains<Building>())
ChangeInfluence(a, a.traits.Get<Building>(), true); };
a => { if (a.HasTrait<Building>())
ChangeInfluence(a, a.Trait<Building>(), true); };
world.ActorRemoved +=
a => { if (a.traits.Contains<Building>())
ChangeInfluence(a, a.traits.Get<Building>(), false); };
a => { if (a.HasTrait<Building>())
ChangeInfluence(a, a.Trait<Building>(), false); };
}
void ChangeInfluence( Actor a, Building building, bool isAdd )

View File

@@ -1,29 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
// THIS STUFF NEEDS TO GO DIE IN A FIRE.
namespace OpenRA.Traits
{
public class GlobalDefaultsInfo : TraitInfo<GlobalDefaults>
{
/* Repair & Refit */
public readonly float RefundPercent = 0.5f;
public readonly float RepairPercent = 0.2f;
public readonly float RepairRate = 0.016f;
public readonly int RepairStep = 7;
/* Audo/Visual Map Controls */
public readonly float ConditionRed = 0.25f;
public readonly float ConditionYellow = 0.5f;
}
public class GlobalDefaults {}
}

View File

@@ -1,75 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Traits
{
public class HazardLayerInfo : ITraitInfo
{
public object Create( ActorInitializer init ) { return new HazardLayer( init.world ); }
}
public class HazardLayer : ITerrainCost
{
List<Pair<Actor, Hazard>>[,] hazards;
public HazardLayer( World world )
{
hazards = new List<Pair<Actor, Hazard>>[world.Map.MapSize.X, world.Map.MapSize.Y];
for (int i = 0; i < world.Map.MapSize.X; i++)
for (int j = 0; j < world.Map.MapSize.Y; j++)
hazards[ i, j ] = new List<Pair<Actor, Hazard>>();
world.ActorRemoved += a => Remove( a, a.traits.GetOrDefault<IProvideHazard>() );
}
public float GetTerrainCost(int2 p, Actor forActor)
{
var avoid = forActor.traits.WithInterface<IAvoidHazard>().Select(h => h.Type).ToList();
var intensity = hazards[p.X,p.Y].Where(a => avoid.Contains(a.Second.type))
.Select(b => b.Second.intensity)
.Sum();
return intensity;
}
public void Add( Actor self, IProvideHazard hazard )
{
foreach( var h in hazard.HazardCells(self) )
{
hazards[h.location.X, h.location.Y].Add(Pair.New(self, h));
}
}
public void Remove( Actor self, IProvideHazard hazard )
{
if (hazard != null)
foreach (var h in hazard.HazardCells(self))
hazards[h.location.X, h.location.Y].Remove(Pair.New(self,h));
}
public void Update(Actor self, IProvideHazard hazard)
{
Remove(self, hazard);
if (!self.IsDead) Add(self, hazard);
}
public struct Hazard
{
public int2 location;
public string type;
public float intensity;
}
}
}

View File

@@ -55,7 +55,7 @@ namespace OpenRA.Traits
this.world = w;
content = new CellContents[w.Map.MapSize.X, w.Map.MapSize.Y];
resourceTypes = w.WorldActor.traits.WithInterface<ResourceType>().ToArray();
resourceTypes = w.WorldActor.TraitsImplementing<ResourceType>().ToArray();
foreach (var rt in resourceTypes)
rt.info.Sprites = rt.info.SpriteNames.Select(a => SpriteSheetBuilder.LoadAllSprites(a)).ToArray();

View File

@@ -14,6 +14,7 @@ using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Traits
{
@@ -63,7 +64,11 @@ namespace OpenRA.Traits
void AddActor(Actor a)
{
if (a.Owner == null || a.Owner != a.Owner.World.LocalPlayer) return;
if (!a.HasTrait<RevealsShroud>())
return;
if (a.Owner == null || a.Owner.World.LocalPlayer == null
|| a.Owner.Stances[a.Owner.World.LocalPlayer] != Stance.Ally) return;
if (vis.ContainsKey(a))
{
@@ -73,7 +78,7 @@ namespace OpenRA.Traits
var v = new ActorVisibility
{
range = a.Info.Traits.Get<OwnedActorInfo>().Sight,
range = a.Trait<RevealsShroud>().RevealRange,
vis = GetVisOrigins(a).ToArray()
};
@@ -96,6 +101,24 @@ namespace OpenRA.Traits
Dirty();
}
public void UpdatePlayerStance(World w, Player player, Stance oldStance, Stance newStance)
{
if (oldStance == newStance)
return;
// No longer our ally; remove unit vis
if (oldStance == Stance.Ally)
{
var toRemove = new List<Actor>(vis.Select(a => a.Key).Where(a => a.Owner == player));
foreach (var a in toRemove)
RemoveActor(a);
}
// Is now our ally; add unit vis
if (newStance == Stance.Ally)
foreach (var a in w.Queries.OwnedBy[player])
AddActor(a);
}
public static IEnumerable<int2> GetVisOrigins(Actor a)
{
@@ -106,7 +129,7 @@ namespace OpenRA.Traits
}
else
{
var mobile = a.traits.GetOrDefault<Mobile>();
var mobile = a.TraitOrDefault<Mobile>();
if (mobile != null)
return new[] { mobile.fromCell, mobile.toCell };
else
@@ -130,7 +153,9 @@ namespace OpenRA.Traits
public void UpdateActor(Actor a)
{
if (a.Owner == null || a.Owner != a.Owner.World.LocalPlayer) return;
if (a.Owner == null || a.Owner.World.LocalPlayer == null
|| a.Owner.Stances[a.Owner.World.LocalPlayer] != Stance.Ally) return;
RemoveActor(a); AddActor(a);
}
@@ -145,6 +170,16 @@ namespace OpenRA.Traits
Dirty();
}
public void ExploreAll(World world)
{
for (int i = map.TopLeft.X; i < map.BottomRight.X; i++)
for (int j = map.TopLeft.Y; j < map.BottomRight.Y; j++)
exploredCells[i, j] = true;
exploredBounds = new Rectangle(world.Map.TopLeft.X,world.Map.TopLeft.Y,world.Map.Width,world.Map.Height);
Dirty();
}
public void ResetExploration() // for `hide map` crate
{

View File

@@ -34,7 +34,7 @@ namespace OpenRA.Traits
for (int j = 0; j < world.Map.MapSize.Y; j++)
influence[ i, j ] = new List<Actor>();
world.ActorRemoved += a => Remove( a, a.traits.GetOrDefault<IOccupySpace>() );
world.ActorRemoved += a => Remove( a, a.TraitOrDefault<IOccupySpace>() );
}
public void Tick( Actor self )
@@ -49,7 +49,7 @@ namespace OpenRA.Traits
for( int y = 0 ; y < self.World.Map.MapSize.Y ; y++ )
if( influence[ x, y ] != null )
foreach (var a in influence[ x, y ])
if (!a.traits.Get<IOccupySpace>().OccupiedCells().Contains( new int2( x, y ) ) )
if (!a.Trait<IOccupySpace>().OccupiedCells().Contains( new int2( x, y ) ) )
throw new InvalidOperationException( "UIM: Sanity check failed A" );
foreach( var t in self.World.Queries.WithTraitMultiple<IOccupySpace>() )
@@ -65,6 +65,11 @@ namespace OpenRA.Traits
return influence[ a.X, a.Y ];
}
public bool AnyUnitsAt(int2 a)
{
return /*map.IsInMap(a) && */influence[a.X, a.Y].Count > 0;
}
public void Add( Actor self, IOccupySpace unit )
{
foreach( var c in unit.OccupiedCells() )
@@ -81,7 +86,7 @@ namespace OpenRA.Traits
public void Update(Actor self, IOccupySpace unit)
{
Remove(self, unit);
if (!self.IsDead) Add(self, unit);
if (!self.IsDead()) Add(self, unit);
}
}
}

View File

@@ -14,6 +14,7 @@ using System.Linq;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
using OpenRA.Widgets;
namespace OpenRA
{
@@ -43,7 +44,7 @@ namespace OpenRA
{
if (Game.Settings.UnitDebug)
{
var uim = world.WorldActor.traits.Get<UnitInfluence>();
var uim = world.WorldActor.Trait<UnitInfluence>();
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++)
@@ -54,7 +55,7 @@ namespace OpenRA
public void DrawBuildingGrid( World world, string name, BuildingInfo bi )
{
var position = Game.controller.MousePosition.ToInt2();
var position = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2();
var topLeft = position - Footprint.AdjustForBuildingSize( bi );
// Linebuild for walls.
@@ -67,7 +68,7 @@ namespace OpenRA
}
else
{
var res = world.WorldActor.traits.Get<ResourceLayer>();
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)

View File

@@ -14,7 +14,7 @@ using System.Linq;
namespace OpenRA.Widgets
{
class ChatDisplayWidget : Widget
public class ChatDisplayWidget : Widget
{
public readonly int RemoveTime = 0;
@@ -23,7 +23,7 @@ namespace OpenRA.Widgets
public bool DrawBackground = true;
int ticksUntilRemove = 0;
public List<ChatLine> recentLines = new List<ChatLine>();
internal List<ChatLine> recentLines = new List<ChatLine>();
public ChatDisplayWidget()
: base() { }

View File

@@ -48,6 +48,8 @@ namespace OpenRA.Widgets
public override bool HandleKeyPressInner(KeyInput e)
{
if (e.Event == KeyInputEvent.Up) return false;
if (e.KeyChar == '\r')
{
if (composing)

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